Ejemplo n.º 1
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();
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Generates weather settings (precipitation, cloud coverage, temperature...) for the mission.
        /// Must be called after mission date has been set because min/max temperature changes every month.
        /// </summary>
        /// <param name="mission">The mission.</param>
        /// <param name="weather">The preferred type of weather (clear, cloudy, storm...).</param>
        /// <param name="theater">Theater definition from which to get weather info for this part of the world.</param>
        public void GenerateWeather(DCSMission mission, Weather weather, DefinitionTheater theater)
        {
            DebugLog.Instance.Log("Generating weather conditions...");

            mission.WeatherTemperature = theater.Temperature[(int)mission.DateMonth].GetValue();

            DebugLog.Instance.Log($"  Weather should be {weather.ToString().ToUpperInvariant()}");
            mission.WeatherLevel = (weather == Weather.Random) ? HQTools.RandomFrom(RANDOM_WEATHER) : weather;

            DebugLog.Instance.Log($"    Weather quality set to {mission.WeatherLevel}");

            // Clouds and precipitations
            mission.WeatherCloudBase           = theater.Weather[(int)mission.WeatherLevel].CloudsBase.GetValue();
            mission.WeatherCloudsDensity       = theater.Weather[(int)mission.WeatherLevel].CloudsDensity.GetValue();
            mission.WeatherCloudsPrecipitation = HQTools.RandomFrom(theater.Weather[(int)mission.WeatherLevel].CloudsPrecipitation);
            mission.WeatherCloudsThickness     = theater.Weather[(int)mission.WeatherLevel].CloudsThickness.GetValue();

            // Dust
            mission.WeatherDustEnabled = HQTools.RandomFrom(theater.Weather[(int)mission.WeatherLevel].DustEnabled);
            mission.WeatherDustDensity = mission.WeatherDustEnabled ? theater.Weather[(int)mission.WeatherLevel].DustDensity.GetValue() : 0;

            // Fog
            mission.WeatherFogEnabled    = HQTools.RandomFrom(theater.Weather[(int)mission.WeatherLevel].FogEnabled);
            mission.WeatherFogThickness  = mission.WeatherFogEnabled ? theater.Weather[(int)mission.WeatherLevel].FogThickness.GetValue() : 0;
            mission.WeatherFogVisibility = mission.WeatherFogEnabled ? theater.Weather[(int)mission.WeatherLevel].FogVisibility.GetValue() : 0;

            // Pressure, turbulence and visiblity
            mission.WeatherQNH        = theater.Weather[(int)mission.WeatherLevel].QNH.GetValue();
            mission.WeatherTurbulence = theater.Weather[(int)mission.WeatherLevel].Turbulence.GetValue();
            mission.WeatherVisibility = theater.Weather[(int)mission.WeatherLevel].Visibility.GetValue();

            DebugLog.Instance.Log($"    Cloud base altitude set to {mission.WeatherCloudBase} m");
            DebugLog.Instance.Log($"    Cloud density set to {mission.WeatherCloudBase}");
            DebugLog.Instance.Log($"    Precipitation set to {mission.WeatherCloudsPrecipitation}");
            DebugLog.Instance.Log($"    Cloud thickness set to {mission.WeatherCloudsThickness} m");

            DebugLog.Instance.Log($"    Dust set to {mission.WeatherDustEnabled}");
            DebugLog.Instance.Log($"    Dust density set to {mission.WeatherDustDensity}");

            DebugLog.Instance.Log($"    Fog set to {mission.WeatherFogEnabled}");
            DebugLog.Instance.Log($"    Fog thickness set to {mission.WeatherFogThickness}");
            DebugLog.Instance.Log($"    Fog visibility set to {mission.WeatherFogVisibility} m");

            DebugLog.Instance.Log($"    QNH set to {mission.WeatherQNH}");
            DebugLog.Instance.Log($"    Turbulence set to {mission.WeatherTurbulence} m/s");
            DebugLog.Instance.Log($"    Visibility set to {mission.WeatherVisibility} m");

            DebugLog.Instance.Log();
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Picks a starting time for the mission.
        /// Must be called after mission date has been set because sunrise/sunset time changes every month.
        /// </summary>
        /// <param name="mission">The mission.</param>
        /// <param name="timeOfDay">The preferred time of day (noon, dawn, twilight, night, random...)</param>
        /// <param name="theater">Theater definition from which to get sunrise/sunset time.</param>
        public void GenerateMissionTime(DCSMission mission, TimeOfDay timeOfDay, DefinitionTheater theater)
        {
            DebugLog.Instance.Log("Generating mission starting time...");

            double fullTime;

            DebugLog.Instance.Log($"  Mission should start at {timeOfDay.ToString().ToUpperInvariant()}");

            switch (timeOfDay)
            {
            default:     // aka TimeOfDay.Random;
                mission.TimeHour   = HQTools.RandomInt(0, 24);
                mission.TimeMinute = HQTools.RandomInt(0, 4) * 15;
                return;

            case TimeOfDay.RandomDaytime:
                fullTime = HQTools.RandomInt(theater.DayTime[(int)mission.DateMonth].Min, theater.DayTime[(int)mission.DateMonth].Max - 60);
                break;

            case TimeOfDay.Dawn:
                fullTime = HQTools.RandomInt(theater.DayTime[(int)mission.DateMonth].Min, theater.DayTime[(int)mission.DateMonth].Min + 120);
                break;

            case TimeOfDay.Noon:
                fullTime = HQTools.RandomInt(
                    (theater.DayTime[(int)mission.DateMonth].Min + theater.DayTime[(int)mission.DateMonth].Max) / 2 - 90,
                    (theater.DayTime[(int)mission.DateMonth].Min + theater.DayTime[(int)mission.DateMonth].Max) / 2 + 90);
                break;

            case TimeOfDay.Twilight:
                fullTime = HQTools.RandomInt(theater.DayTime[(int)mission.DateMonth].Max - 120, theater.DayTime[(int)mission.DateMonth].Max + 30);
                break;

            case TimeOfDay.Night:
                fullTime = HQTools.RandomInt(0, theater.DayTime[(int)mission.DateMonth].Min - 120);
                break;
            }

            mission.TimeHour   = HQTools.Clamp((int)Math.Floor(fullTime / 60), 0, 23);
            mission.TimeMinute = HQTools.Clamp((int)Math.Floor((fullTime - mission.TimeHour * 60) / 15) * 15, 0, 45);

            DebugLog.Instance.Log($"    Starting time set to {mission.TimeHour.ToString("00")}:{mission.TimeMinute.ToString("00")}");
            DebugLog.Instance.Log();
        }
        public DCSMission Generate(MissionTemplate template, out string errorMessage)
        {
            int i;

            errorMessage = "";

            // Clear log, begin timing then create an instance of the HQ mission class
            Stopwatch  stopwatch = new Stopwatch(); stopwatch.Start();
            DCSMission mission   = new DCSMission();

            DebugLog.Instance.Clear();
            DebugLog.Instance.Log($"STARTING MISSION GENERATION AT {DateTime.Now.ToLongTimeString()}...");
            DebugLog.Instance.Log(new string('=', DebugLog.Instance.GetLastMessage().Length));
            DebugLog.Instance.Log();

            try
            {
                using (MissionGeneratorTemplateChecker templateChecker = new MissionGeneratorTemplateChecker())
                { templateChecker.CheckTemplate(template); }

                if (template.GetPlayerCount() < 1)
                {
                    throw new HQ4DCSException("Mission must include at least one player-controlled aircraft.");
                }

                // Pick definitions
                DefinitionCoalition[] coalitions = new DefinitionCoalition[2];
                coalitions[(int)Coalition.Blue] = Library.Instance.GetDefinition <DefinitionCoalition>(template.ContextCoalitionBlue);
                coalitions[(int)Coalition.Red]  = Library.Instance.GetDefinition <DefinitionCoalition>(template.ContextCoalitionRed);

                DefinitionLanguage  languageDef  = Library.Instance.GetDefinition <DefinitionLanguage>(template.PreferencesLanguage.ToLowerInvariant());
                DefinitionObjective objectiveDef = Library.Instance.GetDefinition <DefinitionObjective>(template.ObjectiveType.ToLowerInvariant());
                DefinitionTheater   theaterDef   = Library.Instance.GetDefinition <DefinitionTheater>(template.ContextTheater);
                theaterDef.ResetUsedSpawnPoints();

                // Create a list of all available objective names
                List <string> objectiveNames = languageDef.GetStringArray("Mission", "Waypoint.ObjectiveNames").ToList();

                // Create unit generators
                MissionGeneratorCallsign   callsignGenerator   = new MissionGeneratorCallsign(coalitions[(int)Coalition.Blue].NATOCallsigns, coalitions[(int)Coalition.Red].NATOCallsigns);
                MissionGeneratorUnitGroups unitGroupsGenerator = new MissionGeneratorUnitGroups(languageDef, callsignGenerator);

                // Copy values from the template to the mission
                mission.TheaterDefinition   = template.ContextTheater;
                mission.ObjectiveDefinition = template.ObjectiveType;
                mission.Language            = template.PreferencesLanguage;
                mission.CoalitionPlayer     = template.ContextPlayerCoalition;
                mission.SinglePlayer        = (template.GetPlayerCount() < 2);
                mission.UseNATOCallsigns    = coalitions[(int)template.ContextPlayerCoalition].NATOCallsigns;

                // Make sure no countries are shared between both coalitions
                mission.Countries[(int)Coalition.Blue] = coalitions[(int)Coalition.Blue].Countries.ToArray();
                mission.Countries[(int)Coalition.Red]  = coalitions[(int)Coalition.Red].Countries.Except(coalitions[(int)Coalition.Blue].Countries).ToArray();

                if (mission.Countries[(int)Coalition.Red].Length == 0)
                {
                    throw new HQ4DCSException("Red and blue coalitions cannot share the same countries.");
                }

                switch (template.BriefingUnits)
                {
                case UnitSystem.ByCoalition:
                    mission.BriefingImperialUnits = (coalitions[(int)mission.CoalitionPlayer].UnitSystem == UnitSystem.Imperial); break;

                case UnitSystem.Imperial: mission.BriefingImperialUnits = true; break;

                case UnitSystem.Metric: mission.BriefingImperialUnits = false; break;
                }

                // Generate mission environment parameters (weather, time of day, date...)
                using (MissionGeneratorEnvironment environment = new MissionGeneratorEnvironment())
                {
                    environment.GenerateMissionDate(mission, template.ContextTimePeriod, template.EnvironmentSeason);
                    environment.GenerateMissionTime(mission, template.EnvironmentTimeOfDay, theaterDef);
                    environment.GenerateWeather(mission, template.EnvironmentWeather, theaterDef);
                    environment.GenerateWind(mission, template.EnvironmentWind, theaterDef);
                }

                // Randomly select players' airbase
                DefinitionTheaterAirbase missionAirbase = HQTools.RandomFrom((from DefinitionTheaterAirbase ab in theaterDef.Airbases where ab.Coalition == template.ContextPlayerCoalition select ab).ToArray());

                // Randomly select objective spawn points
                int objectiveCount = (int)template.ObjectiveCount;
                if (objectiveCount == 0)
                {
                    objectiveCount = HQTools.RandomFrom(1, 1, 1, 2, 2, 3, 3, 4, 5);                      // Random objective count
                }
                //AmountR objectiveDistance = template.ObjectiveDistance;
                //if (objectiveDistance == AmountR.Random) objectiveDistance =
                //        HQTools.RandomFrom(AmountR.VeryLow, AmountR.VeryLow, AmountR.Low, AmountR.Low, AmountR.Low, AmountR.Average, AmountR.Average, AmountR.Average, AmountR.High, AmountR.High, AmountR.VeryHigh);
                List <DCSMissionObjectiveLocation> objectivesList = new List <DCSMissionObjectiveLocation>();
                List <DCSMissionWaypoint>          waypointsList  = new List <DCSMissionWaypoint>();
                for (i = 0; i < objectiveCount; i++)
                {
                    // If this is the first objective, measure distance from the airbase. Else measure distance from the previous objective.
                    Coordinates previousPoint = (i == 0) ? missionAirbase.Coordinates : objectivesList[i - 1].Coordinates;

                    MinMaxD distanceFromLastPoint = new MinMaxD(template.ObjectiveDistance * 0.75, template.ObjectiveDistance * 1.25) * HQTools.NM_TO_METERS;
                    if (i > 0)
                    {
                        distanceFromLastPoint /= 4.0;
                    }

                    DefinitionTheaterSpawnPoint?spawnPoint =
                        theaterDef.GetRandomSpawnPoint(objectiveDef.SpawnPointType, null, distanceFromLastPoint, previousPoint);

                    if (!spawnPoint.HasValue) // No valid spawn point, throw an error
                    {
                        throw new HQ4DCSException($"Cannot find a valid spawn point for objective #{i + 1}");
                    }

                    // Select a random name for the objective
                    string objName;
                    if (objectiveNames.Count == 0)
                    {
                        objName = $"OBJECTIVE{(i + 1).ToString("00")}";
                    }
                    else
                    {
                        objName = HQTools.RandomFrom(objectiveNames);
                        objectiveNames.Remove(objName);
                    }

                    objectivesList.Add(new DCSMissionObjectiveLocation(spawnPoint.Value.Coordinates, objName, objectiveDef.WaypointOnGround ? 0.0 : 1.0, 0));

                    // Add a waypoint for each objective
                    waypointsList.Add(new DCSMissionWaypoint(spawnPoint.Value.Coordinates + Coordinates.CreateRandomInaccuracy(objectiveDef.WaypointInaccuracy), objName));
                }

                // If required, add additional waypoints on the way to & from the objectives
                if (template.PreferencesExtraWaypoints && (waypointsList.Count > 0))
                {
                    Coordinates firstWPCoos = waypointsList.First().Coordinates;
                    Coordinates lastWPCoos  = waypointsList.Last().Coordinates;

                    int wpBeforeCount = HQTools.RandomMinMax(1, 3);
                    for (i = 0; i < wpBeforeCount; i++)
                    {
                        waypointsList.Insert(i,
                                             new DCSMissionWaypoint(
                                                 Coordinates.Lerp(missionAirbase.Coordinates, firstWPCoos, (double)(i + 1) / (wpBeforeCount + 1)) +
                                                 Coordinates.CreateRandomInaccuracy(firstWPCoos.GetDistanceFrom(missionAirbase.Coordinates) * 0.05, firstWPCoos.GetDistanceFrom(missionAirbase.Coordinates) * 0.15),
                                                 $"WP{(i + 1).ToString()}"));
                    }

                    int wpAfterCount = HQTools.RandomMinMax(1, 2);
                    for (i = 0; i < wpAfterCount; i++)
                    {
                        waypointsList.Add(
                            new DCSMissionWaypoint(
                                Coordinates.Lerp(lastWPCoos, missionAirbase.Coordinates, (double)(i + 1) / (wpAfterCount + 1)) +
                                Coordinates.CreateRandomInaccuracy(lastWPCoos.GetDistanceFrom(missionAirbase.Coordinates) * 0.05, lastWPCoos.GetDistanceFrom(missionAirbase.Coordinates) * 0.15),
                                $"WP{(waypointsList.Count + 1).ToString()}"));
                    }
                }

                mission.Objectives = objectivesList.ToArray();
                mission.Waypoints  = waypointsList.ToArray();

                mission.TotalFlightPlanDistance = 0.0;
                for (i = 0; i <= mission.Waypoints.Length; i++)
                {
                    if (i == 0) // first point, add distance between the takeoff airbase and the first waypoint
                    {
                        mission.TotalFlightPlanDistance += missionAirbase.Coordinates.GetDistanceFrom(mission.Waypoints.First().Coordinates);
                    }
                    else if (i == mission.Waypoints.Length) // last point, add distance between last waypoint and landing airbase
                    {
                        mission.TotalFlightPlanDistance += missionAirbase.Coordinates.GetDistanceFrom(mission.Waypoints.Last().Coordinates);
                    }
                    else // any other point, add distance between this waypoint and the last one
                    {
                        mission.TotalFlightPlanDistance += mission.Waypoints[i].Coordinates.GetDistanceFrom(mission.Waypoints[i - 1].Coordinates);
                    }
                }

                // Create a list of used player aircraft types, so the proper kneeboard subdirectories can be created in the .miz file
                mission.UsedPlayerAircraftTypes =
                    (from MissionTemplatePlayerFlightGroup pfg in template.FlightPackagePlayers select pfg.AircraftType).Distinct().OrderBy(x => x).ToArray();

                // Generate bullseyes and map center
                mission.MapCenter = Coordinates.GetCenter(
                    (from DCSMissionObjectiveLocation o in mission.Objectives select o.Coordinates).Union(new Coordinates[] { missionAirbase.Coordinates }).ToArray());
                mission.Bullseye = new Coordinates[2];
                for (i = 0; i < 2; i++)
                {
                    mission.Bullseye[i] = mission.MapCenter + Coordinates.CreateRandomInaccuracy(10000, 20000);
                }

                // Copy scripts
                //mission.ScriptsMission = missionObjective.ScriptMission.ToList();
                //mission.ScriptsObjective = missionObjective.ScriptObjective.ToList();

                mission.RealismAllowExternalViews = template.RealismAllowExternalViews;
                mission.RealismBirdStrikes        = template.RealismBirdStrikes;
                mission.RealismRandomFailures     = template.RealismRandomFailures;

                // Create list of airbase alignment from the theater definition
                mission.AirbasesCoalition.Clear();
                foreach (DefinitionTheaterAirbase ab in theaterDef.Airbases)
                {
                    if (mission.AirbasesCoalition.ContainsKey(ab.DCSID))
                    {
                        continue;
                    }

                    Coalition airbaseCoalition = ab.Coalition;
                    switch (template.ContextCountriesCoalitions)
                    {
                    case CountriesCoalition.AllBlue: airbaseCoalition = Coalition.Blue; break;

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

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

                    mission.AirbasesCoalition.Add(ab.DCSID, airbaseCoalition);
                }

                // Make sure the starting airbase belongs to the players' coalition no matter which coalition other airbases belong to
                if (mission.AirbasesCoalition.ContainsKey(missionAirbase.DCSID))
                {
                    mission.AirbasesCoalition[missionAirbase.DCSID] = template.ContextPlayerCoalition;
                }

                List <string> oggFilesList = new List <string>();
                oggFilesList.AddRange(Library.Instance.Common.SharedOggFiles); // Default wave files
                oggFilesList.AddRange(objectiveDef.IncludeOgg);                // Objective wave files
                mission.OggFiles = oggFilesList.Distinct().ToArray();

                //mission.Scripts

                /*
                 * // Generate mission flight plan
                 * using (GeneratorFlightPlan flightPlan = new GeneratorFlightPlan(Library, language, csGenerator))
                 * {
                 *  flightPlan.SelectTakeoffAndLandingAirbases(mission, theater);
                 *  mission.MapCenter = mission.Airbases[0].Coordinates; // Center the map on the starting airdrome
                 *  flightPlan.GenerateObjectiveLocations(mission, template, theater, missionObjective);
                 *  flightPlan.GenerateWaypoints(mission, template, theater, missionObjective);
                 *  flightPlan.GenerateBullseye(mission);
                 * }
                 */

                // Generate units
                AmountNR selectedEnemyAirDefense, selectedEnemyCAP; // We have to store these values here because they're used in the briefing remarks
                using (MissionGeneratorUnitGroups unitGenerator = new MissionGeneratorUnitGroups(languageDef, callsignGenerator))
                {
                    foreach (MissionTemplatePlayerFlightGroup pfg in template.FlightPackagePlayers)
                    {
                        unitGenerator.AddPlayerFlightGroup(mission, template, pfg, objectiveDef, missionAirbase);
                    }

                    //unitGroups.GeneratePlayerFlightGroups(mission, template, missionObjective);
                    //unitGroups.GenerateAIEscortFlightGroups(mission, template, coalitions, template.FlightGroupsAICAP, UnitFamily.PlaneFighter, "GroupPlaneEscortCAP", AircraftPayloadType.A2A, DCSAircraftTask.CAP);
                    //unitGroups.GenerateAIEscortFlightGroups(mission, template, coalitions, template.FlightGroupsAISEAD, UnitFamily.PlaneSEAD, "GroupPlaneEscortSEAD", AircraftPayloadType.SEAD, DCSAircraftTask.SEAD);

                    unitGenerator.AddObjectiveUnitGroupsAtEachObjective(mission, template, objectiveDef, coalitions);
                    //unitGroups.GenerateObjectiveUnitGroupsAtCenter(mission, template, missionObjective, coalitions);
                    unitGenerator.AddFriendlySupportAircraft(mission, template, coalitions[(int)mission.CoalitionPlayer], theaterDef, missionAirbase);
                    unitGenerator.AddEnemyAirDefenseUnits(mission, template, theaterDef, objectiveDef, coalitions, missionAirbase, out selectedEnemyAirDefense);
                    unitGenerator.AddFriendlyAirDefenseUnits(mission, template, theaterDef, objectiveDef, coalitions, missionAirbase, out AmountNR selectedFriendlyAirDefense);
                    unitGenerator.AddCombatAirPatrolUnits(mission, template, theaterDef, coalitions, missionAirbase, out AmountNR selectedFriendlyCAP, out selectedEnemyCAP);
                }

                using (MissionGeneratorBriefing briefingGenerator = new MissionGeneratorBriefing(languageDef))
                {
                    // Add briefing remarks
                    for (i = 0; i < objectiveDef.BriefingRemarks.Length; i++)
                    {
                        mission.BriefingRemarks.Add(languageDef.GetStringRandom("Briefing", $"Remark.{objectiveDef.BriefingRemarks}"));
                    }
                    mission.BriefingRemarks.Add(languageDef.GetStringRandom("Briefing", $"Remark.EnemyAirDefense.{selectedEnemyAirDefense}"));
                    mission.BriefingRemarks.Add(languageDef.GetStringRandom("Briefing", $"Remark.EnemyCAP.{selectedEnemyCAP}"));

                    mission.BriefingTasks.Add(languageDef.GetString("Briefing", "Task.TakeOffFrom", "Airbase", missionAirbase.Name));
                    for (i = 0; i < mission.Objectives.Length; i++)
                    {
                        mission.BriefingTasks.Add(languageDef.GetString("Briefing", $"Task.{objectiveDef.BriefingTask}", "Objective", mission.Objectives[i].Name.ToUpperInvariant()));
                    }
                    mission.BriefingTasks.Add(languageDef.GetString("Briefing", "Task.LandAt", "Airbase", missionAirbase.Name));

                    briefingGenerator.GenerateMissionName(mission, template.BriefingName);
                    briefingGenerator.GenerateMissionDescription(mission, template.BriefingDescription, objectiveDef);

                    /*
                     *  briefing.GenerateMissionTasks(mission, template, missionObjective);
                     *  briefing.GenerateMissionRemarks(mission, template, missionObjective);
                     */
                    briefingGenerator.GenerateRawTextBriefing(mission, template /*, missionObjective*/);
                    briefingGenerator.GenerateHTMLBriefing(mission, template /*, missionObjective*/);
                }

                stopwatch.Stop();
                DebugLog.Instance.Log();
                DebugLog.Instance.Log($"COMPLETED MISSION GENERATION AT {DateTime.Now.ToLongTimeString()} (TOOK {stopwatch.Elapsed.TotalMilliseconds.ToString("F0")} MILLISECONDS).");
                DebugLog.Instance.Log();
                mission.GenerationLog = DebugLog.Instance.GetFullLog();
            }
#if DEBUG
            catch (HQ4DCSException e)
#else
            catch (Exception e)
#endif
            {
                stopwatch.Stop();
                DebugLog.Instance.Log($"ERROR: {e.Message}");
                DebugLog.Instance.Log();
                DebugLog.Instance.Log($"MISSION GENERATION FAILED.");
                DebugLog.Instance.Log();
                errorMessage = e.Message;

                mission.Dispose();
                mission = null;
            }

            DebugLog.Instance.SaveToFileAndClear("MissionGeneration");
            return(mission);
        }