
//$reference parts\core\gamePlay.dll
using System;
using System.IO;
using maddox.game;
using maddox.game.world;
using maddox.GP;
using System.Collections.Generic;
using System.Globalization;
/*
  Static0 Stationary.Environment.GuardTower_UK-GER_1 nn 56078.11 56762.54 0.00
  Static4 Stationary.Environment.SandBagWall_Line_8m nn 55766.24 56768.78 -70.00
  Static5 Stationary.Environment.SandBagWall_Line_8m nn 55924.50 56901.02 0.00
  Static6 Stationary.Environment.SandBagWall_Line_8m nn 55924.60 56910.77 0.00
  Static7 Stationary.Trenches.Trench_10m_diameter nn 55791.45 56962.18 0.00
  Static8 Stationary.Trenches.Trench_10m_diameter nn 55748.80 56947.41 0.00
  Static9 Stationary.Trenches.Trench_6m_diameter nn 55784.98 56538.97 0.00
  Static10 Stationary.Trenches.Trench_6m_diameter nn 55793.83 56520.70 0.00
  Static1 Stationary.Environment.SandBagWall_Line_8m nn 55783.32 56773.72 -70.00
  Static2 Stationary.Environment.SandBagWall_Line_8m nn 55799.11 56778.82 -70.00
  Static3 Stationary.Environment.SandBagWall_Line_8m nn 55900.42 56652.63 -165.00
  Static11 Artillery.LeFH_18_Howitzer de 55733.18 56828.100 0.00 /timeout 0/radius_hide 0
  Static12 Stationary.Environment.SandBagWall_Arch nn 55734.20 56829.02 0.00
  Static13 Artillery.LeFH_18_Howitzer gb 64186.32 38188.24 120.00 /timeout 0/radius_hide 0
 */
// fix new FrontMarker when switch advantage
// check missions for only one
// no airbase attack if already hit
public class Mission : AMission
{
    private bool odenDebug = false;// false;//
    const string vFile = "DynMisJ"; // version filename
    const string vName = "DynMis R10"; // version caption
    const int RAF = 1;
    const int LW = 2;
    private int ATK = 0;
    private bool lastCampaignMission = false;
    const string cBattleOfFrance = "Battle of France";
    const string fmArras = "FrontMarker0";
    const string fmStPolSurTernoise = "FrontMarker1";
    const string fmFruges = "FrontMarker2";
    const string fmHesdin = "FrontMarker3";
    const string fmFrevent = "FrontMarker4";
    const string fmAuxiLeChateau = "FrontMarker5";
    const string fmLeCrotoy = "FrontMarker6";
    const string fmAbbeville = "FrontMarker7";
    const string fmBerteaucourt = "FrontMarker8";
    const string fmAmiens = "FrontMarker9";
    const string fmBapaume = "FrontMarker10";
    const string fmRoye = "FrontMarker11";
    const string fmMontdidier = "FrontMarker12";
    const string fmBeauvais = "FrontMarker13";
    const string fmPoixDePicardie = "FrontMarker14";
    const string fmAumale = "FrontMarker15";
    const string fmBlangySurBresle = "FrontMarker16";
    const string fmLeTreport = "FrontMarker17";
    const string fmNeufchatelEnBray = "FrontMarker18";
    const string fmDieppe = "FrontMarker19";
    const string fmBerck = "FrontMarker20";
    const string fmLigescourt = "FrontMarker21";
    const string fmEtaples = "FrontMarker22";
    const string fmSempy = "FrontMarker23";
    const string fmBoulogne = "FrontMarker24";
    const string fmDesvres = "FrontMarker25";
    const string fmLumbres = "FrontMarker26";
    const string fmStOmer = "FrontMarker27";
    const string fmAireSurLaLys = "FrontMarker28";
    const string fmBruayLaBuissiere = "FrontMarker29";
    const string fmMerville = "FrontMarker30";
    const string fmHazelbrouck = "FrontMarker31";
    const string fmLeper = "FrontMarker32";
    const string fmPoperinge = "FrontMarker33";
    const string fmDiksmuide = "FrontMarker34";
    const string fmVeurne = "FrontMarker35";
    const string fmDunkerque = "FrontMarker36";
    const string fmGravelines = "FrontMarker37";
    const string fmCalais = "FrontMarker38";
    const string cBattleOfBritain = "Battle of Britain";
    const string fmDungeness = "FrontMarker13";
    const string fmDover = "FrontMarker14";
    const string fmRamsgate = "FrontMarker17";
    const string fmCanterbury = "FrontMarker18";
    const string fmRochester = "FrontMarker19";
    const string fmLondon = "FrontMarker20";
    const string fmEastbourne = "FrontMarker12";
    const string fmHorsham = "FrontMarker22";
    const string cNorthAfrica = "North Africa";
    const string fmSidi_Barrani = "FrontMarker0";
    const string fmBuq_Buq = "FrontMarker1";
    const string fmHalfaya_Pass = "FrontMarker2";
    const string fmSollum = "FrontMarker3";
    const string fmFort_Capuzzo = "FrontMarker4";
    const string fmSidi_Omar = "FrontMarker5";
    const string fmSidi_Azeiz = "FrontMarker6";
    const string fmBardia = "FrontMarker7";
    const string fmBir_el_Menastir = "FrontMarker8";
    const string fmQasr_el_Arid = "FrontMarker9";
    const string fmGambut = "FrontMarker10";
    const string fmSidi_Rezegh = "FrontMarker11";
    const string fmEd_Dedu = "FrontMarker12";
    const string fmEl_Adem = "FrontMarker13";
    const string fmTobruk = "FrontMarker14";
    const string fmBir_Hacheim = "FrontMarker15";
    const string fmAlem_Hamza = "FrontMarker16";
    const string fmGazala = "FrontMarker17";
    const string fmTmimi = "FrontMarker18";
    const string fmBir_Halegh = "FrontMarker19";
    const string fmMartuba = "FrontMarker20";
    const string fmDerna = "FrontMarker21";
    const string cCobra = "CAS Warfare";
    const string fmWestSeeburg = "FrontMarker0";
    const string fmStHansa = "FrontMarker1";
    const string fmWestStadt = "FrontMarker2";
    const string fmWestigo = "FrontMarker3";
    const string fmSWestheim = "FrontMarker4";
    const string fmSudMarckt = "FrontMarker5";
    const string fmEastUpTrent = "FrontMarker6";
    const string fmEastMinor = "FrontMarker7";
    const string fmEastSherwood = "FrontMarker8";
    const string fmEastLakeCity = "FrontMarker9";
    const string fmEastBromTown = "FrontMarker10";
    const string fmStEastman = "FrontMarker11";
    const string fmSouthKent = "FrontMarker12";
    private string fmCurrent;
    private string CampaignName;
    private int SideOnOffensive = 0, ConsecutiveLosses = 0;
    private DateTime dtBattleOfFrance = new DateTime(1940, 5, 22, 5, 0, 0);
    private DateTime dtBattleOfBritain = new DateTime(1940, 7, 10, 5, 0, 0);
    private DateTime dtCoastalBattles = new DateTime(1940, 8, 8, 0, 0, 0);
    private DateTime dtAdlerTag = new DateTime(1940, 8, 24, 0, 0, 0);
    private DateTime dtBlitz = new DateTime(1940, 9, 7, 0, 0, 0);
    private DateTime dtFighterBomber = new DateTime(1940, 10, 1, 0, 0, 0);
    private DateTime dtOpCompass = new DateTime(1941, 1, 3, 0, 0, 0); // Bardia
    private DateTime dtOpSonnenblume = new DateTime(1941, 4, 6, 0, 0, 0); // Gazala/Bir Hacheim to Sollum
    private DateTime dtOpCrusader = new DateTime(1941, 11, 18, 0, 0, 0); // Sidi-Omar/Maddalena up towards Tobruk
    private DateTime dtOpThesus = new DateTime(1942, 2, 3, 0, 0, 0); // Tmimi
    private DateTime gameDateTime = new DateTime(1941, 1, 3, 5, 0, 0);
    private DateTime StartDateTime = new DateTime(1940, 12, 15, 0, 0, 0); // North Africa, aging only
    private DateTime highOctaneDate = new DateTime(1941, 1, 3, 0, 0, 0);
    private DateTime ReinforcementDate = new DateTime(1941, 1, 5, 0, 0, 0);
    private DateTime timeoutRadio = DateTime.Now;

    internal class MissionAirbase
    {   // Squadron or Gruppe Airbase at Airfield, there may be multiple "airbases" per airfield
        internal string name;
        internal int army;
        internal double x;
        internal double y;
        internal int startAlt;
        internal int maxPlanes;
        internal bool parked;
        internal bool parachute;
        internal string country;
        internal string type;
        internal string sqn;
        internal string sector;
        internal string aircraftType;
        internal AiAirport ap;
        internal string airportName;
        internal Point3d pt3d;

        public Point2d Pos2d() { return new Point2d(x, y); }
        public Point3d Pos() { return pt3d; }
        public void MoveSquadronToAirport(AiAirport apNew)
        {
            this.x = apNew.Pos().x;
            this.y = apNew.Pos().y;
            this.airportName = apNew.Name();
            this.pt3d = apNew.Pos();
        }

        internal MissionAirbase(string name
            , int army
            , double x
            , double y
            , int startAlt
            , int maxPlanes
            , bool parked
            , bool parachute
            , string country
            , string type
            , string sqn
            , string sector
            , string aircraftType
            , AiAirport ap
            , string airportName
            )
        {
            this.name = name;
            this.army = army;
            this.x = x;
            this.y = y;
            this.startAlt = startAlt;
            this.maxPlanes = maxPlanes;
            this.parked = parked;
            this.parachute = parachute;
            this.country = country;
            this.type = type;
            this.sqn = sqn;
            this.sector = sector;
            this.aircraftType = aircraftType;
            this.ap = ap;
            this.airportName = airportName;
            this.pt3d = new Point3d(x, y, 0);
        }
    }
    internal class DynCampEvent
    {
        internal DateTime dateTime;
        internal string action; // add/remove/move
        internal string type; // AirGroup
        internal string typeValue; // BoB_RAF_F_92Sqn
        internal string airportName; // Tangmere
        internal string param1; // 12
        internal string param2; // Aircraft.SpitfireMkIa_100oct
        internal string param3; // n/a
        internal DynCampEvent(DateTime dt, string action, string type, string typeValue, string airportName, string param1, string param2, string param3)
        {
            this.dateTime = dt;
            this.action = action;
            this.type = type;
            this.typeValue = typeValue;
            this.airportName = airportName;
            this.param1 = param1;
            this.param2 = param2;
            this.param3 = param3;
        }
    }
    internal class MissionMarker
    {
        internal double x;
        internal double y;
        internal int army;
        internal string key;
        public Point2d Pos2d() { return new Point2d(x, y); }
        public Point3d Pos3d() { return new Point3d(x, y, 0); }
        internal MissionMarker(double x, double y, int army, string key) { this.x = x; this.y = y; this.army = army; this.key = key; }
    }
    internal class GroundColumn
    {
        internal string name;
        internal Point2d fr2d;
        internal Point2d to2d;
        internal AiGroundGroup group;
        internal IRecalcPathParams pathParams;
        internal GroundColumn(string name, Point2d fr2d, Point2d to2d, IRecalcPathParams pathParams) { this.name = name; this.fr2d = fr2d; this.to2d = to2d; this.group = null; this.pathParams = pathParams; }
    }
    internal class PlayerData
    {
        internal Player player;
        internal AiAirport homeAirport;

    }

    private int bobVicSide = 0;
    Random rnd = new Random();
    private int CAPStaffelIndex = 0, CAPFlightIndex = 0, CASStaffelIndex = 0, CASFlightIndex = 0;
    private int BMBStaffelIndex = 0, BMBFlightIndex = 0, BMBFlightAlt = 0, BMBFlightSpeed = 0;
    private int misConvoyKills = 0, misRAFDeadF = 0, misLWDeadB = 0, misLWDeadF = 0, misRAFDeadB = 0, misLWDeadS = 0;
    private int deadStaticsBlue = 0, deadStaticsRed = 0;
    private int addDays = 0;
    private int BattleProgress = 0;
    private int missionVictory = 0; // RAF, LW
    private int columnUnits = 0, destroyedUnits = 0;
    private MissionAirbase BMBFlightAB = null;
    private int NextMissionNum = 0; // sub missions
    private int playerKilledTargets = 0;
    private double bombsOnTarget = 0;
    private bool gameIsOn = false;
    private bool InitiativeChanged = false;
    private bool playerWasAirborne = false;
    private bool playerHasHitTarget = false;
    private bool playerWasKilled = false;
    private bool playerFlightCAS = false;
    private bool playerFlightBMB = false;
    private bool bombersLeavingTarget = false;
    private bool detectedByObsCorps = false;
    private bool firstMessage = true;
    private string RedCoalition, BlueCoalition;
    private string fSkill = "1 0.26 0.26 0.89 0.89 0.89 0.47 0.47"; // basic,adv,aware,gunnery,tact,vision,brave,dicipline
    private string bSkill = "1 0.26 0.26 0.89 0.89 0.47 0.47 0.89"; // basic,adv,aware,gunnery,tact,vision,brave,dicipline
    private string DoverFolder, CampInitFile, CampMisFile, CampBriFile, CampMapName;
    private string oldSqn = "";
    private string defSquadron, defClass, defCallSign, defSkin, defSerial, defTail; // from mis file
    private string defSatellites = "";
    private string tailNoSerialNo = "(verify tailnumber 'D' and serialno. 'R6708' and";
    private string groundAssaultFrom = "";
    private List<string> CapturedAreas = new List<string>();
    private List<PlayerData> PlayersData = new List<PlayerData>();
    private List<string> mainStoryList = new List<string>();
    private List<string> strDynCampList = new List<string>();
    private List<string> AirGroupNames = new List<string>();
    private List<string> GndStatDead = new List<string>();
    private List<string> GndStatRestore = new List<string>();
    private List<string> GndGrpDead = new List<string>();
    private List<string> AirportsDamaged = new List<string>();
    private List<string> CHRadarDamaged = new List<string>();
    private List<string> PortDamaged = new List<string>();
    private List<string> FactoryDamaged = new List<string>();
    private List<string> Satellites = new List<string>();
    private List<string> activatedGroups = new List<string>();
    private List<string> activatedAirports = new List<string>();
    private List<string> sweepGroups = new List<string>();
    private List<string> SandBagWalls = new List<string>(); // SandBagWall_Line
    private List<string> HeavyAAAs = new List<string>(); // Trench_10m
    private List<string> LightAAAs = new List<string>(); // Trench_6m
    private List<string> ARTYsites = new List<string>(); // SandBagWall_Arch
    private List<string> SupplyDepots = new List<string>(); // GuardTower_UK-GER
    private List<string> AirfieldSpawnPos = new List<string>();
    private List<int> AirGroupIDs = new List<int>();
    private List<GroundStationary> ChainHomeRadars = new List<GroundStationary>();
    private List<GroundStationary> Industries = new List<GroundStationary>();
    private List<GroundStationary> PortCranes = new List<GroundStationary>();
    private List<AiGroundGroup> ConvoyShips = new List<AiGroundGroup>();
    private List<MissionMarker> MissionMarkers = new List<MissionMarker>();
    private List<MissionAirbase> MissionAirbases = new List<MissionAirbase>();
    private List<MissionAirbase> PossibleMissionAirbases = new List<MissionAirbase>();
    private List<DynCampEvent> DynCampEvents = new List<DynCampEvent>();
    private List<GroundColumn> GroundColumns = new List<GroundColumn>();
    private List<AiAirGroup> AiAirGroupsCAP = new List<AiAirGroup>();
    private List<AiAirGroup> AiAirGroupsStdby = new List<AiAirGroup>();
    private List<AiAirport> PossibleAirports = new List<AiAirport>();
    private List<AiAircraft> damagedAircrafts = new List<AiAircraft>();
    private AiAirGroup TargetGroup = null;
    private AiAirGroup EscortedGroup = null;
    private AiAirGroup TriggerGroup = null;
    private MissionAirbase homeBase = null;
    private MissionAirbase transferHomeBase = null;
    private AiAirport homeAirport = null;
    private AiAirport targetAirport = null;
    private AiAirport playerTargetAirport = null;
    private AiAirport playerLandedAtAirport = null;
    private Point3d homeAirport3d;
    private Point2d target2d = new Point2d(0, 0);
    private Point3d target3d = new Point3d(0, 0, 0);
    private string targetName = "";
    private string StrikerGroupName = "";
    private AiAircraft FighterCommand = null;
    private GroundStationary mainGSTarget = null;
    private AiActor convoyTarget = null;
    private AiWayPoint oldWP = null;
    private int idxTarget;
    private IRecalcPathParams pathParams;
    private GroundColumn gc = null;
    private AiGroundGroup GroundTarget = null;
    private MissionMarker mmCurrentBattle = null;
    private MissionMarker mmPrevBattle = null;

    private void Spawn40Tigers(AiAirport ap)
    {   // use this to find 40 spawn positions on target airfield until GamePlay.gpSpawnPoints(AiAirfield) ever gets available
        if (ap == null)
            return;

        if (odenDebug) GamePlay.gpLogServer(null, "Spawn40Tigers: {0} at {1}", new object[] { ap.Name(), ap.Pos() });
        ISectionFile f = GamePlay.gpCreateSectionFile();
        string sag = "BoB_RAF_B_144Sqn.0F"; // not used in any scenario
        f.add("AirGroups", sag, "");
        f.add(sag, "Flight0", "1 2 3 4 5 6 7 8 9 10");
        f.add(sag, "Flight1", "11 12 13 14 15 16 17 18 19 20");
        f.add(sag, "Flight2", "21 22 23 24 25 26 27 28 29 30");
        f.add(sag, "Flight3", "31 32 33 34 35 36 37 38 39 40");
        f.add(sag, "Class", "Aircraft.DH82A");
        f.add(sag, "Formation", "LINEABREAST");
        f.add(sag, "CallSign", "26");
        f.add(sag, "Fuel", "0");
        f.add(sag, "Weapons", "0 0");
        f.add(sag, "SetOnPark", "1");
        f.add(sag, "Idle", "1");
        f.add(sag + "_Way", "TAKEOFF", ap.Pos().x.ToString() + " " + ap.Pos().y.ToString() + " 0 0");
        GamePlay.gpPostMissionLoad(f);
        NextMissionNum++;
    }
    public override void OnBattleStarted()
    {
        base.OnBattleStarted();

        if (odenDebug) GamePlay.gpLogServer(null, "", new object[] { });
        MissionNumberListener = -1;
        NextMissionNum = GamePlay.gpNextMissionNumber();
        if (GamePlay is GameServerDef)
        {
            if (odenDebug) GamePlay.gpLogServer(null, "OnBattleStarted: '{0}' {1}", new object[] { "GameServerDef", NextMissionNum });
            GameServerDef gameServer = (GameServerDef)GamePlay;
            ISectionFile missFile = gameServer.game.FirstMissionFile();
            ReadMissionFile(missFile);
        };
        if (GamePlay is GameSingleDef)
        {
            if (odenDebug) GamePlay.gpLogServer(null, "OnBattleStarted: '{0}' {1}", new object[] { "GameSingleDef", NextMissionNum });
            GameSingleDef gameServer = (GameSingleDef)GamePlay;
            ISectionFile missFile = gameServer.game.FirstMissionFile();
            //gameServer.BattleScriptFileName = "Benny";
            //if (odenDebug) GamePlay.gpLogServer(null, "OnBattleStarted: '{0}' {1}", new object[] { "CheckFiles", gameServer.BattleScriptFileName });
            //if (odenDebug) GamePlay.gpLogServer(null, "OnBattleStarted: '{0}' {1}", new object[] { "CheckFiles", gameServer.battleScriptFileName() });
            //if (odenDebug) GamePlay.gpLogServer(null, "OnBattleStarted: '{0}' {1}", new object[] { "CheckFiles!", gameServer.ArmyName(1) });
            //if (odenDebug) GamePlay.gpLogServer(null, "OnBattleStarted: '{0}' {1}", new object[] { "CheckFiles", maddox.game.play.MissionFile.FileName });
            ReadMissionFile(missFile);
        };
        if (odenDebug) GamePlay.gpLogServer(null, "OnBattleStarted: '{0}' {1}", new object[] { "CheckFiles", GamePlay.gpPlayer().Name() });
        CheckFiles();

        MissionNumberListener = -1;
        NextMissionNum = GamePlay.gpNextMissionNumber();

        if (odenDebug) GamePlay.gpLogServer(null, "OnBattleStarted: '{0}' {1}", new object[] { "ReadInit", "" });
        ReadInitFile();
        ATK = SideOnOffensive;
        if (ATK == 0) ATK = rnd.Next(1, 3);
        if (odenDebug) GamePlay.gpLogServer(null, "OnBattleStarted: '{0}' {1}", new object[] { "BattleOfBritainVictoryCheck", GamePlay.gpPlayer().Name() });
        bobVicSide = BattleOfBritainVictoryCheck();
        StartDateTime = CampaignStartDate();

        // reallocate airbases if in enemy territory by now
        foreach (MissionAirbase mab in MissionAirbases)
            if (mab.army != GamePlay.gpFrontArmy(mab.x, mab.y))
            {
                Point2d pt2d = new Point2d(mab.x, mab.y);
                AiAirport[] sap = SortedAirports(mab.army, pt2d, false).ToArray();
                if (sap.Length > 0) mab.MoveSquadronToAirport(sap[0]); // todo: check stripCount(), stripLength(n) vs bomber sqn
                else mab.maxPlanes = 0; // withdrawn
                activatedGroups.Add(mab.sqn); // block from usage this turn
            };

        if (CampMapName.Contains("Land$English_Channel_1940"))
        {
            ISectionFile f = GamePlay.gpCreateSectionFile();
            // Fighter Command Control Voice, triggers
            f.add("AirGroups", "gb01.01", "");
            f.add("gb01.01", "Flight0", "1");
            f.add("gb01.01", "Class", "Aircraft.AnsonMkI");
            f.add("gb01.01", "Formation", "LINEABREAST");
            f.add("gb01.01", "CallSign", "0");
            f.add("gb01.01", "Fuel", "0");
            f.add("gb01.01", "Weapons", "0 0");
            f.add("gb01.01", "SetOnPark", "1");
            f.add("gb01.01", "Idle", "1");
            f.add("gb01.01", "Skill", "0.54 0.09 0.43 0.54 0.54 0.59 0.43 0.54");
            //f.add("gb01.01", "Person0_0", "1 0.54 0.09 0.43 0.54 0.54 0.59 0.43 0.54"); // gb only have 2 actors (de has 4)
            f.add("gb01.01_Way", "TAKEOFF", "135077.50 284460.35 0 0");

            f.add("AirGroups", "g06.01", "");
            f.add("g06.01", "Flight0", "1");
            f.add("g06.01", "Class", "Aircraft.Bf-108B-2");
            f.add("g06.01", "Formation", "LINEABREAST");
            f.add("g06.01", "CallSign", "26");
            f.add("g06.01", "Fuel", "0");
            f.add("g06.01", "Weapons", "0 0");
            f.add("g06.01", "SetOnPark", "1");
            f.add("g06.01", "Idle", "1");
            f.add("g06.01", "Skill", "0.54 0.09 0.43 0.54 0.54 0.59 0.43 0.54");
            //f.add("g06.01", "Person0_0", "1 0.54 0.09 0.43 0.54 0.54 0.59 0.43 0.54"); // gb only have 2 actors (de has 4)
            f.add("g06.01_Way", "TAKEOFF", "352655.02 14633.14 0 0");

            GamePlay.gpPostMissionLoad(f);
            NextMissionNum++;
        };
        if (odenDebug) GamePlay.gpLogServer(null, "OnBattleStarted: '{0}' {1} {2}", new object[] { "StartMission", GamePlay.gpPlayer().Name(), GamePlay.gpPlayer().Place().Pos() });
        StartMission();

        homeAirport = FindAirport(GamePlay.gpPlayer().Army(), GamePlay.gpPlayer().Place().Pos(), 0);
        GamePlay.gpLogServer(null, " ", new object[] { });
        GamePlay.gpLogServer(null, "New Day", new object[] { });
        GamePlay.gpLogServer(null, "{0} {1}", new object[] { gameDateTime.ToString("D"), homeAirport.Name().Replace('_', ' ') });
    }
    public override void OnBattleStoped()
    {
        base.OnBattleStoped();

        if (playerLandedAtAirport != null)
            //if (Satellites.Contains(playerLandedAtAirport.Name()))
            homeBase.MoveSquadronToAirport(playerLandedAtAirport);

        if (odenDebug)
        {
            //playerKilledTargets++;
            int scoreRed = deadStaticsBlue + misLWDeadF + misLWDeadB + misLWDeadS;
            int scoreBlue = deadStaticsRed + misRAFDeadF + misRAFDeadB;
            GamePlay.gpLogServer(null, "OnBattleStoped: '{0}' playerKilledTargets={1} playerHasHitTarget={2} missionVictory={3} {4}::{5}", new object[] { homeBase.name, playerKilledTargets, playerHasHitTarget, missionVictory, scoreRed, scoreBlue });
            //if(fmCurrent != "") BattleProgress = 3;
            //ConsecutiveLosses = 0;
            int army = GamePlay.gpPlayer().Army();
            if (!playerWasAirborne) // debug victory, esc on runway
            {
                missionVictory = army;
                playerHasHitTarget = true;
            };
            if (playerWasAirborne) // debug loss, take off but do nothing
                if (missionVictory == 0 && ATK == army)
                {
                    missionVictory = (army == RAF ? LW : RAF);
                    playerHasHitTarget = false;
                };
            playerWasAirborne = true;
            bombersLeavingTarget = true;
            //homeBase.maxPlanes -= 3;
            foreach (string str in GndStatDead)
                GamePlay.gpLogServer(null, "OnBattleStoped GndStatDead: {0}", new object[] { str });
        };

        if (playerWasAirborne)
        {
            if (!bombersLeavingTarget)
            {   // someone tried to milk the mission :)
                if (targetAirport != null)
                    if (TargetGroup != null)
                        if (TargetGroup.hasBombs() || TargetGroup.hasBombsInInternalBays())
                            bombsOnTarget += rnd.Next(1, 5) * Math.Pow(targetAirport.CoverageR(), 2) / 100;

                if (convoyTarget != null)
                    if (TargetGroup != null)
                        if (TargetGroup.hasBombs() || TargetGroup.hasTorpedos() || TargetGroup.hasBombsInInternalBays())
                        {
                            if (odenDebug) GamePlay.gpLogServer(null, "playerWasAirborne= {0} bombersLeavingTarget={1} convoyTarget={2}", new object[] { playerWasAirborne, bombersLeavingTarget, convoyTarget.Name() });
                            Point3d pt3d = new Point3d(convoyTarget.Pos().x, convoyTarget.Pos().y, 0);
                            foreach (AiGroundGroup gg in ConvoyShips)
                                if (gg.Pos().distance(ref pt3d) < 16090)
                                {
                                    GndGrpDead.Add(gg.Name());
                                    misConvoyKills += 1;
                                    highOctaneDate = highOctaneDate.AddDays(1);
                                    bombsOnTarget = rnd.Next(1000, 3000);
                                };
                        };

                if (mainGSTarget != null)
                    if (TargetGroup != null)
                        if (TargetGroup.hasBombs() || TargetGroup.hasTorpedos() || TargetGroup.hasBombsInInternalBays())
                        {
                            if (odenDebug) GamePlay.gpLogServer(null, "OnBattleStoped: bombersLeavingTarget={0} mainGSTarget={1}", new object[] { bombersLeavingTarget, mainGSTarget.Name });
                            Point2d pt2d = new Point2d(mainGSTarget.pos.x, mainGSTarget.pos.y);
                            if (mainGSTarget.Title.Contains("EnglishRadar3"))
                            {
                                string areaName = ChainHomeRadarName(pt2d);
                                mainStoryList.Add(CountryAirforce((ATK == LW ? BlueCoalition : RedCoalition)) + " destroyed " + areaName + " Radar Station");
                                GndStatDead.Add(mainGSTarget.Name);
                            };
                            if (mainGSTarget.Title.Contains("PortCrane1_UK1"))
                            {
                                string areaName = PortDockName(pt2d);
                                mainStoryList.Add(CountryAirforce((ATK == LW ? BlueCoalition : RedCoalition)) + " destroyed " + areaName + ", 100 octane fuel deliveries and factory output delayed for a day");
                                GndStatDead.Add(mainGSTarget.Name);
                            };
                            if (mainGSTarget.Title.Contains("Oxygen_Facility"))
                            {
                                mainStoryList.Add(CountryAirforce((ATK == LW ? BlueCoalition : RedCoalition)) + " destroyed industry area, factory output delayed for a week");
                                GndStatDead.Add(mainGSTarget.Name);
                            };
                            mainGSTarget.Destroy();
                            bombsOnTarget = rnd.Next(1000, 3000);
                        };
                if (groundAssaultFrom.Length > 0)
                    MissionMarkers[idxTarget].army = ATK;
            };


            if (odenDebug)
                if (mainStoryList.Count > 0)
                    GamePlay.gpLogServer(null, "summary: bombsOnTarget={0}, {1}", new object[] { bombsOnTarget, mainStoryList[mainStoryList.Count - 1] });



            // 25% randomized kill for damaged aircrafts (until figure out how to get damage %)
            foreach (AiAircraft ac in damagedAircrafts)
                if (ac != null)
                    if (ac.IsAirborne() && rnd.Next(100) < 25)
                        foreach (MissionAirbase ab in MissionAirbases)
                            if (ab.sqn == ac.Regiment().name())
                            {
                                Point3d pt3d = ac.Pos();
                                if (ab.Pos().distance(ref pt3d) > 2000)
                                {
                                    ab.maxPlanes -= 1;
                                    if (ab.type.Contains("Fighter"))
                                        if (ac.Army() == RAF) misRAFDeadF += 1;
                                        else misLWDeadF += 1;
                                    if (ab.type.Contains("Bomber"))
                                        if (ac.Army() == RAF) misRAFDeadB += 1;
                                        else misLWDeadB += 1;
                                    if (ab.type.Contains("Zerstorer")) misLWDeadF += 1;
                                    if (ab.type.Contains("Stuka")) misLWDeadS += 1;
                                };
                                break;
                            };


            int scoreRed = deadStaticsBlue + misLWDeadF + misLWDeadB + misLWDeadS;
            int scoreBlue = deadStaticsRed + misRAFDeadF + misRAFDeadB;
            if (ATK == LW) scoreBlue += (int)Math.Ceiling(bombsOnTarget / 1000); // 1000kg
            else scoreRed += (int)Math.Ceiling(bombsOnTarget / 1000); // 2200lb
            if (scoreRed > scoreBlue) missionVictory = RAF;
            if (scoreBlue > scoreRed) missionVictory = LW; if (missionVictory == 0)
                if (rnd.Next(10) > 5) missionVictory = RAF;
                else missionVictory = LW;

            if (fmCurrent != "")
            {
                mmPrevBattle = mmCurrentBattle;
                if (missionVictory != ATK) ConsecutiveLosses++;
                else ConsecutiveLosses = 0;
                //if(odenDebug)
                //    if (ATK == RAF)
                //        ConsecutiveLosses = 3;

                if (playerKilledTargets > 0) playerHasHitTarget = true;
                BattleProgress++; // normal progress 3 battles per town
                if (!playerWasKilled && !playerHasHitTarget) BattleProgress--; // no job done, stalled progress
                if (!playerWasKilled && playerKilledTargets > 0) BattleProgress++; // killed target, extra progress
                if (!playerWasKilled && playerKilledTargets > 1) BattleProgress++; // killed multiple, extra progress
                if (playerWasKilled && playerKilledTargets == 0) BattleProgress--; // killed but no kills despite any hits
                //if (playerWasKilled && playerKilledTargets > 0) .. // killed with kills, no change

                if (BattleProgress > 2 || ConsecutiveLosses > 2)
                {   // battle victory, find next
                    if (ConsecutiveLosses > 2)
                    {
                        // defender go on offensive
                        if (SideOnOffensive == LW) SideOnOffensive = RAF;
                        else SideOnOffensive = LW;
                        InitiativeChanged = true;
                        ConsecutiveLosses = 0;
                        BattleProgress = 0;
                        ATK = SideOnOffensive;
                    };
                    GndStatDead.Clear(); // make room for other side units if battle returns heading other way
                    // find current campaign battle set
                    List<string[]> currBattleSet = CampaignBattleSet();
                    if (currBattleSet != null)
                    {
                        string currFM = mmCurrentBattle.key;
                        int forEachIdx = 0, currIdx = 0;
                        foreach (string[] fmArr in currBattleSet)
                        {   // find current battle
                            foreach (string str in fmArr)
                                if (currFM.Equals(str))
                                    currIdx = forEachIdx;
                            forEachIdx++;
                        };
                        // update all battles in just captured battle set
                        foreach (MissionMarker mm in MissionMarkers)
                            foreach (string bb in currBattleSet[currIdx])
                                if (mm.key.Equals(bb))
                                {
                                    if (mm.army != ATK)
                                        CapturedAreas.Add(MissionMarkerName(mm.key));
                                    mm.army = ATK;
                                };

                        if (SideOnOffensive == LW) currIdx--; // next battle set Axis
                        else currIdx++; // next battle set Allies

                        if (currIdx < currBattleSet.Count && currIdx > -1)
                        {   // not last battle set captured
                            string[] mmKey = currBattleSet[currIdx]; // battleset containing next FrontMarker#
                            string nextFM = mmKey[0];
                            // find MM of last fm in new battle set
                            foreach (MissionMarker mm in MissionMarkers)
                                if (mm.key.Equals(nextFM))
                                    mmCurrentBattle = mm; // MM of found FM
                            fmCurrent = mmCurrentBattle.key;
                            if (odenDebug) GamePlay.gpLogServer(null, "BattleProgress got {0} {1}", new object[] { mmCurrentBattle.key, mmCurrentBattle.army });
                        }
                        else
                        {   // game over :)
                            fmCurrent = "";
                            mmCurrentBattle = null;
                            bobVicSide = 0;
                        };
                        BattleProgress = 0;
                    }
                    else
                    {   // Warfare, no battlesets
                        mmCurrentBattle.army = ATK;
                        CapturedAreas.Add(MissionMarkerName(mmCurrentBattle.key));
                        mmCurrentBattle = SelectNextMissionMarker(mmCurrentBattle.Pos2d());
                        if (mmCurrentBattle != null)
                        {
                            fmCurrent = mmCurrentBattle.key;
                            BattleProgress = 0;
                        };
                    };
                };

                if (mmCurrentBattle != null)
                {
                    addDays = 1;
                    gameDateTime = gameDateTime.AddDays(addDays);
                    if (highOctaneDate < gameDateTime) highOctaneDate = gameDateTime;

                    if (transferHomeBase != null)
                        homeBase = transferHomeBase;

                    UpdateInitFile();
                    UpdateBriefing();
                    UpdateMissionFile();
                }
                else
                {
                    CreateInitFiles();
                };
            }
            else
            {   // no ground war
                addDays = rnd.Next(2, 8);
                gameDateTime = gameDateTime.AddDays(addDays);
                if (highOctaneDate < gameDateTime) highOctaneDate = gameDateTime;

                if (transferHomeBase != null)
                    homeBase = transferHomeBase;

                if (CampaignName == cBattleOfBritain)
                {
                    bobVicSide = BattleOfBritainVictoryCheck();
                    if (bobVicSide != 0)
                        SideOnOffensive = bobVicSide;
                };
                UpdateInitFile();
                UpdateBriefing();
                UpdateMissionFile();
            };

        };

        //foreach (GPUserLabel ul in UserLabels) GamePlay.gpDeleteUserLabel(ul); // if some are still around
        //UserLabels.Clear();
        //GamePlay.gpLogServer(null, "OnBattleStoped: '{0}'", new object[] { "Oden Dynamic Campaign" });
    }
    public override void OnSingleBattleSuccess(bool success)
    {
        if (success) GamePlay.gpHUDLogCenter(new Player[] { GamePlay.gpPlayer() }, "Mission Success today if everyone makes it home");
        else GamePlay.gpHUDLogCenter(new Player[] { GamePlay.gpPlayer() }, "Looks like we're going to lose today");
    }
    public override void OnMissionLoaded(int missionNumber)
    {
        base.OnMissionLoaded(missionNumber);

        CAPStaffelIndex = 0;
        CAPFlightIndex = 0;
        BMBStaffelIndex = 0;
        BMBFlightIndex = 0;
        BMBFlightAlt = 0;
        BMBFlightSpeed = 0;
        BMBFlightAB = null;
        activatedAirports.Clear();
    }
    public override void OnTickGame()
    {
        base.OnTickGame();

        if (Time.tickCounter() % 3600 == 1500) // every 2min c:a
        {
            DateTime currDT = DateTime.Now;
            if (odenDebug) GamePlay.gpLogServer(null, "OnTickGame: bombersLeavingTarget={0}", new object[] { bombersLeavingTarget }); // debug tracing System.NullReferenceException
            List<AiAirGroup> AirGroups = new List<AiAirGroup>();
            foreach (AiAirGroup ag in GamePlay.gpAirGroups(LW)) AirGroups.Add(ag);
            foreach (AiAirGroup ag in GamePlay.gpAirGroups(RAF)) AirGroups.Add(ag);
            if (StrikerGroupName != "")
            {   // check if strikers got killed prior reaching target
                foreach (AiAirGroup ag in AirGroups)
                    if(ag != null)
                        if (ag.Name().Equals(StrikerGroupName))
                            if (ag.GetItems().Length == 0)
                                bombersLeavingTarget = true;
            };
            // free roaming groups
            if (bombersLeavingTarget)
            {
                UpdatePlayerRTB(true);
            }
            else
            {
                if (odenDebug)
                {
                    if (EscortedGroup != null) GamePlay.gpLogServer(null, "EscortedGroup: '{0}'", new object[] { EscortedGroup.Name() });
                    if (TargetGroup != null) GamePlay.gpLogServer(null, "TargetGroup: '{0}'", new object[] { TargetGroup.Name() });
                    else GamePlay.gpLogServer(null, "No TargetGroup: '{0}' {1} {2}", new object[] { StrikerGroupName, gameIsOn, missionVictory });
                };
                foreach (AiAirGroup ag in AirGroups)
                    if (ag != null)
                        if (AiAirGroupCanIntercept(ag) && !AiAirGroupHasGroundTarget(ag))
                        {
                            if (TargetGroup != null)
                            {
                                if (TargetGroup.Army() != ag.Army()) InterceptWP((AiGroup)ag);
                            }
                            else UpdateWP((AiGroup)ag);
                            if (EscortedGroup != null)
                            {
                                if (EscortedGroup.Army() == ag.Army()) GiveNewWP((AiGroup)ag, HalfwayToTarget2d(ag));
                                else UpdateWP((AiGroup)ag);
                            }
                            else UpdateWP((AiGroup)ag);
                        };
                /*
                if (PlayerIsBomber())
                {
                    AiAircraft pac = (AiAircraft)GamePlay.gpPlayer().Place();
                    AiAirGroup pag = pac.AirGroup();
                    if (pag.GetWay().Length == 2 && pag.GetCurrentWayPoint() == 1)
                    {   // only default wp's
                        if (odenDebug) GamePlay.gpLogServer(null, "PlayerIsBomber: '{0}'", new object[] { pag.Name() });
                        if (convoyTarget != null) CreatePlayerBombMission(convoyTarget.Pos(), convoyTarget);
                        else CreatePlayerBombMission(target3d, null);
                    };
                    sayBombTarget(pac, pag, target2d);
                };*/

                if (EscortedGroup != null && timeoutRadio < currDT)
                    EscortUpdateMsg();

                if (TargetGroup != null && timeoutRadio < currDT)
                {   // ground control Fighter Command
                    GndCtrlUpdateMsg();
                }
                else
                {
                    if (TargetGroup == null)
                    {
                        if (gameIsOn)
                        {
                            if (missionVictory == 0)
                                foreach (AiAirGroup ag in GamePlay.gpAirGroups(ATK))
                                    if (AiAirGroupHasGroundTarget(ag))
                                    {
                                        if (odenDebug) GamePlay.gpLogServer(null, "AiAirGroupHasGroundTarget: '{0}'", new object[] { ag.Name() });
                                        AiActor a = GetFlightLeader(ag);
                                        if (ag.Name().Contains(StrikerGroupName))
                                            if (a != null)
                                            {
                                                if (TargetGroup == null)
                                                    if (ChainHomeRadarDetected((AiAircraft)a))
                                                        TargetGroup = ag;
                                                    else
                                                    {   // Observer Corps
                                                        if (GamePlay.gpFrontArmy(ag.Pos().x, ag.Pos().y) == (ATK == LW ? RAF : LW))
                                                            if (detectedByObsCorps) TargetGroup = ag;
                                                            else detectedByObsCorps = true;
                                                    };
                                                if (EscortedGroup == null)
                                                    EscortedGroup = ag;
                                            };
                                        if (TargetGroup != null)
                                            break;
                                    };

                            if (TargetGroup != null)
                                timeoutRadio = DateTime.Now; // interrupt any chattering
                        };
                    };
                };
            };

        };
    }
    public override void OnTrigger(int missionNumber, string shortName, bool active)
    {
        base.OnTrigger(missionNumber, shortName, active);

        if (odenDebug) GamePlay.gpLogServer(null, "Trigger for ({0}:) {1} active={2}", new object[] { missionNumber,shortName, active.ToString() });

        if (active)
        {
            //AiTrigger trigger = GamePlay.gpGetTrigger(shortName);
            Point2d pt2d;
            switch (shortName)
            {
                case "DeSpawnLW":
                    pt2d = new Point2d(360000, 270000);
                    List<AiActor> actorsLW = FindAircrafts(LW);
                    foreach (AiActor a in actorsLW)
                    {
                        Point2d ac2d = new Point2d(a.Pos().x, a.Pos().y);
                        if (odenDebug) GamePlay.gpLogServer(null, "DeSpawnLW for {0} ({1})", new object[] { a.Name(), ac2d.distance(ref pt2d) });
                        if (a is AiAircraft)
                            if (ac2d.distance(ref pt2d) < 1609)
                                (a as AiAircraft).Destroy();
                    };
                    break;
                case "DeSpawnRAF":
                    pt2d = new Point2d(180000, 310000);
                    List<AiActor> actorsRAF = FindAircrafts(RAF);
                    foreach (AiActor a in actorsRAF)
                    {
                        Point2d ac2d = new Point2d(a.Pos().x, a.Pos().y);
                        if (a is AiAircraft)
                            if (ac2d.distance(ref pt2d) < 1609)
                                (a as AiAircraft).Destroy();
                    };
                    break;
            };
        }
        else
        {   // triggers going false for logic
            if (shortName.Equals("BombersAtTarget"))
            {
                bombersLeavingTarget = true;
                int scoreRed = deadStaticsBlue + misLWDeadF + misLWDeadB + misLWDeadS;
                int scoreBlue = deadStaticsRed + misRAFDeadF + misRAFDeadB;
                if (ATK == LW) scoreBlue += (int)Math.Ceiling(bombsOnTarget / 1000); // 1000kg
                else scoreRed += (int)Math.Ceiling(bombsOnTarget / 1000); // 2200lb
                if (scoreRed > scoreBlue) missionVictory = RAF;
                if (scoreBlue > scoreRed) missionVictory = LW;
                if (missionVictory == 0)
                    if (rnd.Next(10) > 5) missionVictory = RAF;
                    else missionVictory = LW;
                if (GamePlay.gpPlayer() != null) // prelim victory
                    sayMissionOver(missionVictory);

                if (lastCampaignMission && GamePlay.gpPlayer().Army() == missionVictory && missionVictory == SideOnOffensive)
                {   // give player campaign if lastmission victory and initiative no matter battleprogress
                    ConsecutiveLosses = 0;
                    BattleProgress = 3;
                    GamePlay.gpHUDLogCenter(new Player[] { GamePlay.gpPlayer() }, "Congratulations! You have won the Campaign!");
                };
                Battle.doSingleBattleSuccess(missionVictory == GamePlay.gpPlayer().Army());
            };
        };
    }
    public override void OnPlaceEnter(Player player, AiActor actor, int placeIndex)
    {
        base.OnPlaceEnter(player, actor, placeIndex);

        if (player.Place() is AiAircraft)
        {
            AiAircraft ac = player.Place() as AiAircraft;
            if (ac.IsAirborne())
                playerWasAirborne = true;
            if (odenDebug) GamePlay.gpLogServer(null, "OnPlaceEnter: {0} actor: {1} {2}", new object[] { player, actor.Name(), playerWasAirborne });
            if (player.Army() == RAF)
                Timeout(5, () =>
                {   // bite me
                    double dir = ac.getParameter(part.ParameterTypes.Z_Orientation, 0);
                    dir = 90f - dir; // shows 160 heading NW, 0 due east, -90 south and 90 north
                    if (dir < 0) dir += 360f;
                    if (odenDebug) GamePlay.gpLogServer(null, "OnPlaceEnter: dir:{0} mag: {1}", new object[] { dir, ac.getParameter(part.ParameterTypes.Z_Orientation, 0) });
                    GamePlay.gpHUDLogCenter(new Player[] { player }, "Set your gyro to " + dir.ToString("F0"));
                });
            PlayersData.Add(new PlayerData { player = player, homeAirport = FindAirport(player.Army(), player.Place().Pos(), 0) });
            SetOrderMissionMenuOden(player);
        };
    }
    public override void OnActorCreated(int missionNumber, string shortName, AiActor actor)
    {
        base.OnActorCreated(missionNumber, shortName, actor);

        if (shortName == "NONAME") return;
        //if (odenDebug) GamePlay.gpLogServer(null, "OnActorCreated: shortName:{0} actor.Name(): {1}", new object[] { shortName, actor.Name() });
        if (actor != null)
        {
            if (actor is AiAircraft)
            {
                if (shortName.Contains("gb01.") && missionNumber == 1)
                {
                    if (GamePlay.gpPlayer().Army() == RAF)
                        if (!PlayerIsBomber() && !playerFlightCAS && !playerFlightBMB)
                            GroundControlCheckIn(actor as AiAircraft);
                };
                if (shortName.Contains("g06.") && missionNumber == 1)
                {
                    if (GamePlay.gpPlayer().Army() == LW)
                        if (!PlayerIsBomber() && !playerFlightCAS && !playerFlightBMB)
                            GroundControlCheckIn(actor as AiAircraft);
                };
            };

            if (actor is AiAirGroup)
            {
                if (odenDebug) GamePlay.gpLogServer(null, "OnActorCreated AiAirGroup: {0} actor: {1}", new object[] { shortName, actor.Name() });
                AiAirGroup airGroup = (AiAirGroup)actor;
                AirGroupNames.Add(shortName);
                AirGroupIDs.Add(airGroup.ID());
                if (airGroup.Army() != ATK) AiAirGroupsStdby.Add(airGroup);
                if (StrikerGroupName == shortName)
                    TriggerGroup = airGroup;
                //if (odenDebug) GamePlay.gpLogServer(null, "OnActorCreated AiAirGroup: {0} actor: {1} ({2})", new object[] { airGroup.ID(), actor.Name(), TriggerGroup != null });
                //-- find airfield spawnpoints and put proper statics
                if (shortName.Contains("RAF_B_144Sqn"))
                {
                    AirfieldSpawnPos.Clear();
                    Point2d pt2d = new Point2d(0, 0);
                    foreach (AiAircraft ac in (actor as AiAirGroup).GetItems())
                    {
                        pt2d.x = ac.Pos().x;
                        pt2d.y = ac.Pos().y;
                        AirfieldSpawnPos.Add(ac.Pos().x.ToString() + " " + ac.Pos().y.ToString() + " " + ac.getParameter(part.ParameterTypes.Z_Orientation, 0).ToString());
                        ac.Destroy();
                    };
                    int airfieldarmy = GamePlay.gpFrontArmy(pt2d.x, pt2d.y);
                    if (odenDebug) GamePlay.gpLogServer(null, "Airfield statics: {0} at {1}", new object[] { AirfieldSpawnPos.Count, airfieldarmy });
                    string ctry = BlueCoalition;
                    string planeType = LWFighterSet[rnd.Next(LWFighterSet.Count)];
                    if (BlueCoalition == "it") planeType = RAFighterSet[rnd.Next(RAFighterSet.Count)];
                    if (airfieldarmy == RAF)
                    {
                        planeType = RAFFighterSet[rnd.Next(RAFFighterSet.Count)];
                        ctry = RedCoalition;
                    };
                    if (odenDebug) GamePlay.gpLogServer(null, "Airfield statics: {0} default {1}", new object[] { AirfieldSpawnPos.Count, planeType });
                    switch (ctry)
                    {
                        case "cw": ctry = "au";
                            break;
                        case "fr":
                        case "al": ctry = "gb";
                            break;
                        case "ax": ctry = "de";
                            break;
                    };
                    int qty = 15;
                    string keyPrefix = "NoSqn";
                    foreach (MissionAirbase mab in MissionAirbases)
                        if (mab.ap != null)
                            if (mab.Pos2d().distance(ref pt2d) < mab.ap.CoverageR()) // exact type if sqn exists at field
                            {
                                keyPrefix = mab.sqn;
                                planeType = mab.aircraftType;
                                qty = mab.maxPlanes;
                            };

                    planeType = "Stationary" + planeType.Substring(planeType.IndexOf('.'));
                    if (odenDebug) GamePlay.gpLogServer(null, "Airfield static: {0} {1} {2}", new object[] { keyPrefix, planeType, ctry });
                    ISectionFile f = GamePlay.gpCreateSectionFile();
                    string sect = "Stationary";
                    int forEachIdx = 0, aaa = 0;
                    foreach (string posAndDir in AirfieldSpawnPos)
                    {
                        string key = keyPrefix + "_Static" + forEachIdx.ToString();
                        string value = planeType + " " + ctry + " " + posAndDir;
                        if (rnd.Next(10) < 2)
                            if (airfieldarmy == LW) value = BlueStationaryList[rnd.Next(BlueStationaryList.Count)] + " " + posAndDir;
                            else value = RedStationaryList[rnd.Next(RedStationaryList.Count)] + " " + posAndDir;
                        if (qty > forEachIdx) AddToFile(f, sect, key, value);
                        else
                        {
                            if (aaa < 5)
                            {
                                string lightAAA = "Artillery.Bofors gb ";
                                if (airfieldarmy == LW)
                                    if (5 > rnd.Next(10)) lightAAA = "Artillery.4_cm_Flak_28 de ";
                                    else lightAAA = "Artillery.20_mm_Flak_38 de ";
                                value = lightAAA + " " + posAndDir + " /timeout 0/radius_hide 0";
                                AddToFile(f, sect, key, value);
                                aaa++;
                            };
                        };
                        forEachIdx++;
                    };
                    GamePlay.gpPostMissionLoad(f);
                    NextMissionNum++;
                };
            };
        };
    }
    public override void OnActorDamaged(int missionNumber, string shortName, AiActor actor, AiDamageInitiator initiator, part.NamedDamageTypes damageType)
    {
        base.OnActorDamaged(missionNumber, shortName, actor, initiator, damageType);

        if (odenDebug) GamePlay.gpLogServer(null, "OnActorDamaged AiActor: {0} actor: {1}", new object[] { shortName, actor.Name() });

    }
    public override void OnActorDead(int missionNumber, string shortName, AiActor actor, List<DamagerScore> initiatorList)
    {
        base.OnActorDead(missionNumber, shortName, actor, initiatorList);

        // this trigger on classes not starting with "Stationary" such as "Vehicle" and "Artillery"
        if (actor == null)
            return;
        if (Time.tickCounter() < 900) // spawn error within first 30 secs (30 ticks a second)
            return;

        //if (odenDebug) GamePlay.gpLogServer(null, "OnActorDead shortName: {0} actor: {1} hit by:{2}", new object[] { shortName, actor.Name(), initiatorList.Count });

        if (GamePlay.gpPlayer() != null)
        {
            if (GamePlay.gpPlayer().Place() != null)
            {
                if (GamePlay.gpPlayer().Place() == actor)
                    playerWasKilled = true;

                foreach (DamagerScore ds in initiatorList)
                    if (ds.initiator.Actor == GamePlay.gpPlayer().Place())
                    {
                        if (actor.Army() != GamePlay.gpPlayer().Army())
                            playerKilledTargets++;
                        break;
                    };
            };
        };

        if (shortName.StartsWith("Static"))
            if (shortName.Contains("_"))
                GndStatDead.Add(shortName.Substring(0, shortName.IndexOf('_')));

        if (actor is AiGroundActor)
        {
            AiGroundActor gndActor = (AiGroundActor)actor;
            if (gndActor.Type().ToString().Equals("ShipTransport"))
            {
                misConvoyKills += 1;
                GndGrpDead.Add(actor.Name());
                highOctaneDate = highOctaneDate.AddDays(1);
            }
            else
            {
                if (actor.Army() == ATK) destroyedUnits += 1;
            };
        };

        if (actor is AiAircraft)
        {
            AiAircraft ac = (AiAircraft)actor;
            AiAirGroup ag = ac.AirGroup();
            if (odenDebug) GamePlay.gpLogServer(null, "OnActorDead AiAircraft: '{0}' '{1}' '{2}'", new object[] { ac.InternalTypeName(), ac.Regiment().name(), ag.Name() });
            AircraftUpdateDead(ac);

            if (GamePlay.gpPlayer() == null)
                return;
            if (GamePlay.gpPlayer().Place() == null)
                return;
            if ((AiGroup)ag == GamePlay.gpPlayer().Place().Group())
            {
                AiAircraft pac = (AiAircraft)GamePlay.gpPlayer().Place();
                if (pac != null)
                {
                    AiActor leader = GetFlightLeader(ag);
                    int entry = rnd.Next(0, 17);
                    if (actor == leader)
                        entry = 18 + rnd.Next(0, 2);

                    switch (entry)
                    {
                        case 0: pac.SayToGroup(pac.AirGroup(), "Watch_out1"); break;
                        case 1: pac.SayToGroup(pac.AirGroup(), "Watch_out2"); break;
                        case 2: pac.SayToGroup(pac.AirGroup(), "Watch_out3"); break;
                        case 3: pac.SayToGroup(pac.AirGroup(), "Watch_out4"); break;
                        case 4: pac.SayToGroup(pac.AirGroup(), "We_are_under_attack_Repeat_we_are_under_attack_We_have_lost_aircraft"); requestAssistance(0, false); break;
                        case 5: pac.SayToGroup(pac.AirGroup(), "We_are_under_attack_requesting_immediate_assistance"); requestAssistance(0, false); break;
                        case 6: pac.SayToGroup(pac.AirGroup(), "We_are_under_attack_we_need_assistance_over"); requestAssistance(0, false); break;
                        case 7: pac.SayToGroup(pac.AirGroup(), "You_Come_on_men_we_can_do_better_than_that"); break;
                        case 8: pac.SayToGroup(pac.AirGroup(), "Hell"); break;
                        case 9: pac.SayToGroup(pac.AirGroup(), "Hell1"); break;
                        case 10: pac.SayToGroup(pac.AirGroup(), "Hell2"); break;
                        case 11: pac.SayToGroup(pac.AirGroup(), "Hell3"); break;
                        case 12: pac.SayToGroup(pac.AirGroup(), "Hell4"); break;
                        case 13: pac.SayToGroup(pac.AirGroup(), "Damn"); break;
                        case 14: pac.SayToGroup(pac.AirGroup(), "Damn1"); break;
                        case 15: pac.SayToGroup(pac.AirGroup(), "Bail_out_for_Gods_sakes"); break;
                        case 16: pac.SayToGroup(pac.AirGroup(), "Bail_out_Bail_out"); break;
                        case 17: pac.SayToGroup(pac.AirGroup(), "Bail_Out"); break;

                        case 18: pac.SayToGroup(pac.AirGroup(), "Blast_it_Is_that_the_squadron_leader_going_down"); break;
                        case 19: pac.SayToGroup(pac.AirGroup(), "Bloody_hell_we_ve_lost_the_squadron_leader"); break;
                        case 20: pac.SayToGroup(pac.AirGroup(), "The_squadron_leader_s_done_for_What_are_we_going_to_do"); break;
                    };
                };
            };
        }
        else
        {
            if (actor.Army() == RAF) deadStaticsRed++;
            if (actor.Army() == LW) deadStaticsBlue++;
        };
    }
    public override void OnStationaryKilled(int missionNumber, GroundStationary gs, AiDamageInitiator initiator, int eventArgInt)
    {
        base.OnStationaryKilled(missionNumber, gs, initiator, eventArgInt);

        // this trigger on classes starting with "Stationary"
        if (odenDebug) GamePlay.gpLogServer(null, "OnStationaryKilled: {0} {1} {2} {3} Initiator: {4}", new object[] { gs.Category, gs.country, gs.Name, gs.Title, initiator.Actor.Name() });
        if (initiator.Player != null)
            //if (odenDebug) GamePlay.gpLogServer(null, "OnStationaryKilled by Player: {0}", new object[] { initiator.Player.Name() });
            playerKilledTargets++;

        if (CountrySide(gs.country) == RAF) deadStaticsRed++;
        if (CountrySide(gs.country) == LW) deadStaticsBlue++;

        string shortName = gs.Name;
        if (shortName.Contains(":"))
            shortName = shortName.Substring(shortName.IndexOf(':') + 1);
        if (shortName.StartsWith("Static"))
            if (shortName.Contains("_"))
                shortName = shortName.Substring(0, shortName.IndexOf('_'));
        GndStatDead.Add(shortName);
        if (shortName.Contains("BoB_"))
            foreach (MissionAirbase mab in MissionAirbases)
                if (shortName.Contains(mab.sqn))
                    mab.maxPlanes--;
    }
    public override void OnBombExplosion(string title, double mass, Point3d pos3d, AiDamageInitiator initiator, int eventArgInt)
    {
        base.OnBombExplosion(title, mass, pos3d, initiator, eventArgInt);

        //if (GamePlay.gpLandType(pos3d.x, pos3d.y).ToString().Equals("WATER")) return;
        //if (odenDebug) GamePlay.gpLogServer(null, "OnBombExplosion: a:{0} p:{1}/{2}", new object[] { initiator.Actor, initiator.Person, initiator.Player });
        if (targetAirport != null)
            if (targetAirport.Pos().distance(ref pos3d) < targetAirport.CoverageR())
            {
                bombsOnTarget += mass;
                if (initiator.Player != null)
                    playerHasHitTarget = true;
            };
        if (mainGSTarget != null)
            if (mainGSTarget.pos.distance(ref pos3d) < 1000) // 1km target radius
            {
                bombsOnTarget += mass;
                if (initiator.Player != null)
                    playerHasHitTarget = true;
            };
        if (playerTargetAirport != null)
            if (playerTargetAirport.Pos().distance(ref pos3d) < playerTargetAirport.CoverageR())
            {
                if (initiator.Player != null)
                    playerHasHitTarget = true;
            };
    }
    /*
    public override void OnBuildingKilled(string title, maddox.GP.Point3d pos, maddox.game.world.AiDamageInitiator initiator, int eventArgInt)
    {
        base.OnBuildingKilled(title, pos, initiator, eventArgInt);
        if (odenDebug) GamePlay.gpLogServer(null, "OnBuildingKilled: '{0}' '{1}' '{2}' '{3}'", new object[] { title, pos, initiator, eventArgInt });
    }
    */
    public override void OnAircraftTookOff(int missionNumber, string shortName, AiAircraft aircraft)
    {
        base.OnAircraftTookOff(missionNumber, shortName, aircraft);

        if (aircraft != null)
            if (aircraft.Player(0) != null)
            {
                playerWasAirborne = true;
                //Battle.doSingleBattleSuccess(true);
                if (playerFlightCAS || playerFlightBMB)
                {
                    List<GroundStationary> targets = new List<GroundStationary>();
                    foreach (GroundStationary gs in GamePlay.gpGroundStationarys(target2d.x, target2d.y, 5000))
                        if (!gs.Name.Contains("NONAME") && !gs.Name.StartsWith("0:"))
                            targets.Add(gs);
                    if (!playerFlightBMB)
                        if (targets.Count == 0)
                            return;
                    while (targets.Count > 5)
                        targets.RemoveAt(rnd.Next(targets.Count - 1));
                    if (odenDebug) GamePlay.gpLogServer(null, "PlayerCASMission: bmb:{0} tgts:{1}", new object[] { playerFlightBMB, targets.Count });
                    Point2d pt2d = target2d;
                    Point3d pt3d = target3d;
                    if (playerFlightBMB)
                    {
                        pt2d = new Point2d(playerTargetAirport.Pos().x, playerTargetAirport.Pos().y);
                        pt3d = playerTargetAirport.Pos();
                    };

                    AiWayPoint[] arrWP = aircraft.Group().GetWay();
                    AiAirWayPoint lastAWP = (AiAirWayPoint)arrWP[arrWP.Length - 1];
                    Point2d ib2d = new Point2d(lastAWP.P.x, lastAWP.P.y);
                    Point2d ip2d = calcPos(pt2d, ib2d.distance(ref pt2d) / 2, calcDir(pt2d, ib2d) - 30 + rnd.Next(60));
                    List<AiAirWayPoint> arrAWP = new List<AiAirWayPoint> { };

                    AiAirWayPoint nextAWP = new AiAirWayPoint(ref lastAWP.P, lastAWP.Speed);
                    nextAWP.Action = AiAirWayPointType.NORMFLY;
                    arrAWP.Add(nextAWP);

                    int alt = rnd.Next(1200, 2500);
                    if (aircraft.Type().ToString().Contains("DiveBomber"))
                        alt = rnd.Next(2300, 3300);
                    if (aircraft.Type().ToString().Contains("Blenheim"))
                        alt = rnd.Next(800, 1200);
                    if (aircraft.Type().ToString().Contains("HeavyFighter"))
                        alt = rnd.Next(800, 1200);
                    if (aircraft.Type().ToString().Contains("TorpedoBomber"))
                        alt = rnd.Next(500, 800);
                    Point3d wp3d = new Point3d(ip2d.x, ip2d.y, alt);
                    nextAWP = new AiAirWayPoint(ref wp3d, 401);
                    nextAWP.Action = AiAirWayPointType.NORMFLY;
                    arrAWP.Add(nextAWP); // ingress point
                    if (targets.Count > 0 && alt > 2000 && !aircraft.Type().ToString().Contains("DiveBomber"))
                    {
                        mainGSTarget = targets[0];
                        targets.Clear();
                    };
                    foreach (GroundStationary gs in targets)
                    {
                        if (odenDebug) GamePlay.gpLogServer(null, "PlayerCASMission: {0} {1}", new object[] { "2", gs.Name });
                        nextAWP = new AiAirWayPoint(ref pt3d, 350);
                        if (aircraft.Type().ToString().Contains("DiveBomber"))
                        {
                            nextAWP.Action = AiAirWayPointType.GATTACK_TARG;
                            nextAWP.GAttackType = AiAirWayPointGAttackType.DIVE;
                        }
                        else
                        {
                            nextAWP.Action = AiAirWayPointType.GATTACK_TARG;
                            if (aircraft.Type().ToString().Contains("Fighter")) nextAWP.GAttackType = AiAirWayPointGAttackType.SHALLOW_DIVE;
                            else nextAWP.GAttackType = AiAirWayPointGAttackType.LEVEL;
                        };
                        if (aircraft.Type().ToString().Contains("DiveBomber")) nextAWP.GAttackPasses = AiAirWayPointGAttackPasses._2;
                        else nextAWP.GAttackPasses = AiAirWayPointGAttackPasses._1;
                        nextAWP.Target = (gs as AiActor);
                        arrAWP.Add(nextAWP);
                    };

                    if (targets.Count == 0)
                    {
                        nextAWP = new AiAirWayPoint(ref pt3d, alt);
                        if (aircraft.Type().ToString().Contains("DiveBomber")) nextAWP.GAttackType = AiAirWayPointGAttackType.DIVE;
                        else
                            if (aircraft.Type().ToString().Contains("Fighter")) nextAWP.GAttackType = AiAirWayPointGAttackType.SHALLOW_DIVE;
                            else nextAWP.GAttackType = AiAirWayPointGAttackType.LEVEL;

                        nextAWP.Action = AiAirWayPointType.GATTACK_POINT;
                        nextAWP.GAttackPasses = AiAirWayPointGAttackPasses._1;
                        arrAWP.Add(nextAWP);
                    };

                    if (playerFlightBMB)
                    {
                        int qty = 8;
                        if (homeBase.army == RAF && gameDateTime.Year < 1941) qty = 6; // todo italians
                        ISectionFile f = GamePlay.gpCreateSectionFile();
                        if (rnd.Next(10) > 7) CreateCAPMission(f, pt2d, qty, homeBase.army, false); // surprise TARCAP
                        string sqn = GamePlay.gpPlayer().Place().Group().Name();
                        sqn = sqn.Substring(sqn.IndexOf('.') + 1);
                        f.add("Trigger", "BombersAtTarget", "TPassThrough 1 " + sqn + " " + pt2d.x.ToString() + " " + pt2d.y.ToString() + " 12000");
                        if (odenDebug) GamePlay.gpLogServer(null, "PlayerCASMission awp: {0} vs {1}", new object[] { homeBase.sqn, GamePlay.gpPlayer().Place().Group().Name() });
                        StrikerGroupName = homeBase.sqn;
                        GamePlay.gpPostMissionLoad(f);
                        NextMissionNum++;
                        // no redirectCAP but may run into other flights still since opposing side attacks
                    };

                    // RTB
                    wp3d = new Point3d(ib2d.x, ib2d.y, 1700);
                    nextAWP = new AiAirWayPoint(ref wp3d, 402);
                    //nextAWP.Action = AiAirWayPointType.NORMFLY;
                    if (aircraft.Type().ToString().Contains("DiveBomber")) nextAWP.Action = AiAirWayPointType.NORMFLY;
                    else nextAWP.Action = AiAirWayPointType.AATTACK_FIGHTERS;
                    arrAWP.Add(nextAWP); // inbound landing

                    wp3d = homeBase.Pos();
                    nextAWP = new AiAirWayPoint(ref wp3d, 0);
                    nextAWP.Action = AiAirWayPointType.LANDING;
                    arrAWP.Add(nextAWP);
                    //if (odenDebug)
                    //    foreach (AiAirWayPoint wp in arrAWP)
                    //        GamePlay.gpLogServer(null, "PlayerCASMission awp: {0} {1} {2} {3}", new object[] { wp.Speed, (wp as AiAirWayPoint).Action, (wp as AiAirWayPoint).GAttackType, wp.P });

                    if (odenDebug)
                        if (playerFlightBMB) GamePlay.gpLogServer(null, "playerFlightBMB", new object[] { });
                        else GamePlay.gpLogServer(null, "PlayerCASMission", new object[] { });
                    aircraft.Group().SetWay(arrAWP.ToArray());
                    if (odenDebug)
                        foreach (AiWayPoint wp in aircraft.Group().GetWay())
                            GamePlay.gpLogServer(null, "PlayerCASMission wp: {0} {1} {2} {3}", new object[] { wp.Speed, (wp as AiAirWayPoint).Action, (wp as AiAirWayPoint).GAttackType, wp.P });
                    string prefix = "Defend ";
                    if (aircraft.Player(0).Army() == ATK) prefix = "TARCAP over ";
                    if (playerFlightCAS || playerFlightBMB) prefix = "Attack ";
                    if (prefix != "Defend ")
                    {
                        GamePlay.gpHUDLogCenter(new Player[] { aircraft.Player(0) }, prefix + targetName);
                        GamePlay.gpLogServer(new Player[] { aircraft.Player(0) }, "{0}", new object[] { prefix + targetName });
                    };
                }
                else
                {
                    string prefix = "Defend ";
                    if (aircraft.Player(0).Army() == ATK) prefix = "TARCAP over ";
                    if (playerFlightCAS || playerFlightBMB) prefix = "Attack ";
                    if (prefix != "Defend ")
                    {
                        GamePlay.gpHUDLogCenter(new Player[] { aircraft.Player(0) }, prefix + targetName);
                        GamePlay.gpLogServer(new Player[] { aircraft.Player(0) }, "{0}", new object[] { prefix + targetName });
                    };
                };
            };
    }
    public override void OnAircraftDamaged(int missionNumber, string shortName, AiAircraft aircraft, AiDamageInitiator initiator, part.NamedDamageTypes damageType)
    {
        base.OnAircraftDamaged(missionNumber, shortName, aircraft, initiator, damageType);

        //if (odenDebug) GamePlay.gpLogServer(null, "OnAircraftDamaged: {0}", new object[] { shortName });
        //OnAircraftDamaged: BoB_RA_56St_20Gruppo_353Sq.020
        if (Time.tickCounter() < 900) // spawn error within first 30 secs (30 ticks a second)
            return;

        if (initiator != null)
            if (initiator.Actor != null)
                if (initiator.Actor.Army() < 1)
                    return;

        if (aircraft != null)
        {
            Player localPlayer = GamePlay.gpPlayer();
            if (!playerHasHitTarget)
                if (localPlayer != null)
                    if (localPlayer.Place() != null)
                        if (initiator.Actor == localPlayer.Place())
                            if (aircraft.Army() != localPlayer.Place().Army())
                                playerHasHitTarget = true;

            if (!damagedAircrafts.Exists(element => element == aircraft))
            {   // planes
                if (initiator != null)
                {
                    if (initiator.Actor != (aircraft as AiActor))
                    {
                        damagedAircrafts.Add(aircraft);
                    };
                };
            };
        };
    }
    public override void OnAircraftLanded(int missionNumber, string shortName, AiAircraft aircraft)
    {
        base.OnAircraftLanded(missionNumber, shortName, aircraft);

        if (aircraft == null)
            return;
        AiAirGroup ag = aircraft.AirGroup();
        if (ag == null)
            return;

        Point2d lnd2d = new Point2d(aircraft.Pos().x, aircraft.Pos().y);
        AiAirport ap = FindAirport(ag.Army(), lnd2d, 0);
        if (ap != null)
        {
            Point3d pt3d = aircraft.Pos();
            if (ap.Pos().distance(ref pt3d) < ap.CoverageR())
            {
                if (ag.Army() == GamePlay.gpFrontArmy(lnd2d.x, lnd2d.y))
                {
                    if (aircraft.Player(0) != null)
                    {
                        if (Satellites.Contains(ap.Name()))
                            playerLandedAtAirport = ap;
                        if (playerKilledTargets > 0)
                        {
                            if (playerKilledTargets > 1) GamePlay.gpHUDLogCenter(new Player[] { aircraft.Player(0) }, "Mission Success, Well Done");
                            else GamePlay.gpHUDLogCenter(new Player[] { aircraft.Player(0) }, "Mission Success, Very Well Done!");
                        }
                        else if (playerHasHitTarget) GamePlay.gpHUDLogCenter(new Player[] { aircraft.Player(0) }, "Mission Success");
                    };
                }
                else AircraftUpdateDead(aircraft);
            }
            else AircraftUpdateDead(aircraft);
        }
        else AircraftUpdateDead(aircraft);

        Timeout(150, () => { if (aircraft != null) aircraft.Destroy(); });
    }
    public virtual void OnAircraftCrashLanded(int missionNumber, string shortName, AiAircraft aircraft)
    {
        base.OnAircraftCrashLanded(missionNumber, shortName, aircraft);
        if (aircraft != null) AircraftUpdateDead(aircraft);
    }


    private void StartMission()
    {
        timeoutRadio = DateTime.Now;
        timeoutRadio.AddSeconds(120);
        if (odenDebug) GamePlay.gpLogServer(null, "StartMission: {0}", new object[] { "" });


        AiAircraft pac = (AiAircraft)GamePlay.gpPlayer().Place();
        if (pac == null)
        {
            if (File.Exists(CampInitFile))
                File.Delete(CampInitFile);
            CheckFiles();
            return; // let user reset all setup
        };


        string strSay = "You_re_cleared_for_take_off";
        switch (rnd.Next(1, 5))
        {
            case 1: strSay = "Takeoff";
                break;
            case 2: strSay = "Wingmen_make_sure_you_stay_with_your_leaders";
                break;
            case 3: strSay = "Stay_sharp_gentlemen_And_make_sure_to_stay_in_formation";
                if (GamePlay.gpPlayer().Army() == LW) strSay = "Use_your_rudder_to_counter_the_yaw";
                break;
            case 4: strSay = "Prepare_For_Takeoff";
                break;
        };

        AiAirGroup pag = pac.AirGroup();
        AiActor leader = GetFlightLeader(pag);
        AiAircraft lac = (AiAircraft)leader;
        if (lac != null)
            Timeout(rnd.Next(4, 12), () => { lac.SayToGroup(pag, strSay); });
        Point3d pt3d = pac.Pos();
        oldWP = new AiWayPoint(ref pt3d, 0);

        Point2d pt2d = new Point2d(pt3d.x, pt3d.y);
        foreach (MissionAirbase mab in MissionAirbases)
            if (pag.Name().Contains(mab.sqn))
                homeBase = mab;

        if (homeBase == null)
        {
            CreateInitFiles();
            //GamePlay.gpHUDLogCenter("Mission Error: " + pag.Name() + " not found at any base, check DynMis.ini");
            return;
        };

        if (odenDebug) GamePlay.gpLogServer(null, "homeBase: '{0}' '{1}' '{2}'", new object[] { homeBase.ap, homeBase.ap.Name(), homeBase.sqn });
        homeAirport = homeBase.ap;
        homeAirport3d = homeAirport.Pos();
        activatedGroups.Add(homeBase.sqn);
        if (fmCurrent != "")
        {
            foreach (MissionMarker mm in MissionMarkers)
                if (mm.key == fmCurrent) mmCurrentBattle = mm;
            if (mmCurrentBattle == null)
            {
                GamePlay.gpHUDLogCenter("Mission Error: " + fmCurrent + " not found as FrontMarker, check DynMis.ini");
                return;
            };
        };

        if (odenDebug) GamePlay.gpLogServer(null, "GroundStationary", new object[] { });
        // update target list
        foreach (GroundStationary gs in GamePlay.gpGroundStationarys())
            if (gs != null)
            {
                if (gs.Name != "NONAME")
                {
                    //if (odenDebug) GamePlay.gpLogServer(null, "gpGroundStationaries: '{0}'", new object[] { gs.Name });
                    if (GndStatDead.Contains(gs.Name.Substring(2)))
                    {
                        if (odenDebug) GamePlay.gpLogServer(null, "Removing: '{0}'", new object[] { gs.Name });
                        if (!gs.Title.Contains("Trench_"))
                            gs.Destroy();
                    }
                    else
                    {
                        if (gs.Title.Contains("EnglishRadar3"))
                            ChainHomeRadars.Add(gs);
                        if (gs.Title.Contains("PortCrane1_UK1"))
                            PortCranes.Add(gs);
                        if (gs.Title.Contains("Oxygen_Facility"))
                            Industries.Add(gs);
                    };
                };
            };
        if (odenDebug) GamePlay.gpLogServer(null, "fmCurrent", new object[] { });
        if (fmCurrent != "")
        {
            ActivateGroundUnits(mmCurrentBattle);
            List<string[]> currBattleSet = CampaignBattleSet();
            if (currBattleSet != null)
            {
                int forEachIdx = 0, currIdx = 0;
                foreach (string[] fmArr in currBattleSet)
                {   // find current battle
                    foreach (string str in fmArr)
                        if (fmCurrent.Equals(str))
                            currIdx = forEachIdx;
                    forEachIdx++;
                };
                if (SideOnOffensive == LW) currIdx--; // next battleset Axis
                else currIdx++; // next battleset Allies
                if (currIdx == currBattleSet.Count || currIdx < 0)
                    lastCampaignMission = true;
            }
            else
            {
                int RedMarkers = 0, BlueMarkers = 0;
                foreach (MissionMarker mm in MissionMarkers)
                    if (mm.army == RAF) RedMarkers++;
                    else BlueMarkers++;
                if(RedMarkers == 1 || BlueMarkers == 1)
                    lastCampaignMission = true;
            };
        };
        if (odenDebug) GamePlay.gpLogServer(null, "Timeout", new object[] { });
        // select mission
        Timeout(5, () =>
        {
            switch (CampaignName)
            {
                case cBattleOfFrance:
                    if (ATK == LW)
                    {
                        if (!gameIsOn)
                            CreateInterdictionMission(mmCurrentBattle);
                        if (!gameIsOn)
                            CreateBombingMission(mmCurrentBattle, false);
                        if (!gameIsOn || rnd.Next(10) > 7)
                            CreateAirbaseMission(false);
                    }
                    else
                    {   // Allied initiative, attack ground units
                        if (!gameIsOn)
                            CreateInterdictionMission(mmCurrentBattle);
                        if (!gameIsOn || rnd.Next(10) > 7)
                            CreateAirbaseMission(false);
                    };
                    break;
                case cBattleOfBritain:
                    if (bobVicSide == 0)
                    {
                        if (ATK == LW)
                        {
                            if (gameDateTime > dtFighterBomber)
                            {   // Fighter Bomber Attacks along coastal assets (Sea Lion cancelled) during Oct
                                if (ConvoyShips.Count > 0 && (highOctaneDate - gameDateTime).Days < rnd.Next(4) && rnd.Next(10) > 5 && !gameIsOn)
                                    CreateConvoyMission(false);
                                if (PortCranes.Count > 0 && rnd.Next(10) > 6 && !gameIsOn)
                                    CreatePortMission(false);
                                if (ChainHomeRadars.Count > 0 && rnd.Next(10) > 5 && !gameIsOn)
                                    CreateCHRadarMission(false);
                                if (!gameIsOn)
                                    CreateAirbaseMission(false);
                            };
                            if (gameDateTime > dtBlitz)
                            {   // Daylight Attack on London, 7 - 30 Sept
                                if (Industries.Count > 0 && (ReinforcementDate - gameDateTime).Days < rnd.Next(4) && !gameIsOn)
                                    CreateIndustryMission(false);
                                if (PortCranes.Count > 0 && !gameIsOn)
                                    CreatePortMission(false);
                                if (ConvoyShips.Count > 0 && (highOctaneDate - gameDateTime).Days < rnd.Next(4) && rnd.Next(10) > 5 && !gameIsOn)
                                    CreateConvoyMission(false);
                            };
                            if (gameDateTime > dtAdlerTag)
                            {   // Assault on Fighter Command (AdlerTag), 24 Aug - 6 Sept
                                if (rnd.Next(10) > 2 && !gameIsOn)
                                    CreateAirbaseMission(false);
                                if (ChainHomeRadars.Count > 0 && rnd.Next(10) > 5 && !gameIsOn)
                                    CreateCHRadarMission(false);
                                if (PortCranes.Count > 0 && rnd.Next(10) > 6 && !gameIsOn)
                                    CreatePortMission(false);
                                if (ConvoyShips.Count > 0 && (highOctaneDate - gameDateTime).Days < rnd.Next(4) && rnd.Next(10) > 5 && !gameIsOn)
                                    CreateConvoyMission(false);
                            };
                            if (gameDateTime > dtCoastalBattles)
                            {   // Coastal Battles (Kanalkampf), 8 - 23 August
                                if (PortCranes.Count > 0 && rnd.Next(10) > 5 && !gameIsOn)
                                    CreatePortMission(false);
                                if (ChainHomeRadars.Count > 0 && rnd.Next(10) > 5 && !gameIsOn)
                                    CreateCHRadarMission(false);
                                if (ConvoyShips.Count > 0 && (highOctaneDate - gameDateTime).Days < rnd.Next(4) && rnd.Next(10) > 5 && !gameIsOn)
                                    CreateConvoyMission(false);
                                if (!gameIsOn)
                                    CreateAirbaseMission(false);
                            };
                            // Convoy Battles (Kanalkampf), 10 July - 7 August
                            if (ConvoyShips.Count > 0 && (highOctaneDate - gameDateTime).Days < rnd.Next(4) && rnd.Next(10) > 3 && !gameIsOn)
                                CreateConvoyMission(false);
                            if (PortCranes.Count > 0 && rnd.Next(10) > 3 && !gameIsOn)
                                CreatePortMission(false);
                            if (!gameIsOn)// only LW for now. ToDo: Blenheim dayraids
                                CreateAirbaseMission(false);
                        }
                        else
                        {   // british initiative
                            if (!gameIsOn)
                                CreateAirbaseMission(false);
                        };
                    }
                    else
                    {   // seelöwe or RAF Circus/Roadsted/Rodeo/Rhubarb
                        if (ATK == LW) CreateInterdictionMission(mmCurrentBattle);
                        else CreateAirbaseMission(false);
                        if (!gameIsOn)
                            CreateAirbaseMission(false);
                    };
                    break;
                case cNorthAfrica:
                    CreateInterdictionMission(mmCurrentBattle);
                    gameIsOn = false;
                    if (ATK == LW && ConvoyShips.Count > 0 && (highOctaneDate - gameDateTime).Days < rnd.Next(4) && rnd.Next(10) > 5 && !gameIsOn)
                        CreateConvoyMission(false);
                    if (PortCranes.Count > 0 && rnd.Next(0, 9) > 6 && !gameIsOn)
                        CreatePortMission(false);
                    if (!gameIsOn && rnd.Next(10) > 7)
                        CreateAirbaseMission(false);
                    break;
                case cCobra:
                    CreateInterdictionMission(mmCurrentBattle);
                    if (rnd.Next(10) > 5)
                        CreateAirbaseMission(false);
                    break;
            };

            if (PlayerIsBomber() && !playerFlightCAS)
            {
                playerFlightBMB = true; // enemy initiative or whatever, see AircraftTookOff
                pt2d = new Point2d(homeBase.x, homeBase.y);
                List<AiAirport> saps = SortedAirports((homeBase.army == LW ? RAF : LW), pt2d, true); // if battlearea only no damaged will be included
                if (odenDebug) GamePlay.gpLogServer(null, "PlayerIsBomber BMB mission #{0}", new object[] { saps.Count });
                if (saps.Count > 0)
                {
                    if (saps.Count > 5) playerTargetAirport = saps[rnd.Next(5)];
                    else playerTargetAirport = saps[0];
                    if (playerTargetAirport == null) GamePlay.gpLogServer(null, "PlayerIsBomber BMB mission failed", new object[] { });
                    Timeout(60.0, () => { Spawn40Tigers(playerTargetAirport); });
                    pt2d.x = playerTargetAirport.Pos().x;
                    pt2d.y = playerTargetAirport.Pos().y;
                    targetName = "Airbase at " + playerTargetAirport.Name().Replace('_', ' ') + " in " + GamePlay.gpSectorName(pt2d.x, pt2d.y);
                    if (ATK == GamePlay.gpPlayer().Army())
                    {
                        target2d = pt2d;
                        target3d = playerTargetAirport.Pos();
                    };
                };
            };
            ISectionFile fcap = GamePlay.gpCreateSectionFile();
            bool capexists = false;
            int cap = rnd.Next(1, 4);
            List<MissionAirbase> CAPbases = new List<MissionAirbase>();
            CAPbases = SortedAirbases(ATK == LW ? RAF : LW, target2d, false, false, true);
            if (odenDebug) GamePlay.gpLogServer(null, "CAP# {0} to {1} select from {2}", new object[] { cap, target2d, CAPbases.Count });
            foreach (MissionAirbase ab in CAPbases)
            {
                if (cap < 1) break;
                Point2d cap2d = calcPos(target2d, rnd.Next(2000, 16093), rnd.Next(360));
                CreateCAPMission(fcap, cap2d, 6, ab.army, false);
                capexists = true;
                cap--;
            };
            if (capexists)
            {
                GamePlay.gpPostMissionLoad(fcap);
                NextMissionNum++;
            };
        });

    }
    private void ReadMissionFile(ISectionFile missFile)
    {
        string key, value;
        CampMapName = missFile.get("MAIN", "MAP");
        int n = missFile.lines("FrontMarker");
        for (int i = 0; i < n; i++)
        {
            key = "FrontMarker" + i.ToString();
            if (missFile.exist("FrontMarker", key))
            {	//FrontMarker0 287950.90 85215.27 2
                value = missFile.get("FrontMarker", key);
                string[] strs = value.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                if (strs.Length == 3)
                {	//double.TryParse(s, System.Globalization.NumberStyles.Any, rts.RTSConf.enCultureInfo, out res)
                    MissionMarker mm = new MissionMarker(0, 0, 0, key);
                    double.TryParse(strs[0], System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture.NumberFormat, out mm.x);
                    double.TryParse(strs[1], System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture.NumberFormat, out mm.y);
                    int.TryParse(strs[2], out mm.army);
                    MissionMarkers.Add(mm);
                };
            };
        };
        n = missFile.lines("Stationary");
        for (int i = 0; i < n; i++)
        {
            missFile.get("Stationary", i, out key, out value);
            string[] strs = value.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
            if (strs[0].Contains("SandBagWall_Line")) SandBagWalls.Add(key + " " + strs[2] + " " + strs[3] + " " + strs[4]);
            if (strs[0].Contains("Trench_10m")) HeavyAAAs.Add(key + " " + strs[2] + " " + strs[3] + " " + strs[4]);
            if (strs[0].Contains("Trench_6m")) LightAAAs.Add(key + " " + strs[2] + " " + strs[3] + " " + strs[4]);
            if (strs[0].Contains("SandBagWall_Arch")) ARTYsites.Add(key + " " + strs[2] + " " + strs[3] + " " + strs[4]);
            if (strs[0].Contains("GuardTower_UK-GER")) SupplyDepots.Add(key + " " + strs[2] + " " + strs[3] + " " + strs[4]);
            //if (odenDebug) GamePlay.gpLogServer(null, "Stationary:  {0}", new object[] { key + " " + strs[2] + " " + strs[3] + " " + strs[4] });
        };


        if (!missFile.exist("DYNMIS", "DynMisPlayer"))
        {
            if (missFile.exist("MAIN", "player"))
            {
                string sPlayer = missFile.get("MAIN", "player");
                defSquadron = sPlayer.Substring(0, sPlayer.IndexOf("."));
                string sect = sPlayer.Substring(sPlayer.IndexOf(".") + 1, 1); // identifies AirGroup
                for (int a = 0; a < 10; a++)
                    if (missFile.exist("AirGroups", defSquadron + "." + sect + a.ToString()))
                    {
                        sect = defSquadron + "." + sect + a.ToString();
                        break;
                    };

                defClass = missFile.get(sect, "Class");
                defCallSign = missFile.get(sect, "CallSign");
                string slot = sPlayer.Substring(sPlayer.IndexOf(".") + 2); // 001 for 2nd slot first section, 010 for first slot 2nd section, 101 2nd slot second section, 000 first-first
                // slot is now 2 chars, 00, 01, 02 from first section or 10 11 12 from 2nd section (talking 3-ship sections)
                if (missFile.exist(sect, "Skin" + slot))
                    defSkin = missFile.get(sect, "Skin" + slot);
                if (missFile.exist(sect, "Serial" + slot))
                    defSerial = missFile.get(sect, "Serial" + slot);
                defTail = missFile.get(sect, "Flight" + slot[0].ToString());
                string[] strs = defTail.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                defTail = strs[int.Parse(slot[1].ToString())]; // Flight1 4 5 6 > defTail is now "4" denoting 'D' marker on plane
                if (defSquadron.Contains("_Early"))
                    defSquadron = defSquadron.Remove(defSquadron.IndexOf("_Early"));
                if (defSquadron.Contains("_Late"))
                    defSquadron = defSquadron.Remove(defSquadron.IndexOf("_Late"));
            }
            else GamePlay.gpHUDLogCenter("This mission has no player slot");
        }
        else
        {
            defSquadron = missFile.get("DYNMIS", "DynMisSquadron");
            defClass = missFile.get("DYNMIS", "DynMisClass");
            defCallSign = missFile.get("DYNMIS", "DynMisCallSign");
            defSkin = missFile.get("DYNMIS", "DynMisSkin");
            defSerial = missFile.get("DYNMIS", "DynMisSerial");
            defTail = missFile.get("DYNMIS", "DynMisTail");
            if (odenDebug) GamePlay.gpLogServer(null, "DYNMIS: {0} {1} {2} {3}", new object[] { defSquadron, defClass, defCallSign, defSerial });
        };
        if(CampMapName.Contains("Land$Online_Cobra"))
        {
            CampaignName = cCobra;
        } else {
            switch (defSerial.Substring(0, 2))
            {
                case "P4": // use for SF Mk I mainland UK

                case "N2": // Hurricane Mk I, Block 2, Second Hawker Produced Block N2318 - N2367 (50), N2380 - N2409 (30), N2422 - N2441 (20), N2453 - N2502 (50), N2520 - N2559 (40), N2582 - N2631 (50), N2645 - N2674 (30), N2700 - N2729 (30) - Total 300
                    //deliveries commenced on the 29th September, 1939 and were completed on the 1st May, 1940. The average rate of production was one-two aircraft per day.
                    //Most aircraft fought with R.A.F. squadrons in Battle of France, and Battle of Britain.
                    // beaufighter case "R2": // Hurricane Mk I, Block 3, Third Hawker Produced Block R2680 - R2689 (10)
                    CampaignName = cBattleOfFrance;
                    break;

                case "P6": // use for SF Mk I
                case "P7": //Vickers Armstrong (Castle Bromwich)Ltd Contract no.B981687/39/C.23
                // Built as MkIIA/IIB/VA/VB between June 1940 and July 1941. First delivered P7280 27 June 1940, last P8799 21 July 1941.
                // SF MkII from P7280-7329, P7350-7389, P7420-7499, P7490-7509, P7520-7569, P7590-7629, P7661-7699, P7730-7759, PP7770-7789, P7810-7859, P7880-7929, P7960-7999

                case "P2": // Hurricane Mk I, Block 1/G, First Gloster Produced Block P2535 - P2584 (50), P2614 - P2653 (40), P2672 - P2701 (30), P2713 - P2732 (20), P2751 - P2770 (20), P2792 - P2836 (45), P2854 - P2888 (35), P2900 - P2924 (25), P2946 - P2995 (50)
                // use P3 in africa case "P3": // Hurricane Mk I, Block 1/G, First Gloster Produced Block P3020 - P3069 (50), P3080 - P3124 (45), P3140 - P3179 (40), P3200 - P3234 (35), P3250 - P3264 (15)
                //Aircraft deliveries commenced in November, 1939 and were completed by April 1940, the average rate of production was three aircraft per day.

                case "P5": // Hurricane Mk I, Block 1/C, First C.C.F. Produced Block P5170 - P5209 (40) Canadian Hurricane Mk. I
                //All the aircraft were shipped to Britain between February and August 1940, they served with R.A.F. and R.C.A.F. squadrons during the Battle Of Britain.

                case "AE": // Hurricane Mk I, Block 2/C, Second C.C.F. Produced Block AE958 - AE977 (20) BH/BJ-series at first and re-alloted to old series
                //The first 20 aircraft arrived in Britain in June, 1940.

                case "R4": // Hurricane Mk I, Block 2/G, Second Gloster Produced Block R4074 - R4123 (50), R4171 - R4200 (30), R4213 - R4232 (20) Total 100
                //All aircraft delivered between May 1940 and July 1940, average rate of production 2-3 aircraft per day.

                case "T9": // Hurricane Mk I, Block 3, Third Hawker Produced Block T9519 - T9538 (20)
                case "W6": // Hurricane Mk I, Block 3, Third Hawker Produced Block W6667 - W6670 (4)
                // Aircraft deliveries commenced on the 21st February, 1940, and were completed on the 20th July, 1940. The average rate of production was three-four aircraft per day.
                // The majority of these aircraft served with R.A.F. squadrons during the Battle Of France, and the Battle Of Britain.

                case "V6": // Hurricane Mk I, Block 3/G, Third Gloster Produced Block V6533 - V6582 (50) Mk. I, V6600 - V6649 (50) Mk. I, V6665 - V6704 (40) Mk. I, V6722 - V6761 (40) Mk. I, V6776 - V6825 (50) Mk. I, V6840 - V6889 (50) Mk. I, V6913 - V6962 (50) Mk. I, V6979 - V7028 (50) Mk. I
                // use V7 in africa case "V7": // Hurricane Mk I, Block 3/G, Third Gloster Produced Block V7042 - V7081 (40) Mk. I, V7099 - V7138 (40) Mk. I, V7156 - V7195 (40) Mk. I
                case "W9": // Hurricane Mk I, Block 3/G, Third Gloster Produced Block W9110 - W9159 (50) Mk. I, W9170 - W9209 (40) Mk. I, W9215 - W9244 (30) Mk. I, W9260 - W9279 (20) Mk. I, W9290 - W9329 (40) Mk. I, W9340 - W9359 (20) Mk. I
                case "Z4": // Hurricane Mk I, Block 3/G, Third Gloster Produced Block Z4022 - Z4071 (50) Mk. I, Z4085 - Z4119 (35) Mk. I, Z4161 - Z4205 (45) Mk. I, Z4223 - Z4272 (50) Mk. I, Z4308 - Z4327 (20) Mk. I, Z4347 - Z4391 (45) Mk. I, Z4415 - Z4434 (20) Mk. I, Z4482 - Z4516 (35) Mk. I, Z4532 - Z4581 (50) Mk. I, Z4603 - Z4652 (50) Mk. I, Z4686 - Z4720 (35) Mk. I, Z4760 - Z4809 (50) Mk. I, Z4832 - Z4876 (45) Mk. I, Z4920 - Z4939 (20) Mk. I
                case "Z5": // Hurricane Mk IIb, Block 3/G, Third Gloster Produced Block Z4990 - Z5006 (17) Mk. IIB, Z5038 - Z5087 (50) Mk. IIB, Z5117 - Z5161 (45) Mk. IIB, Z5202 - Z5236 (35) Mk. IIB, Z5252 - Z5271 (20) Mk. IIB, Z5302 - Z5351 (50) Mk. IIB, Z5376 - Z5395 (20) Mk. IIB, Z5434 - Z5483 (50) Mk. IIB, Z5529 - Z5563 (35) Mk. IIB, Z5580 - Z5629 (50) Mk. IIB, Z5649 - Z5693 (45) Mk. IIB - Total 1,700
                //"V7" Hurricane Mk I, Block 4, Fourth Hawker Produced Block V7200 - V7209 (10), V7221 - V7260 (40), V7276 - V7318 (43), V7337 - V7386 (50), V7400 - V7446 (47), V7461 - V7510 (50), V7533 - V7572 (40), V7588 - V7627 (40), V7644 - V7690 (47), V7705 - V7737 (33), V7741 - V7780 (40), V7795 - V7838 (44), V7851 - V7862 (12), AS987 - AS990 (4) Total 500
                //Aircraft deliveries commenced on the 2nd July, 1940 and were completed on the 5th February, 1941.
                //Hurricane Mk I, Block 3/G, Third Gloster Produced Block Z4940 - Z4969 (30) Mk. IIA, Z4987 - Z4989 (3) Mk. IIA
                //Aircraft delivered between July 1940 and August 1941, average rate of production 4-5 aircraft per day.

                case "L1": // Blenheim Mk I
                case "L6": // Blenheim Mk I
                case "N3": // Blenheim Mk IV
                case "Z6": // Blenheim Mk IV
                case "R0": // Beaufighter
                    CampaignName = cBattleOfBritain;
                    break;

                //case "P8": // Hurricane Mk I, Block 3, Third Hawker Produced Block P8809 - P8818 (10)
                case "P3": // Hurricane Mk I, Block 3, Third Hawker Produced Block P3265 - P3279 (15), P3300 - P3324 (25), P3345 - P3364 (20), P3380 - P3429 (50), P3448 - P3492 (45), P3515 - P3554 (40), P3574 - P3623 (50), P3640 - P3684 (45), P3700 - P3739 (40), P3755 - P3789 (35), P3802 - P3836 (35), P3854 - P3903 (50), P3920 - P3944 (25), P3960 - P3984 (25)
                // Many aircraft were also tropicalised and shipped to the Mediterranean and Middle East from late 1940.

                case "V7": // Hurricane Mk I, Block 4, Fourth Hawker Produced Block
                case "N5": // Gladiator Mk II, by Gloster Aircraft Co., Ltd., during 1938-39.
                case "R2": // Beaufighter

                //Aircraft deliveries commenced on the 14th January, 1941 and were completed by the 28th July, 1941, average rate of production was five aircraft per day.
                case "AG": // Hurricane Mk I, Block 2/C, Second C.C.F. Produced Block AG665 - AG684 (20)  BJ-series at first and re-alloted to old series
                case "AF": // Hurricane Mk I, Block 2/C, Second C.C.F. Produced Block AF945 - AG344 (300)
                //Second delivery of 300 aircraft arrived between August, 1940 and April, 1941.
                //The final 20 aircraft arriving in April, 1941.

                case "AM": // Hurricane Mk I, Block 3/C, Third C.C.F. Produced Block AM270 - AM369 (100) BJ-series at first and re-alloted to old series

                case "Z2": // Hurricane Mk IIb, Block 5, Fifth Hawker Produced Block Z2308 - Z2357 (50), Z2382 - Z2426 (45), Z2446 - Z2465 (20), Z2479 - Z2528 (50), Z2560 - Z2594 (35), Z2624 - Z2643 (20), Z2661 - Z2705 (45), Z2741 - Z2775 (35), Z2791 - Z2840 (50), Z2882 - Z2931 (50), Z2959 - Z2993 (35)
                case "Z3": // Hurricane Mk IIb, Block 5, Fifth Hawker Produced Block Z3017 - Z3036 (20), Z3050 - Z3099 (50), Z3143 - Z3187 (45), Z3221 - Z3270 (50), Z3310 - Z3359 (50), Z3385 - Z3404 (20), Z3421 - Z3470 (50), Z3489 - Z3523 (35), Z3554 - Z3598 (45), Z3642 - Z3691 (50), Z3740 - Z3784 (45), Z3826 - Z3845 (20), Z3885 - Z3919 (35), Z3969 - Z4018 (50) Total 1,000

                case "BD": // Hurricane Mk IIb, Block 6, Sixth Hawker Produced Block BD696 - BD745 (50), BD759 - BD793 (35), BD818 - BD837 (20), BD855 - BD899 (45), BD914 - BD963 (50), BD980 - BD986 (7)
                case "BE": // Hurricane Mk IIb, Block 6, Sixth Hawker Produced Block BE105 - BE117 (13), BE130 - BE174 (45), BE193 - BE242 (50), BE274 - BE308 (35), BE323 - BE372 (50), BE394 - BE428 (35), BE468 - BE517 (50), BE546 - BE590 (45), BE632 - BE651 (20), BE667 - BE716 (50)
                case "BM": // Hurricane Mk IIb, Block 6, Sixth Hawker Produced Block BM898 - BM936 (39), BM947 - BM996 (50)
                case "BN": // Hurricane Mk IIb, Block 6, Sixth Hawker Produced Block BN103 - BN142 (40), BN155 - BN189 (35), BN203 - BN242 (40), BN265 - BN298 (34), BN311 - BN337 (27), BN346 - BN389 (44), BN399 - BN435 (37), BN449 - BN497 (49), BN512 - BN547 (36), BN559 - BN603 (45), BN624 - BN654 (31), BN667 - BN705 (39), BN719 - BN759 (41), BN773 - BN802 (30), BN818 - BN846 (29), BN859 - BN882 (24), BN896 - BN940 (45), BN953 - BN987 (35), Total 1,350
                //Powered by Rolls-Royce Merlin XX engines. Aircraft were delivered between the 24th July, 1941 and the 18th March 1942. Average rate of production was 5-6 aircraft per day.

                case "BG": // Hurricane Mk IIb, Block 4/G, Fourth Gloster Produced Block BG674 - BG723 (50), BG737 - BG771 (35), BG783 - BG832 (50), BG844 - BG888 (45), BG901 - BG920 (20), BG933 - BG977 (45), BG990 - BG999 (10) Powered by Rolls-Royce Merlin XX engines. The aircraft were delivered between September, 1941 and December, 1941. The average rate of production was 4-5 aircraft per day.
                //Hurricane Mk IIb, Block 4/G, Fourth Gloster Produced Block BH115 - BH154 (40), BH167 - BH201 (35), BH215 - BH264 (50), BH277 - BH296 (20), BH312 - BH361 (50) Total 450

                case "P8": // Tobruk Spitfires P8081-8049, P8070-8099, P8130-8149, P8160-8209, P8230-8279, P8310-8349, P8360-8399, P8420-8449, P8460-8479, P8500-8549, P8560-8609, P8640-8679, P8690-8729, P8740-8759, P8790-8799.
                case "BP": // Hurricane Mk IIb, Block 7, Seventh Hawker Produced Block BP109 - BP141 (33), BP154 - BP200 (47), BP217 - BP245 (29), BP259 - BP302 (44), BP316 - BP362 (47), BP378 - BP416 (39), BP430 - BP479 (50), BP493 - BP526 (34), BP538 - BP566 (29), BP579 - BP614 (36), BP628 - BP675 (48), BP692 - BP711 (20), BP734 - BP772 (39)
                case "HL": // Hurricane Mk IIb, Block 7, Seventh Hawker Produced Block HL544 - HL591 (48), HL603 - HL634 (32), HL654 - HL683 (30), HL698 - HL747 (50), HL767 - HL809 (43), HL828 - HL867 (40), HL879 - HL913 (35), HL925 - HL941 (17), HL953 - HL997 (45)
                case "HM": // Hurricane Mk IIb, Block 7, Seventh Hawker Produced Block HM110 - HM157 (48)
                case "HV": // Hurricane Mk IIb, Block 7, Seventh Hawker Produced Block HV275 - HV317 (43), HV333 - HV370 (38), HV396 - HV445 (50), HV468 - HV516 (49), HV534 - HV560 (27), HV577 - HV612 (36), HV634 - HV674 (41), HV696 - HV745 (50), HV768 - HV799 (32), HV815 - HV858 (44), HV873 - HV921 (49), HV943 - HV989 (47)
                case "HW": // Hurricane Mk IIb, Block 7, Seventh Hawker Produced Block HW115 - HW146 (32), HW167 - HW207 (41), HW229 - HW278 (50), HW291 - HW323 (33), HW345 - HW373 (29), HW399 - HW444 (46), HW467 - HW501 (35), HW533 - HW572 (40), HW596 - HW624 (29), HW651 - HW686 (36), HW713 - HW757 (45), HW779 - HW808 (30), HW834 - HW881 (48) Total 1,888
                    //Aircraft were delivered betwwen the 17th March, 1942 and the 23rd November 1942. Average rate of production was 7-8 aircraft per day.
                    CampaignName = cNorthAfrica;
                    break;

                // later sqns
                case "KW": // Hurricane Mk IIb, Block 8, Eighth Hawker Produced Block KW696 - KW731 (36), KW745 - KW777 (33), KW791 - KW832 (42), KW846 - KW881 (36), KW893 - KW936 (44), KW949 - KW982 (34)
                case "KX": // Hurricane Mk IIb, Block 8, Eighth Hawker Produced Block KX101 - KX146 (46), KX161 - KX202 (42), KX220 - KX261 (42), KX280 - KX307 (28), KX321 - KX369 (49), KX382 - KX425 (44), KX452 - KX491 (40), KX521 - KX567 (47), KX579 - KX621 (43), KX691 - KX736 (46), KX749 - KX784 (36), KX796 - KX838 (43), KX851 - KX892 (42), KX922 - KX967 (46)
                case "KZ": // Hurricane Mk IIb, Block 8, Eighth Hawker Produced Block KZ111 - KZ156 (46), KZ169 - KZ201 (33), KZ216 - KZ250 (35), KZ266 - KZ301 (36), KZ319 - KZ356 (38), KZ370 - KZ412 (43), KZ424 - KZ470 (47), KZ483 - KZ526 (44), KZ540 - KZ582 (43), KZ597 - KZ612 (16) Total 1,200
                //Powered by Rolls-Royce Merlin XX and 27 engines. The aircraft were delivered between the 20th November, 1942 and the 19th April, 1943. Average rate of production 7-8 aircraft per day.
                //Hurricane Mk IIb, Block 9, Ninth Hawker Produced Block KZ613 - KZ632 (20), KZ646 - KZ688 (43), KZ702 - KZ750 (49), KZ766 - KZ801 (36), KZ817 - KZ862 (46), KZ877 - KZ920 (44), KZ933 - KZ949 (17)

                case "LA": // Hurricane Mk IIb, Block 9, Ninth Hawker Produced Block LA101 - LA144 (44)
                case "LB": // Hurricane Mk IIb, Block 9, Ninth Hawker Produced Block LB542 - LB575 (34), LB588 - LB624 (37), LB639 - LB687 (49), LB707 - LB744 (38), LB769 - LB801 (33), LB827 - LB862 (36), LB873 - LB913 (41), LB927 - LB973 (47), LB986 - LB999 (14)
                case "LD": // Hurricane Mk IIb, Block 9, Ninth Hawker Produced Block LD100 - LD131 (32), LD157 - LD185 (29), LD199 - LD219 (21), LD232 - LD266 (35), LD287 - LD315 (29), LD334 - LD351 (18), LD369 - LD416 (48), LD435 - LD470 (36), LD487 - LD508 (22), LD524 - LD539 (16), LD577 - LD580 (4), LD594 - LD632 (39), LD651 - LD695 (45), LD723 - LD749 (27), LD772 - LD809 (38), LD827 - LD866 (40), LD885 - LD905 (21), LD931 - LD979 (49), LD993 - LD999 (7) Total 1,184
                //Powered by Rolls-Royce Merlin XX and 27 engines. Aircraft were delivered between the 18th April, 1943 and the 29th September, 1943. The average rate of production was 6-7 aircraft per day.

                case "LE": // Hurricane Mk IIb, Block 10, Tenth Hawker Produced Block LE121 - LE146 (26), LE163 - LE183 (21), LE201 - LE214 (14), LE247 - LE273 (27), LE291 - LE309 (19), LE334 - LE368 (35), LE387 - LE405 (19), LE432 - LE449 (18), LE456 - LE484 (29), LE499 - LE535 (37), LE552 - LE593 (42), LE617 - LE665 (49), LE679 - LE713 (35), LE737 - LE769 (33), LE784 - LE816 (33), LE829 - LE867 (39), LE885 - LE925 (41), LE938 - LE966 (29), LE979 - LE999 (21)
                case "LF": // Hurricane Mk IIb, Block 10, Tenth Hawker Produced Block LF101 - LF135 (35), LF153 - LF184 (32), LF197 - LF237 (41), LF256 - LF298 (43), LF313 - LF346 (34), LF359 - LF405 (47), LF418 - LF435 (18), LF451 - LF482 (32), LF494 - LF516 (23), LF529 - LF542 (14), LF559 - LF601 (43), LF620 - LF660 (41), LF674 - LF721 (48), LF737 - LF774 (38)
                case "MW": // Hurricane Mk IIb, Block 10, Tenth Hawker Produced Block MW335 - MW373 (39)
                case "PG": // Hurricane Mk IIb, Block 10, Tenth Hawker Produced Block PG425 - PG456 (32), PG469 - PG499 (31), PG512 - PG554 (43), PG567 - PG610 (44)
                case "PZ": // Hurricane Mk IIb, Block 10, Tenth Hawker Produced Block PZ730 - PZ778 (49), PZ791 - PZ835 (45), PZ848 - PZ865 (18) Total 1,357
                    // Powered by Rolls-Royce Merlin XX, 24, and 27 engines. The aircraft were delivered between the 29th September, 1943 and the 24th May, 1944. The average rate of production was 5-6 aircraft per day.
                    break;
                default:
                    int ser;
                    int.TryParse(defSerial, out ser);
                    CampaignName = cNorthAfrica;
                    if (ser < 5700) CampaignName = cBattleOfBritain; // use 5600 series for BoB F-2
                    if (ser < 2000) CampaignName = cBattleOfFrance;
                    // A total of 1,183 E-1 were built, 110 of them were E-1/B
                    // Bf 109E-4 1394 Erla Leipzig. Erla E-4s fell into blocks W.Nr.1575 - 1659, W.Nr.1980 - 2063 and W.Nr.4091 - 4222
                    // upgraded from an E-3 in the W.Nr 1074-1574 Erla block, E-3 from 790 A total of 1,276 E-3 were built, including 83 E-3a export versions
                    // Bf 109E-4, A total of 561 of all E-4 versions were built, including 496 E-4s built as such: 250 E-4, 211 E-4/B, 15 E-4/N and 20 E-4/BN. A total of 438 E-7s of all variants were built.
                    // Bf 109F,
                    //case 10000: // 109G
                    break;
            };
        };
        oldSqn = missFile.get("MAIN", "player"); // if forced switch or transfer
        oldSqn = oldSqn.Substring(0, oldSqn.IndexOf("."));
        string abc = " ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        int pos = int.Parse(defTail);
        //tailNoSerialNo = "(verify tailnumber 'D' and serialno. 'R6708' in <Player Plane>)";
        if (defClass.Contains("109") || defSquadron.Contains("RA_")) tailNoSerialNo = "Verify tailnumber '" + defTail + "', serialno. '" + defSerial + "' and";
        else tailNoSerialNo = "Verify tailnumber '" + abc[pos].ToString() + "', serialno. '" + defSerial + "' and";

    }
    private void ReadInitFile()
    {
        string[] strDynCamp = File.ReadAllLines(CampInitFile);

        int forEachIndex = 0;
        foreach (string str in strDynCamp)
        {
            //if(odenDebug) GamePlay.gpLogServer(null, "OdenDynCamp: {0}", new object[] { str });
            if (str.Length > 0)
            {
                string[] strs = str.Split(new char[] { ',' }, StringSplitOptions.None);
                switch (strs[0])
                {
                    case "CampaignDate":
                        gameDateTime = DateTime.Parse(strs[1]);
                        gameDateTime = gameDateTime.AddHours(5);
                        break;
                    case "ReinforcementDate":
                        ReinforcementDate = DateTime.Parse(strs[1]);
                        break;
                    case "HighOctaneDate":
                        highOctaneDate = DateTime.Parse(strs[1]);
                        break;
                    case "RedCoalition":
                        RedCoalition = strs[1];
                        break;
                    case "BlueCoalition":
                        BlueCoalition = strs[1];
                        break;
                    case "CurrentBattle":
                        fmCurrent = strs[1];
                        break;
                    case "OnOffensive":
                        int.TryParse(strs[1], out SideOnOffensive);
                        break;
                    case "BattleProgress":
                        int.TryParse(strs[1], out BattleProgress);
                        break;
                    case "ConsecutiveLosses":
                        int.TryParse(strs[1], out ConsecutiveLosses);
                        break;
                    case "Satellites":
                        Satellites.Clear();
                        foreach (string s in strs)
                            if (s != "Satellites" && s != "")
                                Satellites.Add(s);
                        if (Satellites.Count > 0)
                            defSatellites = string.Join(",", Satellites.ToArray());
                        break;
                    case "AirportDamage":
                        AirportsDamaged.Add(strs[1] + "," + strs[2]);
                        break;
                    case "CHRadarDamage":
                        CHRadarDamaged.Add(strs[1] + "," + strs[2]);
                        break;
                    case "PortDamage":
                        PortDamaged.Add(strs[1] + "," + strs[2]);
                        break;
                    case "FactoryDamage":
                        FactoryDamaged.Add(strs[1] + "," + strs[2]);
                        break;
                    case "GndStatDead":
                        GndStatDead.Add(strs[1]);
                        break;
                    case "GndGrpDead":
                        GndGrpDead.Add(strs[1]);
                        break;
                    case "AirGroup":
                        //AirGroup,RAF Hornchurch,BoB_RAF_F_54Sqn,12,Sounthend,Aircraft.SpitfireMkIa_100oct
                        //if (odenDebug) GamePlay.gpLogServer(null, "Airgroup status: {1} {0} at {3} flying {2} {4}", new object[] { strs[1], strs[2], strs[3], strs[4], strs[5] });
                        MissionAirbase ab = ParseAirGroup(strs);
                        MissionAirbases.Add(ab);
                        //if(odenDebug) GamePlay.gpLogServer(null, "MissionAirbase: {0} at {1}", new object[] { ab.name, ab.airportName });
                        break;
                    case "Event":
                        string[] strEvent = new string[9];
                        for (int i = 0; i < strEvent.Length; i++)
                            if (strs.Length > i) strEvent[i] = strs[i];
                            else strEvent[i] = "";

                        DynCampEvent e = new DynCampEvent(DateTime.Parse(strEvent[1])
                            , strEvent[2] //action
                            , strEvent[3] //type
                            , strEvent[4] //typeValue
                            , strEvent[5] //airportName
                            , strEvent[6] //param1, qty for add
                            , strEvent[7] //param2, planetype for add
                            , strEvent[8] //param3, sector for add
                            );
                        DynCampEvents.Add(e);
                        break;
                };
            };
        };

        //if(odenDebug) GamePlay.gpLogServer(null, "gameDateTime: {0}", new object[] { gameDateTime.ToString("D") });
        foreach (DynCampEvent e in DynCampEvents)
        {
            //if(odenDebug) GamePlay.gpLogServer(null, "DynCampEvent?: {0} {1} {2} {3}", new object[] { e.dateTime.ToString("D"), e.typeValue, e.param1, e.airportName });
            if (e.dateTime <= gameDateTime)
            {
                //if(odenDebug) GamePlay.gpLogServer(null, "DynCampEvent: {0} {1} {2} {3}", new object[] { e.dateTime.ToString("D"), e.typeValue, e.param1, e.airportName });
                switch (e.action)
                {
                    case "add":
                        if (e.type == "AirGroup")
                        {   //Event,1 September 1940,add,AirGroup,BoB_RAF_F_46Sqn,North_weald,12,Aircraft.HurricaneMkI_100oct,RAF North Weald
                            string[] strs = { "AirGroup", e.param3, e.typeValue, e.param1, e.airportName, e.param2 };
                            MissionAirbase ab = ParseAirGroup(strs);
                            MissionAirbases.Add(ab);
                            if (ab.sector.Contains(ab.airportName.Substring(0, 3))) mainStoryList.Add(ab.name + " moved to " + ab.airportName.Replace('_', ' '));
                            else mainStoryList.Add(ab.name + " moved to " + ab.airportName.Replace('_', ' ') + " " + ab.sector);

                        };
                        break;
                    case "move":
                        if (e.type == "AirGroup")
                        {   //Event,7 September 1940,move,AirGroup,BoB_RAF_F_111Sqn,Kenley
                            MissionAirbase xab = null;
                            List<int> removeAirbaseAt = new List<int>();
                            int forEachIdx = 0;
                            foreach (MissionAirbase mab in MissionAirbases)
                            {
                                if (mab.sqn.Contains(e.typeValue) && !mab.sqn.Contains(defSquadron))
                                {
                                    xab = mab;
                                    removeAirbaseAt.Add(forEachIdx);
                                    break;
                                };
                                forEachIdx++;
                            };
                            foreach (int i in removeAirbaseAt)
                                MissionAirbases.RemoveAt(i);
                            string[] strs = { "AirGroup", e.param3, e.typeValue, e.param1, e.airportName, e.param2 };
                            MissionAirbase ab = ParseAirGroup(strs);
                            MissionAirbases.Add(ab);
                            if (xab != null)
                                if (ab.sector.Contains(ab.airportName.Substring(0, 3))) mainStoryList.Add(ab.name + " " + xab.sector + " moved to " + ab.airportName.Replace('_', ' '));
                                else mainStoryList.Add(ab.name + " " + xab.sector + " moved to " + ab.airportName.Replace('_', ' ') + " " + ab.sector);
                            else
                                if (ab.sector.Contains(ab.airportName.Substring(0, 3))) mainStoryList.Add(ab.name + " moved to " + ab.airportName.Replace('_', ' '));
                                else mainStoryList.Add(ab.name + " moved to " + ab.airportName.Replace('_', ' ') + " " + ab.sector);

                        };
                        break;
                    case "remove":
                        if (e.type == "AirGroup")
                        {   //Event,7 September 1940,remove,AirGroup,BoB_RAF_F_601Sqn,Exeter
                            MissionAirbase xab = null;
                            List<int> removeAirbaseAt = new List<int>();
                            int forEachIdx = 0;
                            foreach (MissionAirbase mab in MissionAirbases)
                            {
                                if (mab.sqn.Contains(e.typeValue) && !mab.sqn.Contains(defSquadron))
                                {
                                    xab = mab;
                                    removeAirbaseAt.Add(forEachIdx);
                                    break;
                                };
                                forEachIdx++;
                            };
                            foreach (int i in removeAirbaseAt)
                                MissionAirbases.RemoveAt(i);
                            string[] strs = { "AirGroup", e.param3, e.typeValue, e.param1, e.airportName, e.param2 };
                            MissionAirbase ab = ParseAirGroup(strs);
                            if (xab != null) mainStoryList.Add(ab.name + " " + xab.sector + " moved away to " + ab.airportName.Replace('_', ' '));
                            else mainStoryList.Add(ab.name + " moved away to " + ab.airportName.Replace('_', ' '));
                        };
                        break;
                    case "type":
                        if (e.type == "AirGroup")
                        {   //Event,1 October 1940,type,AirGroup,BoB_LW_JG2_III,Le_Havre_Octeville,0,Aircraft.Bf-109E-3B
                            foreach (MissionAirbase mab in MissionAirbases)
                                if (mab.sqn.Contains(e.typeValue))
                                {
                                    mab.aircraftType = e.param2;
                                    break;
                                };
                            string[] strs = { "AirGroup", e.param3, e.typeValue, e.param1, e.airportName, e.param2 };
                            MissionAirbase ab = ParseAirGroup(strs);
                            mainStoryList.Add(ab.name + " recieved " + Designation(ab.aircraftType));
                        };
                        break;
                };
            };
        };

        DynCampEvents.RemoveAll(e => e.dateTime <= gameDateTime);

    }
    private void CheckFiles()
    {
        string myDocPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
        DoverFolder = myDocPath + @"\1C SoftClub\il-2 sturmovik cliffs of dover";
        if (!Directory.Exists(DoverFolder))
        {
            GamePlay.gpHUDLogCenter("Cannot locate '1C SoftClub' folder");
            return;
        };
        //if (odenDebug) GamePlay.gpHUDLogCenter("'1C SoftClub' folder is there");
        //string[] filenames = Directory.GetFiles(DoverFolder, vFile +".*", SearchOption.AllDirectories);
        string subType = "";
        if (defSquadron.Contains("RAF_")) subType = defSquadron.Substring(10); // BoB_RAF_F_264Sqn >> 264Sqn same goes for BoB_RAF_B_123Sqn
        if (defSquadron.Contains("LW_")) subType = defSquadron.Substring(7); // BoB_LW_KG2_I >> KG2_I
        if (defSquadron.Contains("RA_")) subType = "RA" + defSquadron.Substring(defSquadron.LastIndexOf("_") + 1); // BoB_RA_56St_20Gruppo_353Sq >> 56St_20Gruppo_353Sq
        if (CampMapName.Contains("Land$Online_Cobra"))
            if(GamePlay.gpPlayer().Army() == RAF) subType = "RedCAS";
            else subType = "BlueCAS";
        if (odenDebug) GamePlay.gpLogServer(null, "subType: {0}", new object[] { subType });
        string[] filenames = Directory.GetFiles(DoverFolder, vFile + subType + ".*", SearchOption.AllDirectories);
        foreach (string str in filenames)
        {
            //if (odenDebug) GamePlay.gpLogServer(null, "Found: {0}", new object[] { str });
            //if (str.Contains(vFile +".mis")) CampMisFile = str;
            //if (str.Contains(vFile +".bri")) CampBriFile = str;
            if (str.Contains(vFile + subType + ".mis"))
            {
                CampMisFile = str;
                CampBriFile = CampMisFile.Replace(".mis", ".briefing");
            };
        };
        string MisFolder = CampMisFile.Substring(0, CampMisFile.LastIndexOf('\\'));
        if (odenDebug) GamePlay.gpLogServer(null, "MisFolder: {0}", new object[] { MisFolder });
        CampInitFile = MisFolder + "\\" + vFile + subType + ".ini";
        /*
        if (odenDebug)
            if (File.Exists(CampInitFile))
                File.Delete(CampInitFile);
        */
        if (!File.Exists(CampInitFile))
            CreateInitFiles();
    }
    private void CreateInitFiles()
    {
        foreach (MissionMarker mm in MissionMarkers)
            switch (CampaignName)
            {
                case cBattleOfFrance:
                    switch (mm.key)
                    {
                        case fmArras:
                        case fmStPolSurTernoise:
                        case fmFruges:
                        case fmHesdin:
                        case fmFrevent:
                        case fmAuxiLeChateau:
                        case fmLeCrotoy:
                        case fmAbbeville:
                        case fmBerteaucourt:
                        case fmAmiens:
                        case fmBapaume:
                            mm.army = LW;
                            break;
                        default:
                            if (mm.army > 0)
                                mm.army = RAF;
                            break;
                    };
                    break;
                case cBattleOfBritain:
                    switch (mm.key)
                    {
                        case "FrontMarker0":
                        case "FrontMarker1":
                        case "FrontMarker2":
                        case "FrontMarker3":
                        case "FrontMarker4":
                        case "FrontMarker5":
                        case "FrontMarker6":
                        case "FrontMarker7":
                        case "FrontMarker8":
                        case "FrontMarker16":
                            mm.army = LW;
                            break;
                        default:
                            mm.army = RAF;
                            break;
                    };
                    break;
                case cNorthAfrica:
                    switch (mm.key)
                    {
                        case fmSidi_Barrani:
                        case fmBuq_Buq:
                        case fmHalfaya_Pass:
                        case fmSollum:
                        case fmFort_Capuzzo:
                        case fmSidi_Azeiz:
                            mm.army = RAF;
                            break;
                        default:
                            if (mm.army > 0)
                                mm.army = LW;
                            break;
                    };
                    break;
                case cCobra:
                    switch (mm.key)
                    {
                        case "FrontMarker0":
                        case "FrontMarker1":
                        case "FrontMarker2":
                        case "FrontMarker3":
                        case "FrontMarker4":
                        case "FrontMarker5":
                        case "FrontMarker13":
                            mm.army = LW;
                            break;
                        case "FrontMarker6":
                        case "FrontMarker7":
                        case "FrontMarker8":
                        case "FrontMarker9":
                        case "FrontMarker10":
                        case "FrontMarker11":
                        case "FrontMarker12":
                            mm.army = RAF;
                            break;
                        default:
                            mm.army = 0;
                            break;
                    };
                    break;
            };
        gameDateTime = CampaignStartDate();
        highOctaneDate = CampaignStartDate();
        ReinforcementDate = CampaignStartDate();
        ReinforcementDate = ReinforcementDate.AddDays(rnd.Next(2, 5));
        BlueCoalition = CampaignCoalition(LW);
        RedCoalition = CampaignCoalition(RAF);
        ATK = CampaignStartInitiative();
        fmCurrent = CampaignStartFM();
        string[] strDynCamp = { "//" +CampaignName +" " +CampaignPhase()
                            , "//Dynamic Mission by theOden"
                            , "//This file keeps track of units etc. and may carefully be edited manually"
                            , "//Entries can be in any order"
                            , "//AirGroup,Sector,Squadron/Gruppe,Quantity,Airportname,AircraftType - all CliffsOfDover data"
                            , "//AirportDamage,Airportname,Damage - all CliffsOfDover data (GamePlay.gpAirports())"
                            , "//GndStatDead,StaticName - all CliffsOfDover data as per mis-file [Stationary]"
                            , "//Event,add/remove/move/newplanetype,date as '16 August 1940',AirGroup,{newAirport/newPlaneType}"
                            , "//Player Squadron must be edited in mission editor"
                            , "//Coalition can be country code or 'al' for Allied, 'cw' for commonwealth and 'ax' for Axis"
                            , "//-"
                            , "CampaignDate,"+gameDateTime.ToString("D")
                            , "ReinforcementDate,"+ReinforcementDate.ToString("D")
                            , "highOctaneDate,"+highOctaneDate.ToString("D")
                            , "RedCoalition,"+RedCoalition
                            , "BlueCoalition,"+BlueCoalition
                            , "CurrentBattle,"+fmCurrent
                            , "OnOffensive,"+ATK.ToString()
                            , "ConsecutiveLosses,0"
                            };
        foreach (string str in strDynCamp)
            strDynCampList.Add(str);


        /* WIP on winter map
         * Sidi Haneish = Plumetot
         * Shallufa = Bernay_Saint_Martin
         * Fuka = Le_Havre_Octeville
         * Ismalia (RAF Fayid) = Bernay_Saint_Martin
         * Ma'aten Bagush = Caen_carpiquet
         * El Daba = Deauville_Saint_Gatien
         * Helwan = Bernay_Saint_Martin
         */
        switch (CampaignName)
        {
            case cBattleOfFrance:
                // Fighter Command (July 10th but will do)
                strDynCampList.Add("AirGroup,RAF Biggin Hill,BoB_RAF_F_32Sqn,12,Biggin_Hill,Aircraft.HurricaneMkI_dH5-20");
                strDynCampList.Add("AirGroup,RAF Biggin Hill,BoB_RAF_F_141Sqn,12,Maidstone,Aircraft.DefiantMkI");
                strDynCampList.Add("AirGroup,RAF Biggin Hill,BoB_RAF_F_610Sqn,12,Gravesend,Aircraft.SpitfireMkI");
                strDynCampList.Add("AirGroup,RAF Biggin Hill,BoB_RAF_F_600Sqn,12,Manston,Aircraft.BlenheimMkIVF");
                strDynCampList.Add("AirGroup,RAF North Weald,BoB_RAF_F_56Sqn,12,North_weald,Aircraft.HurricaneMkI_dH5-20");
                strDynCampList.Add("AirGroup,RAF North Weald,BoB_RAF_F_151Sqn,12,North_weald,Aircraft.HurricaneMkI_dH5-20");
                //strDynCampList.Add("AirGroup,RAF North Weald,BoB_RAF_F_85Sqn,12,Martlesham,Aircraft.HurricaneMkI_dH5-20");
                //strDynCampList.Add("AirGroup,RAF North Weald,BoB_RAF_F_25Sqn,12,Martlesham,Aircraft.BlenheimMkIVF");
                strDynCampList.Add("AirGroup,RAF Kenley,BoB_RAF_F_64Sqn,12,Kenley,Aircraft.SpitfireMkI");
                strDynCampList.Add("AirGroup,RAF Kenley,BoB_RAF_F_111Sqn,12,Croydon,Aircraft.HurricaneMkI_dH5-20");
                // AASF strDynCampList.Add("AirGroup,RAF Kenley,BoB_RAF_F_501Sqn,12,Croydon,Aircraft.HurricaneMkI_dH5-20");
                strDynCampList.Add("AirGroup,RAF Hornchurch,BoB_RAF_F_65Sqn,12,Hawkinge,Aircraft.SpitfireMkI");
                strDynCampList.Add("AirGroup,RAF Hornchurch,BoB_RAF_F_74Sqn,12,Hornchurch,Aircraft.SpitfireMkI");
                strDynCampList.Add("AirGroup,RAF Hornchurch,BoB_RAF_F_54Sqn,12,Rochford,Aircraft.SpitfireMkI"); // Rochford
                strDynCampList.Add("AirGroup,RAF Tangmere,BoB_RAF_F_43Sqn,12,Tangmere,Aircraft.HurricaneMkI_dH5-20");
                strDynCampList.Add("AirGroup,RAF Tangmere,BoB_RAF_F_145Sqn,12,Tangmere,Aircraft.HurricaneMkI_dH5-20");
                strDynCampList.Add("AirGroup,RAF Tangmere,BoB_RAF_F_601Sqn,12,Tangmere,Aircraft.HurricaneMkI_dH5-20");
                // AASF strDynCampList.Add("AirGroup,RAF Northolt,BoB_RAF_F_1Sqn,12,Northolt,Aircraft.HurricaneMkI_dH5-20");
                strDynCampList.Add("AirGroup,RAF Northolt,BoB_RAF_F_604Sqn,12,Northolt,Aircraft.BlenheimMkIVF");
                strDynCampList.Add("AirGroup,RAF Northolt,BoB_RAF_F_257Sqn,12,Hendon,Aircraft.HurricaneMkI_dH5-20");
                // Coastal Command
                strDynCampList.Add("AirGroup,Coastal Command,BoB_RAF_F_235Sqn,12,Manston,Aircraft.BlenheimMkIVF");
                // RAF Filton until July 1940 strDynCampList.Add("AirGroup,Coastal Command,BoB_RAF_F_236Sqn,12,Thorney_Island,Aircraft.BlenheimMkIVF");
                // Scotland strDynCampList.Add("AirGroup,Coastal Command,BoB_RAF_F_248Sqn,12,Dyce,Aircraft.BlenheimMkIVF");
                // Sqn N/A strDynCampList.Add("AirGroup,Coastal Command,BoB_RAF_F_254Sqn,12,Hatston,Aircraft.BlenheimMkIVF");

                // Bomber Command (airstart on RedSpawn trigger)
                strDynCampList.Add("AirGroup,RAF Mildenhall,BoB_RAF_B_9Sqn,12,Mildenhall,Aircraft.WellingtonMkIc");
                strDynCampList.Add("AirGroup,RAF Mildenhall,BoB_RAF_B_37Sqn,12,Mildenhall,Aircraft.WellingtonMkIc");
                strDynCampList.Add("AirGroup,RAF Mildenhall,BoB_RAF_B_38Sqn,12,Mildenhall,Aircraft.WellingtonMkIc");
                strDynCampList.Add("AirGroup,RAF Mildenhall,BoB_RAF_B_99Sqn,12,Mildenhall,Aircraft.WellingtonMkIc");
                strDynCampList.Add("AirGroup,RAF Mildenhall,BoB_RAF_B_115Sqn,12,Mildenhall,Aircraft.WellingtonMkIc");
                strDynCampList.Add("AirGroup,RAF Mildenhall,BoB_RAF_B_149Sqn,12,Mildenhall,Aircraft.WellingtonMkIc");
                // N/A strDynCampList.Add("AirGroup,RAF Wyton,BoB_RAF_B_18Sqn,12,Upper_Heyford,Aircraft.BlenheimMkIV");
                // N/A strDynCampList.Add("AirGroup,RAF Wyton,BoB_RAF_B_57Sqn,12,Upper_Heyford,Aircraft.BlenheimMkIV");
                strDynCampList.Add("AirGroup,RAF Wyton,BoB_RAF_B_21Sqn,12,Watton,Aircraft.BlenheimMkIV");
                strDynCampList.Add("AirGroup,RAF Wyton,BoB_RAF_B_82Sqn,12,Watton,Aircraft.BlenheimMkIV");
                strDynCampList.Add("AirGroup,RAF Wyton,BoB_RAF_B_90Sqn,12,West_Raynham,Aircraft.BlenheimMkIV");
                strDynCampList.Add("AirGroup,RAF Wyton,BoB_RAF_B_101Sqn,12,West_Raynham,Aircraft.BlenheimMkIV");
                // AASF strDynCampList.Add("AirGroup,RAF Wyton,BoB_RAF_B_114Sqn,12,Watton,Aircraft.BlenheimMkIV");
                // AASF strDynCampList.Add("AirGroup,RAF Wyton,BoB_RAF_B_139Sqn,12,West_Raynham,Aircraft.BlenheimMkIV");
                strDynCampList.Add("AirGroup,RAF Wyton,BoB_RAF_B_107Sqn,12,Wattisham,Aircraft.BlenheimMkIV");
                strDynCampList.Add("AirGroup,RAF Wyton,BoB_RAF_B_110Sqn,12,Wattisham,Aircraft.BlenheimMkIV");

                // BEF
                strDynCampList.Add("AirGroup,RAF 60 Wing,BoB_RAF_F_85Sqn,12,Oye-Plage,Aircraft.HurricaneMkI_dH5-20"); // Lille-Seclin
                strDynCampList.Add("AirGroup,RAF 60 Wing,BoB_RAF_F_87Sqn,12,Guines,Aircraft.HurricaneMkI_dH5-20"); // Senon
                strDynCampList.Add("AirGroup,RAF 61 Wing,BoB_RAF_F_607Sqn,12,Rely_Norrent_Fontes,Aircraft.HurricaneMkI_dH5-20"); // part Gladiators 10.May
                strDynCampList.Add("AirGroup,RAF 61 Wing,BoB_RAF_F_615Sqn,12,St-Omer-Clairmarais,Aircraft.HurricaneMkI_dH5-20"); // part Gladiators 10.May
                strDynCampList.Add("AirGroup,RAF 63 Wing,BoB_RAF_F_3Sqn,12,Colembert,Aircraft.HurricaneMkI_dH5-20");
                strDynCampList.Add("AirGroup,RAF 63 Wing,BoB_RAF_F_79Sqn,12,Merville_Calonne,Aircraft.HurricaneMkI_dH5-20");
                strDynCampList.Add("AirGroup,RAF 70 Wing,BoB_RAF_B_15Sqn,16,Marquise_West,Aircraft.BlenheimMkIV"); //18.Sqn Blenheim Mk V, 20-26.May Watton
                strDynCampList.Add("AirGroup,RAF 70 Wing,BoB_RAF_B_58Sqn,16,Boulogne_Alprech,Aircraft.BlenheimMkIV"); //57.Sqn Blenheim Mk V, May-June Gatwick
                strDynCampList.Add("AirGroup,RAF 52 Wing,BoB_RAF_B_52Sqn,16,St-Omer-Arques,Aircraft.BlenheimMkIV"); //53.Sqn 20.May Lympne/Andover
                strDynCampList.Add("AirGroup,RAF 52 Wing,BoB_RAF_B_61Sqn,16,Lympne,Aircraft.BlenheimMkIV"); //59.Sqn May Lympne/Andover
                //strDynCampList.Add("AirGroup,RAF 50 Wing,BoB_RAF_F_41Sqn,12,Coquelles,Aircraft.DH82A"); //4.Sqn January 1939-September 1940: Lysander I, II, 16-21 May 1940: Lille/ Ronchin, 21-24 May 1940: Clairmarais, 24-25 May 1940: Hawkinge
                //strDynCampList.Add("AirGroup,RAF 50 Wing,BoB_RAF_F_23Sqn,12,Ramsgate,Aircraft.DH82A"); //13.Sqn 22-29 May 1940: Abbeville (?), 1-17 June 1940: Hooton Park
                strDynCampList.Add("AirGroup,RAF 50 Wing,BoB_RAF_F_17Sqn,12,Lympne,Aircraft.GladiatorMkII"); //16.Sqn 19 May-2 June 1940: Lympne

                // RAF: Advanced Air Striking Force -----------------------------------
                strDynCampList.Add("AirGroup,RAF 67 AASF,BoB_RAF_F_1Sqn,12,Roye_Amy,Aircraft.HurricaneMkI_dH5-20"); // Wassincourt
                strDynCampList.Add("AirGroup,RAF 67 AASF,BoB_RAF_F_73Sqn,12,Montdidier,Aircraft.HurricaneMkI_dH5-20"); // Rouvre (between Amiens/Montdidier)
                strDynCampList.Add("AirGroup,RAF 67 AASF,BoB_RAF_F_501Sqn,12,Poix_Nord,Aircraft.HurricaneMkI_dH5-20"); // Bethenville (east Reims)
                strDynCampList.Add("AirGroup,RAF 71 AASF,BoB_RAF_B_105Sqn,16,Grandvilliers,Aircraft.BlenheimMkI"); // Fairey Battle, Villeneuve
                strDynCampList.Add("AirGroup,RAF 71 AASF,BoB_RAF_B_114Sqn,16,Haute-Fontaine,Aircraft.BlenheimMkIV"); // Conde
                strDynCampList.Add("AirGroup,RAF 71 AASF,BoB_RAF_B_139Sqn,16,Dieppe_Saint_Aubin,Aircraft.BlenheimMkIV"); // Plivot (south Reims)
                strDynCampList.Add("AirGroup,RAF 71 AASF,BoB_RAF_B_150Sqn,16,Creil,Aircraft.BlenheimMkI"); // Fairey Battle, Ecury
                strDynCampList.Add("AirGroup,RAF 75 AASF,BoB_RAF_B_88Sqn,16,Crecy,Aircraft.BlenheimMkI"); // Fairey Battle, Mourmelon
                strDynCampList.Add("AirGroup,RAF 75 AASF,BoB_RAF_B_103Sqn,16,Rouen_Boos,Aircraft.BlenheimMkI"); // Fairey Battle, Betheniville
                strDynCampList.Add("AirGroup,RAF 75 AASF,BoB_RAF_B_207Sqn,16,Dieppe_Saint_Aubin,Aircraft.BlenheimMkI"); //208.Sqn Fairey Battle, Auberive
                strDynCampList.Add("AirGroup,RAF 76 AASF,BoB_RAF_B_12Sqn,16,Brombos,Aircraft.BlenheimMkI"); // Fairey Battle, Amifontaine
                strDynCampList.Add("AirGroup,RAF 76 AASF,BoB_RAF_B_142Sqn,16,Haute-Fontaine,Aircraft.BlenheimMkI"); // Fairey Battle, Berry-au-Bac
                strDynCampList.Add("AirGroup,RAF 76 AASF,BoB_RAF_B_218Sqn,16,Rosieres_en_Santerre,Aircraft.BlenheimMkI"); //226.Sqn Fairey Battle, Reims

                strDynCampList.Add("AirGroup,GC I/1,BoB_RAF_F_232Sqn,12,Persan_Beaumont,Aircraft.HurricaneMkI_dH5-20"); // Chantilly-les-aigles (Oise): Bloch 152
                strDynCampList.Add("AirGroup,GC II/1,BoB_RAF_F_234Sqn,12,Pontoise/Cormeilles,Aircraft.HurricaneMkI_dH5-20"); // Yvelines: Bloch 152
                strDynCampList.Add("AirGroup,GC III/3,BoB_RAF_F_229Sqn,12,Sempy,Aircraft.HurricaneMkI"); // Norrent-Fontes (Pas-de-Calais): Morane Saulnier 406
                strDynCampList.Add("AirGroup,GC I/2,BoB_RAF_F_236Sqn,12,Crecy,Aircraft.HurricaneMkI"); // Toul-Ochey (Meurthe et Moselle): Morane Saulnier 406
                strDynCampList.Add("AirGroup,GC II/2,BoB_RAF_F_238Sqn,12,Beauvais_Nivillers,Aircraft.HurricaneMkI"); // Laon-Chambry (Aisne): Morane Saulnier 406
                //strDynCampList.Add("AirGroup,GC III/2,BoB_RAF_F_232Sqn,12,Roye_Amy,Aircraft.HurricaneMkI"); // Cambrai-Niergnies (Nord): Morane Saulnier 406
                strDynCampList.Add("AirGroup,GC I/3,BoB_RAF_F_242Sqn,12,Creil,Aircraft.SpitfireMkI"); // Cannes-Mandelieu (Alpes Maritimes): Dewoitine 520
                strDynCampList.Add("AirGroup,GC II/3,BoB_RAF_F_245Sqn,12,Grandvilliers,Aircraft.SpitfireMkI"); // du Luc (Var): Morane Saulnier 406 au Dewoitine 520
                strDynCampList.Add("AirGroup,GC III/3,BoB_RAF_F_247Sqn,12,Beauvais_Tille,Aircraft.HurricaneMkI"); // Beauvais-Tillé (Oise): Morane Saulnier 406
                //strDynCampList.Add("AirGroup,GC I/4,BoB_RAF_F_232Sqn,12,Creil,Aircraft.SpitfireMkI"); // Wez-Thuisy (Marne): Curtiss H75
                //strDynCampList.Add("AirGroup,GC II/4,BoB_RAF_F_232Sqn,12,Creil,Aircraft.SpitfireMkI"); // Xaffévillers (Vosges): Curtiss H75
                //strDynCampList.Add("AirGroup,GC III/4,BoB_RAF_F_248Sqn,12,Beauvais_Tille,Aircraft.SpitfireMkI"); // Casablanca (Maroc): Dewoitine 520
                //strDynCampList.Add("AirGroup,GC I/5,BoB_RAF_F_232Sqn,12,Creil,Aircraft.SpitfireMkI"); // de Suippes (Marne): Curtiss H75
                //strDynCampList.Add("AirGroup,GC II/5,BoB_RAF_F_232Sqn,12,Creil,Aircraft.SpitfireMkI"); // Toul-Croix-de-Metz (Meurthe et Moselle): Curtiss H75
                //strDynCampList.Add("AirGroup,GC III/5,BoB_RAF_F_232Sqn,12,Creil,Aircraft.HurricaneMkI"); // Bizerte-Sidi Ahmed (Tunisie): Morane Saulnier 406
                //strDynCampList.Add("AirGroup,GC I/6,BoB_RAF_F_249Sqn,12,Beauvais_Tille,Aircraft.HurricaneMkI"); // Marseille-Marignane (Bouches du Rhône): Morane Saulnier 406
                //strDynCampList.Add("AirGroup,GC II/6,BoB_RAF_F_232Sqn,12,Creil,Aircraft.HurricaneMkI"); // Anglure-Vouarces (Marne): Morane Saulnier 406
                //strDynCampList.Add("AirGroup,GC III/6,BoB_RAF_F_232Sqn,12,Creil,Aircraft.HurricaneMkI0"); // Chissey (Jura): Morane Saulnier 406
                //strDynCampList.Add("AirGroup,GC I/7,BoB_RAF_F_232Sqn,12,Creil,Aircraft.HurricaneMkI"); // Rayak (Syrie): Morane Saulnier 406
                //strDynCampList.Add("AirGroup,GC II/7,BoB_RAF_F_232Sqn,12,Creil,Aircraft.HurricaneMkI"); // Luxeuil-St Sauveur (Haute Saone): Morane Saulnier 406
                //strDynCampList.Add("AirGroup,GC III/7,BoB_RAF_F_232Sqn,12,Creil,Aircraft.HurricaneMkI"); // Vitry-le-François (Marne): Morane Saulnier 406
                //strDynCampList.Add("AirGroup,GC I/8,BoB_RAF_F_232Sqn,12,Creil,Aircraft.HurricaneMkI_dH5-20"); // Velaine-en-Haye (Meurthe et Moselle): Bloch 152
                strDynCampList.Add("AirGroup,GC II/8,BoB_RAF_F_253Sqn,12,Zutkerque,Aircraft.HurricaneMkI_dH5-20"); // Calais-Marck (Pas-de-Calais): Bloch 152
                //strDynCampList.Add("AirGroup,GC I/9,BoB_RAF_F_232Sqn,12,Creil,Aircraft.HurricaneMkI"); // Tunis-el-Aouina (Tunisie): Morane Saulnier 406
                //strDynCampList.Add("AirGroup,GC II/9,BoB_RAF_F_232Sqn,12,Creil,Aircraft.HurricaneMkI_dH5-20"); // Marseille-Marignane: Bloch 152
                //strDynCampList.Add("AirGroup,GC III/9,BoB_RAF_F_232Sqn,12,Creil,Aircraft.HurricaneMkI_dH5-20"); // Lyon-Bron (Rhône): Bloch 152
                //strDynCampList.Add("AirGroup,GC I/10,BoB_RAF_F_232Sqn,12,Creil,Aircraft.HurricaneMkI"); // d'Oran-la-Sénia (Algérie): Morane Saulnier 406
                strDynCampList.Add("AirGroup,GC II/10,BoB_RAF_F_249Sqn,12,Rouen_Boos,Aircraft.HurricaneMkI_dH5-20"); // Rouen-Boos (Seine-Maritime): Bloch 152
                strDynCampList.Add("AirGroup,GC III/10,BoB_RAF_F_263Sqn,12,Le_Havre_Octeville,Aircraft.HurricaneMkI_dH5-20"); // Havre-Octeville (Seine-Maritime): Bloch 152
                //strDynCampList.Add("AirGroup,GC I/145,BoB_RAF_F_302_PL,12,Creil,Aircraft.HurricaneMkI_dH5-20"); // Rochefort-Médis (Charente Maritime): Caudron C.714

                strDynCampList.Add("AirGroup,Flottille F1C,BoB_RAF_F_264Sqn,12,Calais_Marck,Aircraft.Bf-110C-2"); // Potez 631 (Bf110)
                strDynCampList.Add("AirGroup,GCN I/13,BoB_RAF_F_266Sqn,12,Pontoise/Cormeilles,Aircraft.Bf-110C-2"); // Etampes (S Paris): Potez 631
                //strDynCampList.Add("AirGroup,GCN II.13,BoB_RAF_F_232Sqn,12,Creil,Aircraft.Bf-110C-2"); // Reims: Potez 631 (Bf110)

                //strDynCampList.Add("AirGroup,GB I/11,BoB_RAF_B_218Sqn,16,Bernay_Saint_Martin,Aircraft.WellingtonMkIc"); // Toulouse: Bloch 210
                //strDynCampList.Add("AirGroup,GB II/11,BoB_RAF_B_218Sqn,16,Bernay_Saint_Martin,Aircraft.WellingtonMkIc"); // Toulouse: Bloch 210
                //strDynCampList.Add("AirGroup,GB I/23,BoB_RAF_B_218Sqn,16,Bernay_Saint_Martin,Aircraft.WellingtonMkIc"); // Le Vallon: Bloch 210
                //strDynCampList.Add("AirGroup,GB II/23,BoB_RAF_B_218Sqn,16,Bernay_Saint_Martin,Aircraft.WellingtonMkIc"); // Le Vallon: Bloch 210
                strDynCampList.Add("AirGroup,GB I/12,BoB_RAF_B_50Sqn,16,Beauvais_Tille,Aircraft.WellingtonMkIc"); // Rheims: Bloch 210
                strDynCampList.Add("AirGroup,GB II/12,BoB_RAF_B_51Sqn,16,Beauvais_Tille,Aircraft.WellingtonMkIc"); // Rheims: Bloch 210
                //strDynCampList.Add("AirGroup,GB I/21,BoB_RAF_B_38Sqn,16,Bernay_Saint_Martin,Aircraft.WellingtonMkIc"); // Bordeaux: Bloch 210
                //strDynCampList.Add("AirGroup,GB II/21,BoB_RAF_B_40Sqn,16,Bernay_Saint_Martin,Aircraft.WellingtonMkIc"); // Bordeaux: Bloch 210
                //strDynCampList.Add("AirGroup,GB I/51,BoB_RAF_B_44Sqn,16,Bernay_Saint_Martin,Aircraft.WellingtonMkIc"); // Tours: Bloch 210
                //strDynCampList.Add("AirGroup,GB II/51,BoB_RAF_B_48Sqn,16,Bernay_Saint_Martin,Aircraft.WellingtonMkIc"); // Tours: Bloch 210

                //strDynCampList.Add("AirGroup,GBA I/51,BoB_RAF_B_101Sqn,12,Rosieres_en_Santerre,Aircraft.Bf-110C-7"); // Reims: Breguet 690 (Bf110)
                //strDynCampList.Add("AirGroup,GBA II/51,BoB_RAF_B_102Sqn,12,Beaumont_Le_Roger,Aircraft.Bf-110C-7"); // Reims: Breguet 690 (Bf110)
                //strDynCampList.Add("AirGroup,GBA I/54,BoB_RAF_B_103Sqn,12,Creil,Aircraft.Bf-110C-7"); // ?: Breguet 690 (Bf110)
                //strDynCampList.Add("AirGroup,GBA II/54,BoB_RAF_B_104Sqn,12,Creil,Aircraft.Bf-110C-7"); // ?: Breguet 690 (Bf110)
                //strDynCampList.Add("AirGroup,GBA II/35,BoB_RAF_B_106Sqn,12,Creil,Aircraft.Bf-110C-7"); // ?: Breguet 690 (Bf110)

                //-- Luftwaffe (I. Fliegerkorps, II. Fliegerkorps and V. Fliegerkorps)
                //strDynCampList.Add("AirGroup,I. Fliegerkorps,BoB_LW_KG51_Stab,5,Caen_carpiquet,Aircraft.He-111H-2"); // Giessen > Rosieres-en-Santerre
                strDynCampList.Add("AirGroup,I. Fliegerkorps,BoB_LW_KG1_I,27,Giessen,Aircraft.He-111H-2"); // Giessen > Montdidier
                strDynCampList.Add("AirGroup,I. Fliegerkorps,BoB_LW_KG1_II,27,Kirtorf,Aircraft.He-111H-2"); // Kirtorf > Rosieres-en-Santerre
                strDynCampList.Add("AirGroup,I. Fliegerkorps,BoB_LW_KG1_III,27,Ettinghausen,Aircraft.He-111H-2"); // Ettinghausen > Rosieres-en-Santerre
                //strDynCampList.Add("AirGroup,I. Fliegerkorps,BoB_LW_KG76_Stab,5,Caen_carpiquet,Aircraft.Do-17Z-1"); // Bonn-Hangelar, St. Leger > Cormeilles-en-Vexin
                strDynCampList.Add("AirGroup,I. Fliegerkorps,BoB_LW_KG76_I,27,Brias,Aircraft.Do-17Z-2"); // Köln-Ostheim > Cambrai
                strDynCampList.Add("AirGroup,I. Fliegerkorps,BoB_LW_KG76_II,27,Brias,Aircraft.Do-17Z-2"); // Köln-Wahn > Creil
                strDynCampList.Add("AirGroup,I. Fliegerkorps,BoB_LW_KG76_III,27,Brias,Aircraft.Do-17Z-1"); // Bonn-Hangelar > Cormeilles-en-Vexin
                //strDynCampList.Add("AirGroup,I. Fliegerkorps,BoB_LW_KG76_IV,25,Caen_carpiquet,Aircraft.Do-17Z-1"); // Beaumont-le-Roger July 1940
                //strDynCampList.Add("AirGroup,I. Fliegerkorps,BoB_LW_ZG76_Stab,5,Arras,Aircraft.Bf-110C-2"); // Köln-Wahn > Laval
                //strDynCampList.Add("AirGroup,X. Fliegerkorps,BoB_LW_ZG76_I,33,Abbeville,Aircraft.Bf-110C-2"); // Stavanger/Trondheim
                strDynCampList.Add("AirGroup,I. Fliegerkorps,BoB_LW_ZG76_II,33,Amiens_Glisy,Aircraft.Bf-110C-2"); // Köln-Wahn > Nellingen, Le Mans >> Abbeville
                //strDynCampList.Add("AirGroup,Jafü 3/Luftflotte 5,BoB_LW_ZG76_III,33,Abbeville,Aircraft.Bf-110C-2"); // Trier-Euren >> Laval >> Stavanger
                //strDynCampList.Add("AirGroup,I. Fliegerkorps,BoB_LW_JG77_Stab,5,Abbeville,Aircraft.Bf-109E-1"); // Philippeville > Montecouvez-Süd
                strDynCampList.Add("AirGroup,I. Fliegerkorps,BoB_LW_JG77_I,36,Amiens_Allonville,Aircraft.Bf-109E-1"); // Escarmain > Berlin-Tempelhof/Aalborg-West >>  	Marquise (august)
                //strDynCampList.Add("AirGroup,I. Fliegerkorps,BoB_LW_JG77_II,36,Abbeville,Aircraft.Bf-109E-1"); // Stavanger > Kristiansand
                strDynCampList.Add("AirGroup,I. Fliegerkorps,BoB_LW_JG3_I,36,Tramecourt,Aircraft.Bf-109E-3"); // Cambrai-Niergnies > Montecouvez >> Berneuil >> Brombos >> Merville (june) >> Le Mans >> Colembert (aug) >> St. Omer-Wizernes (okt)
                strDynCampList.Add("AirGroup,I. Fliegerkorps,BoB_LW_AufklGr_122,4,Arras,Aircraft.Ju-88A-1"); // 5.(F)/122 Köln-Wahn > Haute Fontaine

                //strDynCampList.Add("AirGroup,II. Fliegerkorps,BoB_LW_KG2_Stab,5,Caen_carpiquet,Aircraft.Do-17Z-1"); // Biblis > Trier-Euren > Saint Léger
                strDynCampList.Add("AirGroup,II. Fliegerkorps,BoB_LW_KG2_I,21,Arras_Saint_Liger,Aircraft.Do-17Z-2"); // Geinsheim  >  Epinoy (july)
                strDynCampList.Add("AirGroup,II. Fliegerkorps,BoB_LW_KG2_II,24,Arras_Saint_Liger,Aircraft.Do-17Z-2"); // Groß-Ostheim/Ober-Olm > Saint Léger
                strDynCampList.Add("AirGroup,II. Fliegerkorps,BoB_LW_KG2_III,25,Arras_Saint_Liger,Aircraft.Do-17Z-1"); // Biblis/Kirchberg   >  Cambrai-Süd (july)
                //strDynCampList.Add("AirGroup,II. Fliegerkorps,BoB_LW_KG3_Stab,5,Caen_carpiquet,Aircraft.Do-17Z-1"); // Würzburg > Le Culot
                strDynCampList.Add("AirGroup,II. Fliegerkorps,BoB_LW_KG3_I,27,Barly,Aircraft.Do-17Z-2"); // Aschaffenburg  >  Le Culot
                strDynCampList.Add("AirGroup,II. Fliegerkorps,BoB_LW_KG3_II,27,Barly,Aircraft.Do-17Z-2"); // Schweinfurt > Antwerpen-Deurne
                strDynCampList.Add("AirGroup,II. Fliegerkorps,BoB_LW_KG3_III,27,Barly,Aircraft.Do-17Z-1"); // Würzburg > St. Trond
                //strDynCampList.Add("AirGroup,II. Fliegerkorps,BoB_LW_KG53_Stab,5,Caen_carpiquet,Aircraft.He-111H-2"); // Wiesbaden > Lille-Nord (july)
                strDynCampList.Add("AirGroup,II. Fliegerkorps,BoB_LW_KG53_I,27,Arras,Aircraft.He-111H-2"); // Gelchsheim > Evreux-le-Courdray > Wevelghem > Vitry-en-Artois (july)
                strDynCampList.Add("AirGroup,II. Fliegerkorps,BoB_LW_KG53_II,27,Arras,Aircraft.He-111H-2"); // Zellhausen > Schallhausen > Lille-Nord (july)
                strDynCampList.Add("AirGroup,II. Fliegerkorps,BoB_LW_KG53_III,27,Arras,Aircraft.He-111H-2"); // Frankfurt > Lille-Mouvaux
                //strDynCampList.Add("AirGroup,II. Fliegerkorps,BoB_LW_StG1_Stab,5,Arras,Aircraft.Ju-87B-2"); //
                strDynCampList.Add("AirGroup,II. Fliegerkorps,BoB_LW_StG2_II,27,Brias,Aircraft.Ju-87B-2"); // Cambrai, Guise > Lannion (july)
                strDynCampList.Add("AirGroup,II. Fliegerkorps,BoB_LW_AufklGr_121,4,Monchy-Breton,Aircraft.He-111H-2"); // 3.(F)/121 Frankfurt > Chateaudun > Dinard (okt)

                //strDynCampList.Add("AirGroup,V. Fliegerkorps,BoB_LW_KG51_Stab,5,Caen_carpiquet,Aircraft.Ju-88A-1"); // Landsberg > Paris-Orly (july)
                strDynCampList.Add("AirGroup,V. Fliegerkorps,BoB_LW_KG51_I,27,Arras_Saint_Liger,Aircraft.Ju-88A-1"); // Lechfeld > Paris-Orly (july) > Villaroche (aug)
                strDynCampList.Add("AirGroup,V. Fliegerkorps,BoB_LW_KG51_II,27,Arras,Aircraft.Ju-88A-1"); // München > Étampes-Mondésir (july/aug) > Paris-Orly (sept)
                strDynCampList.Add("AirGroup,V. Fliegerkorps,BoB_LW_KG51_III,27,Arras_Saint_Liger,Aircraft.Ju-88A-1"); // Landsberg (He-111H) > Étampes-Mondésir (july) > Brétigny (nov)
                //strDynCampList.Add("AirGroup,V. Fliegerkorps,BoB_LW_KG55_Stab,5,Caen_carpiquet,Aircraft.He-111P-2"); // Leipheim > Schwäbisch (june) > Villacoublay (july)
                strDynCampList.Add("AirGroup,V. Fliegerkorps,BoB_LW_KG55_I,27,Baltringen,Aircraft.He-111P-2"); // Baltringen > Malmsheim (june) > Villacoublay (july) > Dreux (aug)
                strDynCampList.Add("AirGroup,V. Fliegerkorps,BoB_LW_KG55_II,27,Schwaighofen,Aircraft.He-111P-2"); // Schwaighofen > Oedheim (june) > Villacoublay (july) > Chartres (aug)
                strDynCampList.Add("AirGroup,V. Fliegerkorps,BoB_LW_KG55_III,27,Ehingen,Aircraft.He-111P-2"); // Ehingen > Eutingen (june) > Villacoublay (july)

                strDynCampList.Add("AirGroup,V. Fliegerkorps,BoB_LW_ZG2_I,27,Monchy-Breton,Aircraft.Bf-110C-2"); // Mannheim > Freiburg (june)
                strDynCampList.Add("AirGroup,V. Fliegerkorps,BoB_LW_LG1_V,27,Barly,Aircraft.Bf-110C-7"); // St. Marie/Libramont > Ligescourt/Rocquancourt/Theville/Lessay (july-oct)
                //
                strDynCampList.Add("AirGroup,V. Fliegerkorps,BoB_LW_JG52_I,36,Abbeville,Aircraft.Bf-109E-3"); // Hoppstätten > Charleville/Laon > Cocquelles (aug-oct)
                strDynCampList.Add("AirGroup,V. Fliegerkorps,BoB_LW_JG52_II,36,Cramont/Yvrench,Aircraft.Bf-109E-1"); // Ober-Olm/Wengenrohr/Speyer > Luxemburg/Laon/Karlsruhe (june) >
                strDynCampList.Add("AirGroup,V. Fliegerkorps,BoB_LW_JG54_I,36,Achiet-Grevillers,Aircraft.Bf-109E-3"); // Eutingen > Vitry-en-Artois/Cramont/Coulonvillers/Poix/Sotteville/Paris-Orly/Chateaudun (june) > Eindhoven/Schiphol (july)
                strDynCampList.Add("AirGroup,V. Fliegerkorps,BoB_LW_JG51_II,36,Yvrench,Aircraft.Bf-109E-1"); // Böblingen/Emptinne > Vitry-en-Artois/Abbeville/Buc (june) > Desvres/Marquise-West (july/aug)
                strDynCampList.Add("AirGroup,V. Fliegerkorps,BoB_LW_AufklGr_121,4,Gablingen,Aircraft.He-111H-2"); // 4.(F)/121 Gablingen > Caen-Carpiquet
                if (defSquadron.Contains("RA_")) // CAI version get G.50 sqns as "what if scenario"
                {
                    strDynCampList.Add("AirGroup,Corpo Aereo Italiano,BoB_RA_56St_18Gruppo_83Sq,12,Barly,Aircraft.G50"); // editor only allows 3x3
                    strDynCampList.Add("AirGroup,Corpo Aereo Italiano,BoB_RA_56St_18Gruppo_85Sq,12,Barly,Aircraft.G50");
                    strDynCampList.Add("AirGroup,Corpo Aereo Italiano,BoB_RA_56St_18Gruppo_95Sq,12,Barly,Aircraft.G50");
                    strDynCampList.Add("AirGroup,Corpo Aereo Italiano,BoB_RA_56St_20Gruppo_351Sq,12,Arras,Aircraft.CR42");
                    strDynCampList.Add("AirGroup,Corpo Aereo Italiano,BoB_RA_56St_20Gruppo_352Sq,12,Arras,Aircraft.CR42");
                    strDynCampList.Add("AirGroup,Corpo Aereo Italiano,BoB_RA_56St_20Gruppo_353Sq,12,Arras,Aircraft.CR42");
                };
                break;
            case cBattleOfBritain:

                // RAF: July10 -----------------------------------
                // 12 Group
                // RAF Duxford -  airstart north entry point
                strDynCampList.Add("AirGroup,RAF Duxford,BoB_RAF_F_264Sqn,12,Duxford,Aircraft.DefiantMkI"); // S Cambridge
                strDynCampList.Add("AirGroup,RAF Duxford,BoB_RAF_F_19Sqn,12,Fowlmere,Aircraft.SpitfireMkIa_100oct"); // S Cambridge
                // RAF Coltishall -  airstart north entry point
                strDynCampList.Add("AirGroup,RAF Coltishall,BoB_RAF_F_66Sqn,12,Coltishall,Aircraft.SpitfireMkIa_100oct"); // N Norwich
                strDynCampList.Add("AirGroup,RAF Coltishall,BoB_RAF_F_242Sqn,12,Coltishall,Aircraft.HurricaneMkI_100oct");
                // skipping RAF Kirton-in-Lindsay, RAF Digby
                // RAF Wittering, NW Cambridge, E Norwich -  airstart north entry point
                strDynCampList.Add("AirGroup,RAF Wittering,BoB_RAF_F_229Sqn,12,Wittering,Aircraft.HurricaneMkI_100oct");
                strDynCampList.Add("AirGroup,RAF Wittering,BoB_RAF_F_266Sqn,12,Wittering,Aircraft.SpitfireMkIa_100oct");
                strDynCampList.Add("AirGroup,RAF Wittering,BoB_RAF_F_23Sqn,12,Collyweston,Aircraft.BlenheimMkIVF");
                // skipping RAF Church Fenton (NE Leeds)
                // skipping 13 Group

                // 11 Group
                // RAF Biggin Hill
                strDynCampList.Add("AirGroup,RAF Biggin Hill,BoB_RAF_F_32Sqn,12,Biggin_Hill,Aircraft.HurricaneMkI_100oct");
                strDynCampList.Add("AirGroup,RAF Biggin Hill,BoB_RAF_F_141Sqn,12,Biggin_Hill,Aircraft.DefiantMkI");
                strDynCampList.Add("AirGroup,RAF Biggin Hill,BoB_RAF_F_610Sqn,12,Gravesend,Aircraft.SpitfireMkIa_100oct");
                strDynCampList.Add("AirGroup,RAF Biggin Hill,BoB_RAF_F_600Sqn,12,Manston,Aircraft.BlenheimMkIVF");
                strDynCampList.Add("AirGroup,RAF Biggin Hill,BoB_RAF_F_1Sqn,12,Hawkinge,Aircraft.HurricaneMkI_100oct"); // gameplay (RAF Northolt)
                // RAF North Weald
                strDynCampList.Add("AirGroup,RAF North Weald,BoB_RAF_F_56Sqn,12,North_weald,Aircraft.HurricaneMkI_100oct");
                strDynCampList.Add("AirGroup,RAF North Weald,BoB_RAF_F_151Sqn,12,North_weald,Aircraft.HurricaneMkI_100oct");
                strDynCampList.Add("AirGroup,RAF North Weald,BoB_RAF_F_85Sqn,12,Martlesham,Aircraft.HurricaneMkI_100oct"); // airstart north entry point
                strDynCampList.Add("AirGroup,RAF North Weald,BoB_RAF_F_25Sqn,12,Martlesham,Aircraft.BlenheimMkIVF");
                // RAF Kenley
                strDynCampList.Add("AirGroup,RAF Kenley,BoB_RAF_F_64Sqn,12,Kenley,Aircraft.SpitfireMkIa_100oct");
                strDynCampList.Add("AirGroup,RAF Kenley,BoB_RAF_F_615Sqn,12,Kenley,Aircraft.HurricaneMkI_100oct");
                strDynCampList.Add("AirGroup,RAF Kenley,BoB_RAF_F_111Sqn,12,Croydon,Aircraft.HurricaneMkI_100oct");
                strDynCampList.Add("AirGroup,RAF Kenley,BoB_RAF_F_501Sqn,12,Croydon,Aircraft.HurricaneMkI_100oct");
                // RAF Hornchurch
                strDynCampList.Add("AirGroup,RAF Hornchurch,BoB_RAF_F_65Sqn,12,Hornchurch,Aircraft.SpitfireMkIa_100oct");
                strDynCampList.Add("AirGroup,RAF Hornchurch,BoB_RAF_F_74Sqn,12,Hornchurch,Aircraft.SpitfireMkIa_100oct");
                strDynCampList.Add("AirGroup,RAF Hornchurch,BoB_RAF_F_54Sqn,12,Rochford,Aircraft.SpitfireMkIa_100oct"); // Rochford
                // RAF Tangmere
                strDynCampList.Add("AirGroup,RAF Tangmere,BoB_RAF_F_43Sqn,12,Tangmere,Aircraft.HurricaneMkI_100oct");
                strDynCampList.Add("AirGroup,RAF Tangmere,BoB_RAF_F_145Sqn,12,Tangmere,Aircraft.HurricaneMkI_100oct");
                strDynCampList.Add("AirGroup,RAF Tangmere,BoB_RAF_F_601Sqn,12,Tangmere,Aircraft.HurricaneMkI_100oct");
                strDynCampList.Add("AirGroup,RAF Tangmere,BoB_RAF_F_219Sqn,12,Lympne,Aircraft.BeaufighterMkIF"); // gameplay
                // RAF Debden
                strDynCampList.Add("AirGroup,RAF Debden,BoB_RAF_F_17Sqn,12,North_weald,Aircraft.HurricaneMkI_100oct"); // Debden
                // RAF Northolt
                strDynCampList.Add("AirGroup,RAF Northolt,BoB_RAF_F_604Sqn,12,Northolt,Aircraft.BeaufighterMkIF");
                strDynCampList.Add("AirGroup,RAF Northolt,BoB_RAF_F_257Sqn,12,Northolt,Aircraft.HurricaneMkI_100oct");

                // 10 Group
                // skipping RAF Filton
                // RAF Middle Wallop
                strDynCampList.Add("AirGroup,RAF Middle Wallop,BoB_RAF_F_609Sqn,12,Andover,Aircraft.SpitfireMkIa_100oct"); // Middle Wallop not present
                strDynCampList.Add("AirGroup,RAF Middle Wallop,BoB_RAF_F_238Sqn,12,Andover,Aircraft.HurricaneMkI_100oct");

                // Coastal Command - Thorney_Island
                strDynCampList.Add("AirGroup,RAF Thorney_Island,BoB_RAF_F_58Sqn,12,Thorney_Island,Aircraft.BlenheimMkIV"); // use 58 as 59Sqn
                strDynCampList.Add("AirGroup,RAF Thorney_Island,BoB_RAF_F_236Sqn,12,Thorney_Island,Aircraft.BlenheimMkIVF");

                // Bomber Command
                // No. 2 Group RAF Wyton (NE London), Blenheim MkI and MkIV
                //strDynCampList.Add("AirGroup,RAF Wyton,BoB_RAF_B_18Sqn,12,Upper_Heyford,Aircraft.BlenheimMkI");
                //strDynCampList.Add("AirGroup,RAF Wyton,BoB_RAF_B_57Sqn,12,Upper_Heyford,Aircraft.BlenheimMkI");
                strDynCampList.Add("AirGroup,RAF Wyton,BoB_RAF_B_21Sqn,16,Watton,Aircraft.BlenheimMkI");
                strDynCampList.Add("AirGroup,RAF Wyton,BoB_RAF_B_82Sqn,16,Watton,Aircraft.BlenheimMkI");
                strDynCampList.Add("AirGroup,RAF Wyton,BoB_RAF_B_90Sqn,16,West_Raynham,Aircraft.BlenheimMkIV");
                strDynCampList.Add("AirGroup,RAF Wyton,BoB_RAF_B_101Sqn,16,West_Raynham,Aircraft.BlenheimMkIV");
                strDynCampList.Add("AirGroup,RAF Wyton,BoB_RAF_B_114Sqn,16,Wyton,Aircraft.BlenheimMkIV");
                strDynCampList.Add("AirGroup,RAF Wyton,BoB_RAF_B_139Sqn,16,Wyton,Aircraft.BlenheimMkIV");
                strDynCampList.Add("AirGroup,RAF Wyton,BoB_RAF_B_107Sqn,16,Wattisham,Aircraft.BlenheimMkIV");
                strDynCampList.Add("AirGroup,RAF Wyton,BoB_RAF_B_110Sqn,16,Wattisham,Aircraft.BlenheimMkIV");
                if (defClass.Contains("BlenheimMkIV")) // reallocated from RAF Wyton :)
                    strDynCampList.Add("AirGroup,RAF Wyton,BoB_RAF_B_40Sqn,16,Manston,Aircraft.BlenheimMkIV");
                //No. 3 Group RAF Mildenhall (NNE London), Wellington
                strDynCampList.Add("AirGroup,RAF Mildenhall,BoB_RAF_B_10Sqn,16,Dishforth,Aircraft.WellingtonMkIc");
                strDynCampList.Add("AirGroup,RAF Mildenhall,BoB_RAF_B_78Sqn,16,Dishforth,Aircraft.WellingtonMkIc");
                strDynCampList.Add("AirGroup,RAF Mildenhall,BoB_RAF_B_77Sqn,16,Driffield,Aircraft.WellingtonMkIc");
                strDynCampList.Add("AirGroup,RAF Mildenhall,BoB_RAF_B_102Sqn,16,Driffield,Aircraft.WellingtonMkIc");
                strDynCampList.Add("AirGroup,RAF Mildenhall,BoB_RAF_B_51Sqn,16,Linton-on-Ouse,Aircraft.WellingtonMkIc");
                strDynCampList.Add("AirGroup,RAF Mildenhall,BoB_RAF_B_58Sqn,16,Linton-on-Ouse,Aircraft.WellingtonMkIc");
                // skipping No. 5 Group Lincolnshire (offmap NE coast), Hampden (later Lancaster)

                // LuftWaffe: Aug 13 -----------------------------------
                //I. Fliegerkorps, Beauvais, LF2
                //strDynCampList.Add("AirGroup,BoB_LW_KG1_Stab,4,Amiens_Glisy,Aircraft.He-111H-2"); // Jumo211
                strDynCampList.Add("AirGroup,I. Fliegerkorps,BoB_LW_KG1_I,23,Tramecourt,Aircraft.He-111P-2"); //DB601A
                strDynCampList.Add("AirGroup,I. Fliegerkorps,BoB_LW_KG1_II,29,Amiens_Glisy,Aircraft.He-111H-2"); // Jumo211
                strDynCampList.Add("AirGroup,I. Fliegerkorps,BoB_LW_KG1_III,15,Rosieres_en_Santerre,Aircraft.He-111H-2");

                //strDynCampList.Add("AirGroup,BoB_LW_KG76_Stab,5,Pontoise/Cormeilles,Aircraft.Do-17Z-2"); //1000hp BMW Bramo 323P Fafnir, 1000kg
                strDynCampList.Add("AirGroup,I. Fliegerkorps,BoB_LW_KG76_I,29,Beauvais_Tille,Aircraft.Do-17Z-1"); //900hp BMW Bramo 323A-1 Fafnir, 500kg
                //strDynCampList.Add("AirGroup,I. Fliegerkorps,BoB_LW_KG76_II,28,Creil,Aircraft.Ju-88A-1");
                strDynCampList.Add("AirGroup,I. Fliegerkorps,BoB_LW_KG76_II,28,Merville_Calonne,Aircraft.Ju-88A-1"); // for playability - Creil is rather far away
                strDynCampList.Add("AirGroup,I. Fliegerkorps,BoB_LW_KG76_III,19,Pontoise/Cormeilles,Aircraft.Do-17Z-1");

                strDynCampList.Add("AirGroup,I. Fliegerkorps,BoB_LW_AufklGr_122,4,Haute-Fontaine,Aircraft.Do-17Z-1"); //BoB_LW_AufklGr_122.01, 4 single-flights

                //II. Fliegerkorps, Ghent, LF2
                //strDynCampList.Add("AirGroup,BoB_LW_KG2_Stab,5,Arras_Saint_Liger,Aircraft.Do-17Z-2"); //Epinoy (SE Arras)
                strDynCampList.Add("AirGroup,II. Fliegerkorps,BoB_LW_KG2_I,27,Arras_Saint_Liger,Aircraft.Do-17Z-1"); //Epinoy (SE Arras)
                strDynCampList.Add("AirGroup,II. Fliegerkorps,BoB_LW_KG2_II,27,Arras,Aircraft.Do-17Z-2");
                strDynCampList.Add("AirGroup,II. Fliegerkorps,BoB_LW_KG2_III,18,Arras_Saint_Liger,Aircraft.Do-17Z-1"); //Cambrai (SE Arras)

                //strDynCampList.Add("AirGroup,BoB_LW_KG3_Stab,5,Rosieres_en_Santerre,Aircraft.Do-17Z-2"); //Le Culot (Belgium)
                strDynCampList.Add("AirGroup,II. Fliegerkorps,BoB_LW_KG3_I,27,Rosieres_en_Santerre,Aircraft.Do-17Z-1"); //Le Culot (Belgium)
                strDynCampList.Add("AirGroup,II. Fliegerkorps,BoB_LW_KG3_II,27,Rosieres_en_Santerre,Aircraft.Do-17Z-2"); //Antwerp/Deurne (Belgium)
                strDynCampList.Add("AirGroup,II. Fliegerkorps,BoB_LW_KG3_III,18,Rosieres_en_Santerre,Aircraft.Do-17Z-1"); //Sint-Truiden (Belgium)

                //strDynCampList.Add("AirGroup,BoB_LW_KG53_Stab,5,Rosieres_en_Santerre,Aircraft.He-111H-2"); //Lille-Nord (Belgium)
                strDynCampList.Add("AirGroup,II. Fliegerkorps,BoB_LW_KG53_I,27,Rosieres_en_Santerre,Aircraft.He-111H-2"); //Lille-Nord (Belgium)
                strDynCampList.Add("AirGroup,II. Fliegerkorps,BoB_LW_KG53_II,27,Rosieres_en_Santerre,Aircraft.He-111H-2"); //Lille-Nord (Belgium)
                strDynCampList.Add("AirGroup,II. Fliegerkorps,BoB_LW_KG53_III,18,Rosieres_en_Santerre,Aircraft.He-111H-2"); //Lille-Nord (Belgium)

                strDynCampList.Add("AirGroup,II. Fliegerkorps,BoB_LW_StG1_II,27,Rosieres_en_Santerre,Aircraft.Ju-87B-2"); //Lille-Nord (Belgium)
                strDynCampList.Add("AirGroup,II. Fliegerkorps,BoB_LW_LG1_IV,27,Rosieres_en_Santerre,Aircraft.Ju-87B-2"); //Lille-Nord (Belgium)

                strDynCampList.Add("AirGroup,II. Fliegerkorps,BoB_LW_ErprGr210,24,Calais_Marck,Aircraft.Bf-110C-7"); //from 1./ZG1 with Bf 110C and 3./St.G.77 with Bf 110D
                strDynCampList.Add("AirGroup,II. Fliegerkorps,BoB_LW_ErprGr210F,12,Calais_Marck,Aircraft.Bf-109E-4B"); //4./TrGr.186 with Bf 109E-4B

                strDynCampList.Add("AirGroup,II. Fliegerkorps,BoB_LW_LG2_I,36,Calais_Marck,Aircraft.Bf-109E-4");
                strDynCampList.Add("AirGroup,II. Fliegerkorps,BoB_LW_LG2_II,27,Calais_Marck,Aircraft.Bf-109E-4B");

                //IX. Fliegerkorps, Soesterberg (Utrecht NL)
                strDynCampList.Add("AirGroup,IX. Fliegerkorps,BoB_LW_KG4_I,27,Soesterberg,Aircraft.He-111H-2");
                strDynCampList.Add("AirGroup,IX. Fliegerkorps,BoB_LW_KG4_II,27,Eindhoven,Aircraft.He-111H-2"); //Eindhoven
                strDynCampList.Add("AirGroup,IX. Fliegerkorps,BoB_LW_KG4_III,27,Schiphol,Aircraft.Ju-88A-1"); //Amsterdam/Schiphol

                strDynCampList.Add("AirGroup,IX. Fliegerkorps,BoB_LW_AufklGr_122,4,Eindhoven,Aircraft.Ju-88A-1"); // 3.Staffel ?  //BoB_LW_AufklGr_122.03, 4 single-flights

                //Jagdfliegerfuhrer 2, Wissant
                strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 2,BoB_LW_JG3_I,36,Colembert,Aircraft.Bf-109E-4");
                strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 2,BoB_LW_JG3_II,36,Samer,Aircraft.Bf-109E-1B");
                strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 2,BoB_LW_JG3_III,36,Wissant,Aircraft.Bf-109E-1");

                strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 2,BoB_LW_JG26_I,36,Audembert,Aircraft.Bf-109E-4N");
                strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 2,BoB_LW_JG26_II,36,Marquise_West,Aircraft.Bf-109E-4B");
                strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 2,BoB_LW_JG26_III,36,Caffiers,Aircraft.Bf-109E-1");

                //strDynCampList.Add("AirGroup,BoB_LW_JG51_Stab,36,Saint_Inglevert,Aircraft.Bf-109E-4");
                strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 2,BoB_LW_JG51_I,36,Wissant,Aircraft.Bf-109E-4");
                strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 2,BoB_LW_JG51_II,36,Saint_Inglevert,Aircraft.Bf-109E-1B");
                strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 2,BoB_LW_JG51_III,36,St-Omer-Clairmarais,Aircraft.Bf-109E-3");

                strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 2,BoB_LW_JG52_I,36,Coquelles,Aircraft.Bf-109E-3");
                strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 2,BoB_LW_JG52_II,36,Peuplingues,Aircraft.Bf-109E-1B");

                strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 2,BoB_LW_JG54_I,36,Guines,Aircraft.Bf-109E-4");
                strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 2,BoB_LW_JG54_II,36,Hermelinghen,Aircraft.Bf-109E-4B");
                strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 2,BoB_LW_JG54_III,36,Campagne_Les_Guines,Aircraft.Bf-109E-1");

                strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 2,BoB_LW_ZG26_I,36,Yvrench,Aircraft.Bf-110C-4");
                strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 2,BoB_LW_ZG26_II,36,Crecy,Aircraft.Bf-110C-7");
                strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 2,BoB_LW_ZG26_III,36,Barly,Aircraft.Bf-110C-4");

                // Scandinavia strDynCampList.Add("AirGroup,BoB_LW_ZG76_I,36,Yvrench,Aircraft.Bf-110C-4");
                strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 2,BoB_LW_ZG76_II,36,Bernay_Saint_Martin,Aircraft.Bf-110C-4"); // Laval
                strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 2,BoB_LW_ZG76_III,36,Bernay_Saint_Martin,Aircraft.Bf-110C-4"); // Laval

                //IV. Fliegerkorps, Dinard, LF3
                strDynCampList.Add("AirGroup,IV. Fliegerkorps,BoB_LW_LG1_I,23,Creil,Aircraft.Ju-88A-1"); // Orléans/Bricy south Paris
                strDynCampList.Add("AirGroup,IV. Fliegerkorps,BoB_LW_LG1_II,24,Creil,Aircraft.Ju-88A-1"); // Orléans/Bricy south Paris
                strDynCampList.Add("AirGroup,IV. Fliegerkorps,BoB_LW_LG1_III,23,Creil,Aircraft.Ju-88A-1"); // Châteaudun

                strDynCampList.Add("AirGroup,IV. Fliegerkorps,BoB_LW_KG27_I,22,Caen_carpiquet,Aircraft.He-111P-2"); // Tours (C France offmap)
                strDynCampList.Add("AirGroup,IV. Fliegerkorps,BoB_LW_KG27_II,21,Caen_carpiquet,Aircraft.He-111H-2"); // Dinard (just west offmap)
                strDynCampList.Add("AirGroup,IV. Fliegerkorps,BoB_LW_KG27_III,23,Caen_carpiquet,Aircraft.He-111H-2"); // Rennes (just s.west offmap)

                strDynCampList.Add("AirGroup,IV. Fliegerkorps,BoB_LW_AufklGr_31,4,Caen_carpiquet,Aircraft.Ju-88A-1"); // Rennes

                strDynCampList.Add("AirGroup,IV. Fliegerkorps,BoB_LW_KG51_I,21,Caen_carpiquet,Aircraft.Ju-88A-1"); // Melun (S Paris)
                strDynCampList.Add("AirGroup,IV. Fliegerkorps,BoB_LW_KG51_II,24,Caen_carpiquet,Aircraft.Ju-88A-1"); // Étampes (S Paris)
                strDynCampList.Add("AirGroup,IV. Fliegerkorps,BoB_LW_KG51_III,25,Caen_carpiquet,Aircraft.Ju-88A-1"); // Étampes (S Paris)

                strDynCampList.Add("AirGroup,IV. Fliegerkorps,BoB_LW_KG54_I,29,Bernay_Saint_Martin,Aircraft.Ju-88A-1"); // Évreux (Normandy, SSE of Rouen)
                strDynCampList.Add("AirGroup,IV. Fliegerkorps,BoB_LW_KG54_II,23,Bernay_Saint_Martin,Aircraft.Ju-88A-1"); // St. Andre-de-L’Eure

                strDynCampList.Add("AirGroup,IV. Fliegerkorps,BoB_LW_KG55_I,35,Bernay_Saint_Martin,Aircraft.He-111P-2"); // Dreux (W Paris)
                strDynCampList.Add("AirGroup,IV. Fliegerkorps,BoB_LW_KG55_II,28,Bernay_Saint_Martin,Aircraft.He-111H-2"); // Chartres (SW Paris)
                strDynCampList.Add("AirGroup,IV. Fliegerkorps,BoB_LW_KG55_III,33,Bernay_Saint_Martin,Aircraft.He-111H-2"); // Villacoublay (Paris)

                strDynCampList.Add("AirGroup,IV. Fliegerkorps,BoB_LW_AufklGr_14,9,Theville,Aircraft.Bf-110C-4"); // Cherbourg

                // VIII. Fliegerkorps
                strDynCampList.Add("AirGroup,VIII. Fliegerkorps,BoB_LW_StG1_I,27,Carquebut,Aircraft.Ju-87B-2"); // Angers (S Caen/SW Paris)
                strDynCampList.Add("AirGroup,VIII. Fliegerkorps,BoB_LW_StG1_III,26,Carquebut,Aircraft.Ju-87B-2"); // Angers (S Caen/SW Paris)

                strDynCampList.Add("AirGroup,VIII. Fliegerkorps,BoB_LW_StG2_I,29,Carquebut,Aircraft.Ju-87B-2"); // St Malo (N.Coast S Jersey)
                strDynCampList.Add("AirGroup,VIII. Fliegerkorps,BoB_LW_StG2_II,33,Carquebut,Aircraft.Ju-87B-2"); // Lannion (N.Coast SW Jersey)

                strDynCampList.Add("AirGroup,VIII. Fliegerkorps,BoB_LW_StG3_I,24,Caen_carpiquet,Aircraft.Ju-87B-2");

                strDynCampList.Add("AirGroup,VIII. Fliegerkorps,BoB_LW_StG77_I,33,Caen_carpiquet,Aircraft.Ju-87B-2");
                strDynCampList.Add("AirGroup,VIII. Fliegerkorps,BoB_LW_StG77_II,25,Caen_carpiquet,Aircraft.Ju-87B-2");
                strDynCampList.Add("AirGroup,VIII. Fliegerkorps,BoB_LW_StG77_III,37,Caen_carpiquet,Aircraft.Ju-87B-2");

                strDynCampList.Add("AirGroup,VIII. Fliegerkorps,BoB_LW_LG1_V,29,Caen_carpiquet,Aircraft.Bf-110C-7");

                strDynCampList.Add("AirGroup,VIII. Fliegerkorps,BoB_LW_AufklGr_11,6,Bernay_Saint_Martin,Aircraft.Bf-110C-4");

                // Jagdfliegerfuhrer 3
                strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 3,BoB_LW_JG2_I,32,Beaumont_Le_Roger,Aircraft.Bf-109E-4");
                strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 3,BoB_LW_JG2_II,28,Beaumont_Le_Roger,Aircraft.Bf-109E-4B");
                strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 3,BoB_LW_JG2_III,28,Le_Havre_Octeville,Aircraft.Bf-109E-1");

                strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 3,BoB_LW_JG27_I,32,Plumetot,Aircraft.Bf-109E-4");
                strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 3,BoB_LW_JG27_II,32,Crepon,Aircraft.Bf-109E-1B");
                strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 3,BoB_LW_JG27_III,32,Le_Havre_Octeville,Aircraft.Bf-109E-1");
                /* too far off west
                strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 3,BoB_LW_JG53_I,37,Rennes,Aircraft.Bf-109E-4");
                strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 3,BoB_LW_JG53_II,34,Dinan,Aircraft.Bf-109E-4");
                strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 3,BoB_LW_JG53_III,35,Brest,Aircraft.Bf-109E-3");
                */
                strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 3,BoB_LW_ZG2_I,35,Caen_carpiquet,Aircraft.Bf-110C-4");
                //strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 3,BoB_LW_ZG2_II,34,Crepon,Aircraft.Bf-110C-4"); // Guyancourt (Paris)
                if (defSquadron.Contains("RA_")) // CAI version get G.50 sqns from 10 July as "what if scenario"
                {
                    strDynCampList.Add("AirGroup,Corpo Aereo Italiano,BoB_RA_13St_11Gruppo_1Sq,9,Merville_Calonne,Aircraft.BR-20M");
                    strDynCampList.Add("AirGroup,Corpo Aereo Italiano,BoB_RA_13St_11Gruppo_4Sq,9,Merville_Calonne,Aircraft.BR-20M");
                    strDynCampList.Add("AirGroup,Corpo Aereo Italiano,BoB_RA_13St_43Gruppo_3Sq,9,Merville_Calonne,Aircraft.BR-20M");
                    strDynCampList.Add("AirGroup,Corpo Aereo Italiano,BoB_RA_13St_43Gruppo_5Sq,9,Merville_Calonne,Aircraft.BR-20M");
                    strDynCampList.Add("AirGroup,Corpo Aereo Italiano,BoB_RA_43St_98Gruppo_240Sq,9,Merville_Calonne,Aircraft.BR-20M");
                    strDynCampList.Add("AirGroup,Corpo Aereo Italiano,BoB_RA_43St_98Gruppo_241Sq,9,Merville_Calonne,Aircraft.BR-20M");
                    strDynCampList.Add("AirGroup,Corpo Aereo Italiano,BoB_RA_43St_99Gruppo_242Sq,9,Merville_Calonne,Aircraft.BR-20M");
                    //strDynCampList.Add("AirGroup,Corpo Aereo Italiano,BoB_RA_43St_99Gruppo_243Sq,9,Merville_Calonne,Aircraft.BR-20M");
                    strDynCampList.Add("AirGroup,Corpo Aereo Italiano,BoB_RA_56St_18Gruppo_83Sq,12,Oye-Plage,Aircraft.CR42"); // editor only allows 3x3
                    strDynCampList.Add("AirGroup,Corpo Aereo Italiano,BoB_RA_56St_18Gruppo_85Sq,12,Oye-Plage,Aircraft.CR42");
                    strDynCampList.Add("AirGroup,Corpo Aereo Italiano,BoB_RA_56St_18Gruppo_95Sq,12,Oye-Plage,Aircraft.CR42");
                    strDynCampList.Add("AirGroup,Corpo Aereo Italiano,BoB_RA_56St_20Gruppo_351Sq,12,Oye-Plage,Aircraft.G50");
                    strDynCampList.Add("AirGroup,Corpo Aereo Italiano,BoB_RA_56St_20Gruppo_352Sq,12,Oye-Plage,Aircraft.G50");
                    strDynCampList.Add("AirGroup,Corpo Aereo Italiano,BoB_RA_56St_20Gruppo_353Sq,12,Oye-Plage,Aircraft.G50");
                };

                // Events
                strDynCampList.Add("Event,12 July 1940,remove,AirGroup,BoB_RAF_F_79Sqn,Turnhouse");
                strDynCampList.Add("Event,20 July 1940,remove,AirGroup,BoB_RAF_F_245Sqn,Aldergrove");
                strDynCampList.Add("Event,24 July 1940,move,AirGroup,BoB_RAF_F_1Sqn,Northolt");
                strDynCampList.Add("Event,13 August 1940,move,AirGroup,BoB_RAF_F_266Sqn,Eastchurch");
                strDynCampList.Add("Event,14 August 1940,move,AirGroup,BoB_RAF_F_74Sqn,Wittering");
                strDynCampList.Add("Event,14 August 1940,remove,AirGroup,BoB_RAF_F_145Sqn,Dyce");
                strDynCampList.Add("Event,14 August 1940,add,AirGroup,BoB_RAF_F_249Sqn,Boscombe_Down,12,Aircraft.HurricaneMkI_100oct,RAF Middle Wallop");
                strDynCampList.Add("Event,19 August 1940,move,AirGroup,BoB_RAF_F_17Sqn,Tangmere");
                strDynCampList.Add("Event,19 August 1940,remove,AirGroup,BoB_RAF_F_64Sqn,Leconfield");
                strDynCampList.Add("Event,19 August 1940,remove,AirGroup,BoB_RAF_F_601Sqn,Debden");
                strDynCampList.Add("Event,20 August 1940,add,AirGroup,BoB_RAF_F_616Sqn,Kenley,12,Aircraft.SpitfireMkIa_100oct,RAF Kenley");
                strDynCampList.Add("Event,21 August 1940,move,AirGroup,BoB_RAF_F_266Sqn,Manston");
                strDynCampList.Add("Event,22 August 1940,move,AirGroup,BoB_RAF_F_264Sqn,Hornchurch");
                strDynCampList.Add("Event,24 August 1940,move,AirGroup,BoB_RAF_F_600Sqn,Hornchurch");
                strDynCampList.Add("Event,27 August 1940,remove,AirGroup,BoB_RAF_F_65Sqn,Turnhouse");
                strDynCampList.Add("Event,27 August 1940,add,AirGroup,BoB_RAF_F_603Sqn,Hornchurch,12,Aircraft.SpitfireMkIa_100oct,RAF Hornchurch");
                strDynCampList.Add("Event,27 August 1940,add,AirGroup,BoB_RAF_F_79Sqn,Hawkinge,12,Aircraft.HurricaneMkI_100oct,RAF Biggin Hill");
                strDynCampList.Add("Event,28 August 1940,move,AirGroup,BoB_RAF_F_32Sqn,Acklington");
                strDynCampList.Add("Event,29 August 1940,remove,AirGroup,BoB_RAF_F_151Sqn,Stapleford");
                strDynCampList.Add("Event,29 August 1940,remove,AirGroup,BoB_RAF_F_264Sqn,Kirton");
                strDynCampList.Add("Event,29 August 1940,remove,AirGroup,BoB_RAF_F_615Sqn,Prestwick");
                strDynCampList.Add("Event,30 August 1940,add,AirGroup,BoB_RAF_F_253Sqn,Kenley,12,Aircraft.HurricaneMkI_100oct,RAF Kenley");
                strDynCampList.Add("Event,30 August 1940,add,AirGroup,BoB_RAF_F_222Sqn,Hornchurch,12,Aircraft.SpitfireMkIa_100oct,RAF Hornchurch");
                strDynCampList.Add("Event,31 August 1940,move,AirGroup,BoB_RAF_F_610Sqn,Acklington");
                strDynCampList.Add("Event,31 August 1940,add,AirGroup,BoB_RAF_F_303_PL,Croydon,12,Aircraft.HurricaneMkI_100oct,RAF Kenley");
                strDynCampList.Add("Event,31 August 1940,remove,AirGroup,BoB_RAF_F_257Sqn,Martlesham");
                strDynCampList.Add("Event,31 August 1940,add,AirGroup,BoB_RAF_F_72Sqn,Biggin_Hill,12,Aircraft.SpitfireMkIa_100oct,RAF Biggin Hill");
                strDynCampList.Add("Event,1 September 1940,move,AirGroup,BoB_RAF_F_249Sqn,North_weald");
                strDynCampList.Add("Event,2 September 1940,remove,AirGroup,BoB_RAF_F_17Sqn,Debden");
                strDynCampList.Add("Event,2 September 1940,move,AirGroup,BoB_RAF_F_601Sqn,Tangmere");
                strDynCampList.Add("Event,1 September 1940,add,AirGroup,BoB_RAF_F_46Sqn,North_weald,12,Aircraft.HurricaneMkI_100oct,RAF North Weald");
                strDynCampList.Add("Event,1 September 1940,move,AirGroup,BoB_RAF_F_72Sqn,Croydon");
                strDynCampList.Add("Event,2 September 1940,remove,AirGroup,BoB_RAF_F_242Sqn,Duxford"); // already offmap unit..
                strDynCampList.Add("Event,3 September 1940,move,AirGroup,BoB_RAF_F_66Sqn,Hornchurch");
                //strDynCampList.Add("Event,3 September 1940,move,AirGroup,BoB_RAF_F_54Sqn,Catterick");
                strDynCampList.Add("Event,3 September 1940,remove,AirGroup,BoB_RAF_F_111Sqn,Debden");
                strDynCampList.Add("Event,3 September 1940,remove,AirGroup,BoB_RAF_F_616Sqn,Kirton");
                strDynCampList.Add("Event,5 September 1940,type,AirGroup,BoB_RAF_F_266Sqn,Manston,0,Aircraft.SpitfireMkIIa");
                strDynCampList.Add("Event,6 September 1940,add,AirGroup,BoB_RAF_F_504Sqn,Hendon,12,Aircraft.HurricaneMkI_100oct,RAF Northolt");
                strDynCampList.Add("Event,7 September 1940,remove,AirGroup,BoB_RAF_F_601Sqn,Exeter");
                strDynCampList.Add("Event,7 September 1940,move,AirGroup,BoB_RAF_F_111Sqn,Kenley");
                strDynCampList.Add("Event,7 September 1940,add,AirGroup,BoB_RAF_F_213Sqn,Tangmere,12,Aircraft.HurricaneMkI_100oct,RAF Tangmere");
                strDynCampList.Add("Event,7 September 1940,add,AirGroup,BoB_RAF_F_234Sqn,Andover,12,Aircraft.SpitfireMkIa_100oct,RAF Middle Wallop"); // middle wallop
                strDynCampList.Add("Event,7 September 1940,add,AirGroup,BoB_RAF_F_605Sqn,Croydon,12,Aircraft.HurricaneMkI_100oct,RAF Kenley");
                strDynCampList.Add("Event,8 September 1940,remove,AirGroup,BoB_RAF_F_43Sqn,Usworth");
                strDynCampList.Add("Event,8 September 1940,add,AirGroup,BoB_RAF_F_92Sqn,Biggin_Hill,12,Aircraft.SpitfireMkIa_100oct,RAF Biggin Hill");
                strDynCampList.Add("Event,8 September 1940,remove,AirGroup,BoB_RAF_F_79Sqn,Pembrey");
                strDynCampList.Add("Event,9 September 1940,remove,AirGroup,BoB_RAF_F_1Sqn,Wittering");
                strDynCampList.Add("Event,9 September 1940,move,AirGroup,BoB_RAF_F_229Sqn,Northolt");
                strDynCampList.Add("Event,9 September 1940,add,AirGroup,BoB_RAF_F_607Sqn,Tangmere,12,Aircraft.HurricaneMkI_100oct,RAF Tangmere");
                strDynCampList.Add("Event,10 September 1940,type,AirGroup,BoB_RAF_F_74Sqn,Wittering,0,Aircraft.SpitfireMkIIa");
                strDynCampList.Add("Event,10 September 1940,move,AirGroup,BoB_RAF_F_501Sqn,Kenley");
                strDynCampList.Add("Event,11 September 1940,remove,AirGroup,BoB_RAF_F_234Sqn,StEval");
                strDynCampList.Add("Event,11 September 1940,move,AirGroup,BoB_RAF_F_66Sqn,Gravesend");
                strDynCampList.Add("Event,13 September 1940,move,AirGroup,BoB_RAF_F_23Sqn,Ford"); // Fleet Air Arm Station
                strDynCampList.Add("Event,14 September 1940,move,AirGroup,BoB_RAF_F_604Sqn,Andover"); // middle wallop
                strDynCampList.Add("Event,15 September 1940,move,AirGroup,BoB_RAF_F_600Sqn,Kenley");
                strDynCampList.Add("Event,20 September 1940,type,AirGroup,BoB_RAF_F_19Sqn,Fowlmere,0,Aircraft.SpitfireMkIIa");
                strDynCampList.Add("Event,25 September 1940,type,AirGroup,BoB_RAF_F_66Sqn,Gravesend,0,Aircraft.SpitfireMkIIa");
                //strDynCampList.Add("Event,10 October 1940,type,AirGroup,BoB_RAF_F_41Sqn,Catterick,0,Aircraft.SpitfireMkIIa");
                strDynCampList.Add("Event,15 October 1940,type,AirGroup,BoB_RAF_F_603Sqn,Hornchurch,0,Aircraft.SpitfireMkIIa");

                if (defSquadron.Contains("RA_")) // CAI version get G.50 sqns from 10 July as "what if scenario"
                {
                    strDynCampList.Add("Event,28 September 1940,add,AirGroup,BoB_RA_13St_11Gruppo_1Sq,Melsbroech,9,Aircraft.BR-20M,Corpo Aereo Italiano");
                    strDynCampList.Add("Event,28 September 1940,add,AirGroup,BoB_RA_13St_11Gruppo_4Sq,Melsbroech,9,Aircraft.BR-20M,Corpo Aereo Italiano");
                    strDynCampList.Add("Event,28 September 1940,add,AirGroup,BoB_RA_13St_43Gruppo_3Sq,Melsbroech,9,Aircraft.BR-20M,Corpo Aereo Italiano");
                    strDynCampList.Add("Event,28 September 1940,add,AirGroup,BoB_RA_13St_43Gruppo_5Sq,Melsbroech,9,Aircraft.BR-20M,Corpo Aereo Italiano");
                    strDynCampList.Add("Event,28 September 1940,add,AirGroup,BoB_RA_43St_98Gruppo_240Sq,Chievres,9,Aircraft.BR-20M,Corpo Aereo Italiano");
                    strDynCampList.Add("Event,28 September 1940,add,AirGroup,BoB_RA_43St_98Gruppo_241Sq,Chievres,9,Aircraft.BR-20M,Corpo Aereo Italiano");
                    strDynCampList.Add("Event,28 September 1940,add,AirGroup,BoB_RA_43St_99Gruppo_242Sq,Chievres,9,Aircraft.BR-20M,Corpo Aereo Italiano");
                    //strDynCampList.Add("Event,28 September 1940,add,AirGroup,BoB_RA_43St_99Gruppo_243Sq,Chievres,9,Aircraft.BR-20M,Corpo Aereo Italiano");
                    strDynCampList.Add("Event,22 October 1940,add,AirGroup,BoB_RA_56St_18Gruppo_83Sq,Ursel,12,Aircraft.CR42,Corpo Aereo Italiano"); // editor only allows 3x3
                    strDynCampList.Add("Event,22 October 1940,add,AirGroup,BoB_RA_56St_18Gruppo_85Sq,Ursel,12,Aircraft.CR42,Corpo Aereo Italiano");
                    strDynCampList.Add("Event,22 October 1940,add,AirGroup,BoB_RA_56St_18Gruppo_95Sq,Ursel,12,Aircraft.CR42,Corpo Aereo Italiano");
                    strDynCampList.Add("Event,22 October 1940,add,AirGroup,BoB_RA_56St_20Gruppo_351Sq,Ursel,12,Aircraft.G50,Corpo Aereo Italiano");
                    strDynCampList.Add("Event,22 October 1940,add,AirGroup,BoB_RA_56St_20Gruppo_352Sq,Ursel,12,Aircraft.G50,Corpo Aereo Italiano");
                    strDynCampList.Add("Event,22 October 1940,add,AirGroup,BoB_RA_56St_20Gruppo_353Sq,Ursel,12,Aircraft.G50,Corpo Aereo Italiano");
                };
                break;
            case cNorthAfrica:
                // WIP Le Havre region
                strDynCampList.Add("AirGroup,253 Wing RAF Egypt,BoB_RAF_B_21Sqn,14,Deauville_Saint_Gatien,Aircraft.BlenheimMkI");
                strDynCampList.Add("AirGroup,253 Wing RAF Egypt,BoB_RAF_B_44Sqn,14,Le_Havre_Octeville,Aircraft.BlenheimMkI");
                strDynCampList.Add("AirGroup,250 Wing RAF Egypt,BoB_RAF_F_32Sqn,14,Le_Havre_Octeville,Aircraft.BlenheimMkIVF");
                strDynCampList.Add("AirGroup,250 Wing RAF Egypt,BoB_RAF_B_52Sqn,14,Le_Havre_Octeville,Aircraft.BlenheimMkIV");
                strDynCampList.Add("AirGroup,250 Wing RAF Egypt,BoB_RAF_B_114Sqn,14,Caen_carpiquet,Aircraft.BlenheimMkIV");
                strDynCampList.Add("AirGroup,RAF Egypt,BoB_RAF_F_111Sqn,14,Plumetot,Aircraft.GladiatorMkII");
                strDynCampList.Add("AirGroup,RAF Egypt,BoB_RAF_F_213Sqn,14,Plumetot,Aircraft.HurricaneMkI");
                strDynCampList.Add("AirGroup,RAF Egypt,BoB_RAF_F_73Sqn,14,Crepon,Aircraft.HurricaneMkI");
                strDynCampList.Add("AirGroup,RAF Egypt,BoB_RAF_F_247Sqn,14,Crepon,Aircraft.HurricaneMkI");
                strDynCampList.Add("AirGroup,RAF Egypt,BoB_RAF_B_37Sqn,16,Bernay_Saint_Martin,Aircraft.WellingtonMkIc");
                strDynCampList.Add("AirGroup,RAF Egypt,BoB_RAF_B_7Sqn,16,Bernay_Saint_Martin,Aircraft.WellingtonMkIc");
                strDynCampList.Add("AirGroup,RAF Egypt,BoB_RAF_B_38Sqn,16,Bernay_Saint_Martin,Aircraft.WellingtonMkIc");

                strDynCampList.Add("AirGroup,Regia Aeronautica,BoB_RA_56St_20Gruppo_353Sq,14,Carquebut,Aircraft.CR42");
                strDynCampList.Add("AirGroup,Regia Aeronautica,BoB_RA_56St_18Gruppo_83Sq,14,Querqueville,Aircraft.CR42");
                strDynCampList.Add("AirGroup,Regia Aeronautica,BoB_RA_56St_18Gruppo_85Sq,14,Querqueville,Aircraft.CR42");
                strDynCampList.Add("AirGroup,Regia Aeronautica,BoB_RA_56St_18Gruppo_95Sq,14,Querqueville,Aircraft.CR42");
                strDynCampList.Add("AirGroup,Regia Aeronautica,BoB_RA_56St_20Gruppo_351Sq,14,Theville,Aircraft.G50");
                strDynCampList.Add("AirGroup,Regia Aeronautica,BoB_RA_56St_20Gruppo_352Sq,13,Theville,Aircraft.G50");
                strDynCampList.Add("AirGroup,Regia Aeronautica,BoB_RA_13St_11Gruppo_4Sq,14,Theville,Aircraft.BR-20M");
                break;
            case cCobra:
                strDynCampList.Add("AirGroup,RAF Duxford,BoB_RAF_F_264Sqn,15,mini2,Aircraft.DefiantMkI");
                strDynCampList.Add("AirGroup,RAF Biggin Hill,BoB_RAF_F_141Sqn,15,mini3,Aircraft.DefiantMkI");
                strDynCampList.Add("AirGroup,RAF Duxford,BoB_RAF_F_19Sqn,15,mini2,Aircraft.SpitfireMkIa_100oct");
                strDynCampList.Add("AirGroup,RAF Coltishall,BoB_RAF_F_66Sqn,15,mini2,Aircraft.SpitfireMkIa_100oct");
                strDynCampList.Add("AirGroup,RAF Biggin Hill,BoB_RAF_F_66Sqn,mini3,15,Aircraft.SpitfireMkIIa");
                strDynCampList.Add("AirGroup,RAF Coltishall,BoB_RAF_F_242Sqn,15,mini2,Aircraft.HurricaneMkI_FB");
                strDynCampList.Add("AirGroup,RAF Wittering,BoB_RAF_F_229Sqn,15,mini2,Aircraft.HurricaneMkI_FB");
                strDynCampList.Add("AirGroup,RAF Tangmere,BoB_RAF_F_43Sqn,12,mini3,Aircraft.HurricaneMkI_100oct");
                strDynCampList.Add("AirGroup,RAF Tangmere,BoB_RAF_F_145Sqn,12,mini3,Aircraft.HurricaneMkI_100oct");
                strDynCampList.Add("AirGroup,RAF Wittering,BoB_RAF_F_23Sqn,15,mini2,Aircraft.BlenheimMkIVF");
                strDynCampList.Add("AirGroup,RAF Biggin Hill,BoB_RAF_F_600Sqn,15,mini3,Aircraft.BlenheimMkIVF");
                strDynCampList.Add("AirGroup,RAF Tangmere,BoB_RAF_F_219Sqn,15,mini3,Aircraft.BeaufighterMkIF");
                strDynCampList.Add("AirGroup,RAF Northolt,BoB_RAF_F_604Sqn,15,mini3,Aircraft.BeaufighterMkIF");
                // Bomber Command
                strDynCampList.Add("AirGroup,RAF Wyton,BoB_RAF_B_21Sqn,16,Bomb_2,Aircraft.BlenheimMkI");
                strDynCampList.Add("AirGroup,RAF Wyton,BoB_RAF_B_82Sqn,16,Bomb_2,Aircraft.BlenheimMkI");
                strDynCampList.Add("AirGroup,RAF Wyton,BoB_RAF_B_90Sqn,16,Bomb_2,Aircraft.BlenheimMkIV");
                strDynCampList.Add("AirGroup,RAF Wyton,BoB_RAF_B_101Sqn,16,Bomb_2,Aircraft.BlenheimMkIV");
                strDynCampList.Add("AirGroup,RAF Mildenhall,BoB_RAF_B_10Sqn,16,Bomb_3,Aircraft.WellingtonMkIc");
                strDynCampList.Add("AirGroup,RAF Mildenhall,BoB_RAF_B_78Sqn,16,Bomb_3,Aircraft.WellingtonMkIc");

                strDynCampList.Add("AirGroup,I. Fliegerkorps,BoB_LW_KG1_I,16,Bomb_1,Aircraft.He-111P-2");
                strDynCampList.Add("AirGroup,I. Fliegerkorps,BoB_LW_KG1_II,16,Bomb_1,Aircraft.He-111H-2");
                strDynCampList.Add("AirGroup,I. Fliegerkorps,BoB_LW_KG76_I,16,Bomb_4,Aircraft.Do-17Z-1");
                strDynCampList.Add("AirGroup,I. Fliegerkorps,BoB_LW_KG76_II,16,Bomb_4,Aircraft.Ju-88A-1");
                strDynCampList.Add("AirGroup,I. Fliegerkorps,BoB_LW_KG76_II,16,Bomb_4,Aircraft.Ju-88A-1");
                strDynCampList.Add("AirGroup,I. Fliegerkorps,BoB_LW_KG76_III,16,Bomb_4,Aircraft.Do-17Z-1");
                strDynCampList.Add("AirGroup,II. Fliegerkorps,BoB_LW_StG1_II,16,mini4,Aircraft.Ju-87B-2");
                strDynCampList.Add("AirGroup,II. Fliegerkorps,BoB_LW_LG1_IV,16,mini4,Aircraft.Ju-87B-2");

                strDynCampList.Add("AirGroup,II. Fliegerkorps,BoB_LW_ErprGr210,15,mini4,Aircraft.Bf-110C-6");
                strDynCampList.Add("AirGroup,II. Fliegerkorps,BoB_LW_LG2_I,15,mini4,Aircraft.Bf-109E-4");
                strDynCampList.Add("AirGroup,II. Fliegerkorps,BoB_LW_LG2_II,15,mini4,Aircraft.Bf-109E-4B");
                strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 2,BoB_LW_JG3_II,15,mini1,Aircraft.Bf-109E-1");
                strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 2,BoB_LW_JG3_III,15,mini1,Aircraft.Bf-109E-1B");
                strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 2,BoB_LW_JG26_I,15,mini1,Aircraft.Bf-109E-4N");
                strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 2,BoB_LW_JG51_I,15,mini1,Aircraft.Bf-109E-3");
                strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 2,BoB_LW_JG51_II,15,mini1,Aircraft.Bf-109E-3B");

                strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 2,BoB_LW_ZG26_I,15,mini4,Aircraft.Bf-110C-4");
                strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 2,BoB_LW_ZG26_II,15,mini4,Aircraft.Bf-110C-7");
                strDynCampList.Add("AirGroup,Jagdfliegerfuhrer 2,BoB_LW_ZG26_III,15,mini4,Aircraft.Bf-110C-2");
                strDynCampList.Add("AirGroup,Corpo Aereo Italiano,BoB_RA_13St_11Gruppo_1Sq,16,Bomb_1,Aircraft.BR-20M");
                strDynCampList.Add("AirGroup,Corpo Aereo Italiano,BoB_RA_13St_43Gruppo_5Sq,16,Bomb_4,Aircraft.BR-20M");
                strDynCampList.Add("AirGroup,Corpo Aereo Italiano,BoB_RA_56St_18Gruppo_83Sq,15,mini4,Aircraft.CR42");
                strDynCampList.Add("AirGroup,Corpo Aereo Italiano,BoB_RA_56St_18Gruppo_85Sq,15,mini4,Aircraft.CR42");
                strDynCampList.Add("AirGroup,Corpo Aereo Italiano,BoB_RA_56St_20Gruppo_352Sq,15,mini1,Aircraft.G50");
                strDynCampList.Add("AirGroup,Corpo Aereo Italiano,BoB_RA_56St_20Gruppo_353Sq,15,mini1,Aircraft.G50");
                break;

        };

        homeBase = null;
        foreach (string str in strDynCampList)
            if (str.Contains("AirGroup"))
                if (str.Contains(defSquadron))
                {   // "AirGroup,RAF Hornchurch,BoB_RAF_F_54Sqn,12,Sounthend,Aircraft.SpitfireMkIa_100oct"
                    string[] strs = str.Split(new char[] { ',' }, StringSplitOptions.None);
                    homeBase = ParseAirGroup(strs);
                    break;
                };

        if (homeBase == null)
        {   // add whatever player is sitting in
            homeAirport = FindAirport(GamePlay.gpPlayer().Army(), GamePlay.gpPlayer().Place().Pos(), 0);
            string sqn = GamePlay.gpPlayer().Place().Group().Name();
            if (odenDebug) GamePlay.gpLogServer(null, "GamePlay.gpPlayer().Place().Group().Name(): {0}", new object[] { sqn });
            sqn = sqn.Substring(sqn.IndexOf(':') +1);
            sqn = sqn.Substring(0,sqn.IndexOf('.'));
            string str = "AirGroup," + CountryAirforce(bobCountryOfOrigin((GamePlay.gpPlayer().Place() as AiAircraft).InternalTypeName())) + "," + sqn + ",14," + homeAirport.Name() + "," + (GamePlay.gpPlayer().Place() as AiAircraft).InternalTypeName().Substring(4);
            if (odenDebug) GamePlay.gpLogServer(null, "ParseAirGroup: {0}", new object[] { str });
            string[] strs = str.Split(new char[] { ',' }, StringSplitOptions.None);
            homeBase = ParseAirGroup(strs);
            defSquadron = sqn;
            strDynCampList.Add(str);
        };
        if (odenDebug) GamePlay.gpLogServer(null, "CreateIniFiles: {0}", new object[] { homeBase.airportName });

        // refresh briefing
        string strBase = homeBase.airportName.Replace('_', ' ');
        switch (strBase)
        {
            case "Sounthend": strBase = "Rochford"; break;
            case "mini1": strBase = "South Central"; break;
            case "mini2": strBase = "East Central"; break;
            case "mini3": strBase = "North East Lake"; break;
            case "mini4": strBase = "North West Lake"; break;
            case "Bomb_1": strBase = "South West"; break;
            case "Bomb_2": strBase = "South East"; break;
            case "Bomb_3": strBase = "North East"; break;
            case "Bomb_4": strBase = "North West"; break;
            case "Vip_Airdrome": strBase = "North Island"; break;
        };
        int len = 6;
        if (homeBase.aircraftType.Length < 9 + 6)
            len = homeBase.aircraftType.Length - 9;

        defSatellites = SatelliteStations(homeBase.sector);
        strDynCampList.Add("Satellites," + defSatellites);

        using (StreamWriter sw = File.CreateText(CampInitFile))
        {
            foreach (string str in strDynCampList)
                sw.WriteLine(str);
        };

        string missionCaption = homeBase.name + ", " + Designation(homeBase.aircraftType) + " (" + vName + ")";
        if (SquadronIsFrench(homeBase.sqn)) missionCaption = homeBase.name + ", " + DesignationAdA(homeBase.aircraftType) + " (" + vName + ")";
        switch (CampaignName)
        {
            case cBattleOfFrance:
                missionCaption = "BoF " + missionCaption;
                break;
            case cBattleOfBritain:
                missionCaption = "BoB " + missionCaption;
                break;
            case cNorthAfrica:
                missionCaption = "Afr " + missionCaption;
                break;
            case cCobra:
                missionCaption = "CAS " + missionCaption;
                break;
        };
        string type = homeBase.aircraftType.Substring(9, len).ToLower();
        switch (CampaignName)
        {
            case cBattleOfFrance: type = "bof" + type;
                break;
            case cBattleOfBritain: type = "bob" + type;
                break;
            case cNorthAfrica: type = "des" + type;
                break;
        };
        string slide = type + ".jpg";
        string thin = type + "_thin.jpg";
        if (CampaignName == cCobra)
        {
            slide = "cas.jpg";
            thin = "cas_thin.jpg";
        };
        AiAircraft ac = (AiAircraft)GamePlay.gpPlayer().Place();

        string situation = "";
        if (CampaignName != cBattleOfBritain)
        {
            fmCurrent = CampaignStartFM();
            if (odenDebug) GamePlay.gpLogServer(null, "CreateIniFiles: {0} {1} {2} {3}", new object[] { fmCurrent, BlueCoalition, RedCoalition, ATK });
            string unit = CountryArmyUnit((ATK == LW ? BlueCoalition : RedCoalition));
            situation = CountryOwnership((ATK == LW ? BlueCoalition : RedCoalition)) + " " + unit + " attacks " + BattleSetNames(fmCurrent);
        };
        string planeDesignation = Designation(homeBase.aircraftType);
        if (SquadronIsFrench(homeBase.sqn)) planeDesignation = DesignationAdA(homeBase.aircraftType);
        string[] strBriefing =
        {
            "[Info]"
            , "Info"
            , "<Slide>"
            , slide
            , ""
            , "<Caption>"
            , missionCaption
            , "<Slide>"
            , thin
            , ""
            , "<Caption>"
            , CampaignName
            , gameDateTime.ToString("D") //"10 July 1940" format
            , situation
            , ""
            , homeBase.sector
            , homeBase.name +" (" +strBase +")"
            , "[Mission]"
            , "<Name>"
            , "Mission"
            , "<Description>"
            , CampaignPhase()
            , "This is the first mission in "+CampaignName +" and it will change each time you fly (if you take off)"
            , ""
            , "Victory conditions:"
            , VictoryCondition(homeBase.army)
            , ""
            , CampaignName
            , gameDateTime.ToString("D") //"July 10th 1940"
            , ""
            , homeBase.sector
            , homeBase.name +" (" +strBase +"), " + planeDesignation//"Spitfire Mk Ia"
            , tailNoSerialNo
            , "check your callsign and skin in [Player Plane]"
            , ""
            , "Just follow flight lead and listen to instructions."
            , "Mission description will include events from the previous day."
            , "Overall Status will also be shown such as next date for reinforcement aircraft and airfields repair status etc."
            , ""
            , (CampaignName == cBattleOfBritain ? "Ground war (only if 'Sea Lion' triggers):" : "Ground War:")
            , "Mission lost 3 times consecutive will give opposing side the initiative (and vice versa)."
            , "Score a hit (plane/vehicle) for mission success to keep timeline, do nothing and current battle will add 1 additional day (campaign stalls)."
            , "Kill a plane/vehicle to gain 1 day and current 3-day battle will be done in 2 days, kill 2 targets (max) to win current battle in 1 day."
            , ""
            , (CampaignName == cBattleOfBritain ? "Land at a satellite airfield (if available) to reallocate your squadron" : "Land at any friendly airfield to reallocate your squadron")
            , "<Slide>"
            , slide
            , "<Caption>"
            , ""
        };

        if (odenDebug) GamePlay.gpLogServer(null, "CreateIniFiles: {0}", new object[] { CampBriFile });
        using (StreamWriter sw = File.CreateText(CampBriFile))
        {
            foreach (string str in strBriefing)
                sw.WriteLine(str);
        };


        odenDebug = false;
        UpdateMissionFile();

        GamePlay.gpHUDLogCenter("Mission files have been restored, please return to the main menu");
    }

    private MissionMarker SelectNextMissionMarker(Point2d pt2d)
    {
        List<MissionMarker> SortedMM = SortedMissionMarkers(pt2d, (ATK == LW ? RAF : LW));
        if (SortedMM.Count == 0)
            return null;

        if (odenDebug)
            foreach (MissionMarker mm in SortedMM)
                GamePlay.gpLogServer(null, "SortedMissionMarkers {0} {1}", new object[] { mm.key, mm.army });

        if (SortedMM.Count > 3) return SortedMM[rnd.Next(3)];
        return SortedMM[0];
    }
    internal void ActivateGroundUnits(MissionMarker mm)
    {
        List<string> mmTargets = new List<string>();
        string sect = "Stationary";
        string key;
        string value;
        bool loadMission = false;
        Point2d pt2d = new Point2d();
        double dir;
        ISectionFile f = GamePlay.gpCreateSectionFile();

        string lightAAA = "Artillery.Bofors gb ";
        if (mm.army == LW)
            if (5 > rnd.Next(10)) lightAAA = "Artillery.4_cm_Flak_28 de ";
            else lightAAA = "Artillery.20_mm_Flak_38 de ";
        foreach (string str in LightAAAs)
        {
            string[] strs = str.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
            if (!GndStatDead.Contains(strs[0]))
            {
                double.TryParse(strs[1], out pt2d.x);
                double.TryParse(strs[2], out pt2d.y);
                double.TryParse(strs[3], out dir);
                dir -= 90;
                if (mm.Pos2d().distance(ref pt2d) < 5000)
                {
                    key = strs[0] + "_AA";
                    mmTargets.Add(strs[0]); // keep
                    value = lightAAA + (pt2d.x).ToString() + " " + (pt2d.y).ToString() + " " + dir.ToString() + " /timeout 0/radius_hide 0/hstart -0.3";
                    AddToFile(f, sect, key, value);
                    loadMission = true;
                };
            };
        };

        bool supportAAA = true;
        string heavyAAA = "Artillery.3_7_inch_QF_Mk_I gb ";
        if (mm.army == LW) heavyAAA = "Artillery.Flak37 de ";
        foreach (string str in HeavyAAAs)
        {
            string[] strs = str.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
            if (!GndStatDead.Contains(strs[0]))
            {
                double.TryParse(strs[1], out pt2d.x);
                double.TryParse(strs[2], out pt2d.y);
                double.TryParse(strs[3], out dir);
                dir -= 90;
                if (mm.Pos2d().distance(ref pt2d) < 5000)
                {
                    key = strs[0] + "_AAA";
                    mmTargets.Add(strs[0]); // keep
                    value = heavyAAA + (pt2d.x).ToString() + " " + (pt2d.y).ToString() + " " + dir.ToString() + " /timeout 0/radius_hide 0/hstart -1.4";
                    AddToFile(f, sect, key, value);
                    loadMission = true;
                    if (supportAAA)
                    {
                        key = strs[0] + "_GE";
                        string supName = "Stationary.Environment.JP3_Generator_15_KW_UK1 gb ";
                        if (mm.army == LW) supName = "Stationary.Environment.Maschinensatz_15_KW_GER1 de ";
                        value = supName + (pt2d.x + 10).ToString() + " " + (pt2d.y + 10).ToString() + " " + dir.ToString();
                        AddToFile(f, sect, key, value);
                        key = strs[0] + "_SL";
                        supName = "Searchlight.150_cm_SearchLight_UK1 gb ";
                        if (mm.army == LW) supName = "Searchlight.150_cm_Flakscheinwerfer_GER1 de ";
                        value = supName + (pt2d.x - 10).ToString() + " " + (pt2d.y + 10).ToString() + " " + dir.ToString();
                        AddToFile(f, sect, key, value);
                        key = strs[0] + "_HF";
                        supName = "Stationary.Environment.HeightFinder_UK1 gb ";
                        if (mm.army == LW) supName = "Stationary.Environment.Em_4m_R(H)34_GER1 de ";
                        value = supName + (pt2d.x + 10).ToString() + " " + (pt2d.y - 10).ToString() + " " + dir.ToString();
                        AddToFile(f, sect, key, value);
                        key = strs[0] + "_PR";
                        supName = "Stationary.Environment.Predictor gb ";
                        if (mm.army == LW) supName = "Stationary.Environment.Kdo_Hi_Ger35_GER1 de ";
                        value = supName + (pt2d.x - 10).ToString() + " " + (pt2d.y - 10).ToString() + " " + dir.ToString();
                        AddToFile(f, sect, key, value);
                        supportAAA = false;
                    };
                };
            };
        };

        foreach (string str in SandBagWalls)
        {
            string[] strs = str.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
            GroundStationary gs = GroundStationaryByName("0:" + strs[0]);
            if (gs != null) gs.Destroy();
            if (!GndStatDead.Contains(strs[0]))
            {
                double.TryParse(strs[1], out pt2d.x);
                double.TryParse(strs[2], out pt2d.y);
                double.TryParse(strs[3], out dir);
                dir += 90;
                if (mm.Pos2d().distance(ref pt2d) < 5000)
                {
                    key = strs[0] + "_Truck";
                    if (mm.army == LW) value = BlueStationaryList[rnd.Next(BlueStationaryList.Count)] + " " + (pt2d.x).ToString() + " " + (pt2d.y).ToString() + " " + dir.ToString() + " /timeout 0/radius_hide 5000";
                    else value = RedStationaryList[rnd.Next(RedStationaryList.Count)] + " " + (pt2d.x).ToString() + " " + (pt2d.y).ToString() + " " + dir.ToString() + " /timeout 0/radius_hide 5000";
                    AddToFile(f, sect, key, value);
                    loadMission = true;
                };
            };
        };

        foreach (string str in ARTYsites)
        {
            string[] strs = str.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
            if (!GndStatDead.Contains(strs[0]))
            {
                double.TryParse(strs[1], out pt2d.x);
                double.TryParse(strs[2], out pt2d.y);
                double.TryParse(strs[3], out dir);
                if (mm.Pos2d().distance(ref pt2d) < 5000)
                {
                    //0 is 90 deg
                    pt2d = calcPos(pt2d, -2, dir - 90);
                    key = strs[0] + "_Arty";
                    mmTargets.Add(strs[0]); // keep
                    if (mm.army == LW) value = "Artillery.LeFH_18_Howitzer de " + (pt2d.x).ToString() + " " + (pt2d.y).ToString() + " " + dir.ToString() + " /timeout 0/radius_hide 5000";
                    else value = "Artillery.LeFH_18_Howitzer gb " + (pt2d.x).ToString() + " " + (pt2d.y).ToString() + " " + dir.ToString() + " /timeout 0/radius_hide 5000";
                    AddToFile(f, sect, key, value);
                    loadMission = true;
                };
            };
        };

        foreach (string str in SupplyDepots)
        {
            string[] strs = str.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
            if (!GndStatDead.Contains(strs[0]))
            {
                double.TryParse(strs[1], out pt2d.x);
                double.TryParse(strs[2], out pt2d.y);
                double.TryParse(strs[3], out dir);
                if (mm.Pos2d().distance(ref pt2d) < 5000)
                {
                    key = strs[0] + "_Fuel";
                    mmTargets.Add(strs[0]); // keep
                    if (mm.army == LW) value = "Stationary.Ford_G917_CargoFuel1 de " + (pt2d.x + 10).ToString() + " " + (pt2d.y + 10).ToString() + " " + dir.ToString() + " /timeout 0/radius_hide 5000";
                    else value = "Stationary.Morris_CS8-Bedford_MW_CargoFuel gb " + (pt2d.x + 10).ToString() + " " + (pt2d.y + 10).ToString() + " " + dir.ToString() + " /timeout 0/radius_hide 5000";
                    AddToFile(f, sect, key, value);
                    key = strs[0] + "_Crate";
                    mmTargets.Add(NextMissionNum.ToString() + ":" + key);
                    if (mm.army == LW) value = "Stationary.Ford_G917_CargoCrate14 de " + (pt2d.x - 10).ToString() + " " + (pt2d.y + 10).ToString() + " " + dir.ToString() + " /timeout 0/radius_hide 5000";
                    else value = "Stationary.Morris_CS8-Bedford_MW_CargoCrate10 gb " + (pt2d.x - 10).ToString() + " " + (pt2d.y + 10).ToString() + " " + dir.ToString() + " /timeout 0/radius_hide 5000";
                    AddToFile(f, sect, key, value);
                    key = strs[0] + "_Ammo";
                    mmTargets.Add(NextMissionNum.ToString() + ":" + key);
                    if (mm.army == LW) value = "Stationary.Ford_G917_CargoAmmo2 de " + (pt2d.x - 10).ToString() + " " + (pt2d.y - 10).ToString() + " " + dir.ToString() + " /timeout 0/radius_hide 5000";
                    else value = "Stationary.Morris_CS8-Bedford_MW_CargoAmmo1 gb " + (pt2d.x - 10).ToString() + " " + (pt2d.y - 10).ToString() + " " + dir.ToString() + " /timeout 0/radius_hide 5000";
                    AddToFile(f, sect, key, value);
                    key = strs[0] + "_Tent";
                    mmTargets.Add(NextMissionNum.ToString() + ":" + key);
                    if (mm.army == LW) value = "Stationary.Environment.TentTroopLarge_GER1 de " + (pt2d.x + 15).ToString() + " " + (pt2d.y - 15).ToString() + " " + dir.ToString() + " /timeout 0/radius_hide 5000";
                    else value = "Stationary.Environment.TentRidgeTent_UK1 gb " + (pt2d.x + 15).ToString() + " " + (pt2d.y - 15).ToString() + " " + dir.ToString() + " /timeout 0/radius_hide 5000";
                    AddToFile(f, sect, key, value);
                    key = strs[0] + "_Truck1";
                    mmTargets.Add(NextMissionNum.ToString() + ":" + key);
                    if (mm.army == LW) value = BlueStationaryList[rnd.Next(BlueStationaryList.Count)] + " " + (pt2d.x + 10).ToString() + " " + (pt2d.y).ToString() + " " + dir.ToString() + " /timeout 0/radius_hide 5000";
                    else value = RedStationaryList[rnd.Next(RedStationaryList.Count)] + " " + (pt2d.x + 10).ToString() + " " + (pt2d.y).ToString() + " " + dir.ToString() + " /timeout 0/radius_hide 5000";
                    AddToFile(f, sect, key, value);
                    key = strs[0] + "_Truck2";
                    mmTargets.Add(NextMissionNum.ToString() + ":" + key);
                    if (mm.army == LW) value = BlueStationaryList[rnd.Next(BlueStationaryList.Count)] + " " + (pt2d.x - 10).ToString() + " " + (pt2d.y).ToString() + " " + dir.ToString() + " /timeout 0/radius_hide 5000";
                    else value = RedStationaryList[rnd.Next(RedStationaryList.Count)] + " " + (pt2d.x - 10).ToString() + " " + (pt2d.y).ToString() + " " + dir.ToString() + " /timeout 0/radius_hide 5000";
                    AddToFile(f, sect, key, value);
                    loadMission = true;

                    key = "StaticBalloonTarget";
                    string dirStr = (rnd.Next(0, 360)).ToString();
                    value = " Stationary.Balloons.Barrage_Balloon_Uk1 gb " + (pt2d.x).ToString("F2") + " " + (pt2d.y).ToString("F2") + ' ' + dirStr + " /hstart 700";
                    if (GamePlay.gpFrontArmy(pt2d.x, pt2d.y) == LW)
                        value = " Stationary.Balloons.Barrage_Balloon_Ger1 de " + (pt2d.x).ToString("F2") + " " + (pt2d.y).ToString("F2") + ' ' + dirStr + " /hstart 700";
                    AddToFile(f, sect, key, value);
                };
            };
        };

        if (loadMission)
        {
            sect = "Stationary";
            key = "StaticBalloonHomebase";
            string dirStr = (rnd.Next(360)).ToString();
            value = " Stationary.Balloons.Barrage_Balloon_Uk1 gb " + (homeBase.x).ToString("F2") + " " + (homeBase.y).ToString("F2") + ' ' + dirStr + " /hstart 700";
            if (GamePlay.gpFrontArmy(homeBase.x, homeBase.y) == LW)
                value = " Stationary.Balloons.Barrage_Balloon_Ger1 de " + (homeBase.x).ToString("F2") + " " + (homeBase.y).ToString("F2") + ' ' + dirStr + " /hstart 700";
            AddToFile(f, sect, key, value);

            GamePlay.gpPostMissionLoad(f);
            NextMissionNum++;
        };
        foreach (GroundStationary gs in GamePlay.gpGroundStationarys("nn"))
            if (!mmTargets.Contains(gs.Name))
                gs.Destroy();
    }
    private void AircraftUpdateDead(AiAircraft ac)
    {
        if (ac == null)
            return;

        AiAirGroup ag = ac.AirGroup();
        foreach (MissionAirbase ab in MissionAirbases)
            if (ab.sqn == ac.Regiment().name())
            {
                Point3d pt3d = ac.Pos();
                // ignore AI lawn darting for fun
                if (ab.Pos().distance(ref pt3d) > 2000)
                {
                    ab.maxPlanes -= 1;
                    //if (odenDebug) GamePlay.gpLogServer(null, "MissionAirbase: '{0}' '{1}' '{2}'", new object[] { ab.name, ab.sqn, ab.maxPlanes });
                    if (ab.type.Contains("Fighter"))
                        if (ac.Army() == RAF) misRAFDeadF += 1;
                        else misLWDeadF += 1;
                    if (ab.type.Contains("Bomber"))
                        if (ac.Army() == RAF) misRAFDeadB += 1;
                        else misLWDeadB += 1;
                    if (ab.type.Contains("Zerstorer")) misLWDeadF += 1;
                    if (ab.type.Contains("Stuka")) misLWDeadS += 1;
                };
                break;
            };
    }
    private void GroundControlCheckIn(AiAircraft ac)
    {
        if (ac == null)
            return;
        FighterCommand = ac;
        Timeout(60.0, () =>
        {
            Player localPlayer = GamePlay.gpPlayer();
            AiAircraft localAircraft = (AiAircraft)localPlayer.Place();
            AiAirGroup localGroup = localAircraft.AirGroup();
            ac.SayToGroup(localGroup, "Ground_control_here_Stand_by");
        });
    }
    private void ArmyHUDLogCenter(int army, string msg)
    {
        Player localPlayer = GamePlay.gpPlayer();
        List<Player> players = new List<Player>();
        if (GamePlay.gpRemotePlayers() != null)
            foreach (Player p in GamePlay.gpRemotePlayers())
            {
                if (p.Army() == army) players.Add(p);
            };

        if (localPlayer != null)
            if (localPlayer.Army() == army) players.Add(localPlayer);
        GamePlay.gpHUDLogCenter(players.ToArray(), msg);
        //if(odenDebug) GamePlay.gpLogServer(null, "SendMessage: {0} {1}", new object[] { players.ToArray(), msg });
    }
    private List<Player> AllPlayers(int army)
    {
        List<Player> players = new List<Player>();
        Player lp = GamePlay.gpPlayer();
        if (lp != null)
            if (lp.Army() == army || army == 0)
                players.Add(lp);
        if (GamePlay.gpRemotePlayers() != null)
            foreach (Player p in GamePlay.gpRemotePlayers())
                if (p.Army() == army || army == 0)
                    players.Add(p);
        return players;
    }
    private bool PlayerIsBomber()
    {
        Player lp = GamePlay.gpPlayer();
        if (lp == null)
            return false;
        AiActor actor = lp.Place();
        if (actor == null)
            return false;
        AiAircraft pac = (actor as AiAircraft);
        if (pac == null)
            return false;
        AiAirGroup pag = pac.AirGroup();
        return (pag.hasBombs()
            || pag.hasTorpedos()
            || pag.hasBombsInInternalBays()
            || pac.Type() > AircraftType.JaBo);
    }
    private bool AiAirGroupHasGroundTarget(AiAirGroup ag)
    {   // tags fighters going groundtarget too
        if (ag == null)
            return false;
        AiWayPoint[] arrWP = ag.GetWay();
        foreach (AiWayPoint wp in arrWP)
            if (wp is AiAirWayPoint)
                switch ((wp as AiAirWayPoint).Action)
                {
                    case AiAirWayPointType.GATTACK_POINT:
                    case AiAirWayPointType.GATTACK_TARG:
                        return true;
                        break;
                };
        return false;
    }
    private bool AiAirGroupCanIntercept(AiAirGroup ag)
    {
        if (ag == null)
            return false;
        AiAircraft ac = (AiAircraft)GetFlightLeader(ag);
        if (ac == null)
            return false;
        if (!ac.IsAirborne())
            return false;
        return !(ag.hasBombs()
            || ag.hasTorpedos()
            || ag.hasBombsInInternalBays()
            || ac.Type() > AircraftType.JaBo);
    }
    internal AiAirport FindAirport(int army, Point2d pt2d, int runwaylength)
    {   // requires fronline
        AiAirport result = null;
        Point3d pt3d = new Point3d(pt2d.x, pt2d.y, 0);
        string sectorName;

        foreach (AiAirport ap in GamePlay.gpAirports())
        {
            sectorName = ""; // GamePlay.gpSectorName(airport.Pos().x, airport.Pos().y);

            if (GamePlay.gpFrontArmy(ap.Pos().x, ap.Pos().y) == army && ap.FieldR() > runwaylength && (sectorName.IndexOf(">") == -1 && sectorName.IndexOf("<") == -1))
            {
                if (result != null)
                {
                    if (result.Pos().distance(ref pt3d) > ap.Pos().distance(ref pt3d))
                        //if (1000 < ap.Pos().distance(ref pt3d)) // not same airport
                        result = ap;
                }
                else
                    result = ap;
            };
        };
        return result;
    }
    internal AiAirport FindAirport(int army, Point3d pt3d, int runwaylength)
    {   // requires fronline
        AiAirport result = null;
        string sectorName;

        foreach (AiAirport ap in GamePlay.gpAirports())
        {
            sectorName = ""; // GamePlay.gpSectorName(airport.Pos().x, airport.Pos().y);

            if (GamePlay.gpFrontArmy(ap.Pos().x, ap.Pos().y) == army && ap.FieldR() > runwaylength && (sectorName.IndexOf(">") == -1 && sectorName.IndexOf("<") == -1))
            {
                if (result != null)
                {
                    if (result.Pos().distance(ref pt3d) > ap.Pos().distance(ref pt3d))
                        //if (1000 < ap.Pos().distance(ref pt3d)) // not same airport
                        result = ap;
                }
                else
                    result = ap;
            };
        };
        return result;
    }
    internal List<AiAirport> SortedAirports(int army, Point2d pt2d, bool onlyBattleArea)
    {   // requires fronline
        List<AiAirport> SortedAirports = new List<AiAirport>();
        Point3d pt3d = new Point3d(pt2d.x, pt2d.y, 0);

        foreach (AiAirport ap in GamePlay.gpAirports())
        {
            string sectorName = "";
            if (onlyBattleArea)
                sectorName = GamePlay.gpSectorName(ap.Pos().x, ap.Pos().y);
            foreach (string apdmg in AirportsDamaged)
                if (apdmg.Contains(ap.Name()))
                    sectorName = "<>";
            //GamePlay.gpLogServer(null, "SortedAirports: {0} {1} ?= {2} at {3}", new object[] { ap.Name(), GamePlay.gpFrontArmy(ap.Pos().x, ap.Pos().y), army, sectorName });
            if (GamePlay.gpFrontArmy(ap.Pos().x, ap.Pos().y) == army && (sectorName.IndexOf(">") == -1 && sectorName.IndexOf("<") == -1))
            {
                int forEachIndex = 0;
                foreach (AiAirport sap in SortedAirports)
                {
                    if (sap.Pos().distance(ref pt3d) > ap.Pos().distance(ref pt3d))
                    {
                        SortedAirports.Insert(forEachIndex, ap);
                        break;
                    };
                    forEachIndex++;
                };
                if (!SortedAirports.Contains(ap)) SortedAirports.Add(ap); // add last
            };
        };
        return SortedAirports;
    }
    internal List<MissionAirbase> SortedAirbases(int army, Point2d pt2d, bool bomber, bool fbmb, bool onlyBattleArea)
    {
        List<MissionAirbase> SortedBases = new List<MissionAirbase>();
        Point3d pt3d = new Point3d(pt2d.x, pt2d.y, 0);
        string sectorName = "";
        double runwaylength = 90;
        if (bomber)
            runwaylength = 900;

        foreach (MissionAirbase ab in MissionAirbases)
        {
            if (onlyBattleArea)
                sectorName = GamePlay.gpSectorName(ab.x, ab.y);
            double fieldR = 0;
            if (ab.ap == null)
            {
                fieldR = 9999; // airstart
                if (onlyBattleArea)
                    sectorName = "<>";
            }
            else fieldR = ab.ap.FieldR();

            bool fighterBase = false;
            if (ab.type.Contains("Fighter"))
                fighterBase = true;
            if (ab.type.Contains("Zerstorer"))
                fighterBase = true;
            if (ab.type.Contains("Stab"))
                fighterBase = ab.sqn.Contains("JG"); // Stab./JG is only "Luftwaffe_Stabstaffel_1940", no type indicator
            if (fbmb)
            {
                if (ab.aircraftType == "Aircraft.Bf-110C-7") fighterBase = !bomber;
                if (ab.aircraftType == "Aircraft.Bf-110C-4B") fighterBase = !bomber;
                if (ab.aircraftType == "Aircraft.Bf-109E-1B") fighterBase = !bomber;
                if (ab.aircraftType == "Aircraft.Bf-109E-3B") fighterBase = !bomber;
                if (ab.aircraftType == "Aircraft.Bf-109E-4B") fighterBase = !bomber;
                if (ab.aircraftType == "Aircraft.Bf-109E-4B_Late") fighterBase = !bomber;
                if (ab.aircraftType == "Aircraft.HurricaneMkI_FB") fighterBase = !bomber;
            };
            foreach (string apdmg in AirportsDamaged)
                if (apdmg.Contains(ab.airportName))
                    fieldR = 0;

            if (bomber != fighterBase && ab.maxPlanes > 2 && !activatedGroups.Contains(ab.sqn) && ab.army == army && !ab.type.Contains("Recon") && fieldR > runwaylength && (sectorName.IndexOf(">") == -1 && sectorName.IndexOf("<") == -1))
            {
                int forEachIndex = 0;
                foreach (MissionAirbase sab in SortedBases)
                {
                    if (sab.Pos().distance(ref pt3d) > ab.Pos().distance(ref pt3d))
                    {
                        SortedBases.Insert(forEachIndex, ab);
                        break;
                    };
                    forEachIndex++;
                };
                if (!SortedBases.Contains(ab)) SortedBases.Add(ab); // add last
            };
        };
        return SortedBases;
    }
    internal List<MissionMarker> SortedMissionMarkers(Point2d pt2d, int army)
    {   // requires frontline
        List<MissionMarker> SortedMissionMarkers = new List<MissionMarker>();
        foreach (MissionMarker mm in MissionMarkers)
        {
            if (mm.army == army)
            {
                int forEachIndex = 0;
                foreach (MissionMarker smm in SortedMissionMarkers)
                {
                    if (smm.Pos2d().distance(ref pt2d) > mm.Pos2d().distance(ref pt2d))
                    {
                        SortedMissionMarkers.Insert(forEachIndex, mm);
                        break;
                    };
                    forEachIndex++;
                };
                if (!SortedMissionMarkers.Exists(m => m.key == mm.key)) SortedMissionMarkers.Add(mm); // add last
            };
        };
        return SortedMissionMarkers;
    }
    internal GroundStationary FindChainHomeRadar(Point2d pt2d)
    {
        GroundStationary result = null;
        Point3d pt3d = new Point3d(pt2d.x, pt2d.y, 0);
        foreach (GroundStationary gs in ChainHomeRadars)
        {
            if (gs != null)
                if (result != null)
                {
                    if (result.pos.distance(ref pt3d) > gs.pos.distance(ref pt3d))
                        result = gs;
                }
                else
                    result = gs;
        };
        return result;
    }
    internal List<AiAircraft> SortedAircrafts(int army, Point3d pt3d)
    {
        List<AiAircraft> sorted = new List<AiAircraft>();
        AiAirGroup[] airGroups = GamePlay.gpAirGroups(army);

        if (airGroups != null)
            foreach (AiAirGroup airGroup in airGroups)
                if (airGroup != null)
                    if (airGroup.GetItems().Length > 0)
                        foreach (AiActor actor in airGroup.GetItems())
                            if (actor != null)
                                if (actor is AiAircraft)
                                {
                                    AiAircraft ac = (AiAircraft)actor;
                                    int forEachIndex = 0;
                                    foreach (AiAircraft sac in sorted)
                                    {
                                        if (sac.Pos().distance(ref pt3d) > ac.Pos().distance(ref pt3d))
                                        {
                                            sorted.Insert(forEachIndex, ac);
                                            break;
                                        };
                                        forEachIndex++;
                                    };
                                    if (!sorted.Contains(ac)) sorted.Add(ac); // add last
                                };

        return sorted;
    }
    internal List<AiActor> FindAircrafts(int army)
    {
        List<AiActor> AllActors = new List<AiActor>();
        foreach (AiAirGroup airGroup in GamePlay.gpAirGroups(army))
        {
            foreach (AiActor actor in ((airGroup as AiGroup).GetItems()))
                AllActors.Add(actor);
        };
        return AllActors;
    }
    internal AiActor GetFlightLeader(AiAirGroup ag)
    {
        if (ag == null)
            return null;
        if (ag.GetItems().Length < 1)
            return null;
        foreach (AiActor a in ag.GetItems())
            if (GamePlay.gpActorIsValid(a))
                return a;
        return null;
    }
    internal List<Point2d> SortByDistance(List<Point2d> ListPt2d, Point2d RefPt2d)
    {
        List<Point2d> SortedPt2d = new List<Point2d>();

        foreach (Point2d pt2d in ListPt2d)
        {
            if (SortedPt2d.Count == 0) SortedPt2d.Add(pt2d);
            else
            {
                int forEachIndex = 0;
                foreach (Point2d spt2d in SortedPt2d)
                {
                    if (spt2d.distance(ref RefPt2d) > pt2d.distance(ref RefPt2d))
                    {
                        SortedPt2d.Insert(forEachIndex, pt2d);
                        break;
                    };
                    forEachIndex++;
                };
            };
            if (!SortedPt2d.Contains(pt2d)) SortedPt2d.Add(pt2d);
        };

        return SortedPt2d;
    }
    private int BattleOfBritainVictoryCheck()
    {
        if (fmCurrent != "") return LW; // Seelöwe already started

        int gbTotal = 0, deTotal = 0;
        foreach (MissionAirbase mab in MissionAirbases)
            if (mab.army == RAF) gbTotal += mab.maxPlanes;
            else deTotal += mab.maxPlanes;
        if (gbTotal > deTotal)
            return RAF;
        if (gameDateTime.Month > 9 && deTotal > gbTotal * 3)
        {   // initiate seelöwe
            string[] fms = UntSeelowe[UntSeelowe.Count - 1]; // axis campaign, runs from end to start
            fmCurrent = fms[rnd.Next(fms.Length)]; // grab random in "first" battleset
            foreach (MissionMarker mm in MissionMarkers)
                if (mm.key == fmCurrent) mmCurrentBattle = mm;
            return LW;
        };
        if (gameDateTime.Month > 9)
            return RAF;
        return 0;
    }

    private bool SquadronIsFrench(string sqn)
    {   // WIP
        //return (mab.sector.StartsWith("GC") || mab.sector.StartsWith("GB") || mab.sector.StartsWith("Flottille F1"));
        if (CampaignName != cBattleOfFrance) return false;
        List<string> GC = new List<string>();
        GC.Add("BoB_RAF_F_232Sqn");
        GC.Add("BoB_RAF_F_234Sqn");
        GC.Add("BoB_RAF_F_229Sqn");
        GC.Add("BoB_RAF_F_236Sqn");
        GC.Add("BoB_RAF_F_238Sqn");
        GC.Add("BoB_RAF_F_242Sqn");
        GC.Add("BoB_RAF_F_245Sqn");
        GC.Add("BoB_RAF_F_247Sqn");
        GC.Add("BoB_RAF_F_253Sqn");
        GC.Add("BoB_RAF_F_249Sqn");
        GC.Add("BoB_RAF_F_263Sqn");
        GC.Add("BoB_RAF_F_264Sqn");
        GC.Add("BoB_RAF_F_266Sqn");
        GC.Add("BoB_RAF_B_50Sqn");
        GC.Add("BoB_RAF_B_51Sqn");
        foreach (string str in GC)
            if (sqn.Contains(str)) return true;
        return false;
    }

    private void AddToFile(ISectionFile f, string sect, string key, string value)
    {
        if (odenDebug) GamePlay.gpLogServer(null, "AddToFile {0} {1} {2}", new object[] { sect, key, value });
        f.add(sect, key, value);
    }

    private string CreateCAPMission(ISectionFile f, Point2d CAP2d, int size, int army, bool isEscort)
    {
        MissionAirbase abCAP = null;
        List<MissionAirbase> MAList = SortedAirbases(army, CAP2d, false, false, false);
        if (odenDebug) GamePlay.gpLogServer(null, "CreateCAPMission #{0} x{1} army:{2} ({3} sq avail)", new object[] { CAPFlightIndex, size, army, MAList.Count });
        if (MAList == null)
            return "";
        if (MAList.Count == 0)
            return "";
        if (MAList.Count > 12)
            abCAP = MAList[rnd.Next(0, 11)];
        else
            if (MAList.Count > 3) // random 1 of 4 first/closest
                abCAP = MAList[rnd.Next(0, 3)];
            else abCAP = MAList[0];
        if (abCAP == null)
            return "";

        AiAirport ap = abCAP.ap;
        activatedGroups.Add(abCAP.sqn);

        if (size > abCAP.maxPlanes) size = abCAP.maxPlanes;
        if (odenDebug) GamePlay.gpLogServer(null, "CreateCAPMission {0} {1} max:{2} of {3}", new object[] { abCAP.name, abCAP.sqn, abCAP.maxPlanes, abCAP.aircraftType });

        AiActor[] actorsQueue = null;
        string apName = "AIR";
        if (ap != null)
        {
            actorsQueue = ap.QueueTakeoff();
            apName = ap.Name();
        };
        bool setOnPark = false;
        if (actorsQueue != null || CAPFlightIndex > 0 || activatedAirports.Contains(apName))
            setOnPark = true;
        if (ap != null)
            activatedAirports.Add(apName);

        string value;
        Point2d pt2d = new Point2d(abCAP.x, abCAP.y);

        // each MAB should represent a RAF Sqn (12) or LW Gruppe (36)
        // RAF Airfields usually house 2-4 squadrons while a LW airfield usually house a Gruppe's 2-3 Staffeln
        // "II/JG52" 2 276985 209109 0 36 1 1 de"Luftwaffe_Fighter_1940 BoB_LW_JG52_II
        // "I/LG2" 2 291127 216041 0 36 1 1 de"Luftwaffe_Fighter_1940 BoB_LW_LG2_I
        // "66 Sqn" 1 180549 264239 0 12 1 1 gb RAF_Fighter_1940 BoB_RAF_F_66Sqn_Late

        string sqn = abCAP.sqn; // bp.Regiment().name();
        //string[] PlaneSet = abCAP.aircraftTypes; // bp.GetAircraftTypes();
        string planeType = abCAP.aircraftType; // PlaneSet[rnd.Next(0, PlaneSet.Length)];

        string form = "FINGERFOUR";
        if (sqn.Contains("Early")) form = "VIC3";
        if (sqn.Contains("RA_")) form = "VIC3";

        string form2 = form;
        if (army == RAF && form == "VIC3" && size > 6) form2 = "VIC6"; // fake to put 12 in 2x6
        string[] FlightSection = FlightSections(army, size, form2, CAPStaffelIndex);
        sqn += "." + FlightSection[4];
        AddToFile(f, "AirGroups", sqn, "");
        int sectionQty = (FlightSection[0].Length + 1) / 2;
        if (FlightSection[0].Length > 0) AddToFile(f, sqn, "Flight0", FlightSection[0]);
        if (FlightSection[1].Length > 0) AddToFile(f, sqn, "Flight1", FlightSection[1]);
        if (FlightSection[2].Length > 0) AddToFile(f, sqn, "Flight2", FlightSection[2]);
        if (FlightSection[3].Length > 0) AddToFile(f, sqn, "Flight3", FlightSection[3]);

        AddToFile(f, sqn, "Class", planeType);
        AddToFile(f, sqn, "Formation", form);
        // Stuka max 8 +VIC
        // Bomber max 3 +VIC3
        // Zerstörer max 4 +FF
        // Fighter max 4 +FF
        // Recon max 1 +LINEABREAST
        // Transp. max 3 +VIC
        // UK Bomber max 10 +VIC
        // UK Fighter max 6 +VIC3
        // UK Fighter max 4 +FF

        AddToFile(f, sqn, "CallSign", ((int)(rnd.Next(0, 35))).ToString());
        AddToFile(f, sqn, "Fuel", "84");
        AddToFile(f, sqn, "Weapons", "1");
        if (setOnPark)
            AddToFile(f, sqn, "SetOnPark", "1");
        //AddToFile(f, sqn, "SpawnFromScript", "1");
        AddToFile(f, sqn, "Skill", fSkill);
        int aging = (gameDateTime - StartDateTime).Days;
        if (aging > 99) aging = 99;
        AddToFile(f, sqn, "Aging", aging.ToString());
        string skin = DefaultSkins(planeType, sqn);
        bool ada = SquadronIsFrench(sqn);
        if (skin != "")
            for (int i = 0; i < 4; i++)
            {
                if (FlightSection[i].Length > 0)
                {
                    int cnt = FlightSection[i].Split(' ').Length + 1;
                    for (int j = 0; j < cnt; j++)
                    {
                        if (i == 0) AddToFile(f, sqn, "Skin" + j.ToString(), skin);
                        else AddToFile(f, sqn, "Skin" + i.ToString() + j.ToString(), skin);
                        if (ada)
                            if (i == 0) AddToFile(f, sqn, "MarkingsOn" + j.ToString(), "0");
                            else AddToFile(f, sqn, "MarkingsOn" + i.ToString() + j.ToString(), "0");
                    };
                };
            };

        if (!isEscort)
        {
            double heading = calcDir(pt2d, CAP2d);

            int alt = rnd.Next(1200, 3500);
            int speed = rnd.Next(300, 400);
            if (ap == null)
            {   // airstart if map entry point
                pt2d = calcPos(pt2d, rnd.Next(2000, 3000), heading);
                AddToFile(f, sqn + "_Way", "NORMFLY", pt2d.x.ToString() + " " + pt2d.y.ToString() + " " + alt.ToString() + " " + speed.ToString());
            }
            else
            {
                AddToFile(f, sqn + "_Way", "TAKEOFF", abCAP.x.ToString("F2") + " " + abCAP.y.ToString("F2") + " 0 0");
                double dir = calcDir(pt2d, CAP2d);
                Point2d wp2d = calcPos(pt2d, 16090 / 2, dir);
                AddToFile(f, sqn + "_Way", "HUNTING", wp2d.x.ToString("F2") + " " + wp2d.y.ToString("F2") + " 1680.00" + " 280.00");
            };
            if (abCAP.ap == null)
                if (army == RAF) CAP2d = calcPos(CAP2d, 1609 * rnd.Next(8, 20), 120 + rnd.Next(0, 120));
                else CAP2d = calcPos(CAP2d, 1609 * rnd.Next(8, 20), 210 + rnd.Next(0, 120));

            AddToFile(f, sqn + "_Way", "HUNTING", CAP2d.x.ToString("F2") + " " + CAP2d.y.ToString("F2") + " " + alt.ToString() + ".00 " + speed.ToString() + ".00");
        };

        //CAPFlightIndex++;
        //CAPStaffelIndex++;

        return sqn;
    }
    private string CreateCASMission(ISectionFile f, Point2d CAS2d, int size, int army, List<GroundStationary> targets, bool activeMis)
    {
        MissionAirbase abCAS = null;
        List<MissionAirbase> MAList = new List<MissionAirbase>();
        foreach (MissionAirbase ab in MissionAirbases)
            if (!activatedGroups.Contains(ab.sqn))
                if (ab.army == ATK)
                    if (ab.aircraftType.Contains("Ju-87"))
                        MAList.Add(ab);
        if (MAList.Count == 0) MAList = SortedAirbases(army, CAS2d, false, true, false);

        if (odenDebug) GamePlay.gpLogServer(null, "CreateCASMission #{0} x{1} army:{2} ({3} sq avail)", new object[] { CASFlightIndex, size, army, MAList.Count });
        if (MAList == null)
            return "";
        if (MAList.Count == 0)
            return "";
        if (MAList.Count > 12)
            abCAS = MAList[rnd.Next(0, 11)];
        else
            if (MAList.Count > 3) // random 1 of 4 first/closest
                abCAS = MAList[rnd.Next(0, 3)];
            else abCAS = MAList[0];
        if (abCAS == null)
            return "";

        AiAirport ap = abCAS.ap;
        activatedGroups.Add(abCAS.sqn);

        if (size > abCAS.maxPlanes) size = abCAS.maxPlanes;
        if (odenDebug) GamePlay.gpLogServer(null, "CreateCASMission {0} {1} max:{2} of {3}", new object[] { abCAS.name, abCAS.sqn, abCAS.maxPlanes, abCAS.aircraftType });
        if (odenDebug)
            foreach (GroundStationary gs in targets)
                GamePlay.gpLogServer(null, "GroundStationary {0} {1} {2}", new object[] { gs.Name, gs.Title, gs.Type });
        //if (odenDebug)
        //    foreach (AiActor a in targets)
        //        GamePlay.gpLogServer(null, "AiActor {0} {1} {2}", new object[] { a.Name(), a.Group(), a.Army() });
        AiActor[] actorsQueue = null;
        string apName = "AIR";
        if (ap != null)
        {
            actorsQueue = ap.QueueTakeoff();
            apName = ap.Name();
        };
        bool setOnPark = false;
        if (actorsQueue != null || CASFlightIndex > 0 || activatedAirports.Contains(apName))
            setOnPark = true;
        if (ap != null)
            activatedAirports.Add(apName);

        double rwlen = 0;
        if (ap != null)
            rwlen = ap.FieldR();
        string value;
        Point2d pt2d = new Point2d(abCAS.x, abCAS.y);
        double misDist = CAS2d.distance(ref pt2d);

        string sqn = abCAS.sqn; // bp.Regiment().name();
        string planeType = abCAS.aircraftType; // PlaneSet[rnd.Next(0, PlaneSet.Length)];

        string form = "FINGERFOUR";
        if (sqn.Contains("Early")) form = "VIC3";
        if (sqn.Contains("RA_")) form = "VIC3";
        if (planeType.Contains("Ju-87")) form = "VIC";

        string form2 = form;
        if (army == RAF && form == "VIC3" && size > 6) form2 = "VIC6"; // fake to put 12 in 2x6
        string[] FlightSection = FlightSections(army, size, form2, CASStaffelIndex);
        sqn += "." + FlightSection[4];
        AddToFile(f, "AirGroups", sqn, "");
        int sectionQty = (FlightSection[0].Length + 1) / 2;
        if (FlightSection[0].Length > 0) AddToFile(f, sqn, "Flight0", FlightSection[0]);
        if (FlightSection[1].Length > 0) AddToFile(f, sqn, "Flight1", FlightSection[1]);
        if (FlightSection[2].Length > 0) AddToFile(f, sqn, "Flight2", FlightSection[2]);
        if (FlightSection[3].Length > 0) AddToFile(f, sqn, "Flight3", FlightSection[3]);

        AddToFile(f, sqn, "Class", planeType);
        AddToFile(f, sqn, "Formation", form);
        // Stuka max 8 +VIC
        // Bomber max 3 +VIC3
        // Zerstörer max 4 +FF
        // Fighter max 4 +FF
        // Recon max 1 +LINEABREAST
        // Transp. max 3 +VIC
        // UK Bomber max 10 +VIC
        // UK Fighter max 6 +VIC3
        // UK Fighter max 4 +FF

        AddToFile(f, sqn, "CallSign", ((int)(rnd.Next(0, 35))).ToString());
        if (activeMis) AddToFile(f, sqn, "Fuel", "64");
        else AddToFile(f, sqn, "Fuel", "84");

        value = "1";
        switch (planeType)
        {
            case "Aircraft.BlenheimMkI": value = "1 1 2 1 1"; break;
            case "Aircraft.BlenheimMkIV": value = "1 1 3 1 1"; break;
            case "Aircraft.Bf-110C-7": value = "1 1 1 2"; break;
            case "Aircraft.Bf-110C-4B": value = "1 1 1 2"; break;
            case "Aircraft.Bf-109E-1B": value = "1 1 2"; break;
            case "Aircraft.Bf-109E-3B": value = "1 1 2"; break;
            case "Aircraft.Bf-109E-4B":
            case "Aircraft.Bf-109E-4B_Late": value = "1 1 2"; break;
            case "Aircraft.Ju-87B-2": value = "1 1 2 1"; break;
            case "Aircraft.Do-17Z-1": value = "1 1 1 1 4 2"; break;
            case "Aircraft.Do-17Z-2": value = "1 1 1 1 1 1 4 2"; break;
            case "Aircraft.Do-215B-1": value = "1 1 1 2"; break;
            case "Aircraft.Ju-88A-1": value = "1 1 1 2 2 4"; break;
            case "Aircraft.HurricaneMkI_FB": value = "1 2"; break;
        };
        AddToFile(f, sqn, "Weapons", value);

        if (setOnPark)
            AddToFile(f, sqn, "SetOnPark", "1");
        //AddToFile(f, sqn, "SpawnFromScript", "1");
        AddToFile(f, sqn, "Skill", fSkill);
        int aging = (gameDateTime - StartDateTime).Days;
        if (aging > 99) aging = 99;
        AddToFile(f, sqn, "Aging", aging.ToString());
        string skin = DefaultSkins(planeType, sqn);
        bool ada = SquadronIsFrench(sqn);
        if (skin != "")
            for (int i = 0; i < 4; i++)
            {
                if (FlightSection[i].Length > 0)
                {
                    int cnt = FlightSection[i].Split(' ').Length + 1;
                    for (int j = 0; j < cnt; j++)
                    {
                        if (i == 0) AddToFile(f, sqn, "Skin" + j.ToString(), skin);
                        else AddToFile(f, sqn, "Skin" + i.ToString() + j.ToString(), skin);
                        if (ada)
                            if (i == 0) AddToFile(f, sqn, "MarkingsOn" + j.ToString(), "0");
                            else AddToFile(f, sqn, "MarkingsOn" + i.ToString() + j.ToString(), "0");
                    }
                };
            };

        double heading = calcDir(pt2d, CAS2d);
        int alt = rnd.Next(800, 1500);
        if (planeType.Contains("Ju-87")) alt = rnd.Next(2500, 4500);
        if (alt < 1000)
            switch (planeType)
            {
                case "Aircraft.BlenheimMkI": AddToFile(f, sqn, "Detonator", "Bomb.Bomb_GP_250lb_MkIV 0 30 11"); break;
                case "Aircraft.BlenheimMkIV": AddToFile(f, sqn, "Detonator", "Bomb.Bomb_GP_500lb_MkIV 1 30 11"); break;
                case "Aircraft.Bf-110C-7": AddToFile(f, sqn, "Detonator", "Bomb.SC-250_Type1_J 2 -1 14"); break;
                case "Aircraft.Bf-110C-4B": AddToFile(f, sqn, "Detonator", "Bomb.SC-250_Type1_J 2 -1 14"); break;
                case "Aircraft.Bf-109E-1B": AddToFile(f, sqn, "Detonator", "Bomb.SC-50_GradeII_J 1 -1 14"); break;
                case "Aircraft.Bf-109E-3B": AddToFile(f, sqn, "Detonator", "Bomb.SC-50_GradeII_J 1 -1 14"); break;
                case "Aircraft.Bf-109E-4B": AddToFile(f, sqn, "Detonator", "Bomb.SC-250_Type1_J 2 -1 14"); break;
                case "Aircraft.Ju-87B-2": AddToFile(f, sqn, "Detonator", "Bomb.SC-500_GradeIII_J 0 -1 14"); break;
                case "Aircraft.Do-17Z-1": AddToFile(f, sqn, "Detonator", "Bomb.SC-50_GradeII_J 1 -1 14"); break;
                case "Aircraft.Do-17Z-2": AddToFile(f, sqn, "Detonator", "Bomb.SC-50_GradeII_J 1 -1 14"); break;
                case "Aircraft.Ju-88A-1": AddToFile(f, sqn, "Detonator", "Bomb.SC-250_Type1_J 2 -1 14"); break;
            };
        int speed = rnd.Next(300, 400);
        double dir = calcDir(pt2d, CAS2d);
        Point2d wp2d = calcPos(pt2d, 16090 / 2, dir);
        if (activeMis)
        {
            misDist = homeAirport.Pos().distance(ref target3d);
            Point2d air2d = calcPos(CAS2d, -Math.Max(misDist, 2 * 16090.0), heading);
            AddToFile(f, sqn + "_Way", "NORMFLY", air2d.x.ToString("F2") + " " + air2d.y.ToString("F2") + " " + alt.ToString("F2") + " " + speed.ToString("F2"));
        }
        else
        {
            if (ap == null)
            {   // airstart if map entry point
                pt2d = calcPos(pt2d, rnd.Next(2000, 3000), heading);
                AddToFile(f, sqn + "_Way", "NORMFLY", pt2d.x.ToString() + " " + pt2d.y.ToString() + " " + alt.ToString() + " " + speed.ToString());
            }
            else
            {
                AddToFile(f, sqn + "_Way", "TAKEOFF", abCAS.x.ToString("F2") + " " + abCAS.y.ToString("F2") + " 0 0");
                AddToFile(f, sqn + "_Way", "NORMFLY", wp2d.x.ToString("F2") + " " + wp2d.y.ToString("F2") + " 1200.00" + " 280.00");
            };
        };

        wp2d = calcPos(CAS2d, 8000, calcDir(CAS2d, pt2d));
        AddToFile(f, sqn + "_Way", "NORMFLY", wp2d.x.ToString("F2") + " " + wp2d.y.ToString("F2") + " " + alt.ToString() + " " + speed.ToString() + ".00");
        //foreach (AiActor act in targets)
        foreach (GroundStationary gs in targets)
        {
            wp2d = calcPos(CAS2d, 500, rnd.Next(360));
            if (planeType.Contains("Ju-87")) AddToFile(f, sqn + "_Way", "GATTACK_TARG", CAS2d.x.ToString("F2") + " " + CAS2d.y.ToString("F2") + " 600.00 " + speed.ToString() + ".00 " + gs.Name + " 0 /GAttackType DIVE /GAttackPasses _2"); // is 1 bomb and 2 trafe
            else AddToFile(f, sqn + "_Way", "GATTACK_TARG", CAS2d.x.ToString("F2") + " " + CAS2d.y.ToString("F2") + " 600.00 " + speed.ToString() + ".00 " + gs.Name + " 0 /GAttackType GATTACK_TARG /GAttackPasses _2");
            //AddToFile(f, sqn + "_Way", "GATTACK_TARG", CAS2d.x.ToString("F2") + " " + CAS2d.y.ToString("F2") + " 600.00 " + speed.ToString() + ".00 " + act.Name() + " 0 /GAttackType SHALLOW_DIVE /GAttackPasses _1");
        };

        // RTB
        wp2d = calcPos(pt2d, 16090 / 2, dir);
        AddToFile(f, sqn + "_Way", "NORMFLY", wp2d.x.ToString("F2") + " " + wp2d.y.ToString("F2") + " " + alt.ToString() + ".00 " + speed.ToString() + ".00");

        alt = (int)(alt / 2);
        string strWP = abCAS.x.ToString("F2") + " " + abCAS.y.ToString("F2") + " " + alt.ToString() + ".00 " + speed.ToString() + ".00";
        if (rwlen == 0)
            AddToFile(f, sqn + "_Way", "NORMFLY", strWP);
        else
            AddToFile(f, sqn + "_Way", "LANDING", strWP);

        return sqn;
    }
    private string CreateBMBMission(ISectionFile f, Point2d BMB2d, int size, int army, AiActor aTarget, GroundStationary gs, bool escortReq, bool activeMis)
    {
        //if (odenDebug) GamePlay.gpLogServer(null, "CreateBMBMission {0} {1} {2} {3}", new object[] { BMB2d.x, size, army, escortReq });
        MissionAirbase abBMB = null;

        if (BMBFlightAB == null)
        {
            List<MissionAirbase> MAList = SortedAirbases(army, BMB2d, true, aTarget != null, false);
            if (MAList == null)
                return "";
            if (MAList.Count == 0)
                return "";
            if (MAList.Count > 12)
                abBMB = MAList[rnd.Next(0, 12)];
            else
                if (MAList.Count > 3) // random 1 of 4 first/closest
                    abBMB = MAList[rnd.Next(0, 3)];
                else abBMB = MAList[0];
        }
        else abBMB = BMBFlightAB;

        if (abBMB == null)
            return "";
        activatedGroups.Add(abBMB.sqn);
        if (size > abBMB.maxPlanes) size = abBMB.maxPlanes;
        if (!abBMB.aircraftType.Contains("Ju-87"))
            gs = null; // just area bomb

        BMBFlightAB = abBMB;
        if (odenDebug) GamePlay.gpLogServer(null, "CreateBMBMission {0} from {1} in {2}", new object[] { abBMB.name, abBMB.airportName, abBMB.aircraftType });

        AiAirport ap = abBMB.ap;
        bool antiShip = false;
        if (aTarget != null)
        {
            if (aTarget is AiGroundActor)
            {
                //AiGroundActor gndActor = (AiGroundActor)aTarget;
                //if (gndActor.Type().ToString().Equals("ShipTransport"))
                // always go low on fround units
                antiShip = true;
            };
        };
        //if(odenDebug) GamePlay.gpLogServer(null, "antiShip {0} {1} {2} {3}", new object[] { BMB2d.x, size, antiShip, abBMB.name });

        AiActor[] actorsQueue = null;
        string apName = "AIR";
        if (ap != null)
        {
            actorsQueue = ap.QueueTakeoff();
            apName = ap.Name();
        };
        bool setOnPark = false;
        if (actorsQueue != null || BMBFlightIndex > 0 || activatedAirports.Contains(apName))
            setOnPark = true;
        activatedAirports.Add(apName);

        Point2d pt2d = new Point2d(abBMB.x, abBMB.y);
        double misDist = BMB2d.distance(ref pt2d);

        //if(odenDebug) GamePlay.gpLogServer(null, "pt2d {0} {1} {2} {3}", new object[] { pt2d.x, pt2d.y, antiShip, abBMB.name });
        string sqn = abBMB.sqn; // bp.Regiment().name();
        //string[] PlaneSet = abBMB.aircraftTypes; // bp.GetAircraftTypes();
        string planeType = abBMB.aircraftType; // PlaneSet[rnd.Next(0, PlaneSet.Length - 1)];
        if (odenDebug) GamePlay.gpLogServer(null, "CreateBMBMission {0} {1} {2} {3}", new object[] { abBMB.name, abBMB.airportName, planeType, antiShip });

        // 01 = Stab./1plane
        // 11 = 1./1plane
        // 21 = 2./1plane
        // 31 = 3./1plane
        // 17 = 1./3x1plane
        // 27 = 1./3x2plane
        // 37 = 1./3x3plane
        // 11 = 1./1x3plane#1
        // 12 = 1./1x3plane#2
        // 14 = 1./1x3plane#3
        // 01 = 1./1x1plane
        // 02 = 2./1x1plane
        // 04 = 3./1x1plane
        // 08 = 4./1x1plane
        // == 27 is 2nd flight planes in section 3 (+04), 2 (+02) and 1 (+01)
        /*
        string[] section = { "1", "2", "4" };
        if (size < 6)
            sqn = sqn + "." + BMBFlightIndex.ToString() + section[BMBSectionIndex]; // only single flight, max 3x4 planes (2x3 planes early style)
        else
            sqn = sqn + "." + BMBFlightIndex.ToString() + "3"; // only single flight, max 3x4 planes (2x3 planes early style)
        // big sets fly bad anyway, use max 2 flights of 3 or 4 planes
        */
        Point2d offset2d = new Point2d(0, 0);
        double heading = calcDir(pt2d, BMB2d);
        int mult = 0;
        foreach (string str in activatedAirports)
            if (str.Equals(apName))
                mult++;
        if (ap == null) offset2d = calcPos(offset2d, (1609 * 3) - (mult * 700), heading); // map entry point trigger
        else offset2d = calcPos(offset2d, -mult * 700, heading);
        /*
        switch (BMBSectionIndex)
        {
            case 1: { offset2d = calcPos(offset2d, 300, heading + 120); break; };
            case 2: { offset2d = calcPos(offset2d, 300, heading - 120); break; };
        };
        */
        string form = "VIC3";
        if (abBMB.type.Contains("Stuka")) form = "VIC";
        if (abBMB.type.Contains("Zerstorer")) form = "FINGERFOUR";
        if (abBMB.type.Contains("Fighter")) form = "FINGERFOUR";
        if (abBMB.type.Contains("Recon")) form = "LINEABREAST";
        if (abBMB.type.Contains("Bomber") && abBMB.sqn.Contains("RAF_")) form = "VIC";
        if (abBMB.type.Contains("Fighter") && abBMB.sqn.Contains("Early")) form = "VIC3";

        if (abBMB.type.Contains("Recon") && size > 4) size = 4;

        string value = "1"; // LINEABREAST Recon flights
        string[] FlightSection = FlightSections(army, size, form, BMBStaffelIndex);
        sqn += "." + FlightSection[4];
        AddToFile(f, "AirGroups", sqn, "");
        if (FlightSection[0].Length > 0) AddToFile(f, sqn, "Flight0", FlightSection[0]);
        if (FlightSection[1].Length > 0) AddToFile(f, sqn, "Flight1", FlightSection[1]);
        if (FlightSection[2].Length > 0) AddToFile(f, sqn, "Flight2", FlightSection[2]);
        if (FlightSection[3].Length > 0) AddToFile(f, sqn, "Flight3", FlightSection[3]);

        AddToFile(f, sqn, "Class", planeType);

        //if (size > 3) AddToFile(f, sqn, "Formation", "LINEABREAST");
        //else AddToFile(f, sqn, "Formation", "VIC3");
        if (aTarget != null)
            if (aTarget is AiGroundActor)
                if (!(aTarget as AiGroundActor).Type().ToString().Equals("ShipTransport"))
                    form = "LINEASTERN";
        AddToFile(f, sqn, "Formation", form);

        AddToFile(f, sqn, "CallSign", ((int)(rnd.Next(0, 35))).ToString());
        if (activeMis) AddToFile(f, sqn, "Fuel", "64");
        else AddToFile(f, sqn, "Fuel", "84");

        switch (planeType)
        {
            case "Aircraft.BlenheimMkI": value = "1 1 2 1 1"; break;
            case "Aircraft.BlenheimMkIV": value = "1 1 3 1 1"; break;
            case "Aircraft.WellingtonMkIc": value = "1 1 3"; break;
            case "Aircraft.Bf-110C-7": value = "1 1 1 2"; break;
            case "Aircraft.Bf-110C-4B": value = "1 1 1 2"; break;
            case "Aircraft.Bf-109E-1B": value = "1 1 2"; break;
            case "Aircraft.Bf-109E-3B": value = "1 1 2"; break;
            case "Aircraft.Bf-109E-4B": value = "1 1 3"; break;
            case "Aircraft.Ju-87B-2": value = "1 1 2 1"; break;
            case "Aircraft.Do-17Z-1": value = "1 1 1 1 4 2"; break;
            case "Aircraft.Do-17Z-2": value = "1 1 1 1 1 1 4 2"; break;
            case "Aircraft.Do-215B-1": value = "1 1 1 2"; break;
            case "Aircraft.Ju-88A-1": value = "1 1 1 1 1 4"; break;
            case "Aircraft.He-111P-2": value = "1 1 1 1 1 2"; break;
            case "Aircraft.He-111H-2": value = "1 1 1 1 1 1 2"; break;
            case "Aircraft.FW-200C-1": value = "1 1 1 1 2 2 2"; break;
            case "Aircraft.BR-20M": value = "1 1 1 3"; break;
        };
        if (antiShip)
            switch (planeType)
            {
                case "Aircraft.Bf-110C-7": value = "1 1 1 5"; break;
                case "Aircraft.Ju-87B-2": value = "1 1 4 1"; break;
                case "Aircraft.Do-17Z-1": value = "1 1 1 1 5 3"; break;
                case "Aircraft.Do-17Z-2": value = "1 1 1 1 1 1 5 3"; break;
                case "Aircraft.Do-215B-1": value = "1 1 1 3"; break;
                case "Aircraft.Ju-88A-1": value = "1 1 1 3 2 7"; break;
                case "Aircraft.He-111P-2": value = "1 1 1 1 1 3"; break;
                case "Aircraft.He-111H-2": value = "1 1 1 1 1 1 3"; break;
                case "Aircraft.BR-20M": value = "1 1 1 6"; break;
                case "Aircraft.He-115B-2": value = "1 1 2"; break;
            };
        AddToFile(f, sqn, "Weapons", value);

        if (setOnPark)
            AddToFile(f, sqn, "SetOnPark", "1");
        //AddToFile(f, sqn, "SpawnFromScript", "1");
        AddToFile(f, sqn, "Skill", bSkill);
        int aging = (gameDateTime - StartDateTime).Days;
        if (aging > 99) aging = 99;
        AddToFile(f, sqn, "Aging", aging.ToString());
        string skin = DefaultSkins(planeType, sqn);
        bool ada = SquadronIsFrench(sqn);
        if (skin != "")
            for (int i = 0; i < 4; i++)
            {
                if (FlightSection[i].Length > 0)
                {
                    int cnt = FlightSection[i].Split(' ').Length + 1;
                    for (int j = 0; j < cnt; j++)
                    {
                        if (i == 0) AddToFile(f, sqn, "Skin" + j.ToString(), skin);
                        else AddToFile(f, sqn, "Skin" + i.ToString() + j.ToString(), skin);
                        if (ada)
                            if (i == 0) AddToFile(f, sqn, "MarkingsOn" + j.ToString(), "0");
                            else AddToFile(f, sqn, "MarkingsOn" + i.ToString() + j.ToString(), "0");
                    }
                };
            };

        int alt = rnd.Next(2500, 4500);
        if (planeType.Contains("Do-17Z")) alt = rnd.Next(100, 800); // schnellbomber best utilized at low alt (engines)
        if (planeType.Contains("Bf-110")) alt = rnd.Next(100, 800);
        //if (antiShip && !planeType.Contains("Ju-87"))
        //    alt = rnd.Next(600, 1200);
        if (!antiShip && alt < 1000)
            switch (planeType)
            {
                case "Aircraft.BlenheimMkI": AddToFile(f, sqn, "Detonator", "Bomb.Bomb_GP_250lb_MkIV 0 30 11"); break;
                case "Aircraft.BlenheimMkIV": AddToFile(f, sqn, "Detonator", "Bomb.Bomb_GP_500lb_MkIV 1 30 11"); break;
                case "Aircraft.Bf-110C-7": AddToFile(f, sqn, "Detonator", "Bomb.SC-250_Type1_J 2 -1 14"); break;
                case "Aircraft.Bf-110C-4B": AddToFile(f, sqn, "Detonator", "Bomb.SC-250_Type1_J 2 -1 14"); break;
                case "Aircraft.Bf-109E-1B": AddToFile(f, sqn, "Detonator", "Bomb.SC-50_GradeII_J 1 -1 14"); break;
                case "Aircraft.Bf-109E-3B": AddToFile(f, sqn, "Detonator", "Bomb.SC-50_GradeII_J 1 -1 14"); break;
                case "Aircraft.Bf-109E-4B": AddToFile(f, sqn, "Detonator", "Bomb.SC-250_Type1_J 2 -1 14"); break;
                case "Aircraft.Ju-87B-2": AddToFile(f, sqn, "Detonator", "Bomb.SC-500_GradeIII_J 0 -1 14"); break;
                case "Aircraft.Do-17Z-1": AddToFile(f, sqn, "Detonator", "Bomb.SC-50_GradeII_J 1 -1 14"); break;
                case "Aircraft.Do-17Z-2": AddToFile(f, sqn, "Detonator", "Bomb.SC-50_GradeII_J 1 -1 14"); break;
                case "Aircraft.Ju-88A-1": AddToFile(f, sqn, "Detonator", "Bomb.SC-250_Type1_J 2 -1 14"); break;
            };
        if (BMBFlightAlt == 0) BMBFlightAlt = alt;
        else alt = BMBFlightAlt;
        if (activeMis) BMBFlightAlt = 0;

        int speed = rnd.Next(300, 350);
        if (planeType.Contains("Bf-109")) speed = rnd.Next(350, 400);
        if (planeType.Contains("Bf-110")) speed = rnd.Next(320, 380);
        if (planeType.Contains("Blenheim")) speed = 320;
        if (planeType.Contains("Wellington")) speed = 290;
        if (planeType.Contains("Beaufighter")) speed = rnd.Next(350, 400);
        if (planeType.Contains("Ju-88")) speed = rnd.Next(320, 380);
        if (planeType.Contains("He-111P")) speed = rnd.Next(310, 370);
        if (planeType.Contains("He-111H")) speed = rnd.Next(310, 370);
        if (BMBFlightSpeed == 0) BMBFlightSpeed = speed;
        else speed = BMBFlightSpeed;
        if (activeMis) BMBFlightSpeed = 0;

        double rwlen = 0;
        if (ap != null)
            rwlen = ap.FieldR();
        if (army == LW)
        {   // fast forward to CH Radar range (85 miles at 15kft)
            // 25miles at 1000ft, 35miles at 2000ft, 50miles at 5000ft and 83miles at 13000ft +
            // 207ft /mile = 63m /mile
            int rng = 25 + (int)(alt / 63); // miles
            if (rng > 85)
                rng = 85;
            //Chain Home Low 500ft 35 miles
            if (alt < 200)
                rng = 35;

            GroundStationary chRadar = FindChainHomeRadar(pt2d);
            if (chRadar != null)
            {
                Point2d radar2d = new Point2d(chRadar.pos.x, chRadar.pos.y);
                double dir = calcDir(radar2d, pt2d);
                Point2d rdp2d = calcPos(radar2d, rng * 1609, dir);
                //if(odenDebug) GamePlay.gpLogServer(null, "CH Radar: target to RDP {0}, target to spawn {1}, RDP to spawn {2} at {3} deg", new object[] { BMB2d.distance(ref rdp2d).ToString("F2"), BMB2d.distance(ref pt2d).ToString("F2"), rdp2d.distance(ref pt2d).ToString("F2"), dir.ToString("F2") });
                if (BMB2d.distance(ref rdp2d) < BMB2d.distance(ref pt2d))
                {
                    //pt2d = rdp2d; // radar detection point (rdp2d) is closer to target (BMB2d) than base (pt2d) is
                    pt2d = calcPos(radar2d, rng * 1609, dir);
                    rwlen = 0; // airstart
                    //if(odenDebug) GamePlay.gpLogServer(null, "CH Radar: new spawn {0} {1} at {2} deg from {3} {4}", new object[] { pt2d.x.ToString("F2"), pt2d.y.ToString("F2"), dir.ToString("F2"), radar2d.x.ToString("F2"), radar2d.y.ToString("F2") });
                };
            }
            else
            {   // all radars destroyed
                rwlen = 0;
                Point2d spawn2d = calcPos(BMB2d, -15 * 1609, heading);
                if (BMB2d.distance(ref spawn2d) < BMB2d.distance(ref pt2d))
                    pt2d = spawn2d; // detection point 15 miles out - check land/observer corps?
            };
        };

        pt2d.x = pt2d.x + offset2d.x;
        pt2d.y = pt2d.y + offset2d.y;
        string strWP = "";
        List<string> listWP = new List<string>();
        Point2d esc2d;
        int escAlt = 100 + rnd.Next(0, 200);

        if (activeMis)
        {
            //Point2d air2d = calcPos(BMB2d, Math.Max(misDist,16090f) / 2, -heading);
            misDist = homeAirport.Pos().distance(ref target3d);
            Point2d air2d = calcPos(BMB2d, -Math.Max(misDist,2 *16090.0), heading);
            AddToFile(f, sqn + "_Way", "NORMFLY", air2d.x.ToString("F2") + " " + air2d.y.ToString("F2") + " " + alt.ToString("F2") + " " + speed.ToString("F2"));
            if (odenDebug) GamePlay.gpLogServer(null, "CreateBMBMission activeMis {0} from {1} {2}m/{3} in {4}", new object[] { abBMB.name, abBMB.airportName, misDist.ToString("F0"), heading, GamePlay.gpSectorName(air2d.x, air2d.y) });
            esc2d = calcPos(air2d, 700, heading + 90);
            strWP = esc2d.x.ToString("F2") + " " + esc2d.y.ToString("F2") + " " + (alt + escAlt).ToString("F2") + " " + speed.ToString("F2");
            listWP.Add(strWP);
        }
        else
        {
            if (1000 > rwlen)
            {   // airstart if short runway or map entry point
                //pt2d = calcPos(pt2d, rnd.Next(1000, 3000), rnd.Next(0, 359));
                AddToFile(f, sqn + "_Way", "NORMFLY", pt2d.x.ToString("F2") + " " + pt2d.y.ToString("F2") + " " + alt.ToString("F2") + " " + speed.ToString("F2"));
                esc2d = calcPos(pt2d, 700, heading + 90);
                strWP = esc2d.x.ToString("F2") + " " + esc2d.y.ToString("F2") + " " + (alt + escAlt).ToString("F2") + " " + speed.ToString("F2");
                listWP.Add(strWP);
            }
            else
            {
                AddToFile(f, sqn + "_Way", "TAKEOFF", abBMB.x.ToString("F2") + " " + abBMB.y.ToString("F2") + " 0 0");
                double dir = calcDir(pt2d, BMB2d);
                Point2d wp2d = calcPos(pt2d, 16090 / 2, dir);
                AddToFile(f, sqn + "_Way", "NORMFLY", wp2d.x.ToString("F2") + " " + wp2d.y.ToString("F2") + " 1680.00" + " 280.00");
            };
        };
        Point2d mid2d = calcPos(BMB2d, -16090 / 2, heading);
        AddToFile(f, sqn + "_Way", "NORMFLY", mid2d.x.ToString("F2") + " " + mid2d.y.ToString("F2") + " " + alt.ToString() + ".00 " + speed.ToString() + ".00");

        esc2d = calcPos(BMB2d, 700, heading + 90);
        strWP = esc2d.x.ToString("F2") + " " + esc2d.y.ToString("F2") + " " + (alt + escAlt).ToString("F2") + " " + speed.ToString("F2");
        listWP.Add(strWP);
        if (aTarget == null && gs == null)
        {
            AddToFile(f, sqn + "_Way", "GATTACK_POINT", BMB2d.x.ToString("F2") + " " + BMB2d.y.ToString("F2") + " " + alt.ToString() + ".00 " + speed.ToString() + ".00");
        }
        else
        {
            string profile = "SHALLOW_DIVE";
            if (alt < 500) profile = "TOP_MAST";
            if (gs != null) profile = "LEVEL";
            if (planeType.Contains("Ju-87")) profile = "DIVE";
            else alt = rnd.Next(600, 1200);
            BMB2d = calcPos(BMB2d, -16100 / 4, heading);
            //GATTACK_TARG 110495.05 146698.26 3500.00 290.00 0_Chief 0 /GAttackType DIVE
            strWP = BMB2d.x.ToString("F2") + " " + BMB2d.y.ToString("F2") + " " + alt.ToString() + ".00 " + speed.ToString() + ".00";
            if (aTarget != null)
                AddToFile(f, sqn + "_Way", "GATTACK_TARG", strWP + " " + aTarget.Name() + " 0 /GAttackType " + profile);
            if (gs != null)
                AddToFile(f, sqn + "_Way", "GATTACK_TARG", strWP + " " + gs.Name + " 0 /GAttackType " + profile);
        };

        // RTB
        AddToFile(f, sqn + "_Way", "NORMFLY", pt2d.x.ToString("F2") + " " + pt2d.y.ToString("F2") + " " + alt.ToString() + ".00 " + speed.ToString() + ".00");
        //esc2d = calcPos(pt2d, 700, heading + 90);
        //strWP = esc2d.x.ToString("F2") + " " + esc2d.y.ToString("F2") + " " + (alt + 100).ToString("F2") + " " + speed.ToString("F2");
        //listWP.Add(strWP);

        alt = (int)(alt / 2);
        strWP = abBMB.x.ToString("F2") + " " + abBMB.y.ToString("F2") + " " + alt.ToString() + ".00 " + speed.ToString() + ".00";
        if (rwlen == 0)
            AddToFile(f, sqn + "_Way", "NORMFLY", strWP);
        else
            AddToFile(f, sqn + "_Way", "LANDING", strWP);
        listWP.Add(strWP);
        /*
        BMBSectionIndex++;
        if (BMBSectionIndex > 2)
        {
            BMBSectionIndex = 0;
            BMBFlightIndex++;
        };
        */
        switch (form)
        {
            // Bomber max 3 +VIC3
            // Zerstörer max 4 +FF
            // Fighter max 4 +FF
            // Recon max 1 +LINEABREAST
            // Transp. max 3 +VIC
            // UK Bomber max 10 +VIC
            // UK Fighter max 6 +VIC3
            // UK Fighter max 4 +FF
            // LINEASTERN
            case "VIC":
                if (size > 8) BMBFlightIndex = 9;
                break;
            case "VIC3":
                if (army == RAF && size > 11) BMBFlightIndex = 3;
                if (army != RAF && size > 8) BMBFlightIndex = 3;
                break;
            case "FINGERFOUR":
                if (size > 11) BMBFlightIndex = 3;
                break;
            default:
                BMBFlightIndex = 3;
                break;
        };

        BMBFlightIndex++;
        BMBStaffelIndex++;
        if (BMBFlightIndex > 2 || BMBStaffelIndex > 4)
        {
            BMBFlightAB = null;
            BMBFlightIndex = 0;
            BMBStaffelIndex = 0;
        };

        if (escortReq)
        {
            MissionAirbase home = null;
            speed += 50;
            string sqnF;
            if (army == LW)
            {
                sqnF = CreateCAPMission(f, BMB2d, 12, LW, true);
                if (odenDebug) GamePlay.gpLogServer(null, "Escort {0}", new object[] { sqnF });
                if (sqnF.Length > 0)
                {
                    foreach (MissionAirbase mab in MissionAirbases)
                        if (sqnF.Contains(mab.sqn))
                            home = mab;
                    if (rwlen > 0 && !activeMis)
                        AddToFile(f, sqnF + "_Way", "TAKEOFF", home.x.ToString("F2") + " " + home.y.ToString("F2") + " 0 0");
                    foreach (string str in listWP)
                        AddToFile(f, sqnF + "_Way", "ESCORT", str + " " + sqn + " 1");
                    AddToFile(f, sqnF + "_Way", "LANDING", home.x.ToString("F2") + " " + home.y.ToString("F2") + " " + alt.ToString() + ".00 " + speed.ToString() + ".00");
                };
            }
            else
            {
                for (int cnt = 1; cnt < 2; cnt++)
                {
                    sqnF = CreateCAPMission(f, BMB2d, 6, RAF, true);
                    if (sqnF.Length > 0)
                    {
                        foreach (MissionAirbase mab in MissionAirbases)
                            if (sqnF.Contains(mab.sqn))
                                home = mab;
                        if (rwlen > 0 && !activeMis)
                            AddToFile(f, sqnF + "_Way", "TAKEOFF", home.x.ToString("F2") + " " + home.y.ToString("F2") + " 0 0");
                        foreach (string str in listWP)
                            AddToFile(f, sqnF + "_Way", "ESCORT", str + " " + sqn + " 1");
                        AddToFile(f, sqnF + "_Way", "LANDING", home.x.ToString("F2") + " " + home.y.ToString("F2") + " " + alt.ToString() + ".00 " + speed.ToString() + ".00");
                    };
                };
            };

            if (rnd.Next(0, 9) > 6)
            {   // fighter sweep
                sqnF = CreateCAPMission(f, BMB2d, 12, army, true);
                if (odenDebug) GamePlay.gpLogServer(null, "Sweep {0}", new object[] { sqnF });
                sweepGroups.Add(sqnF);
                foreach (MissionAirbase mab in MissionAirbases)
                    if (sqnF.Contains(mab.sqn))
                        home = mab;
                alt = rnd.Next(2500, 4500);
                if (rnd.Next(0, 99) < 10) alt = rnd.Next(700, 1500); // lure defence down low
                esc2d = calcPos(pt2d, 700, heading);

                if (rwlen > 0)
                    AddToFile(f, sqnF + "_Way", "TAKEOFF", home.x.ToString("F2") + " " + home.y.ToString("F2") + " 0 0");
                else
                    AddToFile(f, sqnF + "_Way", "AATTACK_FIGHTERS", esc2d.x.ToString("F2") + " " + esc2d.y.ToString("F2") + " " + alt.ToString("F2") + " " + speed.ToString("F2"));
                AddToFile(f, sqnF + "_Way", "AATTACK_FIGHTERS", BMB2d.x.ToString("F2") + " " + BMB2d.y.ToString("F2") + " " + alt.ToString() + ".00 " + speed.ToString() + ".00");
                AddToFile(f, sqnF + "_Way", "LANDING", home.x.ToString("F2") + " " + home.y.ToString("F2") + " " + alt.ToString() + ".00 " + speed.ToString() + ".00");
            };
        };

        return sqn;
    }

    private Point2d calcPos(Point2d pt2d, double dist, double dir)
    {
        dir = dir * Math.PI / 180;
        return new Point2d(pt2d.x + (dist * Math.Sin(dir)), pt2d.y + (dist * Math.Cos(dir)));
    }
    private double calcDir(Point2d from2d, Point2d to2d)
    {
        double rad = Math.Atan2(to2d.x - from2d.x, to2d.y - from2d.y);
        double deg = rad * 180 / Math.PI;
        if (deg < 0)
            return 360 + deg;
        return deg;
    }

    private bool ChainHomeRadarDetected(AiAircraft ac)
    {
        Point2d pt2d = new Point2d(ac.Pos().x, ac.Pos().y);
        GroundStationary chRadar = FindChainHomeRadar(pt2d);
        if (chRadar == null)
            return false;
        // 25miles at 1000ft, 35miles at 2000ft, 50miles at 5000ft and 83miles at 13000ft +
        // 207ft /mile = 63m /mile
        double alt = ac.Pos().z;
        int rng = 25 + (int)(alt / 63); // miles
        if (rng > 85)
            rng = 85;
        //Chain Home Low 500ft 35 miles
        if (alt < 200)
            rng = 35;

        Point2d radar2d = new Point2d(chRadar.pos.x, chRadar.pos.y);
        if (radar2d.distance(ref pt2d) < rng * 1609)
            return true;
        return false;
    }
    private void UpdateWP(AiGroup ag)
    {
        if (ag == null)
            return;
        if (ag.GetItems().Length < 1)
            return;
        if (TargetGroup != null)
            return;
        if (target2d.x == 0)
            return;

        AiActor agLeader = GetFlightLeader((AiAirGroup)ag);
        Point3d refPos3d = agLeader.Pos();
        Point3d home3d = agLeader.Pos();
        int currWPidx = ag.GetCurrentWayPoint();
        foreach (MissionAirbase ab in MissionAirbases)
            if (ab.sqn == (agLeader as AiAircraft).Regiment().name())
                home3d = ab.Pos();
        home3d.z = refPos3d.z;

        AiWayPoint[] arrWP = ag.GetWay();
        bool StayOnCourse = false;
        foreach (AiWayPoint wp in arrWP)
            if (wp is AiAirWayPoint)
                switch ((wp as AiAirWayPoint).Action)
                {
                    case AiAirWayPointType.HUNTING:
                    case AiAirWayPointType.LANDING:
                    case AiAirWayPointType.NORMFLY:
                    case AiAirWayPointType.TAKEOFF:
                        break;
                    default:
                        StayOnCourse = true;
                        break;
                };
        if (StayOnCourse)
            return;

        AiWayPoint currWP = arrWP[currWPidx];
        AiAirWayPoint currAWP = (AiAirWayPoint)arrWP[currWPidx];
        if (currAWP.Action == AiAirWayPointType.TAKEOFF)
            return;
        // 180 mph = 290 kmh
        // 200 mph = 321 kmh
        // 220 mph = 354 kmh
        // 240 mph = 386 kmh
        // 260 mph = 418 kmh

        if (currWP.P.distance(ref refPos3d) < 16090)
        {   // last wp
            //if (odenDebug) GamePlay.gpLogServer(null, "wp {0} for {1} do {2} {3} at {4} m away", new object[] { currWPidx, ag.Name(), currAWP.Action, currAWP.Target, dist });
            currWP.Speed = 290; // 180 mph
            // seems not if(ag.Army() == RAF ) currWP.Speed = 180; // test: is this why they fly so darn fast?
            currAWP.Action = AiAirWayPointType.NORMFLY;

            Point2d cap2d = HalfwayToTarget2d(ag as AiAirGroup);// calcPos(target2d, rnd.Next(500, 16093), rnd.Next(360));
            Point3d cap3d = new Point3d(cap2d.x, cap2d.y, refPos3d.z);//rnd.Next(800, 3200));
            AiAirWayPoint nextAWP = new AiAirWayPoint(ref cap3d, currAWP.Speed);
            AiAirWayPoint dmmyAWP = new AiAirWayPoint(ref home3d, currAWP.Speed);

            nextAWP.Action = AiAirWayPointType.HUNTING;
            dmmyAWP.Action = AiAirWayPointType.NORMFLY;

            arrWP = new AiWayPoint[] { currAWP, nextAWP, dmmyAWP };
            ag.SetWay(arrWP);
            if (odenDebug) GamePlay.gpLogServer(null, "new wp for {0} curr: {1}/{2} next: {3}/{4}", new object[] { ag.Name(), currAWP.P.distance(ref refPos3d).ToString("F0"), currAWP.Action, nextAWP.P.distance(ref refPos3d).ToString("F0"), nextAWP.Action });
            LeaderUpdateMsg();
        };
    }
    private void InterceptWP(AiGroup ag)
    {
        if (ag == null)
            return;
        if (ag.GetItems().Length < 1)
            return;
        AiActor agLeader = GetFlightLeader((AiAirGroup)ag);
        if (TargetGroup.GetItems().Length < 1)
            return;
        AiActor TargetLeader = GetFlightLeader(TargetGroup);
        if (TargetLeader == null)
        {
            TargetGroup = null;
            return;
        };
        Point3d refPos3d = TargetLeader.Pos();
        Point3d home3d = agLeader.Pos();
        foreach (MissionAirbase ab in MissionAirbases)
            if (ab.sqn == (agLeader as AiAircraft).Regiment().name())
                home3d = ab.Pos();
        home3d.z = agLeader.Pos().z;

        AiWayPoint[] arrWP = ag.GetWay();
        int currWPidx = ag.GetCurrentWayPoint();
        bool StayOnCourse = false;
        foreach (AiWayPoint wp in arrWP)
            if (wp is AiAirWayPoint)
                switch ((wp as AiAirWayPoint).Action)
                {
                    case AiAirWayPointType.HUNTING:
                    case AiAirWayPointType.LANDING:
                    case AiAirWayPointType.NORMFLY:
                    case AiAirWayPointType.TAKEOFF:
                        break;
                    default:
                        StayOnCourse = true;
                        break;
                };
        if (StayOnCourse)
            return;

        AiWayPoint currWP = arrWP[currWPidx];
        AiAirWayPoint currAWP = (AiAirWayPoint)arrWP[currWPidx];
        if (currAWP.Action == AiAirWayPointType.TAKEOFF)
            return;
        // 180 mph = 290 kmh
        // 200 mph = 321 kmh
        // 220 mph = 354 kmh
        // 240 mph = 386 kmh
        // 260 mph = 418 kmh

        Point2d pt2d = new Point2d(agLeader.Pos().x, agLeader.Pos().y);
        Point2d tg2d = new Point2d(TargetLeader.Pos().x, TargetLeader.Pos().y);
        double dir = calcDir(target2d, tg2d);
        int dist = (int)(TargetLeader.Pos().distance(ref target3d)); // bombers to target
        Point2d next2d = calcPos(target2d, dist * 0.5, dir); // intercept point
        Point3d next3d = new Point3d(next2d.x, next2d.y, refPos3d.z +300);
        if (agLeader.Pos().distance(ref next3d) > agLeader.Pos().distance(ref refPos3d))
        {   // target closer to sqn than half-way intercept point is
            next2d = calcPos(tg2d, -1000, dir); // intercept point
            next3d = new Point3d(next2d.x, next2d.y, refPos3d.z + 300);
        };
        if (agLeader.Pos().distance(ref next3d) < 8000)
        {   // next is too close
            next2d = calcPos(next2d, 16093, rnd.Next(360));
            next3d = new Point3d(next2d.x, next2d.y, refPos3d.z + 300);
        };
        string tgtSector = GamePlay.gpSectorName(next2d.x, next2d.y);

        //if (odenDebug) GamePlay.gpLogServer(null, "wp {0} for {1} do {2} {3} at {4} m away", new object[] { currWPidx, ag.Name(), currAWP.Action, currAWP.Target, dist });
        currAWP.Action = AiAirWayPointType.AATTACK_FIGHTERS;
        if ((TargetLeader as AiAircraft).Type().ToString().Contains("Bomber"))
            currAWP.Action = AiAirWayPointType.AATTACK_BOMBERS;
        //currAWP.Action = AiAirWayPointType.HUNTING;
        currAWP.Speed = 354; // 220 mph
        // seems not if (ag.Army() == RAF) currAWP.Speed = 220; // test: is this why they fly so darn fast?

        AiAirWayPoint nextAWP = new AiAirWayPoint(ref next3d, currAWP.Speed);
        AiAirWayPoint dmmyAWP = new AiAirWayPoint(ref home3d, currAWP.Speed);

        nextAWP.Action = currAWP.Action;
        dmmyAWP.Action = AiAirWayPointType.NORMFLY; //currAWP.Action; //AiAirWayPointType.AATTACK_FIGHTERS;//

        currAWP.Target = null;// TargetLeader;
        nextAWP.Target = TargetLeader;
        dmmyAWP.Target = null;

        arrWP = new AiWayPoint[] { currAWP, nextAWP, dmmyAWP };
        if (odenDebug) GamePlay.gpLogServer(null, "icpt wp for {0} curr: {1}/{2} next: {3}/{4}", new object[] { ag.Name(), currAWP.P.distance(ref refPos3d).ToString("F0"), currAWP.Action, nextAWP.P.distance(ref refPos3d).ToString("F0"), nextAWP.Action });

        ag.SetWay(arrWP);
        LeaderUpdateMsg();
    }
    private void UpdateGroundTarget(AiGroup ag)
    {
        if (ag == null)
            return;
        if (ag.Name() == "NONAME")
            return;
        //if (odenDebug) GamePlay.gpLogServer(null, "UpdateGroundTarget for {0}", new object[] { ag.Name() });
        if (ag.GetItems().Length < 1)
            return;

        AiActor agLeader = GetFlightLeader((AiAirGroup)ag);
        Point3d refPos3d = agLeader.Pos();
        double minDist = 999999f;
        GroundTarget = null;
        int enemy = ag.Army() == RAF ? LW : RAF;
        foreach (AiGroundGroup gg in GamePlay.gpGroundGroups(enemy))
            if (gg.GroupType() == AiGroundGroupType.Vehicle)
            {
                Point3d pt3d;
                gg.GetPos(out pt3d);
                double ggDist = ag.Pos().distance(ref pt3d);
                if (ggDist < minDist)
                {
                    GroundTarget = gg;
                    minDist = ggDist;
                };
            };
        if (GroundTarget == null)
            return;
        if (GroundTarget.GetItems().Length < 1)
            return;

        AiActor aTarget = GroundTarget.GetItems()[0];
        AiWayPoint[] arrWP = ag.GetWay();
        int currWPidx = ag.GetCurrentWayPoint();
        AiAirWayPoint currAWP = (AiAirWayPoint)arrWP[currWPidx];

        //if (odenDebug) GamePlay.gpLogServer(null, "UpdateGroundTarget check {0} {1} {2}", new object[] { ag.Name(), currWPidx, arrWP.Length });
        if (currWPidx == arrWP.Length - 1 && aTarget != currAWP.Target && currAWP.P.distance(ref refPos3d) < 16090)
        {   // last wp
            Point2d pt2d = new Point2d(agLeader.Pos().x, agLeader.Pos().y);
            Point2d tg2d = new Point2d(aTarget.Pos().x, aTarget.Pos().y);
            double dir = calcDir(tg2d, pt2d);
            Point2d inb2d = calcPos(tg2d, 5 * 1609, dir);
            Point2d out2d = calcPos(tg2d, 5 * 1609, dir + 90 - rnd.Next(0, 180));
            Point3d inb3d = new Point3d(inb2d.x, inb2d.y, rnd.Next(800, 1200));
            Point3d out3d = new Point3d(out2d.x, out2d.y, inb3d.z);

            AiAirWayPoint nextAWP = new AiAirWayPoint(ref inb3d, currAWP.Speed);
            nextAWP.Action = AiAirWayPointType.GATTACK_TARG;
            nextAWP.Target = aTarget;

            AiAirWayPoint extrAWP = new AiAirWayPoint(ref out3d, currAWP.Speed);
            extrAWP.Action = AiAirWayPointType.NORMFLY;

            arrWP = new AiWayPoint[] { currAWP, nextAWP, extrAWP };
            ag.SetWay(arrWP);
            //if (odenDebug) GamePlay.gpLogServer(null, "UpdateGroundTarget new {0}", new object[] { nextAWP.Target.Name() });
        };
    }
    private void RedirectCAP(int army, Point2d pt2d)
    {
        target2d = pt2d;
        AiAirGroup[] ags = GamePlay.gpAirGroups(army);
        if (ags != null)
            foreach (AiAirGroup ag in ags)
                if (AiAirGroupCanIntercept(ag))
                    if (!AiAirGroupsStdby.Contains(ag))
                        GiveNewWP((AiGroup)ag, pt2d);
    }
    private void GiveNewWP(AiGroup grp, Point2d wp2d)
    {
        if (grp == null)
            return;
        if (grp.GetItems().Length < 1)
            return;
        AiActor grpLeader = GetFlightLeader((AiAirGroup)grp);
        Point3d refPos3d = grpLeader.Pos();
        AiAircraft ac = (AiAircraft)grpLeader;
        AiAirGroup ag = ac.AirGroup();

        AiWayPoint[] arrWP = grp.GetWay();
        int currWPidx = grp.GetCurrentWayPoint();
        AiAirWayPoint currAWP = (AiAirWayPoint)arrWP[currWPidx];
        if (currAWP.Action == AiAirWayPointType.TAKEOFF)
            return;

        if (currAWP.Target == null)
        {
            Point3d wp3d = new Point3d(wp2d.x, wp2d.y, rnd.Next(2000, 4000));
            AiAirWayPoint nextAWP = new AiAirWayPoint(ref wp3d, currAWP.Speed);
            nextAWP.Action = currAWP.Action;
            Point3d tg3d = new Point3d(target2d.x, target2d.y, nextAWP.P.z);
            AiAirWayPoint lastAWP = new AiAirWayPoint(ref tg3d, currAWP.Speed);
            lastAWP.Action = currAWP.Action;

            arrWP = new AiWayPoint[] { currAWP, nextAWP, lastAWP };
            grp.SetWay(arrWP);
        };
    }
    private void UpdatePlayerRTB(bool _bombersLeavingTarget)
    {
        if (GamePlay.gpPlayer() == null)
            return;
        AiAircraft pac = (AiAircraft)GamePlay.gpPlayer().Place();
        if (pac == null || !_bombersLeavingTarget)
            return;
        AiAirGroup pag = pac.AirGroup();
        if (pag == null)
            return;

        if (odenDebug) GamePlay.gpLogServer(null, "UpdatePlayerRTB chk for {0}", new object[] { pag.Name() });
        AiWayPoint[] arrWP = pag.GetWay();
        foreach (AiWayPoint wp1 in arrWP)
            if ((wp1 as AiAirWayPoint).Action == AiAirWayPointType.LANDING)
                return;

        if (odenDebug) GamePlay.gpLogServer(null, "UpdatePlayerRTB do for {0}", new object[] { pag.Name() });
        int currWPidx = pag.GetCurrentWayPoint();
        AiAirWayPoint currAWP = (AiAirWayPoint)arrWP[currWPidx];

        AiAirWayPoint nextAWP = new AiAirWayPoint(ref homeAirport3d, currAWP.Speed);
        nextAWP.Action = AiAirWayPointType.NORMFLY;

        AiAirWayPoint landAWP = new AiAirWayPoint(ref homeAirport3d, 120);
        landAWP.Action = AiAirWayPointType.LANDING;
        landAWP.Target = homeAirport;

        arrWP = new AiWayPoint[] { currAWP, nextAWP, landAWP };
        pag.SetWay(arrWP);

    }
    private void debugWaypointValues()
    {
        if (GamePlay.gpPlayer() == null)
            return;
        AiAircraft pac = (AiAircraft)GamePlay.gpPlayer().Place();
        if (pac == null)
            return;
        AiAirGroup pag = pac.AirGroup();
        GamePlay.gpLogServer(null, "debugWaypointValues for {0}", new object[] { pag.Name() });
        AiWayPoint[] arrWP = pag.GetWay();
        foreach (AiWayPoint wp in arrWP)
        {
            AiAirWayPoint awp = (AiAirWayPoint)wp;
            GamePlay.gpLogServer(null, "WP {0} {1} {2}", new object[] { awp.Action, awp.Target, awp.GAttackType });
        };
        GamePlay.gpLogServer(null, "---", new object[] { });
    }
    private void LeaderUpdateMsg()
    {
        Player localPlayer = GamePlay.gpPlayer();
        if (localPlayer == null)
            return;
        AiAircraft pac = (AiAircraft)localPlayer.Place();
        if (pac == null)
            return; // ejected etc.
        AiAirGroup pag = pac.AirGroup();
        if (pag == null)
            return;
        if (pag.GetItems().Length < 2)
            return; // only talk to myself
        AiAircraft lac = (AiAircraft)GetFlightLeader(pag);
        if (lac == null)
            return; // no one to talk to

        AiWayPoint[] arrWP = pag.GetWay();
        int currWPidx = pag.GetCurrentWayPoint();
        if (timeoutRadio < DateTime.Now)
        {
            AiWayPoint currWP = arrWP[currWPidx];
            Point3d pt3d = currWP.P;
            if (pt3d.x != oldWP.P.x || pt3d.z != oldWP.P.z)
            {
                timeoutRadio = DateTime.Now;
                timeoutRadio.AddSeconds(12);
                if (odenDebug) GamePlay.gpLogServer(null, "LeaderUpdateMsg {0} '{1}m'", new object[] { GamePlay.gpSectorName(pt3d.x, pt3d.y), pt3d.z });
                //acLeader.SayToGroup(acLeader.AirGroup(), "This_is");
                lac.SayToGroup(pag, lac.CallSign());
                lac.SayToGroup(pag, "Next_check_point");
                sayGrid(lac, pag, GamePlay.gpSectorName(pt3d.x, pt3d.y));
                lac.SayToGroup(pag, "Changed_course");
                sayDirection(lac, pag, pt3d);
                sayAltitude(lac, pag, pt3d.z);
            };
            oldWP = currWP;
        };
    }
    private void GndCtrlUpdateMsg()
    {
        if (TargetGroup == null)
            return;
        if (odenDebug) GamePlay.gpLogServer(null, "GndCtrlUpdateMsg", new object[] { });
        if (GamePlay.gpPlayer() == null)
            return;
        AiAircraft pac = (AiAircraft)GamePlay.gpPlayer().Place();
        if (pac == null)
            return;
        if (pac.Army() == ATK)
            return;

        if (TargetGroup.GetItems().Length > 1)
        {
            AiAirGroup pag = pac.AirGroup();
            AiActor TargetLeader = GetFlightLeader(TargetGroup);
            if (TargetLeader == null)
                return;
            string planeSector = GamePlay.gpSectorName(TargetLeader.Pos().x, TargetLeader.Pos().y);
            AiActor refActor = GetFlightLeader(pag);
            if (refActor == null)
                return;
            Point3d refPos3d = refActor.Pos();
            int dist = (int)(TargetLeader.Pos().distance(ref refPos3d) / 1000);
            int miles = (int)(dist * .62f);
            if (miles > 5)
            {
                if ((planeSector.IndexOf(">") == -1 && planeSector.IndexOf("<") == -1))
                {
                    timeoutRadio = DateTime.Now;
                    timeoutRadio.AddSeconds(12);

                    AiAircraft fc = FighterCommand;
                    if (fc == null)
                        return;
                    fc.SayToGroup(pag, "Enemy_group");
                    sayGrid(fc, pag, planeSector);
                    sayAltitude(fc, pag, TargetLeader.Pos().z);
                    gameIsOn = true;
                    if (odenDebug) GamePlay.gpLogServer(null, "GndCtrlUpdateMsg {0} {1}", new object[] { planeSector, TargetGroup.Name() });
                    if (firstMessage)
                    {
                        firstMessage = false;
                        AiAircraft lac = (AiAircraft)GetFlightLeader(pag);
                        if (lac != null)
                        {
                            Timeout(12, () =>
                            {
                                timeoutRadio = DateTime.Now;
                                timeoutRadio.AddSeconds(12);
                                lac.SayToGroup(pag, lac.CallSign());
                                lac.SayToGroup(pag, "Let_s_go_get_them");
                                InterceptWP(pag);
                            });
                        };
                    }
                    else { InterceptWP(pag); };
                }
                else
                {
                    if (gameIsOn && missionVictory > 0 && !TargetGroup.hasTorpedos() && !TargetGroup.hasBombs() && !TargetGroup.hasBombsInInternalBays())
                    {   // mission over
                        if (odenDebug) GamePlay.gpLogServer(null, "GndCtrlUpdateMsg {0} {1}", new object[] { "FC:", "!hasBombs" });
                        sayMissionOver(missionVictory);
                        if (odenDebug) GamePlay.gpLogServer(null, "UpdatePlayerRTB from {0}", new object[] { "GndCtrlUpdateMsg mission over no TargetGroup wpn" });
                        UpdatePlayerRTB(bombersLeavingTarget);
                        TargetGroup = null;
                    };
                };
            };
        }
        else
        {   // look for new target?
            sayMissionOver(missionVictory);
            if (odenDebug) GamePlay.gpLogServer(null, "UpdatePlayerRTB from {0}", new object[] { "GndCtrlUpdateMsg mission over no TargetGroup" });
            UpdatePlayerRTB(bombersLeavingTarget);
            TargetGroup = null;
        };
    }
    private void EscortUpdateMsg()
    {
        if (EscortedGroup == null)
            return;
        if (GamePlay.gpPlayer() == null)
            return;
        AiAircraft pac = (AiAircraft)GamePlay.gpPlayer().Place();
        if (pac == null)
            return;
        if (odenDebug) GamePlay.gpLogServer(null, "EscortUpdateMsg {0} {1}", new object[] { pac.Army(), ATK });
        if (pac.Army() != EscortedGroup.getArmy())
            return;

        if (EscortedGroup.GetItems().Length > 1)
        {
            AiAirGroup pag = pac.AirGroup();
            if (pag == null)
                return;
            AiActor EscortLeader = GetFlightLeader(EscortedGroup);
            if (EscortLeader == null)
                return;

            string planeSector = GamePlay.gpSectorName(EscortLeader.Pos().x, EscortLeader.Pos().y);
            AiActor refActor = GetFlightLeader(pag);
            if (refActor == null)
                return;
            Point3d refPos3d = refActor.Pos();
            int dist = (int)(EscortLeader.Pos().distance(ref refPos3d) / 1000);
            if (dist > 5)
            {
                if ((planeSector.IndexOf(">") == -1 && planeSector.IndexOf("<") == -1))
                {
                    timeoutRadio = DateTime.Now;
                    timeoutRadio.AddSeconds(12);

                    AiAircraft fc = (AiAircraft)EscortLeader;
                    if (fc == null)
                        return;
                    fc.SayToGroup(pag, "Bomber_formation");
                    sayGrid(fc, pag, planeSector);
                    sayAltitude(fc, pag, EscortLeader.Pos().z);
                    gameIsOn = true;
                    //if (odenDebug) GamePlay.gpLogServer(null, "EscortUpdateMsg {0} {1}", new object[] { planeSector, dist });
                }
                else
                {
                    if (gameIsOn && missionVictory > 0 && !EscortedGroup.hasTorpedos() && !EscortedGroup.hasBombs() && !EscortedGroup.hasBombsInInternalBays())
                    {   // mission over
                        sayMissionOver(missionVictory);
                        GamePlay.gpLogServer(null, "UpdatePlayerRTB from {0}", new object[] { "EscortUpdateMsg mission over no EscortedGroup wpn" });
                        UpdatePlayerRTB(bombersLeavingTarget);
                        EscortedGroup = null;
                    };
                };
            };
        }
        else
        {   // look for new target?
            sayMissionOver(missionVictory);
            GamePlay.gpLogServer(null, "UpdatePlayerRTB from {0}", new object[] { "EscortUpdateMsg mission over no EscortedGroup" });
            UpdatePlayerRTB(bombersLeavingTarget);
            EscortedGroup = null;
        };
    }
    private void sayMissionOver(int win)
    {
        timeoutRadio = DateTime.Now;
        timeoutRadio.AddSeconds(12);
        if (GamePlay.gpPlayer() == null)
            return;
        AiAircraft pac = (AiAircraft)GamePlay.gpPlayer().Place();
        if (pac == null)
            return;
        AiAirGroup pag = pac.AirGroup();
        AiAircraft lac = (AiAircraft)GetFlightLeader(pag); // it's ok to talk to one self at times like this :)
        if (win == pag.getArmy())
        {
            switch (rnd.Next(10))
            {
                case 0: lac.SayToGroup(pag, "All_right_gentlemen_I_think_that_was_quite_enough"); break;
                case 1: lac.SayToGroup(pag, "Mission_accomplished_Excellent_Just_like_the_movies"); break;
                case 2: lac.SayToGroup(pag, "Okay_we_are_finished_here_Let_s_go_home"); break;
                case 3: lac.SayToGroup(pag, "That_was_easy_enough_Let_s_go_home"); break;
                default: lac.SayToGroup(pag, "Good_show_everyone"); break;
            };
        }
        else
        {
            switch (rnd.Next(10))
            {
                case 0: lac.SayToGroup(pag, "Disengage_disengage_let_s_get_out_of_here"); break;
                case 1: lac.SayToGroup(pag, "Everyone_let_s_go_home"); break;
                case 2: lac.SayToGroup(pag, "Heading_home"); break;
                case 3: lac.SayToGroup(pag, "Let_s_go_home"); break;
                case 4: lac.SayToGroup(pag, "Return_to_base_I_repeat_return_to_home_base"); break;
                case 5: lac.SayToGroup(pag, "Return_to_base_immediately"); break;
                case 6: lac.SayToGroup(pag, "Returning_to_base"); break;
                case 7: lac.SayToGroup(pag, "We_are_heading_home"); break;
                case 8: lac.SayToGroup(pag, "We_are_returning_to_base"); break;
                default: lac.SayToGroup(pag, "Disengage_disengage_let_s_get_out_of_here"); break;
            };
        };
    }
    private Point2d HalfwayToTarget2d(AiAirGroup ag)
    {
        AiActor a = GetFlightLeader(ag);
        AiAircraft ac = (AiAircraft)a;
        Point2d halfw2d = new Point2d(ac.Pos().x, ac.Pos().y); // temp use
        Point3d refPos3d = new Point3d(target2d.x, target2d.y, ac.Pos().z);
        int dist = (int)(ac.Pos().distance(ref refPos3d));
        double dir = calcDir(halfw2d, target2d);
        halfw2d = calcPos(halfw2d, dist, dir);
        return halfw2d;
    }
    private string[] SquadronsOnCAP()
    {
        List<string> result = new List<string>();

        // CAP
        AiAirGroupsCAP.Clear();
        //foreach (AiAirGroup ag in GamePlay.gpAirGroups(GamePlay.gpPlayer().Army()))
        foreach (AiAirGroup ag in AiAirGroupsStdby)
            if (ag.Army() == GamePlay.gpPlayer().Army())
                if ((AiGroup)ag != GamePlay.gpPlayer().Place().Group())
                    foreach (MissionAirbase ab in MissionAirbases)
                        if (ag.Name().Contains(ab.sqn) && !ab.name.Contains(homeBase.name))
                        {
                            if (SquadronIsFrench(ab.sqn)) result.Add(ab.name + " " + ab.airportName.Replace('_', ' ') + ", " + DesignationAdA(ab.aircraftType));
                            else result.Add(ab.name + " " + ab.airportName.Replace('_', ' ') + ", " + Designation(ab.aircraftType));
                            AiAirGroupsCAP.Add(ag);
                            break;
                        };

        // sweep
        foreach (AiAirGroup ag in GamePlay.gpAirGroups(GamePlay.gpPlayer().Army()))
            if (sweepGroups.Contains(ag.Name()))
                foreach (MissionAirbase ab in MissionAirbases)
                    if (ag.Name().Contains(ab.sqn) && !ab.name.Contains(homeBase.name))
                    {
                        if (SquadronIsFrench(ab.sqn)) result.Add(ab.name + " " + ab.airportName.Replace('_', ' ') + ", " + DesignationAdA(ab.aircraftType));
                        else result.Add(ab.name + " " + ab.airportName.Replace('_', ' ') + ", " + Designation(ab.aircraftType));
                        AiAirGroupsCAP.Add(ag);
                        break;
                    };

        return result.ToArray();
    }
    private string[] PlayerPossibleAirports(Player player)
    {
        List<string> result = new List<string>();

        AiActor actor = player.Place();
        Point3d playerPos3d = actor.Pos();
        Point2d playerPos2d = new Point2d(playerPos3d.x, playerPos3d.y);
        // AiAirports
        PossibleAirports.Clear();
        List<AiAirport> saps = SortedAirports(player.Army(), playerPos2d, false);
        //GamePlay.gpLogServer(null, "PlayerPossibleAirports: {0} from {1}", new object[] { saps.Count, GamePlay.gpAirports().Length });
        foreach (AiAirport ap in saps)
        {
            result.Add(ap.Name().Replace('_', ' '));
            PossibleAirports.Add(ap);
            if (result.Count > 7)
                break;
        };
        //GamePlay.gpLogServer(null, "PlayerPossibleAirports: {0} to {1}", new object[] { saps.Count, PossibleAirports.Count });

        return result.ToArray();
    }

    private void sayDirection(AiAircraft ac, AiAirGroup grp, Point3d pt3d)
    {
        if (ac == null)
            return;
        if (grp == null)
            return;
        AiActor refActor = GetFlightLeader(grp);
        if (refActor == null)
            return;
        int dir = (int)(calcDir(new Point2d(refActor.Pos().x, refActor.Pos().y), new Point2d(pt3d.x, pt3d.y)));
        string strDir = dir.ToString();
        for (int i = 0; i < strDir.Length; i++)
            ac.SayToGroup(grp, strDir[i].ToString());
    }
    private void sayDistance(AiAircraft ac, AiAirGroup grp, Point3d pt3d)
    {
        if (ac == null)
            return;
        if (grp == null)
            return;
        AiActor refActor = GetFlightLeader(grp);
        if (refActor == null)
            return;
        Point3d refPos3d = refActor.Pos();
        int dist = (int)(pt3d.distance(ref refPos3d) / 1000);
        if (grp.Army() == RAF)
        {
            int miles = (int)(dist * .62f);
            if (miles > 5)
            {
                ac.SayToGroup(grp, "Distance"); // "Range"
                if (miles < 16) ac.SayToGroup(grp, miles.ToString() + "_miles");
                else
                {
                    int tens = 10 * (miles / 10); // and hundreds
                    sayNumber(ac, grp, tens.ToString());
                    sayNumber(ac, grp, (miles % 10).ToString() + "_miles");
                };
            };
        }
        else
        {
            if (dist > 34)
                return;
            int km = dist;
            if (km > 15) km = km - (km % 5);
            if (km > 2)
            {
                ac.SayToGroup(grp, "Distance"); // "Range"
                ac.SayToGroup(grp, km.ToString() + "_kilometers");
            };
        };
    }
    private void sayAltitude(AiAircraft ac, AiAirGroup grp, double m)
    {
        if (ac == null)
            return;
        if (grp == null)
            return;
        if (grp.Army() == RAF)
        {
            int angels = (int)((m + 164) / 328);
            if (angels > 0)
                ac.SayToGroup(grp, angels.ToString() + "0hi");
        }
        else
        {
            int km500 = (int)((m + 250) / 100);
            km500 = km500 - (km500 % 5);
            if (km500 > 0)
            {
                ac.SayToGroup(grp, "Height");
                ac.SayToGroup(grp, km500.ToString() + "h");
            }
            else
            {
                int m100 = (int)(m + 50 / 100);
                if (m100 > 0)
                {
                    ac.SayToGroup(grp, "Height");
                    ac.SayToGroup(grp, m100.ToString() + "h");
                }
            };
            //if (odenDebug) GamePlay.gpLogServer(null, "sayAltitude: {0} >> {1}", new object[] { m, km500.ToString() });
        };
    }
    private void sayGrid(AiAircraft ac, AiAirGroup grp, string targetSector)
    {
        if (ac == null)
            return;
        if (grp == null)
            return;
        ac.SayToGroup(grp, "In_square");
        string[] arrEWNS = { "vb_East_of", "vb_West_of" };
        for (int i = 0; i < targetSector.Length; i++)
        {
            switch (targetSector[i])
            {
                case ',':
                    arrEWNS[0] = "vb_North_of";
                    arrEWNS[1] = "vb_South_of";
                    break;
                case '>':
                    ac.SayToGroup(grp, arrEWNS[0]);
                    break;
                case '<':
                    ac.SayToGroup(grp, arrEWNS[1]);
                    break;
                default:
                    ac.SayToGroup(grp, targetSector[i].ToString());
                    break;
            };
        };
    }
    private void sayNumber(AiAircraft ac, AiAirGroup ag, string mixedString)
    {
        if (ac == null)
            return;
        if (ag == null)
            return;
        //char[] numerals = new char[]{'0','1','2','3','4','5','6','7','8','9'};
        List<string> nums = new List<string>();
        string num = "0123456789";

        //foreach (char ch in ac.Regiment().name()) //BoB_RAF_F_141Sqn_Early
        for (int i = 0; i < mixedString.Length; i++)
            if (num.Contains(mixedString[i].ToString()))
                nums.Add(mixedString[i].ToString());

        num = ""; // hundreds
        if (nums.Count == 3)
        {
            num = nums[0] + "h";
            nums.RemoveAt(0);
        };
        if (nums.Count == 2)
            switch (nums[0])
            {
                case "0":
                    nums.RemoveAt(0);
                    break;
                case "1":
                    nums[0] = nums[0] + nums[1];
                    nums.RemoveAt(1);
                    break;
                case "2":
                    if (nums[1].IndexOfAny(new char[] { '4', '5', '6', '7', '8' }) > -1)
                    {
                        nums[0] = nums[0] + nums[1];
                        nums.RemoveAt(1);
                    };
                    break;
                case "3":
                    nums[0] = nums[0] + nums[1];
                    nums.RemoveAt(1);
                    break;
                case "4": nums[0] = "n40"; break;
                case "5": nums[0] = "50s"; break;
                case "6": nums[0] = "60s"; break;
                case "7": nums[0] = "70s"; break;
                case "8": nums[0] = "80s"; break;
                case "9": nums[0] = "90s"; break;
            };

        if (num.Length > 0) ac.SayToGroup(ag, num); // hundreds
        foreach (string str in nums)
            ac.SayToGroup(ag, str);
    }
    private void sayGroundTarget(AiAircraft ac, AiAirGroup ag, Point2d pt2d)
    {
        if (ac == null)
            return;
        if (ag == null)
            return;
        ac.SayToGroup(ag, "Enemy_group");
        if (GamePlay.gpLandType(pt2d.x, pt2d.y) == LandTypes.WATER) ac.SayToGroup(ag, "Cargo_Ships");
        else ac.SayToGroup(ag, "Transport_column");
        ac.SayToGroup(ag, groundAssaultFrom);
        // doesnt work ac.SayToGroup(ag, "Friendlies");
        ac.SayToGroup(ag, "Next_check_point");
        sayGrid(ac, ag, GamePlay.gpSectorName(pt2d.x, pt2d.y));
    }
    private void sayBombTarget(AiAircraft ac, AiAirGroup ag, Point2d pt2d)
    {
        if (ac == null)
            return;
        if (ag == null)
            return;
        string targetType = "Enemy_group";
        if (convoyTarget != null) targetType = "Cargo_Ships";
        if (mainGSTarget != null) targetType = "Enemy_Position";
        if (targetAirport != null) targetType = "Enemy_Airfield";
        ac.SayToGroup(ag, targetType);
        sayGrid(ac, ag, GamePlay.gpSectorName(pt2d.x, pt2d.y));
    }

    private void SetOrderMissionMenuOden(Player player)
    {
        bool isSubMenu = false;
        int menuID = 0;

        PlayerData pd = PlayersData.Find(x => x.player == player);
        string captionSwitchSqn = "Transfer to Squadron";
        if (player.Army() == LW) captionSwitchSqn = "Transfer to Staffel";
        //if (odenDebug) GamePlay.gpLogServer(null, "SetOrderMissionMenuOden {0} {1}", new object[] { captionSwitchSqn, pd.homeAirport.Name().Replace('_', ' ') });
        string[] OrderMissionMenuKeys = new string[]
	    {
            "Request Assistance"
		    ,"Leader, where are you?"
            ,"Closest Friendly Flight"
            ,"Closest Enemy Flight"
            ,"Request Vector to " +pd.homeAirport.Name().Replace('_', ' ')
            ,"Select Airfield"
            ,captionSwitchSqn
	    };

        bool[] OrderMissionMenuSubMenu = new bool[]
	    {
		    true
		    ,false
		    ,false
		    ,false
		    ,false
		    ,true
            ,true
	    };
        if (player.Army() == LW || PlayerIsBomber())
        {
            OrderMissionMenuKeys[5] = "Target Information";
            OrderMissionMenuSubMenu[5] = false;
        };
        GamePlay.gpSetOrderMissionMenu(player, isSubMenu, menuID, OrderMissionMenuKeys, OrderMissionMenuSubMenu);
    }
    private void SetOrderMissionSubMenuRequest()
    {
        bool isSubMenu = true;
        int menuID = 1;
        string[] OrderMissionMenuKeys = SquadronsOnCAP();
        List<bool> menuActive = new List<bool>();
        foreach (string str in OrderMissionMenuKeys)
            menuActive.Add(false);
        bool[] OrderMissionMenuSubMenu = menuActive.ToArray();

        GamePlay.gpSetOrderMissionMenu(GamePlay.gpPlayer(), isSubMenu, menuID, OrderMissionMenuKeys, OrderMissionMenuSubMenu);
    }
    private void SetOrderMissionSubMenuAirfields(Player player)
    {
        bool isSubMenu = true;
        int menuID = 2;
        string[] OrderMissionMenuKeys = PlayerPossibleAirports(player);
        List<bool> menuActive = new List<bool>();
        foreach (string str in OrderMissionMenuKeys)
            menuActive.Add(false);
        bool[] OrderMissionMenuSubMenu = menuActive.ToArray();

        GamePlay.gpSetOrderMissionMenu(player, isSubMenu, menuID, OrderMissionMenuKeys, OrderMissionMenuSubMenu);
    }
    private void SetOrderMissionSubMenuTransfer(Player player)
    {
        bool isSubMenu = true;
        int menuID = 3;
        PossibleMissionAirbases.Clear();
        AiActor actor = player.Place();
        Point3d playerPos3d = actor.Pos();
        Point2d playerPos2d = new Point2d(playerPos3d.x, playerPos3d.y);
        List<string> Flyables = new List<string>();
        Flyables.AddRange(RAFFighterSet);
        Flyables.AddRange(RAFBomberSet);
        Flyables.AddRange(LWFighterSet);
        Flyables.AddRange(LWBomberSet);
        Flyables.AddRange(RAFighterSet);
        Flyables.AddRange(RABomberSet);
        List<MissionAirbase> MAList = SortedAirbases(actor.Army(), playerPos2d, PlayerIsBomber(), true, false); // bomber, battlearea
        List<string> sqnNames = new List<string>();
        foreach (MissionAirbase ma in MAList)
        {
            if (ma.ap != null)
                if (Flyables.Contains(ma.aircraftType))
                {
                    sqnNames.Add(ma.name + " " + ma.airportName.Replace('_', ' ') + ", " + Designation(ma.aircraftType));
                    PossibleMissionAirbases.Add(ma);
                    if (sqnNames.Count > 7)
                        break;
                };
        };
        string[] OrderMissionMenuKeys = sqnNames.ToArray();
        List<bool> menuActive = new List<bool>();
        foreach (string str in OrderMissionMenuKeys)
            menuActive.Add(false);
        bool[] OrderMissionMenuSubMenu = menuActive.ToArray();

        GamePlay.gpSetOrderMissionMenu(player, isSubMenu, menuID, OrderMissionMenuKeys, OrderMissionMenuSubMenu);
    }
    public override void OnOrderMissionMenuSelected(Player player, int ID, int menuItemIndex)
    {
        base.OnOrderMissionMenuSelected(player, ID, menuItemIndex);

        AiAircraft fc = FighterCommand;

        switch (ID)
        {
            case 0:
                AiActor actor = player.Place();
                Point3d playerPos3d = actor.Pos();
                Point2d playerPos2d = new Point2d(playerPos3d.x, playerPos3d.y);
                double mag_compass = 0;
                AiAirGroup playerGroup = (actor as AiAircraft).AirGroup();
                string playerSector = GamePlay.gpSectorName(actor.Pos().x, actor.Pos().y);
                AiActor leader = GetFlightLeader(playerGroup);
                AiAircraft ac;

                switch (menuItemIndex)
                {
                    case 0:
                        SetOrderMissionMenuOden(player);
                        break;
                    case 1: // "Request Fighter Support"
                        if (AiAirGroupsStdby.Count > 0) SetOrderMissionSubMenuRequest();
                        else SetOrderMissionMenuOden(player);
                        break;
                    case 2: //"Leader, where are you?"
                        timeoutRadio = DateTime.Now;
                        timeoutRadio.AddSeconds(12);
                        //(actor as AiAircraft).SayToGroup(playerGroup, (leader as AiAircraft).CallSign()); // Leader
                        //(actor as AiAircraft).SayToGroup(playerGroup, "n_");
                        (actor as AiAircraft).SayToGroup(playerGroup, "Where_are_you");
                        //(actor as AiAircraft).SayToGroup(playerGroup, "Over");
                        if (leader == null)
                            return;
                        ac = (AiAircraft)leader;
                        string leaderSector = GamePlay.gpSectorName(ac.Pos().x, ac.Pos().y);
                        Timeout(5, () =>
                        {
                            ac.SayToGroup(playerGroup, ac.CallSign());
                            ac.SayToGroup(playerGroup, "n1"); // Leader
                            sayGrid(ac, playerGroup, leaderSector);
                            sayAltitude(ac, playerGroup, leader.Pos().z);
                            if (TargetGroup == null && EscortedGroup == null && gameIsOn)
                                sayMissionOver(missionVictory);
                            int angels = (int)((actor.Pos().z + 164) / 328);
                            if (player.Army() == RAF) GamePlay.gpHUDLogCenter(new Player[] { player }, "Flight is in [" + leaderSector + "] at Angels " + angels.ToString());
                            else GamePlay.gpHUDLogCenter(new Player[] { player }, "Flight is in [" + leaderSector + "] at " + actor.Pos().z.ToString("F0") + "m");

                        });
                        break;
                    case 3: // "Closest Friendly Flight"
                        //GamePlay.gpHUDLogCenter(new Player[] { GamePlay.gpPlayer() }, "Set your gyro to " + (actor as AiAircraft).getParameter(part.ParameterTypes.Z_Orientation, 0).ToString());
                        timeoutRadio = DateTime.Now;
                        timeoutRadio.AddSeconds(12);
                        //(actor as AiAircraft).SayToGroup(playerGroup, "callsign1");
                        (actor as AiAircraft).SayToGroup(playerGroup, "Vector");
                        (actor as AiAircraft).SayToGroup(playerGroup, "Friendlies");
                        (actor as AiAircraft).SayToGroup(playerGroup, "Over");
                        Timeout(5, () =>
                        {
                            List<AiAircraft> sacs = SortedAircrafts((actor.Army() == RAF) ? LW : RAF, playerPos3d);
                            if (sacs.Count > 0)
                            {
                                ac = sacs[1];
                                if (ac.IsValid() && ac.IsAlive())
                                {
                                    //string planeType = bobDesignation((actorPlane as AiAircraft).InternalTypeName());
                                    fc.SayToGroup(playerGroup, "Ground_control_here_Stand_by");
                                    //if (actorPlane is AiAircraft) mag_compass = (actorPlane as AiAircraft).getParameter(part.ParameterTypes.I_MagneticCompass, 0);
                                    fc.SayToGroup(playerGroup, "Friendlies");
                                    fc.SayToGroup(playerGroup, "Direction"); // "Bearing"
                                    sayDirection(fc, playerGroup, ac.Pos());
                                    sayDistance(fc, playerGroup, ac.Pos());
                                    /*angels = (int)((ac.Pos().z + 164) / 328);
                                    if (angels > 0)
                                    {
                                        //fc.SayToGroup(localGroup, "Height");
                                        fc.SayToGroup(playerGroup, angels.ToString() + "0hi");
                                    };
                                    */
                                    sayAltitude(fc, playerGroup, leader.Pos().z);

                                    string sn = GamePlay.gpSectorName(ac.Pos().x, ac.Pos().y);
                                    AiActor refActor = GetFlightLeader(playerGroup);
                                    Point3d refPos3d = refActor.Pos();
                                    int dir = (int)(calcDir(new Point2d(refActor.Pos().x, refActor.Pos().y), new Point2d(ac.Pos().x, ac.Pos().y)));
                                    double dist = (int)(ac.Pos().distance(ref refPos3d) / 1000);
                                    int miles = (int)(dist * .62f);
                                    int angels = (int)((ac.Pos().z + 164) / 328);
                                    if (player.Army() == RAF) GamePlay.gpHUDLogCenter(new Player[] { player }, "Nearest Friendly Flight Bearing " + dir.ToString() + ", " + miles.ToString() + " miles at Angels " + angels.ToString() + " [" + sn + "]");
                                    else GamePlay.gpHUDLogCenter(new Player[] { player }, "Nearest Friendly Flight Bearing " + dir.ToString() + ", " + dist.ToString("F0") + "km at " + ac.Pos().z.ToString("F0") + "m" + " [" + sn + "]");

                                }
                                else { fc.SayToGroup(playerGroup, "Return_to_base_immediately"); };
                            }
                            else { fc.SayToGroup(playerGroup, "Return_to_base_immediately"); };
                        });
                        break;
                    case 4: // "Closest Enemy Flight"
                        if (player.Army() == LW)
                            if (EscortedGroup == null) return;
                            else
                                if (EscortedGroup.GetItems().Length > 0) fc = (AiAircraft)GetFlightLeader(EscortedGroup);
                                else return;

                        timeoutRadio = DateTime.Now;
                        timeoutRadio.AddSeconds(12);
                        //(actor as AiAircraft).SayToGroup(playerGroup, "callsign1");
                        (actor as AiAircraft).SayToGroup(playerGroup, "Vector");
                        (actor as AiAircraft).SayToGroup(playerGroup, "Enemy_planes");
                        (actor as AiAircraft).SayToGroup(playerGroup, "Over");
                        Timeout(10, () =>
                        {
                            List<AiAircraft> sacs = SortedAircrafts((actor.Army() == RAF) ? LW : RAF, playerPos3d);
                            if (sacs.Count > 0)
                            {
                                ac = sacs[0];
                                if (ac.IsValid() && ac.IsAlive())
                                {
                                    fc.SayToGroup(playerGroup, "Ground_control_here_Stand_by");
                                    fc.SayToGroup(playerGroup, "Enemy_group");
                                    //fc.SayToGroup(playerGroup, "Direction"); // "Bearing"
                                    sayDirection(fc, playerGroup, ac.Pos());
                                    sayDistance(fc, playerGroup, ac.Pos());
                                    sayAltitude(fc, playerGroup, leader.Pos().z);

                                    string sn = GamePlay.gpSectorName(ac.Pos().x, ac.Pos().y);
                                    AiActor refActor = GetFlightLeader(playerGroup);
                                    Point3d refPos3d = refActor.Pos();
                                    int dir = (int)(calcDir(new Point2d(refActor.Pos().x, refActor.Pos().y), new Point2d(ac.Pos().x, ac.Pos().y)));
                                    double dist = (int)(ac.Pos().distance(ref refPos3d) / 1000);
                                    int miles = (int)(dist * .62f);
                                    int angels = (int)((ac.Pos().z + 164) / 328);
                                    if (player.Army() == RAF) GamePlay.gpHUDLogCenter(new Player[] { player }, "Nearest Enemy Flight Bearing " + dir.ToString() + ", " + miles.ToString() + " miles at Angels " + angels.ToString() + " [" + sn + "]");
                                    else GamePlay.gpHUDLogCenter(new Player[] { player }, "Nearest Enemy Flight Bearing " + dir.ToString() + ", " + dist.ToString("F0") + "km at " + ac.Pos().z.ToString("F0") + "m" + " [" + sn + "]");

                                    if (playerGroup.isAircraftType(AircraftType.Fighter)
                                        || playerGroup.isAircraftType(AircraftType.BNZFighter)
                                        || playerGroup.isAircraftType(AircraftType.HeavyFighter)
                                        || playerGroup.isAircraftType(AircraftType.TNBFighter))
                                    {   // assign as target if none or new is closer
                                        if (TargetGroup == null)
                                            TargetGroup = ac.AirGroup();
                                        else
                                        {
                                            AiAirGroup ag = ac.AirGroup();
                                            if (ag.hasTorpedos() || ag.hasBombs() || ag.hasBombsInInternalBays())
                                            {
                                                if (ag.Pos().distance(ref playerPos3d) < TargetGroup.Pos().distance(ref playerPos3d))
                                                    TargetGroup = ac.AirGroup();
                                            };
                                        };
                                    };
                                }
                                else { fc.SayToGroup(playerGroup, "Mission_accomplished"); };
                            }
                            else { fc.SayToGroup(playerGroup, "Mission_accomplished"); };
                        });
                        break;
                    case 5: // "Request Vector to Airfield"
                        (actor as AiAircraft).SayToGroup(playerGroup, (actor as AiAircraft).CallSign());
                        (actor as AiAircraft).SayToGroup(playerGroup, "Check");
                        (actor as AiAircraft).SayToGroup(playerGroup, "Vector");
                        (actor as AiAircraft).SayToGroup(playerGroup, "Course");
                        Timeout(4, () => { fc.SayToGroup(playerGroup, "Ground_control_here_Stand_by"); });
                        Timeout(8, () =>
                        {
                            fc.SayToGroup(playerGroup, "Vector_to_base_is");
                            sayDirection(fc, playerGroup, homeAirport.Pos());
                            sayDistance(fc, playerGroup, homeAirport.Pos());

                            AiActor refActor = GetFlightLeader(playerGroup);
                            Point3d refPos3d = refActor.Pos();
                            int dir = (int)(calcDir(new Point2d(refActor.Pos().x, refActor.Pos().y), new Point2d(homeAirport.Pos().x, homeAirport.Pos().y)));
                            double dist = (int)(homeAirport.Pos().distance(ref refPos3d) / 1000);
                            int miles = (int)(dist * .62f);
                            if (player.Army() == RAF) GamePlay.gpHUDLogCenter(new Player[] { player }, homeAirport.Name().Replace('_', ' ') + " is Bearing " + dir.ToString() + ", " + miles.ToString() + " miles out");
                            else GamePlay.gpHUDLogCenter(new Player[] { player }, homeAirport.Name().Replace('_', ' ') + " is Bearing " + dir.ToString() + ", " + dist.ToString("F0") + "km out");

                        });
                        break;
                    case 6: // "Select Airfield" for RAF, Target Info for LW
                        if (player.Army() == RAF && !PlayerIsBomber())
                        {
                            SetOrderMissionSubMenuAirfields(player);
                        }
                        else
                        {
                            GamePlay.gpHUDLogCenter(new Player[] { player }, targetName);
                            SetOrderMissionMenuOden(player);
                        };
                        break;
                    case 7:
                        SetOrderMissionSubMenuTransfer(player);
                        break;
                };
                break;
            case 1: // "Request Fighter Support"
                switch (menuItemIndex)
                {
                    case 0:
                        SetOrderMissionMenuOden(player);
                        break;
                    default://
                        if (menuItemIndex <= AiAirGroupsCAP.Count) requestAssistance(menuItemIndex, true);
                        SetOrderMissionMenuOden(player);
                        break;
                };
                break;
            case 2: // "Select Airfield"
                switch (menuItemIndex)
                {
                    case 0:
                        SetOrderMissionMenuOden(player);
                        break;
                    default:
                        if (menuItemIndex <= PossibleAirports.Count) SetTempHomebase(player, menuItemIndex, true);
                        SetOrderMissionMenuOden(player);
                        break;
                };
                break;
            case 3: // Transfer to Sqn
                switch (menuItemIndex)
                {
                    case 0:
                        SetOrderMissionMenuOden(player);
                        break;
                    default:
                        if (menuItemIndex <= PossibleMissionAirbases.Count) TransferToSqn(menuItemIndex, player);
                        SetOrderMissionMenuOden(player);
                        break;
                };
                break;
            default:
                SetOrderMissionMenuOden(player);
                break;
        };
    }

    private void requestAssistance(int menuItemIndex, bool sayRequest)
    {
        if (AiAirGroupsCAP.Count < 1)
            return;
        AiAircraft fc = FighterCommand;
        if (fc == null)
            return;
        AiAircraft pac = (AiAircraft)GamePlay.gpPlayer().Place();
        if (pac == null)
            return;
        AiAirGroup pag = pac.AirGroup();
        timeoutRadio = DateTime.Now;
        timeoutRadio.AddSeconds(30);

        if (sayRequest) pac.SayToGroup(pag, "We_are_under_attack_we_need_assistance_over");
        else SquadronsOnCAP();

        Timeout(4, () => { fc.SayToGroup(pag, "Ground_control_here_Stand_by"); });

        Point2d pt2d = new Point2d(pac.Pos().x, pac.Pos().y);
        if (menuItemIndex > AiAirGroupsCAP.Count)
            Timeout(8, () => { fc.SayToGroup(pag, "Negative_all_available_fighters_are_busy_at_this_time_Sorry"); });
        else
        {
            AiAirGroup agSup = AiAirGroupsCAP[menuItemIndex - 1];
            if (agSup == null)
                Timeout(8, () => { fc.SayToGroup(pag, "Negative_all_available_fighters_are_busy_at_this_time_Sorry"); });
            else
            {
                GiveNewWP((AiGroup)agSup, pt2d);
                AiAirGroupsStdby.Remove(agSup);
                Timeout(8, () => { fc.SayToGroup(pag, "We_are_sending_fighters_to_your_location_Hang_on"); });
                Timeout(12, () =>
                {
                    AiAircraft ac = (AiAircraft)GetFlightLeader(agSup);
                    //ac.SayToGroup(pag, "This_Is_Commander");
                    //sayNumber(ac, pag, ac.Regiment().name());
                    //ac.SayToGroup(pag, ac.Regiment().speech()); //"Squadron");
                    //ac.SayToGroup(pag, "Sqaudron");
                    //ac.SayToGroup(pag, "parts\\bob\\speech\\gb\\Actor1\\Squadron.ogg");
                    ac.SayToGroup(pag, "We_re_coming_in_to_assist");
                    ac.SayToGroup(pag, "1_Flight");
                    sayNumber(ac, pag, ac.Regiment().name());
                    ac.SayToGroup(pag, "Let_s_go_get_them");
                });
            };
        };
    }
    private void TransferToSqn(int menuItemIndex, Player player)
    {
        MissionAirbase ma = PossibleMissionAirbases[menuItemIndex - 1];
        if (ma.name != homeBase.name)
        {
            GamePlay.gpHUDLogCenter(new Player[] { player }, "Transfer from " + homeBase.name + " to " + ma.name + " next mission");
            transferHomeBase = ma;
            playerWasAirborne = true;
            bombersLeavingTarget = true;
            Satellites.Clear();
            string sats = SatelliteStations(ma.sector);
            foreach (string s in sats.Split(','))
                Satellites.Add(s);
        };
    }
    private void SetMissionMarkerArmy(string markerName, int army)
    {
        foreach (MissionMarker mm in MissionMarkers)
            if (mm.key == markerName)
            {
                mm.army = army;
                break;
            };
    }
    private void SetTempHomebase(Player player, int menuItemIndex, bool sayRequest)
    {
        //GamePlay.gpLogServer(null, "SetTempHomebase: {0} at {1}", new object[] { PossibleAirports.Count, menuItemIndex });
        PlayerData pd = PlayersData.Find(x => player == x.player);
        pd.homeAirport = PossibleAirports[menuItemIndex - 1];
        homeAirport = pd.homeAirport;
        List<Player> players = AllPlayers(player.Army());
        foreach (Player p in players)
            SetOrderMissionMenuOden(p);
        ArmyHUDLogCenter(player.Army(), "New homebase: " + homeAirport.Name().Replace('_', ' '));
    }

    private MissionAirbase ParseAirGroup(string[] strs)
    {   // "AirGroup,RAF Biggin Hill,BoB_RAF_F_1Sqn,12,Hawkinge,Aircraft.HurricaneMkI_100oct"
        AiAirport airport = null;
        foreach (AiAirport ap in GamePlay.gpAirports())
            if (ap.Name().Equals(strs[4]))
            {
                airport = ap;
                break;
            };
        string name = strs[2];
        if (name.Contains("RAF_"))
        {
            name = name.Substring(10); // BoB_RAF_F_264Sqn >> 264Sqn
            name = name.Insert(name.Length - 3, " ");
        };
        if (name.Contains("LW_"))
        {
            name = name.Substring(7); // BoB_LW_KG2_I >> KG2_I
            int pos = name.IndexOf('_');
            if (pos > -1 && (name.Contains("I") || name.Contains("Stab")))
            {
                string gruppe = name.Substring(pos + 1);
                name = gruppe + "./" + name.Substring(0, pos);
            };
        };
        if (name.Contains("RA_"))
            name = name.Substring(7); // BoB_RA_56St_20Gruppo_353Sq >> 56St_20Gruppo_353Sq
        if (name.Contains("Gruppo"))
            name = name.Replace("Gruppo", "Gr");
        name = name.Replace('_', ' ');

        string country = "gb";
        if (strs[2].Contains("LW")) country = "de";
        if (strs[2].Contains("RA_")) country = "it";
        if (strs[2].Contains("RAAF_")) country = "au";
        if (strs[2].Contains("SAAF_")) country = "sa";
        if (strs[2].Contains("_PL")) country = "pl";
        if (strs[2].Contains("_CZ")) country = "cz";
        if (strs[2].Contains("_RCAF")) country = "ca";
        if (SquadronIsFrench(strs[2]))
        {
            name = strs[1];
            country = "fr";
        };
        if (!country.Contains("de") && !country.Contains("it")) name = CountryAirforce(country) + " " + name;
        int army = CountrySide(country);

        int maxPlanes = 0;
        if (!int.TryParse(strs[3], out maxPlanes))
            maxPlanes = 0;

        // 360000x:270000y is Belgium/Germany Map Entry Point - use when Base name not found (KG4 Schiphol etc)
        // 180000x:310000y is Essex/Suffolk Map Entry Point (RAF Bomber Squadrons)
        Point2d pt2d = new Point2d(360000, 270000);
        if (airport != null)
        {
            pt2d.x = airport.Pos().x;
            pt2d.y = airport.Pos().y;
        }
        else
        {
            if (country == "gb")
            {
                pt2d.x = 180000;
                pt2d.y = 310000;
            };
        };

        string type = "RAF_Fighter_1939";
        if (strs[2].Contains("RAF_B")) type = "RAF_Bomber_1940";
        if (strs[2].Contains("RA_43St")) type = "RegiaAeronautica_Bomber_1940";
        if (strs[2].Contains("RA_13St")) type = "RegiaAeronautica_Bomber_1940";
        if (strs[2].Contains("RA_53St")) type = "RegiaAeronautica_Fighter_1940";
        if (strs[2].Contains("LW_JG")) type = "Luftwaffe_Fighter_1940";
        if (strs[2].Contains("LW_LG")) type = "Luftwaffe_Fighter_1940";
        if (strs[2].Contains("LW_LG1")) type = "Luftwaffe_Bomber_1940"; // Ju88
        if (strs[2].Contains("LW_LG1_IV")) type = "Luftwaffe_Stuka_1940";
        if (strs[2].Contains("LW_LG1_V")) type = "Luftwaffe_Zerstorer_1940";
        if (strs[2].Contains("LW_LG2_I")) type = "Luftwaffe_Fighter_1940"; // Bf109E-4, Calais-Marck
        if (strs[2].Contains("LW_LG2_II")) type = "Luftwaffe_Bomber_1940"; // Bf109E-4B, St Omer
        if (strs[2].Contains("LW_KG")) type = "Luftwaffe_Bomber_1940";
        if (strs[2].Contains("LW_ZG")) type = "Luftwaffe_Zerstorer_1940";
        if (strs[2].Contains("LW_StG")) type = "Luftwaffe_Stuka_1940";
        if (strs[2].Contains("LW_Auf")) type = "Luftwaffe_Recon_1940";
        if (strs[2].Contains("LW_ErprGr210")) type = "Luftwaffe_Zerstorer_1940";
        if (strs[2].Contains("LW_ErprGr210F")) type = "Luftwaffe_Fighter_1940";
        if (strs[2].Contains("_Stab"))
        {
            if (strs[2].Contains("LW_JG")) type = "Luftwaffe_Stabstaffel_1940";
            if (strs[2].Contains("LW_ZG")) type = "Luftwaffe_Zerstorer_Stabstaffel_1940";
            if (strs[2].Contains("LW_KG")) type = "Luftwaffe_Bomber_Stabstaffel_1940";
            if (strs[2].Contains("LW_StG")) type = "Luftwaffe_Stuka_Stabstaffel_1940";
        };
        string sqn = strs[2];
        string sector = strs[1];
        if (strs[2].Contains("BoB_RAF_F_"))
            if (gameDateTime.Year < 1941) sqn = sqn + "_Early";
            else sqn = sqn + "_Late";
        //if (odenDebug) GamePlay.gpLogServer(null, "ParseAirGroup: {0} {1} {2}", new object[] { name, sqn, type });
        MissionAirbase mab = new MissionAirbase(name
            , army
            , pt2d.x
            , pt2d.y
            , 0, maxPlanes, true, true
            , country, type, sqn, sector, strs[5], airport, strs[4]);
        return mab;
    }
    private void UpdateInitFile()
    {
        //if (odenDebug) GamePlay.gpLogServer(null, "UpdateInitFile: {0} {1}", new object[] { homeBase.airportName, homeBase.aircraftType });
        bool forceSwitchSqn = false;
        using (StreamWriter sw = File.CreateText(CampInitFile))
        {
            string[] strDynCamp = { "//" +CampaignName +" " +CampaignPhase()
                                  , "//Dynamic Mission by theOden"
                                  , "//This file keeps track of units etc. and may carefully be edited manually"
                                  , "//Entries can be in any order"
                                  , "//AirGroup,Sector,Squadron/Gruppe,Quantity,Airfieldname,AircraftType - all CliffsOfDover data"
                                  , "//AirportDamage,Airfieldname,Damage - all CliffsOfDover data (GamePlay.gpAirports())"
                                  , "//GndStatDead,StaticName - all CliffsOfDover data as per mis-file [Stationary]"
                                  , "//Event,add/remove/move/newplanetype,date as '16 August 1940',AirGroup,{newAirport/newPlaneType}"
                                  , "//Player Squadron must be edited in mission editor"
                                  , "//Coalition can be country code or 'al' for Allied, 'cw' for commonwealth and 'ax' for Axis"
                                  , "//-"};
            foreach (string str in strDynCamp)
                sw.WriteLine(str);

            sw.WriteLine("CampaignDate," + gameDateTime.ToString("D"));
            //if (odenDebug) GamePlay.gpLogServer(null, "UpdateInitFile ReinforcementDate: {0}", new object[] { ReinforcementDate.ToString("D") });
            if (ReinforcementDate < gameDateTime)
            {
                foreach (MissionAirbase ab in MissionAirbases)
                    if (ab.army == RAF)
                        ab.maxPlanes += 1;
                ReinforcementDate = ReinforcementDate.AddDays(rnd.Next(2, 5));
                //if (odenDebug) GamePlay.gpLogServer(null, "UpdateInitFile ReinforcementDate: {0}", new object[] { ReinforcementDate.ToString("D") });
            };
            sw.WriteLine("ReinforcementDate," + ReinforcementDate.ToString("D"));
            sw.WriteLine("HighOctaneDate," + highOctaneDate.ToString("D"));
            sw.WriteLine("RedCoalition," + RedCoalition);
            sw.WriteLine("BlueCoalition," + BlueCoalition);
            sw.WriteLine("CurrentBattle," + fmCurrent);
            sw.WriteLine("OnOffensive," + SideOnOffensive.ToString());
            sw.WriteLine("BattleProgress," + BattleProgress.ToString());
            sw.WriteLine("ConsecutiveLosses," + ConsecutiveLosses.ToString());
            if (Satellites.Count > 0)
                sw.WriteLine("Satellites," + string.Join(",", Satellites.ToArray()));

            // Spitfire MkII option
            if (CampaignName == cBattleOfBritain)
                if (gameDateTime.Month > 8)
                    if (homeBase.aircraftType.Contains("Spitfire"))
                        if (!homeBase.aircraftType.Contains("SpitfireMkIIa"))
                            if (rnd.Next(0, 99) > 95)
                            {
                                homeBase.aircraftType = "Aircraft.SpitfireMkIIa";
                                mainStoryList.Add(homeBase.name + " recieved " + Designation(homeBase.aircraftType));
                            };

            int forEachIdx = 0;
            foreach (MissionAirbase ab in MissionAirbases)
            {
                //List<string> newPlaneSet = new List<string>();
                if (highOctaneDate > gameDateTime)
                {
                    switch (ab.aircraftType)
                    {
                        case "Aircraft.HurricaneMkI_dH5-20_100oct": ab.aircraftType = "Aircraft.HurricaneMkI_dH5-20"; break;
                        case "Aircraft.HurricaneMkI_100oct": ab.aircraftType = "Aircraft.HurricaneMkI"; break;
                        case "Aircraft.SpitfireMkI_100oct": ab.aircraftType = "Aircraft.SpitfireMkI"; break;
                        case "Aircraft.SpitfireMkIa_100oct": ab.aircraftType = "Aircraft.SpitfireMkIa"; break;
                    };
                }
                else
                {
                    switch (ab.aircraftType)
                    {
                        case "Aircraft.HurricaneMkI_dH5-20": ab.aircraftType = "Aircraft.HurricaneMkI_dH5-20_100oct"; break;
                        case "Aircraft.HurricaneMkI": ab.aircraftType = "Aircraft.HurricaneMkI_100oct"; break;
                        case "Aircraft.SpitfireMkI": ab.aircraftType = "Aircraft.SpitfireMkI_100oct"; break;
                        case "Aircraft.SpitfireMkIa": ab.aircraftType = "Aircraft.SpitfireMkIa_100oct"; break;
                    };
                };
                string sqn = ab.sqn;
                if (sqn.Contains("_Early"))
                    sqn = sqn.Remove(sqn.IndexOf("_Early"));
                if (sqn.Contains("_Late"))
                    sqn = sqn.Remove(sqn.IndexOf("_Late"));
                if (CampaignName == cBattleOfBritain)
                {
                    bool spreadLosses = false;
                    if (ab.army == LW)
                    {
                        if (ab.type.Contains("Fighter") && misLWDeadF > rnd.Next(0, 10)) spreadLosses = true;
                        if (ab.type.Contains("Bomber") && misLWDeadB > rnd.Next(0, 10)) spreadLosses = true;
                        if (ab.type.Contains("Zerstorer") && misLWDeadF > rnd.Next(0, 10)) spreadLosses = true;
                        if (ab.type.Contains("Stuka") && misLWDeadS > rnd.Next(0, 10)) spreadLosses = true;
                    };
                    if (ab.army == RAF)
                    {
                        if (ab.type.Contains("Fighter") && misRAFDeadF > rnd.Next(0, 10)) spreadLosses = true;
                        if (ab.type.Contains("Bomber") && misRAFDeadB > rnd.Next(0, 10)) spreadLosses = true;
                    };
                    if (activatedGroups.Contains(ab.sqn)) spreadLosses = false; // active in mission
                    if (spreadLosses) ab.maxPlanes--;
                };
                if (ab.maxPlanes > 2 && ab.army == GamePlay.gpFrontArmy(ab.x, ab.y))
                    sw.WriteLine("AirGroup," + ab.sector + "," + sqn + "," + ab.maxPlanes.ToString() + "," + ab.airportName + "," + ab.aircraftType);
                else
                {
                    if (ab.ap != null)
                    {
                        mainStoryList.Add(ab.name + " was withdrawn.");
                        if (ab.name == homeBase.name) forceSwitchSqn = true;
                    };
                };

                forEachIdx++;
            };

            if (bombsOnTarget > 0)
            {
                string story = "";
                if (targetAirport != null)
                {
                    string strDmg = AirportsDamaged.Find(x => x.Contains(targetAirport.Name()));
                    int pos = AirportsDamaged.IndexOf(strDmg);
                    double percent = 100 * (bombsOnTarget / (targetAirport.CoverageR() * targetAirport.CoverageR() / 100) / 2); // 50% is a 2500kg bombload on a 500m base (500*500/100)
                    if (percent > 100) percent = 100;
                    if (pos == -1)
                    {   // add new entry
                        AirportsDamaged.Add(targetAirport.Name() + "," + percent.ToString("F0"));
                        story = CountryAirforce((ATK == LW ? BlueCoalition : RedCoalition)) + " bombed " + targetAirport.Name().Replace('_', ' ') + ", " + percent.ToString("F0") + "% damaged.";
                    }
                    else
                    {   // update existing entry
                        int prevDmg = 0;
                        if (int.TryParse(strDmg.Substring(strDmg.IndexOf(",") + 1), out prevDmg))
                        {
                            AirportsDamaged[pos] = targetAirport.Name() + "," + (prevDmg + percent).ToString();
                            story = CountryAirforce((ATK == LW ? BlueCoalition : RedCoalition)) + " bombed " + targetAirport.Name().Replace('_', ' ') + " again, now +" + percent.ToString("F0") + "% damaged to a total of " + (prevDmg + percent).ToString("F0") + "%";
                        };
                    };
                };
                if (mainGSTarget != null)
                {
                    Point2d pt2d = new Point2d(mainGSTarget.pos.x, mainGSTarget.pos.y);
                    int targetArmy = GamePlay.gpFrontArmy(pt2d.x, pt2d.y);
                    if (mainGSTarget.Title.Contains("EnglishRadar3"))
                    {
                        string areaName = ChainHomeRadarName(pt2d);
                        string strDmg = CHRadarDamaged.Find(x => x.Contains(mainGSTarget.Name));
                        int pos = CHRadarDamaged.IndexOf(strDmg);
                        double percent = 100 * (bombsOnTarget / 10000); // 100% is a 10000kg bombload total
                        if (percent > 100) percent = 100;
                        if (pos == -1)
                        {   // add new entry
                            CHRadarDamaged.Add(mainGSTarget.Name + "," + percent.ToString("F0"));
                            story = CountryAirforce((ATK == LW ? BlueCoalition : RedCoalition)) + " bombed " + areaName + ", " + percent.ToString("F0") + "% damaged.";
                        }
                        else
                        {   // update existing entry
                            int prevDmg = 0;
                            if (int.TryParse(strDmg.Substring(strDmg.IndexOf(",") + 1), out prevDmg))
                            {
                                if (prevDmg + percent > 100) percent = 100 - prevDmg;
                                CHRadarDamaged[pos] = mainGSTarget.Name + "," + (prevDmg + percent).ToString();
                                story = CountryAirforce((ATK == LW ? BlueCoalition : RedCoalition)) + " bombed " + areaName + " again, now +" + percent.ToString("F0") + "% damaged to a total of " + (prevDmg + percent).ToString() + "%";
                            };
                        };
                    };
                    if (mainGSTarget.Title.Contains("PortCrane1_UK1"))
                    {
                        string areaName = PortDockName(pt2d);
                        string strDmg = PortDamaged.Find(x => x.Contains(mainGSTarget.Name));
                        int pos = PortDamaged.IndexOf(strDmg);
                        double percent = 100 * (bombsOnTarget / 10000); // 100% is a 10000kg bombload total
                        if (percent > 100) percent = 100;
                        if (pos == -1)
                        {   // add new entry
                            PortDamaged.Add(mainGSTarget.Name + "," + percent.ToString("F0"));
                            story = CountryAirforce((ATK == LW ? BlueCoalition : RedCoalition)) + " bombed " + areaName + ", " + percent.ToString("F0") + "% damaged.";
                            if (percent > 50 && targetArmy == RAF) ReinforcementDate = ReinforcementDate.AddDays(7 * (percent / 100));
                            if (percent > 50 && targetArmy == RAF) highOctaneDate = highOctaneDate.AddDays(7 * (percent / 100));
                        }
                        else
                        {   // update existing entry
                            int prevDmg = 0;
                            if (int.TryParse(strDmg.Substring(strDmg.IndexOf(",") + 1), out prevDmg))
                            {
                                if (prevDmg + percent > 100) percent = 100 - prevDmg;
                                PortDamaged[pos] = mainGSTarget.Name + "," + (prevDmg + percent).ToString();
                                story = CountryAirforce((ATK == LW ? BlueCoalition : RedCoalition)) + " bombed " + areaName + " again, now +" + percent.ToString() + "% damaged to a total of " + (prevDmg + percent).ToString() + "%";
                                if (percent > 50 && targetArmy == RAF) ReinforcementDate = ReinforcementDate.AddDays(7 * (percent / 100));
                                if (percent > 50 && targetArmy == RAF) highOctaneDate = highOctaneDate.AddDays(7 * (percent / 100));
                            };
                        };
                    };
                    if (mainGSTarget.Title.Contains("Oxygen_Facility"))
                    {
                        string areaName = "Industry Area";
                        string strDmg = FactoryDamaged.Find(x => x.Contains(mainGSTarget.Name));
                        int pos = FactoryDamaged.IndexOf(strDmg);
                        double percent = 100 * (bombsOnTarget / 10000); // 100% is a 10000kg bombload total
                        if (percent > 100) percent = 100;
                        if (pos == -1)
                        {   // add new entry
                            FactoryDamaged.Add(mainGSTarget.Name + "," + percent.ToString("F0"));
                            story = CountryAirforce((ATK == LW ? BlueCoalition : RedCoalition)) + " bombed " + areaName + ", " + percent.ToString("F0") + "% damaged.";
                            ReinforcementDate = ReinforcementDate.AddDays(7 * (percent / 100));
                        }
                        else
                        {   // update existing entry
                            int prevDmg = 0;
                            if (int.TryParse(strDmg.Substring(strDmg.IndexOf(",") + 1), out prevDmg))
                            {
                                if (prevDmg + percent > 100) percent = 100 - prevDmg;
                                FactoryDamaged[pos] = mainGSTarget.Name + "," + (prevDmg + percent).ToString("F0");
                                story = CountryAirforce((ATK == LW ? BlueCoalition : RedCoalition)) + " bombed " + areaName + " again, now +" + percent.ToString("F0") + "% damaged to a total of " + (prevDmg + percent).ToString("F0") + "%";
                                ReinforcementDate = ReinforcementDate.AddDays(7 * (percent / 100));
                            };
                        };
                    };
                };
                if (story.Length > 0)
                    mainStoryList.Add(story);
            };

            List<string> AirportsDamagedUpdate = new List<string>();
            foreach (string apdmg in AirportsDamaged)
            {
                string[] strs = apdmg.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                int dmg = 0;
                if (int.TryParse(strs[1], out dmg))
                {
                    dmg -= 10 * addDays;
                    if (CampaignName == cCobra) dmg -= 50;
                    if (dmg > 0)
                        AirportsDamagedUpdate.Add(strs[0] + "," + dmg.ToString());
                };
            };
            foreach (string str in AirportsDamagedUpdate)
                sw.WriteLine("AirportDamage," + str);
            AirportsDamaged = AirportsDamagedUpdate;

            List<string> CHRadarDamagedUpdate = new List<string>();
            foreach (string chdmg in CHRadarDamaged)
            {
                string[] strs = chdmg.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                int dmg = 0;
                if (int.TryParse(strs[1], out dmg))
                {
                    dmg -= rnd.Next(10, 33) * addDays;
                    if (dmg > 0)
                        CHRadarDamagedUpdate.Add(strs[0] + "," + dmg.ToString());
                };
                if (dmg < 1) GndStatRestore.Add(strs[0]);
            };
            foreach (string str in CHRadarDamagedUpdate)
                sw.WriteLine("CHRadarDamage," + str);
            CHRadarDamaged = CHRadarDamagedUpdate;

            List<string> PortDamagedUpdate = new List<string>();
            foreach (string pdmg in PortDamaged)
            {
                string[] strs = pdmg.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                int dmg = 0;
                if (int.TryParse(strs[1], out dmg))
                {
                    dmg -= 20 * addDays;
                    if (dmg > 0)
                        PortDamagedUpdate.Add(strs[0] + "," + dmg.ToString());
                };
                if (dmg < 1) GndStatRestore.Add(strs[0]);
            };
            foreach (string str in PortDamagedUpdate)
                sw.WriteLine("PortDamage," + str);
            PortDamaged = PortDamagedUpdate;

            List<string> FactoryDamagedUpdate = new List<string>();
            foreach (string fdmg in PortDamaged)
            {
                string[] strs = fdmg.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                int dmg = 0;
                if (int.TryParse(strs[1], out dmg))
                {
                    dmg -= 10 * addDays;
                    if (dmg > 0)
                        FactoryDamagedUpdate.Add(strs[0] + "," + dmg.ToString());
                };
                if (dmg < 1) GndStatRestore.Add(strs[0]);
            };
            foreach (string str in FactoryDamagedUpdate)
                sw.WriteLine("FactoryDamage," + str);
            FactoryDamaged = FactoryDamagedUpdate;

            foreach (string str in GndStatDead)
                if (!GndStatRestore.Contains(str))
                    sw.WriteLine("GndStatDead," + str);
            foreach (string str in GndGrpDead)
                sw.WriteLine("GndGrpDead," + str); // ships permanent
            foreach (DynCampEvent e in DynCampEvents)
                sw.WriteLine("Event," + e.dateTime.ToString("D") + "," + e.action + "," + e.type + "," + e.typeValue + "," + e.airportName + "," + e.param1 + "," + e.param2 + "," + e.param3);
        };
        //if (odenDebug) forceSwitchSqn = true;
        if (forceSwitchSqn)
        {
            if (odenDebug) GamePlay.gpLogServer(null, "forceSwitchSqn: {0} {1}", new object[] { homeBase.airportName, homeBase.aircraftType });
            List<MissionAirbase> mabs = SortedAirbases(homeBase.army, new Point2d(homeBase.x, homeBase.y), PlayerIsBomber(), false, true); // F bases in battlearea
            string name = homeBase.name;
            foreach (MissionAirbase mab in mabs)
            {
                if (mab.name != name && mab.aircraftType == homeBase.aircraftType)
                {
                    homeBase = mab;
                    break;
                };
            };
            // try similar planetype
            if (name == homeBase.name)
                if (homeBase.army == LW)
                {
                    if (homeBase.country == "de")
                    {
                        if (homeBase.type.Contains("Fighter"))
                            foreach (MissionAirbase mab in mabs)
                                if (LWFighterSet.Contains(mab.aircraftType))
                                {
                                    homeBase = mab;
                                    break;
                                };
                        if (homeBase.type.Contains("Zerstorer"))
                            foreach (MissionAirbase mab in mabs)
                                if (LWFighterSet.Contains(mab.aircraftType))
                                {
                                    homeBase = mab;
                                    break;
                                };
                        if (homeBase.type.Contains("Bomber"))
                            foreach (MissionAirbase mab in mabs)
                                if (LWBomberSet.Contains(mab.aircraftType))
                                {
                                    homeBase = mab;
                                    break;
                                };
                    };
                    if (homeBase.country == "it")
                    {
                        if (homeBase.type.Contains("Fighter"))
                            foreach (MissionAirbase mab in mabs)
                                if (RAFighterSet.Contains(mab.aircraftType))
                                {
                                    homeBase = mab;
                                    break;
                                };
                        if (homeBase.type.Contains("Bomber"))
                            foreach (MissionAirbase mab in mabs)
                                if (RABomberSet.Contains(mab.aircraftType))
                                {
                                    homeBase = mab;
                                    break;
                                };
                    };
                }
                else
                {   // RAF
                    if (homeBase.country == "gb")
                    {
                        if (homeBase.type.Contains("Fighter"))
                            foreach (MissionAirbase mab in mabs)
                                if (RAFFighterSet.Contains(mab.aircraftType))
                                {
                                    homeBase = mab;
                                    break;
                                };
                        if (homeBase.type.Contains("Bomber"))
                            foreach (MissionAirbase mab in mabs)
                                if (RAFBomberSet.Contains(mab.aircraftType))
                                {
                                    homeBase = mab;
                                    break;
                                };
                    };
                };

            if (name != homeBase.name)
            {
                mainStoryList.Add("Pilots of " + name + " were transferred to " + homeBase.name);
            };

            if (odenDebug) GamePlay.gpLogServer(null, "forceSwitchSqn: {0} {1}", new object[] { homeBase.airportName, homeBase.aircraftType });
        };
    }
    private void UpdateBriefing()
    {
        string strBase = homeBase.airportName.Replace('_', ' ');
        if (strBase == "Sounthend")
            strBase = "Rochford";

        //if (odenDebug) GamePlay.gpLogServer(null, "UpdateBriefing: {0} {1}", new object[] { homeBase.airportName, homeBase.aircraftType });
        if(fmCurrent != "")
            if (missionVictory > 0) mainStoryList.Add(CountryName((missionVictory == RAF ? RedCoalition : BlueCoalition)) + " won the battle over " + MissionMarkerName(mmPrevBattle.key) +".");

        if (misConvoyKills == 1) mainStoryList.Add(misConvoyKills.ToString() + " Convoy Ship was sunk - 100 octane fuel delayed one day.");
        else if (misConvoyKills > 0) mainStoryList.Add(misConvoyKills.ToString() + " Convoy Ships were sunk - 100 octane fuel delayed for as many days.");

        if (misRAFDeadF > 0) mainStoryList.Add(CountryAirforce(RedCoalition) + " lost " + misRAFDeadF.ToString() + " fighters.");
        if (misLWDeadF + misLWDeadB + misLWDeadS > 0) mainStoryList.Add(CountryAirforce(BlueCoalition) + " lost " + misLWDeadF.ToString() + " fighters, " + (misLWDeadB + misLWDeadS).ToString() + " bombers.");
        if (mainStoryList.Count == 0)
        {
            if (addDays == 1) mainStoryList.Add("The previous day was calm with no reports of hostilities.");
            else mainStoryList.Add("The previous " + addDays.ToString() + " days saw no enemy bombers active.");
            mainStoryList.Add("One could almost think the war was over but they say there is calm before the storm.");
        };
        List<string> campStatus = new List<string>();
        if (defSquadron.Contains("RAF_"))
        {
            campStatus.Add("Next reinforcement: " + ReinforcementDate.ToString("D") + ".");
            if (highOctaneDate > gameDateTime) campStatus.Add("Next deliveries of 100 octane fuel: " + highOctaneDate.ToString("D"));
            campStatus.Add("");
        };

        foreach (string chdmg in CHRadarDamaged)
        {
            string[] strs = chdmg.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            GroundStationary gs = GroundStationaryByName(strs[0]);
            if (gs != null)
            {
                string areaName = ChainHomeRadarName(new Point2d(gs.pos.x, gs.pos.y));
                int dmg = 0;
                if (int.TryParse(strs[1], out dmg))
                    if (dmg > 0)
                        campStatus.Add(areaName + " Radar Station is " + dmg.ToString() + "% damaged.");
            };
        };

        foreach (string pdmg in PortDamaged)
        {
            string[] strs = pdmg.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            GroundStationary gs = GroundStationaryByName(strs[0]);
            if (gs != null)
            {
                string areaName = PortDockName(new Point2d(gs.pos.x, gs.pos.y));
                int dmg = 0;
                if (int.TryParse(strs[1], out dmg))
                    if (dmg > 0)
                        campStatus.Add(areaName + " is " + dmg.ToString() + "% damaged.");
            };
        };

        foreach (string fdmg in FactoryDamaged)
        {
            string[] strs = fdmg.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            GroundStationary gs = GroundStationaryByName(strs[0]);
            if (gs != null)
            {
                string areaName = "Industry Area";
                int dmg = 0;
                if (int.TryParse(strs[1], out dmg))
                    if (dmg > 0)
                        campStatus.Add(areaName + " is " + dmg.ToString() + "% damaged.");
            };
        };

        foreach (string apdmg in AirportsDamaged)
        {
            string[] strs = apdmg.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            int dmg = 0;
            if (int.TryParse(strs[1], out dmg))
                if (dmg > 0)
                    campStatus.Add(strs[0].Replace('_', ' ') + " is " + dmg.ToString() + "% damaged.");
        };

        int gbSqnsF = 0, gbSqnsB = 0, gbTotal = 0, deGrpsF = 0, deGrpsB = 0, deGrpsS = 0, deTotal = 0;
        foreach (MissionAirbase mab in MissionAirbases)
            if (mab.army == RAF)
            {
                if (mab.type.Contains("Fighter")) gbSqnsF += 1;
                if (mab.type.Contains("Bomber")) gbSqnsB += 1;
                gbTotal += mab.maxPlanes;
            }
            else
            {
                if (mab.type.Contains("Fighter")) deGrpsF += 1;
                if (mab.type.Contains("Bomber")) deGrpsB += 1;
                if (mab.type.Contains("Stuka")) deGrpsS += 1;
                deTotal += mab.maxPlanes;
            };

        campStatus.Add(CountryAirforce(RedCoalition) + " air assets: " + gbTotal.ToString() + " aircrafts in " + gbSqnsF.ToString() + " fighter- and " + gbSqnsB.ToString() + " bomber squadrons.");
        if (deGrpsS > 0) campStatus.Add(CountryAirforce(BlueCoalition) + " air assets: " + deTotal.ToString() + " aircrafts in " + deGrpsF.ToString() + " fighter-, " + gbSqnsB.ToString() + " bomber- and " + deGrpsS.ToString() + " Stuka Gruppen.");
        else campStatus.Add(CountryAirforce(BlueCoalition) + " air assets: " + deTotal.ToString() + " aircrafts in " + deGrpsF.ToString() + " fighter-, " + gbSqnsB.ToString() + " bomber squadrons.");
        if (CampaignName == cBattleOfBritain && bobVicSide == 0)
        {
            double ratio = (double)deTotal / (double)gbTotal;
            campStatus.Add("");
            campStatus.Add("Luftwaffe : RAF ratio is " + ratio.ToString("F1"));
            if (ratio > 3f) campStatus.Add("Germany will launch 'Sea Lion' by end of September.");
            else
                if (ratio >= 2f) campStatus.Add("Germany will postpone 'Sea Lion' by end of September.");
                else
                    if (ratio < 1f) campStatus.Add("RAF defeated Luftwaffe and will launch airfield strikes.");
                    else campStatus.Add("Germany will postpone 'Sea Lion' by end of September.");
            campStatus.Add("");

            int inds = Industries.Count;
            if (inds == 1) campStatus.Add("Only one industry area is still operational.");
            else campStatus.Add(inds + " industrial areas are operational."); // if down to zero UK has another problem :)
        };

        if (ChainHomeRadars.Count > 0)
        {
            campStatus.Add("");
            campStatus.Add("Radar Stations still operational (" + ChainHomeRadars.Count.ToString() + "):");
            foreach (GroundStationary gs in ChainHomeRadars)
                campStatus.Add(" -" + ChainHomeRadarName(new Point2d(gs.pos.x, gs.pos.y)));
        };
        if (PortCranes.Count > 0)
        {
            campStatus.Add("");
            campStatus.Add("Port Facilities still operational (" + PortCranes.Count.ToString() + "):");
            foreach (GroundStationary gs in PortCranes)
                campStatus.Add(" -" + PortDockName(new Point2d(gs.pos.x, gs.pos.y)));
        };

        string recentEventsCaption = "Yesterday events:";
        if (addDays > 1) recentEventsCaption = "Recent events last " + addDays.ToString() + " days:";

        string missionCaption = homeBase.name + ", " + Designation(homeBase.aircraftType) + " (" + vName + ") *";
        if (SquadronIsFrench(homeBase.sqn)) missionCaption = homeBase.name + ", " + DesignationAdA(homeBase.aircraftType) + " (" + vName + ") *";
        switch (CampaignName)
        {
            case cBattleOfFrance:
                missionCaption = "BoF " + missionCaption;
                break;
            case cBattleOfBritain:
                missionCaption = "BoB " + missionCaption;
                break;
            case cNorthAfrica:
                missionCaption = "Afr " + missionCaption;
                break;
            case cCobra:
                missionCaption = "CAS " + missionCaption;
                break;
        };
        if (odenDebug) GamePlay.gpLogServer(null, "UpdateBriefing: {0} {1} {2} {3}", new object[] { gameDateTime.ToString("D"), bobVicSide, homeBase.airportName, homeBase.aircraftType });
        int len = 6;
        if (homeBase.aircraftType.Length < 9 + 6)
            len = homeBase.aircraftType.Length - 9;
        string type = homeBase.aircraftType.Substring(9, len).ToLower();
        switch (CampaignName)
        {
            case cBattleOfFrance: type = "bof" + type;
                break;
            case cBattleOfBritain: type = "bob" + type;
                break;
            case cNorthAfrica: type = "des" + type;
                break;
        };
        string slide = type + ".jpg";
        string thin = type + "_thin.jpg";
        if (CampaignName == cCobra)
        {
            slide = "cas.jpg";
            thin = "cas_thin.jpg";
        };

        string situation = "";
        if (CampaignName != cBattleOfBritain || bobVicSide == LW)
        {
            string unit = CountryArmyUnit((ATK == LW ? BlueCoalition : RedCoalition));
            situation = CountryOwnership((ATK == LW ? BlueCoalition : RedCoalition)) + " " + unit + " attacks " + BattleSetNames(fmCurrent) + " and should capture it " + (BattleProgress == 2 ? "today." : " in " + (3 - BattleProgress).ToString() + " days.");
            if (InitiativeChanged) situation = CountryName((ATK == LW ? BlueCoalition : RedCoalition)) + " turned initiative and attacks " + BattleSetNames(fmCurrent) + ".";
            else
                if (ConsecutiveLosses > 1)
                    if (ATK == GamePlay.gpPlayer().Army()) situation = situation + " We have lost " + ConsecutiveLosses.ToString() + " battles in a row, we can do better!";
                    else situation = situation + " They have lost " + ConsecutiveLosses.ToString() + " battles in a row, keep pushing them!";
        };
        string planeDesignation = Designation(homeBase.aircraftType);
        if (SquadronIsFrench(homeBase.sqn)) planeDesignation = DesignationAdA(homeBase.aircraftType);
        string[] strBriefing =
        {
            "[Info]"
            , "Info"
            , "<Slide>"
            , slide
            , ""
            , "<Caption>"
            , missionCaption
            , "<Slide>"
            , thin
            , ""
            , "<Caption>"
            , CampaignName
            , gameDateTime.ToString("D") +" - " +CampaignPhase()//"July 10th 1940"
            , situation
            , ""
            , homeBase.sector //"RAF Hornchurch"
            , homeBase.name +" (" +strBase +")"
            , "[Mission]"
            , "<Name>"
            , "Mission"
            , "<Description>"
            , CampaignName
            , gameDateTime.ToString("D") +" - " +CampaignPhase() //"July 10th 1940"
            , situation
            , ""
            , homeBase.sector //"RAF Hornchurch"
            , homeBase.name +" (" +strBase + ") " + homeBase.maxPlanes.ToString() + "x " +planeDesignation //"Spitfire Mk Ia"
            , tailNoSerialNo
            , "check your callsign and skin in <Player Plane>"
            , ""
            , recentEventsCaption
        };

        string[] endBriefing =
        {
            //"(You may land at Hornchurch, Rochford or Manston to change airfield during the campaign)"
            "<Slide>"
            , slide
            , "<Caption>"
            , ""
        };

        string capture = "";
        if (CapturedAreas.Count > 0)
            foreach (string str in CapturedAreas)
                if (capture == "") capture = CountryOwnership((ATK == LW ? BlueCoalition : RedCoalition)) + " forces captured " + str;
                else capture = capture + ", " + str;

        List<string> sqnListRed = new List<string>();
        foreach (MissionAirbase mab in SortedAirbases(RAF, new Point2d(homeBase.x, homeBase.y), false, false, false))
            if (mab.army == RAF)
                if (sqnListRed.Count < 3)
                    if (SquadronIsFrench(mab.sqn)) sqnListRed.Add(mab.name + " at " + mab.airportName.Replace('_', ' ') + ", " + DesignationAdA(mab.aircraftType));
                    else sqnListRed.Add(mab.name + " at " + mab.airportName.Replace('_', ' ') + ", " + Designation(mab.aircraftType));
        List<string> sqnListBlue = new List<string>();
        foreach (MissionAirbase mab in SortedAirbases(LW, new Point2d(homeBase.x, homeBase.y), false, false, false))
            if (mab.army == LW)
                if (sqnListBlue.Count < 3)
                    sqnListBlue.Add(mab.name + " at " + mab.airportName.Replace('_', ' ') + ", " + Designation(mab.aircraftType));

        using (StreamWriter sw = File.CreateText(CampBriFile))
        {
            foreach (string str in strBriefing)
                sw.WriteLine(str);
            if (capture != "")
                sw.WriteLine(capture);
            foreach (string str in mainStoryList)
                sw.WriteLine(str);
            sw.WriteLine("");
            sw.WriteLine("Status:");
            foreach (string str in campStatus)
                sw.WriteLine(str);
            sw.WriteLine("");
            sw.WriteLine("Nearby Fighter Squadrons:");
            if (GamePlay.gpPlayer().Army() == RAF) foreach (string str in sqnListRed) sw.WriteLine(str);
            else foreach (string str in sqnListBlue) sw.WriteLine(str);
            sw.WriteLine("");
            sw.WriteLine("Nearby Enemy Squadrons:");
            if (GamePlay.gpPlayer().Army() != RAF) foreach (string str in sqnListRed) sw.WriteLine(str);
            else foreach (string str in sqnListBlue) sw.WriteLine(str);
            sw.WriteLine("");
            foreach (string str in endBriefing)
                sw.WriteLine(str);
        };
    }
    private void UpdateMissionFile()
    {
        if (odenDebug) GamePlay.gpLogServer(null, "UpdateMissionFile: {0} {1} {2}", new object[] { homeBase.airportName, homeBase.aircraftType, homeBase.sqn });
        string[] strMisFile = File.ReadAllLines(CampMisFile);
        List<string> strMisList = new List<string>();

        bool setHomeBaseTakeOff = false;
        Point2d wp2d = new Point2d(homeBase.x, homeBase.y);
        if (homeBase.army == RAF) wp2d = calcPos(wp2d, 3 * 1609, 90 + rnd.Next(0, 90));
        else wp2d = calcPos(wp2d, 3 * 1609, 270 + rnd.Next(0, 90));
        int aging = (gameDateTime - StartDateTime).Days;
        if (aging > 99) aging = 99;
        /*
        string firstSection0 = "  Flight0 1 2 3";
        string firstSection1 = "  Flight1 4 5 6";
        string otherSection0 = "  Flight0 7 8 9";
        string otherSection1 = "  Flight1 10 11 12";
        */
        string form = "VIC3";
        if (homeBase.type.Contains("Stuka")) form = "VIC";
        if (homeBase.type.Contains("Zerstorer")) form = "FINGERFOUR";
        if (homeBase.type.Contains("Fighter")) form = "FINGERFOUR";
        if (homeBase.type.Contains("Recon")) form = "LINEABREAST";
        if (homeBase.type.Contains("Bomber") && homeBase.sqn.Contains("RAF_")) form = "VIC";
        if (homeBase.type.Contains("Fighter") && homeBase.sqn.Contains("Early")) form = "VIC3";
        if (homeBase.type.Contains("Fighter") && homeBase.sqn.Contains("RA_")) form = "VIC3";

        int max = homeBase.maxPlanes;
        if (max > 12) max = 12;
        if (form == "VIC") max = 15;
        if (homeBase.army == RAF && form == "VIC3" && max > 6) form = "VIC6";

        int Flight1Qty = max / 2;
        if (form == "FINGERFOUR") Flight1Qty = max / 3;
        int Flight2Qty = max - Flight1Qty;

        string sqn = homeBase.sqn;
        if (odenDebug) GamePlay.gpLogServer(null, "UpdateMissionFile: {0} {1}", new object[] { sqn, oldSqn });

        int flight = 0;
        if (sqn.Contains("_LW_"))
        {
            if (sqn.Contains("_I")) flight = 1; // 1./JG .. 3./JG
            if (sqn.Contains("_II")) flight = 2; // 4./JG .. 6./JG
            if (sqn.Contains("_III")) flight = 3; // 7./JG .. 9./JG
        };
        string[] FlightSection = FlightSections(homeBase.army, max, form, flight); // 0 is first "sqn" in editor, Stab./ for LW dudes
        //player slot is mission editor sqn, flight# and plane (zero based)
        string slot = "";
        if (FlightSection[0] != "") slot = "00"; // leader
        if (FlightSection[0].Length > 1) slot = "01"; // wingman, min 2 planes being 1st flight
        if (FlightSection[0].Length > 3) slot = "02"; // wingman, min 3 planes being 1st flight
        if (FlightSection[1] != "") slot = "10"; // section leader
        if (FlightSection[1].Length > 1) slot = "11"; // wingman, min 2 planes being 2nd flight (even bomber x5 sections: 6 7 8 9 10)
        if (FlightSection[1].Length > 3) slot = "12"; // wingman, min 3 planes being 2nd flight
        if (FlightSection[2] != "") slot = "20"; // section leader
        if (FlightSection[3] != "") slot = "30"; // section leader
        slot = FlightSection[4].Substring(0, 1) + slot;
        string airGroup = homeBase.sqn + "." + FlightSection[4];

        //if (odenDebug) GamePlay.gpLogServer(null, "FlightNames: '{0}' '{1}'", new object[] { Flight1Name, Flight2Name });
        if (odenDebug) GamePlay.gpLogServer(null, "FlightSection 4: '{0}, slot: {1}'", new object[] { FlightSection[4],slot });

        bool isFirstFlight = true;
        bool airStart = false; // AI fails pretty often to taxi/takeoff
        bool dynMisSectionFound = false;
        int id;

        foreach (string str in strMisFile)
        {
            if (str.Length > 0)
            {
                //if (odenDebug) GamePlay.gpLogServer(null, "File: '{0}'", new object[] { str });
                string[] strs = str.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                if (strs.Length > 0)
                {
                    string newStr = str;
                    if (oldSqn != sqn)
                        if (!dynMisSectionFound)
                            newStr = str.Replace(oldSqn, sqn);
                    string suffix = "";
                    if (strs[0].Contains("_Way")) suffix = "_Way";
                    else suffix = "";
                    if (strs[0].Contains(oldSqn)) // BoB_RAF_F_73Sqn_Late.07 to BoB_RAF_F_73Sqn_Late.03 when only 2 flights or similar
                        if (strs[0].StartsWith("[")) newStr = "[" + homeBase.sqn + "." + FlightSection[4] + suffix + "]";
                        else newStr = "  " + homeBase.sqn + "." + FlightSection[4];

                    if (str.Contains("CallSign")) isFirstFlight = false;

                    switch (strs[0])
                    {
                        case "MAP":
                            if (CampaignName == cBattleOfBritain)
                            {
                                newStr = "  MAP Land$English_Channel_1940_Winter";
                                if (gameDateTime.Month > 4)
                                    newStr = "  MAP Land$English_Channel_1940";
                                if (gameDateTime.Month > 9)
                                    newStr = "  MAP Land$English_Channel_1940_Autumn";
                                if (gameDateTime.Month > 10)
                                    newStr = "  MAP Land$English_Channel_1940_Winter";
                            };
                            break;
                        case "BattleArea":
                            if (CampaignName == cBattleOfFrance)
                                if (homeBase.army == RAF) newStr = "  BattleArea 213000 56000 144837 177023 16090";
                                else newStr = "  BattleArea 210000 55000 160000 180000 20000";
                            if (CampaignName == cBattleOfBritain)
                                if (homeBase.army == RAF) newStr = "  BattleArea 115000 175000 193116 128744 16093";
                                else newStr = "  BattleArea 100000 175000 180000 140000 20000";
                            if (CampaignName == cNorthAfrica) // WIP Le Havre
                                if (homeBase.army == RAF) newStr = "  BattleArea 9000 9000 160930 160930 16093";
                                else newStr = "  BattleArea 9000 9000 200000 200000 20000";
                            if (CampaignName == cCobra)
                                if (homeBase.army == RAF) newStr = "  BattleArea 8800 8800 64372 64372 16093";
                                else newStr = "  BattleArea 5986 5986 70000 70000 10000";
                            break;
                        case "TIME":
                            switch (CampMapName)
                            {
                                case "Land$English_Channel_1940_Winter":
                                case "Land$English_Channel_1940_Autumn":
                                    newStr = "  TIME " + rnd.Next(9, 15).ToString() + "." + rnd.Next(0, 99).ToString();
                                    break;
                                default:
                                    newStr = "  TIME " + rnd.Next(7, 19).ToString() + "." + rnd.Next(0, 99).ToString();
                                    break;
                            };
                            break;
                        case "WeatherIndex":
                            newStr = "  WeatherIndex " + rnd.Next(0, 2).ToString();
                            break;
                        case "CloudsHeight":
                            newStr = "  CloudsHeight " + rnd.Next(5, 12).ToString() + "00";
                            break;
                        case "player":
                            newStr = "  player " + homeBase.sqn + "." + slot;
                            break;
                        case "Power":
                            newStr = "  Power " + rnd.Next(-4, 4).ToString("F3") + " " + rnd.Next(-4, 4).ToString("F3") + " 0.000";
                            break;
                        case "GustPower":
                            newStr = "  GustPower " + rnd.Next(1, 5).ToString();
                            break;
                        case "GustAngle":
                            newStr = "  GustAngle " + rnd.Next(-40, 40).ToString();
                            break;
                        case "Flight0":
                            newStr = "  Flight0 " + FlightSection[0];//Flight0;
                            //if (!isFirstFlight) newStr = "  Flight0 " + Second0;
                            break;
                        case "Flight1":
                            newStr = "  Flight1 " + FlightSection[1];//Flight1;
                            //if (!isFirstFlight) newStr = "  Flight1 " + Second1;
                            break;
                        case "Flight2":
                            newStr = "  Flight2 " + FlightSection[2];//Flight2;
                            //if (!isFirstFlight) newStr = "  Flight2 " + Second2;
                            break;
                        case "Flight3":
                            newStr = "  Flight3 " + FlightSection[3];//Flight3;
                            //if (!isFirstFlight) newStr = "  Flight3 " + Second3;
                            break;
                        case "Class":
                            newStr = "  Class " + homeBase.aircraftType;
                            break;
                        case "Aging":
                            newStr = "  Aging " + aging.ToString();
                            break;
                        case "TAKEOFF":
                            newStr = "  TAKEOFF " + homeBase.x.ToString("F2") + " " + homeBase.y.ToString("F2") + " 0 0";
                            break;
                        case "NORMFLY":
                            newStr = "  NORMFLY " + wp2d.x.ToString("F2") + " " + wp2d.y.ToString("F2") + " 914.00 288.00";
                            if (airStart) newStr = "  NORMFLY " + homeBase.x.ToString("F2") + " " + homeBase.y.ToString("F2") + " 914.00 288.00";
                            airStart = !airStart;
                            break;
                        case "[DYNMIS]":
                            dynMisSectionFound = true; // ignore remaining values regarding updates on homebase
                            break;
                        default:
                            if (!strs[0].Contains("["))
                                if (strs[0].Contains("FrontMarker"))
                                {
                                    int.TryParse(strs[0].Remove(0, 11), out id);
                                    //if (odenDebug) GamePlay.gpLogServer(null, "FrontMarker: '{0}' '{1}'", new object[] { strs[0], id });
                                    if (id <= MissionMarkers.Count) newStr = "  " + strs[0] + " " + strs[1] + " " + strs[2] + " " + MissionMarkers[id].army.ToString();
                                };
                            break;
                    };
                    if (!dynMisSectionFound)
                        if (strs[0].Contains("Skin"))
                            newStr = "  " + strs[0] + " " + DefaultSkins(homeBase.aircraftType, homeBase.sqn);

                    if (newStr.Length > 0)
                        strMisList.Add(newStr);
                };
            };
        };
        if (odenDebug) GamePlay.gpLogServer(null, "dynMisSectionFound: '{0}'", new object[] { dynMisSectionFound });
        if (!dynMisSectionFound)
        {
            strMisList.Add("[DYNMIS]");
            strMisList.Add("  DynMisSquadron " + defSquadron);
            strMisList.Add("  DynMisClass " + defClass);
            strMisList.Add("  DynMisCallSign " + defCallSign);
            strMisList.Add("  DynMisSkin " + defSkin);
            strMisList.Add("  DynMisSerial " + defSerial);
            strMisList.Add("  DynMisTail " + defTail);
        };

        using (StreamWriter sw = File.CreateText(CampMisFile))
            foreach (string str in strMisList)
                sw.WriteLine(str);
    }

    internal List<AiActor> SortedConvoyShips(int army, Point3d pt3d, bool onlyBattleArea)
    {   // requires frontline
        List<AiActor> SortedConvoyShips = new List<AiActor>();
        string sn = "";
        foreach (AiGroundGroup gg in ConvoyShips)
            if (gg.GetItems().Length > 0)
            {
                AiActor a = gg.GetItems()[0]; // fix this some day
                if (onlyBattleArea)
                    sn = GamePlay.gpSectorName(a.Pos().x, a.Pos().y);
                if (a.Army() == army && (sn.IndexOf(">") == -1 && sn.IndexOf("<") == -1))
                {
                    int forEachIndex = 0;
                    foreach (AiActor ship in SortedConvoyShips)
                    {
                        if (ship.Pos().distance(ref pt3d) > a.Pos().distance(ref pt3d))
                        {
                            SortedConvoyShips.Insert(forEachIndex, a);
                            break;
                        };
                        forEachIndex++;
                    };
                    if (!SortedConvoyShips.Contains(a)) SortedConvoyShips.Add(a); // add last
                };
            };
        return SortedConvoyShips;
    }

    internal List<GroundStationary> SortedGroundStationaries(List<GroundStationary> GroundStationaries, int army, Point3d pt3d, bool onlyBattleArea)
    {   // requires frontline
        List<GroundStationary> SortedGroundStationaries = new List<GroundStationary>();
        string sn = "";
        foreach (GroundStationary gs in GroundStationaries)
        {
            if (onlyBattleArea)
                sn = GamePlay.gpSectorName(gs.pos.x, gs.pos.y);
            if (GamePlay.gpFrontArmy(gs.pos.x, gs.pos.y) == army && (sn.IndexOf(">") == -1 && sn.IndexOf("<") == -1))
            {
                int forEachIndex = 0;
                foreach (GroundStationary sgs in SortedGroundStationaries)
                {
                    if (sgs.pos.distance(ref pt3d) > gs.pos.distance(ref pt3d))
                    {
                        SortedGroundStationaries.Insert(forEachIndex, gs);
                        break;
                    };
                    forEachIndex++;
                };
                if (!SortedGroundStationaries.Contains(gs)) SortedGroundStationaries.Add(gs); // add last
            };
        };
        return SortedGroundStationaries;
    }

    private void CreateConvoyMission(bool activeMis)
    {
        List<AiActor> SortedShips = SortedConvoyShips((ATK == RAF ? LW : RAF), homeAirport.Pos(), false);
        if (activeMis) SortedShips = SortedConvoyShips((ATK == RAF ? LW : RAF), target3d, false);
        if (SortedShips.Count == 0)
            return;
        AiActor a = SortedShips[0];
        if (SortedShips.Count > 2) a = SortedShips[rnd.Next(0, 3)];

        target3d = a.Pos();
        if (!activeMis)
            if (rnd.Next(10) < 5) CreatePortMission(true);
            else CreateCHRadarMission(true);
        target3d = a.Pos();

        Point2d pt2d = new Point2d(a.Pos().x, a.Pos().y);
        if (odenDebug) GamePlay.gpLogServer(null, "CreateConvoyMission: '{0}'", new object[] { GamePlay.gpSectorName(a.Pos().x, a.Pos().y) });
        if (!activeMis) convoyTarget = a;
        Point3d pt3d = a.Pos();
        if (targetName == "" && !activeMis) targetName = CountryOwnership((ATK == LW ? RedCoalition : BlueCoalition)) + " Convoy in " + GamePlay.gpSectorName(a.Pos().x, a.Pos().y);
        if (!PlayerIsBomber() || ATK != GamePlay.gpPlayer().Army())
        {
            ISectionFile f = GamePlay.gpCreateSectionFile();
            string sqd = CreateBMBMission(f, pt2d, 3, ATK, a, null, true, activeMis);
            if (sqd != "")
            {
                foreach (AiGroundGroup gg in ConvoyShips)
                {
                    if (gg.Pos().distance(ref pt3d) < 16090)
                    {
                        a = gg.GetItems()[0];
                        pt2d.x = a.Pos().x;
                        pt2d.y = a.Pos().y;
                        CreateBMBMission(f, pt2d, 3, ATK, a, null, false, activeMis);
                    };
                };
                if (!activeMis)
                {
                    f.add("Trigger", "BombersAtTarget", "TPassThrough 1 " + sqd + " " + pt3d.x.ToString() + " " + pt3d.y.ToString() + " 12000");
                    if (StrikerGroupName == "") StrikerGroupName = sqd;
                }
                else
                {
                    CreateCAPMission(f, pt2d, 6, ATK == LW ? RAF : LW, false);
                };
                GamePlay.gpPostMissionLoad(f);
                NextMissionNum++;
                if (!activeMis)
                {
                    RedirectCAP(ATK == LW ? RAF : LW, pt2d);
                    gameIsOn = true;
                };
            };
            if (activeMis) BMBFlightAB = null;
        };
    }
    private void CreateCHRadarMission(bool activeMis)
    {
        List<GroundStationary> SortedRadars = SortedGroundStationaries(ChainHomeRadars, (ATK == LW ? RAF : LW), homeAirport.Pos(), false);
        if (activeMis) SortedRadars = SortedGroundStationaries(ChainHomeRadars, (ATK == LW ? RAF : LW), target3d, false);
        if (SortedRadars.Count == 0)
            return;
        GroundStationary gs = SortedRadars[0];
        if (SortedRadars.Count > 2) gs = SortedRadars[rnd.Next(0, 3)];

        target3d = gs.pos;
        if (!activeMis)
            if (rnd.Next(10) < 4) CreateConvoyMission(true);
            else CreateAirbaseMission(true);
        target3d = gs.pos;

        mainGSTarget = gs;
        Point2d pt2d = new Point2d(gs.pos.x, gs.pos.y);
        if (odenDebug) GamePlay.gpLogServer(null, "CreateCHRadarMission: '{0}'", new object[] { gs.Name });
        if (targetName == "" && !activeMis) targetName = "Radar station at " + ChainHomeRadarName(pt2d) + " in " + GamePlay.gpSectorName(pt2d.x, pt2d.y);
        if (!PlayerIsBomber() || ATK != GamePlay.gpPlayer().Army())
        {
            ISectionFile f = GamePlay.gpCreateSectionFile();
            string sqd = CreateBMBMission(f, pt2d, 8, ATK, null, gs, true, activeMis);
            if (sqd != "")
            {
                if (rnd.Next(0, 9) > 6) CreateBMBMission(f, pt2d, 3, ATK, null, gs, false, activeMis);
                if (rnd.Next(0, 9) > 6) CreateBMBMission(f, pt2d, 3, ATK, null, gs, false, activeMis);
                if (!activeMis)
                {
                    f.add("Trigger", "BombersAtTarget", "TPassThrough 1 " + sqd + " " + pt2d.x.ToString() + " " + pt2d.y.ToString() + " 12000");
                    if (StrikerGroupName == "") StrikerGroupName = sqd;
                }
                else
                {
                    CreateCAPMission(f, pt2d, 6, ATK == LW ? RAF : LW, false);
                };
                GamePlay.gpPostMissionLoad(f);
                NextMissionNum++;
                if (!activeMis)
                {
                    RedirectCAP(ATK == LW ? RAF : LW, pt2d);
                    gameIsOn = true;
                };
            };
            if (activeMis) BMBFlightAB = null;
        };
    }
    private void CreatePortMission(bool activeMis)
    {
        List<GroundStationary> SortedPortCranes = SortedGroundStationaries(PortCranes, RAF, homeAirport.Pos(), false);
        if (activeMis) SortedPortCranes = SortedGroundStationaries(PortCranes, RAF, target3d, false);
        if (SortedPortCranes.Count == 0)
            return;
        GroundStationary gs = SortedPortCranes[0];
        if (SortedPortCranes.Count > 2) gs = SortedPortCranes[rnd.Next(0, 3)];
        target3d = gs.pos;
        if (!activeMis)
            if (rnd.Next(10) < 4) CreateConvoyMission(true);
            else CreateAirbaseMission(true);
        target3d = gs.pos;

        mainGSTarget = gs;
        Point2d pt2d = new Point2d(gs.pos.x, gs.pos.y);
        if (odenDebug) GamePlay.gpLogServer(null, "CreatePortMission: '{0}'", new object[] { gs.Name });
        if (targetName == "" && !activeMis) targetName = PortDockName(pt2d) + " in " + GamePlay.gpSectorName(pt2d.x, pt2d.y);
        if (!PlayerIsBomber() || ATK != GamePlay.gpPlayer().Army())
        {
            ISectionFile f = GamePlay.gpCreateSectionFile();
            string sqd = CreateBMBMission(f, pt2d, 9, ATK, null, gs, true, activeMis);
            if (sqd != "")
            {
                if (rnd.Next(0, 9) > 6) CreateBMBMission(f, pt2d, 3, ATK, null, gs, false, activeMis);
                if (rnd.Next(0, 9) > 6) CreateBMBMission(f, pt2d, 3, ATK, null, gs, false, activeMis);
                if (!activeMis)
                {
                    f.add("Trigger", "BombersAtTarget", "TPassThrough 1 " + sqd + " " + pt2d.x.ToString() + " " + pt2d.y.ToString() + " 12000");
                    if (StrikerGroupName == "") StrikerGroupName = sqd;
                }
                else
                {
                    CreateCAPMission(f, pt2d, 6, ATK == LW ? RAF : LW, false);
                };
                GamePlay.gpPostMissionLoad(f);
                NextMissionNum++;
                if (!activeMis)
                {
                    RedirectCAP(ATK == LW ? RAF : LW, pt2d);
                    gameIsOn = true;
                };
            };
            if (activeMis) BMBFlightAB = null;
        };
    }
    private void CreateIndustryMission(bool activeMis)
    {
        List<GroundStationary> SortedIndustries = SortedGroundStationaries(Industries, RAF, homeAirport.Pos(), false);
        if (activeMis) SortedIndustries = SortedGroundStationaries(Industries, RAF, target3d, false);
        if (SortedIndustries.Count == 0)
            return;
        GroundStationary gs = SortedIndustries[0];
        if (SortedIndustries.Count > 2) gs = SortedIndustries[rnd.Next(0, 3)];
        target3d = gs.pos;
        if (!activeMis)
            if (rnd.Next(10) < 4) CreateConvoyMission(true);
            else CreateAirbaseMission(true);
        target3d = gs.pos;

        mainGSTarget = gs;
        Point2d pt2d = new Point2d(gs.pos.x, gs.pos.y);
        if (odenDebug) GamePlay.gpLogServer(null, "CreateIndustryMission: '{0}'", new object[] { gs.Name });
        if (targetName == "" && !activeMis) targetName = "Industrial area in " + GamePlay.gpSectorName(pt2d.x, pt2d.y);
        if (!PlayerIsBomber() || ATK != GamePlay.gpPlayer().Army())
        {
            ISectionFile f = GamePlay.gpCreateSectionFile();
            string sqd = CreateBMBMission(f, pt2d, 9, ATK, null, gs, true, activeMis);
            if (sqd != "")
            {
                if (rnd.Next(0, 9) > 6) CreateBMBMission(f, pt2d, 3, ATK, null, gs, false, activeMis);
                if (rnd.Next(0, 9) > 6) CreateBMBMission(f, pt2d, 3, ATK, null, gs, false, activeMis);
                if (!activeMis)
                {
                    f.add("Trigger", "BombersAtTarget", "TPassThrough 1 " + sqd + " " + pt2d.x.ToString() + " " + pt2d.y.ToString() + " 12000");
                    if (StrikerGroupName == "") StrikerGroupName = sqd;
                }
                else
                {
                    CreateCAPMission(f, pt2d, 6, ATK == LW ? RAF : LW, false);
                };
                GamePlay.gpPostMissionLoad(f);
                NextMissionNum++;
                if (!activeMis)
                {
                    RedirectCAP(ATK == LW ? RAF : LW, pt2d);
                    gameIsOn = true;
                };
            };
            if (activeMis) BMBFlightAB = null;
        };
    }
    private void CreateAirbaseMission(bool activeMis)
    {
        Point2d pt2d = new Point2d(homeBase.x, homeBase.y);
        if (activeMis) pt2d = new Point2d(target3d.x, target3d.y);
        int againstArmy = ATK == LW ? RAF : LW;
        List<MissionAirbase> sabs = SortedAirbases(againstArmy, pt2d, false, false, true); // fighter bases
        if (sabs.Count == 0)
            sabs = SortedAirbases(againstArmy, pt2d, true, false, true); // bomber bases
        if (sabs.Count == 0)
            return;
        if (sabs.Count > 5) targetAirport = sabs[rnd.Next(5)].ap;
        else targetAirport = sabs[0].ap;

        target3d = targetAirport.Pos();
        if (!activeMis)
            if (rnd.Next(10) < 5) CreateCHRadarMission(true);
            else CreatePortMission(true);
        target3d = targetAirport.Pos();

        target2d = new Point2d(target3d.x, target3d.y);
        if (targetName == "" && !activeMis) targetName = "Airbase at " + targetAirport.Name().Replace('_', ' ') + " in " + GamePlay.gpSectorName(target2d.x, target2d.y);
        if (odenDebug) GamePlay.gpLogServer(null, "CreateAirbaseMission: {0}", new object[] { targetName });
        Timeout(60.0, () => { Spawn40Tigers(targetAirport); }); // find spawn positions and create static ac
        int qty = 9;
        if (ATK == RAF) qty = 10;

        if (!PlayerIsBomber() || ATK != GamePlay.gpPlayer().Army())
        {
            ISectionFile f = GamePlay.gpCreateSectionFile();
            string sqd = CreateBMBMission(f, target2d, qty, ATK, null, null, true, activeMis);
            if (sqd != "")
            {
                if (rnd.Next(0, 9) > 6) CreateBMBMission(f, target2d, qty, ATK, null, null, false, activeMis);
                if (!activeMis)
                {
                    f.add("Trigger", "BombersAtTarget", "TPassThrough 1 " + sqd + " " + target2d.x.ToString() + " " + target2d.y.ToString() + " 12000");
                    if (StrikerGroupName == "") StrikerGroupName = sqd;
                }
                else
                {
                    CreateCAPMission(f, target2d, 6, ATK == LW ? RAF : LW, false);
                };
                GamePlay.gpPostMissionLoad(f);
                NextMissionNum++;
                if (!activeMis)
                {
                    RedirectCAP(againstArmy, target2d);
                    gameIsOn = true;
                };
            };
            if (activeMis) BMBFlightAB = null;
        };
        if (activeMis) targetAirport = null;
    }
    private void CreateAirportMission()
    {   // not necessary having a sqn
        Point2d pt2d = new Point2d(homeBase.x, homeBase.y);
        int againstArmy = ATK == LW ? RAF : LW;
        List<AiAirport> saps = SortedAirports(againstArmy, pt2d, true); // if battlearea only no damaged will be included
        if (saps.Count == 0)
            return;
        if (saps.Count > 5) targetAirport = saps[rnd.Next(5)];
        else targetAirport = saps[0];

        target3d = targetAirport.Pos();
        target2d = new Point2d(target3d.x, target3d.y);
        if (targetName == "") targetName = "Airbase at " + targetAirport.Name().Replace('_', ' ') + " in " + GamePlay.gpSectorName(target2d.x, target2d.y);
        if (odenDebug) GamePlay.gpLogServer(null, "CreateAirportMission: {0}", new object[] { targetName });
        Timeout(60.0, () => { Spawn40Tigers(targetAirport); }); // find spawn positions and create static ac
        int qty = 9;
        if (ATK == RAF) qty = 10;

        if (!PlayerIsBomber() || ATK != GamePlay.gpPlayer().Army())
        {
            ISectionFile f = GamePlay.gpCreateSectionFile();
            string sqd = CreateBMBMission(f, target2d, qty, ATK, null, null, true, false);
            if (sqd != "")
            {
                if (rnd.Next(0, 9) > 6) CreateBMBMission(f, target2d, qty, ATK, null, null, false, false);
                f.add("Trigger", "BombersAtTarget", "TPassThrough 1 " + sqd + " " + target2d.x.ToString() + " " + target2d.y.ToString() + " 12000");
                if (StrikerGroupName == "") StrikerGroupName = sqd;
                GamePlay.gpPostMissionLoad(f);
                NextMissionNum++;
                RedirectCAP(againstArmy, target2d);
                gameIsOn = true;
            };
        };
    }
    private void CreateBombingMission(MissionMarker mm, bool activeMis)
    {
        Point2d pt2d = mm.Pos2d();
        Point3d pt3d = mm.Pos3d();
        target3d = pt3d;
        if (!activeMis)
            if (rnd.Next(10) < 5) CreateIndustryMission(true);
            else CreateAirbaseMission(true);
        target3d = pt3d;

        target2d = new Point2d(target3d.x, target3d.y);
        if (targetName == "" && !activeMis) targetName = MissionMarkerName(mm.key) + " in " + GamePlay.gpSectorName(target2d.x, target2d.y);
        if (odenDebug) GamePlay.gpLogServer(null, "CreateBombingMission: {0}", new object[] { targetName });
        int qty = 9;
        if (ATK == RAF) qty = 10;

        if (!PlayerIsBomber() || ATK != GamePlay.gpPlayer().Army())
        {
            ISectionFile f = GamePlay.gpCreateSectionFile();
            string sqd = CreateBMBMission(f, target2d, qty, ATK, null, null, true, activeMis);
            if (sqd != "")
            {
                if (rnd.Next(0, 9) > 6) CreateBMBMission(f, target2d, qty, ATK, null, null, false, activeMis);
                if (!activeMis)
                {
                    f.add("Trigger", "BombersAtTarget", "TPassThrough 1 " + sqd + " " + target2d.x.ToString() + " " + target2d.y.ToString() + " 12000");
                    if (StrikerGroupName == "") StrikerGroupName = sqd;
                }
                else
                {
                    CreateCAPMission(f, target2d, 6, ATK == LW ? RAF : LW, false);
                };
                GamePlay.gpPostMissionLoad(f);
                NextMissionNum++;
                if (!activeMis)
                {
                    RedirectCAP(ATK == LW ? RAF : LW, target2d);
                    gameIsOn = true;
                };
            };
            if (activeMis) BMBFlightAB = null;
        };
    }
    private void CreateInterdictionMission(MissionMarker mm)
    {
        if (odenDebug) GamePlay.gpLogServer(null, "Interdiction: '{0}' '{1}'", new object[] { mm.key, MissionMarkerName(mm.key) });
        List<GroundStationary> targets = new List<GroundStationary>();
        Point2d pt2d = mm.Pos2d();
        Point3d pt3d = mm.Pos3d();
        target3d = pt3d;
        foreach (GroundStationary gs in GamePlay.gpGroundStationarys(pt2d.x, pt2d.y, 5000))
            if (!gs.Name.Contains("NONAME") && !gs.Name.StartsWith("0:") && !gs.Name.Contains("Balloon"))
                targets.Add(gs);
        if (odenDebug) GamePlay.gpLogServer(null, "Interdiction: '{0}' targets={1}", new object[] { mm.key, targets.Count });
        if (targets.Count == 0)
            return;

        while (targets.Count > 5)
            targets.RemoveAt(rnd.Next(targets.Count - 1));
        // CAS is always primary
        targetName = CountryOwnership((ATK == LW ? RedCoalition : BlueCoalition)) + " ground units in " + MissionMarkerName(mm.key) + " sector " + GamePlay.gpSectorName(pt2d.x, pt2d.y);
        if (odenDebug) GamePlay.gpLogServer(null, "Interdiction: {0}", new object[] { targetName });

        int qty = 8;
        if (ATK == RAF && gameDateTime.Year < 1941) qty = 6;

        Player p = GamePlay.gpPlayer();

        if (rnd.Next(10) < 3 || odenDebug)
            if (p != null)
                if (p.Place() != null)
                    if (p.Place().Army() == ATK)
                        if (p.Place().Group() != null)
                            if (p.Place().Group() is AiAirGroup)
                                if (!PlayerIsBomber())
                                {
                                    playerFlightCAS = true; // see OnAircraftTookOff
                                    if (odenDebug) GamePlay.gpLogServer(null, "PlayerCASMission1: '{0}'", new object[] { p.Place().Group().Name() });
                                    string sqdCAS = p.Place().Group().Name();
                                    if (odenDebug) GamePlay.gpLogServer(null, "PlayerCASMission2: '{0}'", new object[] { sqdCAS });
                                    if (sqdCAS.Contains(":"))
                                        sqdCAS = sqdCAS.Substring(sqdCAS.IndexOf(':') + 1);
                                    if (odenDebug) GamePlay.gpLogServer(null, "PlayerCASMission3: '{0}' {1}", new object[] { p.Place().Group().Name(), sqdCAS });

                                    ISectionFile f = GamePlay.gpCreateSectionFile();
                                    CAPFlightIndex++;
                                    CreateCAPMission(f, pt2d, qty, ATK, false); // TARCAP
                                    f.add("Trigger", "BombersAtTarget", "TPassThrough 1 " + sqdCAS + " " + pt2d.x.ToString() + " " + pt2d.y.ToString() + " 12000");
                                    GamePlay.gpPostMissionLoad(f);
                                    NextMissionNum++;
                                    RedirectCAP(ATK == LW ? RAF : LW, pt2d);
                                    gameIsOn = true;
                                }
                                else
                                {
                                    if (odenDebug) GamePlay.gpLogServer(null, "PlayerIsBomber: '{0}'", new object[] { (p.Place() as AiAircraft).Type() });
                                    if ((p.Place() as AiAircraft).Type().ToString().Contains("DiveBomber"))
                                    {
                                        playerFlightCAS = true; // see OnAircraftTookOff
                                        string sqdCAS = p.Place().Group().Name();
                                        if (sqdCAS.Contains(":"))
                                            sqdCAS = sqdCAS.Substring(sqdCAS.IndexOf(':') + 1);
                                        if (odenDebug) GamePlay.gpLogServer(null, "PlayerCASMission3: '{0}' {1}", new object[] { p.Place().Group().Name(), sqdCAS });

                                        ISectionFile f = GamePlay.gpCreateSectionFile();
                                        CAPFlightIndex++;
                                        CreateCAPMission(f, pt2d, qty, ATK, false); // TARCAP
                                        CreateCAPMission(f, pt2d, qty, ATK, false); // TARCAP
                                        f.add("Trigger", "BombersAtTarget", "TPassThrough 1 " + sqdCAS + " " + pt2d.x.ToString() + " " + pt2d.y.ToString() + " 12000");
                                        GamePlay.gpPostMissionLoad(f);
                                        NextMissionNum++;
                                        RedirectCAP(ATK == LW ? RAF : LW, pt2d);
                                        gameIsOn = true;
                                    };
                                };

        if (odenDebug) GamePlay.gpLogServer(null, "CreateCASMission: {0} playerFlightCAS = {1}", new object[] { mm.key, playerFlightCAS });
        if (!playerFlightCAS)
        {
            if (!PlayerIsBomber() || ATK != GamePlay.gpPlayer().Army())
            {
                ISectionFile f = GamePlay.gpCreateSectionFile();
                string sqd = CreateCASMission(f, pt2d, qty, ATK, targets, false);
                if (sqd != "")
                {
                    if (rnd.Next(0, 9) > 6) CreateCASMission(f, pt2d, qty, ATK, targets, false);
                    if (rnd.Next(0, 9) > 6) CreateCAPMission(f, pt2d, qty, ATK, false); // TARCAP
                    f.add("Trigger", "BombersAtTarget", "TPassThrough 1 " + sqd + " " + pt2d.x.ToString() + " " + pt2d.y.ToString() + " 12000");
                    if (StrikerGroupName == "") StrikerGroupName = sqd;
                    GamePlay.gpPostMissionLoad(f);
                    NextMissionNum++;
                    RedirectCAP(ATK == LW ? RAF : LW, pt2d);
                    gameIsOn = true;
                };
            };
        };
    }

    private void CreateLanding(int idx)
    {
        gameIsOn = true;
        idxTarget = idx;
        MissionMarker mm = MissionMarkers[idx];
        int chiefs = 0;
        foreach (int i in GamePlay.gpArmies())
            chiefs += GamePlay.gpGroundGroups(i).Length;

        ISectionFile f = GamePlay.gpCreateSectionFile();
        string value;
        for (int i = chiefs; i < chiefs + 22; i++)
        {
            if (rnd.Next(1, 10) > 1) value = "Ship.MotorBarge_Large1 de" + " /sleep 0/skill 2/slowfire 1";
            else value = "Ship.Minensuchboote de" + " /sleep 0/skill 2/slowfire 1";
            f.add("Chiefs", i.ToString() + "_Chief", value);
            //GamePlay.gpLogServer(null, "CreateBarges: {0} {1} {2}", new object[] { sect, key, value });
        };
        double dir = 120 + rnd.Next(0, 60);
        Point2d mrk2d = new Point2d(mm.x, mm.y);
        Point2d fleet2d = calcPos(mrk2d, 10000, dir); // 10km should take 30mins
        target2d = fleet2d;

        groundAssaultFrom = "vb_East_of";
        if (dir > 135) groundAssaultFrom = "vb_South_of";

        for (int i = chiefs; i < chiefs + 22; i++)
        {   // start and stop wp for each ship
            Point2d nearbyPoint2d = calcPos(fleet2d, (i - chiefs) * 300, dir + 90);
            value = (nearbyPoint2d.x + rnd.Next(0, 80)).ToString() + " " +
                    (nearbyPoint2d.y + rnd.Next(0, 80)).ToString() + " 38.40  0 2 5.56"; // 5.56 == 20 kmh
            f.add(i.ToString() + "_Chief_Road", "", value);

            nearbyPoint2d = calcPos(mrk2d, (i - chiefs) * 50, dir + 90);
            value = (nearbyPoint2d.x).ToString() + ' ' +
                    (nearbyPoint2d.y).ToString() + " 38.40";
            f.add(i.ToString() + "_Chief_Road", "", value);
        };

        CreateCAPMission(f, fleet2d, 12, LW, false);
        CreateBMBMission(f, mrk2d, 9, LW, null, null, false, false);
        if (GamePlay.gpIsServerSingle())
        {
            if (rnd.Next(1, 5) > 2) CreateCAPMission(f, mrk2d, 12, LW, false);
            if (rnd.Next(1, 5) > 2) CreateBMBMission(f, mrk2d, 9, LW, null, null, false, false);
        }
        else
        {
            if (rnd.Next(1, 5) > 2 && GamePlay.gpRemotePlayers().Length < 3) CreateCAPMission(f, mrk2d, 12, LW, false);
            if (rnd.Next(1, 5) > 2 && GamePlay.gpRemotePlayers().Length < 7) CreateCAPMission(f, fleet2d, 12, LW, false);
            if (rnd.Next(1, 5) > 2 && GamePlay.gpRemotePlayers().Length < 11) CreateCAPMission(f, mrk2d, 12, LW, false);

            if (rnd.Next(1, 5) > 2 && GamePlay.gpRemotePlayers().Length < 3) CreateBMBMission(f, mrk2d, 3, LW, null, null, false, false);
            if (rnd.Next(1, 5) > 2 && GamePlay.gpRemotePlayers().Length < 7) CreateBMBMission(f, mrk2d, 3, LW, null, null, false, false);
            if (rnd.Next(1, 5) > 2 && GamePlay.gpRemotePlayers().Length < 11) CreateBMBMission(f, mrk2d, 3, LW, null, null, false, false);
        };
        //f.add("Trigger", "PhaseSequenceOver", "TPassThrough 4 2 " + mrk2d.x.ToString() + " " + mrk2d.y.ToString() + " 1609");
        f.add("Trigger", mm.key, "TPassThrough 4 2 " + mrk2d.x.ToString() + " " + mrk2d.y.ToString() + " 1609");
        if (odenDebug) GamePlay.gpLogServer(null, "gpPostMissionLoad: {0}", new object[] { "SeaLion" });
        targetName = "Operation Sea Lion in " + GamePlay.gpSectorName(mrk2d.x, mrk2d.y);
        GamePlay.gpPostMissionLoad(f);
        NextMissionNum++;
    }

    private string SatelliteStations(string sector)
    {
        switch (sector)
        {
            case "RAF Biggin Hill": return "Biggin_Hill,Gravesend,Manston,Hawkinge";
            case "RAF Kenley": return "Biggin_Hill,Gravesend,Manston,Hawkinge";
            case "RAF Hornchurch": return "Hornchurch,Rochford,Manston,Hawkinge";
            case "RAF Tangmere": return "Tangmere,Westhampnett";
            case "RAF North Weald": return "North_weald,Boscombe_Down"; // Warmwell, Exeter, St. Eval
            case "RAF Debden": return "Debden,Martlesham";
            case "RAF Middle Wallop": return "Andover,Westhampnett";
            case "RAF Northolt": return "Northolt,Hendon";
            case "RAF Duxford": return "Duxford,Fowlmere";
            case "RAF Wittering": return "Wittering,Coltishall,Collyweston";
        };
        return "";
    }
    private string DefaultSkins(string type, string sqn)
    {   // skins relate to planetype
        if (SquadronIsFrench(sqn))
        {
            if (type.Contains("Bf-110")) return "Potez 631.jpg";
            if (type.Contains("Hurricane")) return "Bloch 152.jpg";
            if (type.Contains("Spitfire")) return "Dewoitine 520.jpg";
            if (type.Contains("Wellington")) return "Bloch 210.jpg";
        };
        if (sqn.Contains("_JG") && type.Contains("109"))
        {
            switch (sqn.Substring(sqn.IndexOf("I")))
            {   // "BoB_LW_JG26_I" > return "JG26_1.jpg";
                case "I": return sqn.Substring(7, sqn.LastIndexOf("_") - 6) + "1.jpg"; // staffel
                case "II": return sqn.Substring(7, sqn.LastIndexOf("_") - 6) + "4.jpg";
                case "III": return sqn.Substring(7, sqn.LastIndexOf("_") - 6) + "7.jpg";
            };
        };
        if (sqn.Contains("_ZG26") && type.Contains("110")) return "ZG26.jpg";
        if (sqn.Contains("_ZG76_II") && type.Contains("110")) return "ZG76_II.jpg"; // _III will also catch this one, but yeah
        if (sqn.Contains("ErprGr210") && type.Contains("109")) return "Erpro210.jpg";
        if (sqn.Contains("_LG2_I") && type.Contains("109")) return "LG2_1.jpg"; // staffel
        if (sqn.Contains("_LG2_II") && type.Contains("109")) return "LG2_4.jpg";

        if (type.Contains("Spitfire")) // spit MkI 100oct will fail this, all others have this skin - future Battle of France problem, almost (no 100oct by then?)
            if (gameDateTime.Year > 1940)
                return "Standard_41A.jpg";
        // WIP Black&White Hurri

        return "";
    }
    private string CountryName(string code)
    {
        switch (code)
        {
            case "al": return "Allied";
            case "ax": return "Axis";
            case "gb": return "Great Britain";
            case "pl": return "Poland";
            case "cz": return "Czechoslovakia";
            case "ca": return "Canada";
            case "fr": return "France";
            case "de": return "Germany";
            case "it": return "Italy";
            case "au": return "Australia";
            case "sa": return "South Africa";
            case "in": return "India";
            case "cw": return "Commonwealth";
        };
        return "Unknown";
    }
    private string CountryOwnership(string code)
    {
        switch (code)
        {
            case "al": return "Allied";
            case "ax": return "Axis";
            case "gb": return "British";
            case "pl": return "Polish";
            case "cz": return "Czech";
            case "ca": return "Canadian";
            case "fr": return "French";
            case "de": return "German";
            case "it": return "Italian";
            case "au": return "Australian";
            case "sa": return "South African";
            case "in": return "Indian";
            case "cw":
                switch (rnd.Next(10))
                {
                    case 0: return "Commonwealth";
                    case 1: return "Australian";
                    case 2: return "Australian";
                    case 3: return "Australian";
                    case 4: return "Indian";
                    default: return "British";
                };
        };
        return "Unknown";
    }
    private string CountryAirforce(string code)
    {
        switch (code)
        {
            case "al": return "Allied";
            case "ax": return "Axis";
            case "gb": return "RAF";
            case "pl": return "RAF";
            case "cz": return "RAF";
            case "ca": return "RCAF";
            case "fr": return "AdA";
            case "de": return "Luftwaffe";
            case "it": return "RA";
            case "au": return "RAAF";
            case "sa": return "SAAF";
            case "in": return "RAF";
            case "cw": return "RAF";
        };
        return "Unknown";
    }
    private string CountryArmyUnit(string code)
    {
        switch (CampaignName)
        {
            case cBattleOfFrance:
                switch (fmCurrent)
                {
                    case fmDunkerque:
                        if (code == "de") return "1st Panzer Div.";
                        if (code == "fr") return "150th Infantry Rgmt.";
                        break;
                    case fmCalais:
                        if (code == "gb")
                            if (rnd.Next(10) > 5) return "30th Infantry Bde.";
                            else return "3rd Royal Tank Rgmt.";
                        if (code == "de") return "10th Panzer Div.";
                        break;
                    case fmBoulogne:
                        if (code == "gb") return "20th Guards Bde.";
                        if (code == "de") return "2nd Panzer Div.";
                        if (code == "fr") return "21st Infantry Div.";
                        break;
                };
                if (code == "gb") return "Expeditionary Force";
                return "Army";
                break;
            case cBattleOfBritain:
                return "Army";
                break;
            case cNorthAfrica:
                switch (code)
                {
                    case "gb":
                        switch (rnd.Next(15))
                        {
                            case 0: return "7th Royal Tank Rgmt.";
                            case 1: return "4th Armored Bde.";
                            case 2: return "7th Armored Bde.";
                            case 3: return "7th Support Group"; // Inf Bde
                            case 4: return "4th Royal Tank Rgmt.";
                            case 5: return "2nd Royal Tank Rgmt.";
                            case 6: return "16th Infantry Bde."; // attached to 4th Indian Div
                            case 7: return "Selby Force";
                            case 8: return "7th Hussars Cav. Rgmt.";
                            case 9: return "11th Hussars Cav. Rgmt.";
                            default: return "7th Armoured Div.";
                        };
                    case "it":
                        switch (rnd.Next(10))
                        {
                            case 0: return "Babini Group";
                            case 1: return "60th 'Sabratha' Div.";
                            case 2: return "61st 'Sirte' Div.";
                            case 3: return "62nd 'Marmarica' Div.";
                            case 4: return "63rd 'Cyrene' Div.";
                            case 5: return "64th 'Catanzaro' Div.";
                            case 6: return "4th Blackshirt Div.";
                            //case 2: return "Maletti Group"; // lost at Nibeiwa Camp
                            default: return "10th Army";
                        };
                    case "de":
                        if (gameDateTime < new DateTime(1941, 3, 1)) return "5th Light Div.";
                        else
                            switch (rnd.Next(5))
                            {
                                case 0: return "90th Light Div.";
                                case 1: return "15th Panzer Div.";
                                default: return "21st Panzer Div.";
                            };
                    case "au":
                        switch (rnd.Next(5))
                        {
                            case 0: return "16th Infantry Bde.";
                            case 1: return "17th Infantry Bde.";
                            case 2: return "19th Infantry Bde.";
                            default: return "6th Infantry Div.";
                        };
                    case "in":
                        switch (rnd.Next(10))
                        {
                            case 0: return "5th Infantry Div.";
                            case 1: return "5th Infantry Bde.";
                            case 2: return "7th Infantry Bde.";
                            case 3: return "11th Infantry Bde.";
                            default: return "4th Infantry Div.";
                        };
                    case "cw":
                        switch (rnd.Next(6))
                        {
                            case 0: return CountryArmyUnit("gb");
                            case 2: return CountryArmyUnit("in");
                            default: return CountryArmyUnit("au");
                        };
                    default: return rnd.Next(1, 20).ToString() + ".Infantry Bde.";
                };
                break;
        };
        return "Army";
    }
    private int CountrySide(string code)
    {
        switch (code)
        {
            case "al": return RAF;
            case "ax": return LW;
            case "gb": return RAF;
            case "pl": return RAF;
            case "cz": return RAF;
            case "ca": return RAF;
            case "fr": return RAF;
            case "de": return LW;
            case "it": return LW;
            case "au": return RAF;
            case "sa": return RAF;
            case "in": return RAF;
            case "cw": return RAF;
        };
        return 0;
    }
    private string Designation(string className)
    {
        switch (className)
        {
            case "Aircraft.HurricaneMkI_dH5-20": return "Hurricane Mk I";
            case "Aircraft.HurricaneMkI_dH5-20_100oct": return "Hurricane Mk I";
            case "Aircraft.HurricaneMkI": return "Hurricane Mk I";
            case "Aircraft.HurricaneMkI_100oct": return "Hurricane Mk I";
            case "Aircraft.HurricaneMkI_FB": return "Hurricane Mk I";
            case "Aircraft.SpitfireMkI": return "Spitfire Mk I";
            case "Aircraft.SpitfireMkI_100oct": return "Spitfire Mk I";
            case "Aircraft.SpitfireMkIa": return "Spitfire Mk Ia";
            case "Aircraft.SpitfireMkIa_100oct": return "Spitfire Mk Ia";
            case "Aircraft.SpitfireMkIIa": return "Spitfire Mk IIa";
            case "Aircraft.BlenheimMkI": return "Blenheim Mk I";
            case "Aircraft.BlenheimMkIV": return "Blenheim Mk IV";
            case "Aircraft.BlenheimMkIV_Late": return "Blenheim Mk IV";
            case "Aircraft.BlenheimMkIVF": return "Blenheim Mk IVF";
            case "Aircraft.BlenheimMkIVF_Late": return "Blenheim Mk IVF";
            case "Aircraft.WellingtonMkIc": return "Wellington Mk Ic";
            case "Aircraft.BeaufighterMkIF": return "Beaufighter Mk IF";
            case "Aircraft.DefiantMkI": return "Defiant Mk I";
            case "Aircraft.GladiatorMkII": return "Gladiator MkII";
            case "Aircraft.DH82A": return "Tiger Moth";
            case "Aircraft.Bf-109E-1": return "Bf 109E-1";
            case "Aircraft.Bf-109E-1B": return "Bf 109E-1/B";
            case "Aircraft.Bf-109E-3": return "Bf 109E-3";
            case "Aircraft.Bf-109E-3B": return "Bf 109E-3/B";
            case "Aircraft.Bf-109E-4": return "Bf 109E-4";
            case "Aircraft.Bf-109E-4_Late": return "Bf 109E-4";
            case "Aircraft.Bf-109E-4B": return "Bf 109E-4/B";
            case "Aircraft.Bf-109E-4B_Late": return "Bf 109E-4/B";
            case "Aircraft.Bf-109E-4N": return "Bf 109E-4/N";
            case "Aircraft.Bf-109E-4N_Late": return "Bf 109E-4/N";
            case "Aircraft.Bf-110C-2": return "Bf 110C-2";
            case "Aircraft.Bf-110C-4": return "Bf 110C-4";
            case "Aircraft.Bf-110C-4N": return "Bf 110C-4/N";
            case "Aircraft.Bf-110C-4Late": return "Bf 110C-4";
            case "Aircraft.Bf-110C-6": return "Bf 110C-6";
            case "Aircraft.Bf-110C-7": return "Bf 110C-7";
            case "Aircraft.Ju-87B-2": return "Ju 87B-2";
            case "Aircraft.Do-17Z-1": return "Do 17Z-1";
            case "Aircraft.Do-17Z-2": return "Do 17Z-2";
            case "Aircraft.Do-215B-1": return "Do 215B-1";
            case "Aircraft.Ju-88A-1": return "Ju 88A-1";
            case "Aircraft.He-111P-2": return "He 111P-2";
            case "Aircraft.He-111H-2": return "He 111H-2";
            case "Aircraft.CR42": return "CR.42 Falco";
            case "Aircraft.G50": return "G.50 Freccia";
            case "Aircraft.BR-20M": return "BR.20M Cicogna";
            case "Aircraft.FW-200C-1": return "Fw 200C-1 Condor";
            case "ShipUnit.Tanker_Medium1": return "Cargo Ship";
            case "ShipUnit.MotorBarge_Large1": return "Invasion Barge";
            case "ShipUnit.Minensuchboote": return "Minesweeper";
        };

        return className;
    }
    private string DesignationAdA(string className)
    {
        switch (className)
        {
            case "Aircraft.HurricaneMkI_dH5-20": return "Bloch 152";
            case "Aircraft.HurricaneMkI_dH5-20_100oct": return "Bloch 152";
            case "Aircraft.HurricaneMkI": return "Morane Saulnier 406";
            case "Aircraft.HurricaneMkI_100oct": return "Morane Saulnier 406";
            case "Aircraft.HurricaneMkI_FB": return "Morane Saulnier 406";
            case "Aircraft.SpitfireMkI": return "Dewoitine 520";
            case "Aircraft.SpitfireMkI_100oct": return "Dewoitine 520";
            case "Aircraft.SpitfireMkIa": return "Dewoitine 520";
            case "Aircraft.SpitfireMkIa_100oct": return "Dewoitine 520";
            case "Aircraft.SpitfireMkIIa": return "Dewoitine 520";
            case "Aircraft.WellingtonMkIc": return "Bloch 210";
            case "Aircraft.Bf-110C-2": return "Potez 631";
            case "Aircraft.Bf-110C-4": return "Potez 631";
            case "Aircraft.Bf-110C-4N": return "Potez 631";
            case "Aircraft.Bf-110C-4Late": return "Potez 631";
            case "Aircraft.Bf-110C-6": return "Potez 631";
            case "Aircraft.Bf-110C-7": return "Potez 631";
        };

        return className;
    }
    private string bobDesignation(string internalTypeName)
    {
        return Designation(internalTypeName.Substring(4));
    }
    private string bobCountryOfOrigin(string internalTypeName)
    {
        if (internalTypeName.Contains("Hurricane")) return "gb";
        if (internalTypeName.Contains("Spitfire")) return "gb";
        if (internalTypeName.Contains("Blenheim")) return "gb";
        if (internalTypeName.Contains("Wellington")) return "gb";
        if (internalTypeName.Contains("Beaufighter")) return "gb";
        if (internalTypeName.Contains("Defiant")) return "gb";
        if (internalTypeName.Contains("Gladiator")) return "gb";
        if (internalTypeName.Contains("DH82A")) return "gb";
        if (internalTypeName.Contains("Bf-")) return "de";
        if (internalTypeName.Contains("Ju-")) return "de";
        if (internalTypeName.Contains("Do-")) return "de";
        if (internalTypeName.Contains("He-")) return "de";
        if (internalTypeName.Contains("G50")) return "it";
        if (internalTypeName.Contains("CR42")) return "it";
        if (internalTypeName.Contains("BR-20")) return "it";
        if (internalTypeName.Contains("FW-")) return "de";
        return "nn";
    }
    private GroundStationary GroundStationaryByName(string name)
    {
        foreach (GroundStationary gs in GamePlay.gpGroundStationarys())
            if (gs.Name == name)
                return gs;
        return null;
    }
    private string ChainHomeRadarName(Point2d pt2d)
    {
        AiAirport ap = FindAirport(RAF, pt2d, 0);
        if (ap != null)
        {
            switch (ap.Name())
            {
                case "Ford": return "Poling"; break;
                case "Wilmington": return "Pevensey (Eastbourne)"; break;
                case "Littlestone": return "Rye";
                    //if (pt2d.y > ap.Pos().y) return "Newchurch"; // 1941
                    //else return "Rye";
                    break;
                case "Hawkinge": return "Dover"; break;
                case "Eastchurch": return "Dunkirk (Canterbury West)"; break;
                case "Rochford": return "Canewdon (Rochford)"; break;
                case "Canterbury": return "Wingham (Canterbury East)"; break;
                case "Sandown": return "Ventnor (Isle of Wight)"; break;
            };
            return ap.Name();
        };
        return "N/A";
    }
    private string PortDockName(Point2d pt2d)
    {
        AiAirport ap = FindAirport(RAF, pt2d, 0);
        if (ap != null)
        {
            switch (ap.Name())
            {
                case "Wilmington": return "Port of Hastings"; break;
                case "Hawkinge":
                    if (pt2d.y > ap.Pos().y) return "Port of Dover";
                    else return "Folkstone Port";
                    break;
                case "Rochford": return "Port of Rochford"; break;
                case "Gravesend": return "Docks of Tilbury"; break;
            };
            return ap.Name();
        };
        return "N/A";
    }
    private string BattleSetNames(string key)
    {
        if (odenDebug) GamePlay.gpLogServer(null, "BattleSetNames: {0}/{1}", new object[] { fmCurrent, bobVicSide });
        List<string[]> cbs = CampaignBattleSet();
        if (cbs != null)
            foreach (string[] bs in cbs)
                foreach (string s in bs)
                    if (s.Equals(fmCurrent))
                    {
                        if (bs.Length == 1) return MissionMarkerName(bs[0]);
                        else
                            if (bs.Length == 2) return MissionMarkerName(bs[0]) + " and " + MissionMarkerName(bs[1]);
                            else
                            {
                                string fmName = MissionMarkerName(bs[0]);
                                for (int i = 1; i < bs.Length - 1; i++)
                                    fmName += ", " + MissionMarkerName(bs[i]);
                                return fmName + " and " + MissionMarkerName(bs[bs.Length - 1]);
                            };
                    };
        return MissionMarkerName(key);
    }
    private string MissionMarkerName(string key)
    {
        switch (CampaignName)
        {
            case cBattleOfFrance:
                switch (key)
                {
                    case fmArras: return "Arras";
                    case fmStPolSurTernoise: return "St-Pol-Sur-Ternoise";
                    case fmFruges: return "Fruges";
                    case fmHesdin: return "Hesdin";
                    case fmFrevent: return "Frevent";
                    case fmAuxiLeChateau: return "Auxi-Le-Chateau";
                    case fmLeCrotoy: return "Le Crotoy";
                    case fmAbbeville: return "Abbeville";
                    case fmBerteaucourt: return "Berteaucourt";
                    case fmAmiens: return "Amiens";
                    case fmBapaume: return "Bapaume";
                    case fmRoye: return "Roye";
                    case fmMontdidier: return "Montdidier";
                    case fmBeauvais: return "Beauvais";
                    case fmPoixDePicardie: return "Poix-De-Picardie";
                    case fmAumale: return "Aumale";
                    case fmBlangySurBresle: return "Blangy-Sur-Bresle";
                    case fmLeTreport: return "Le Treport";
                    case fmNeufchatelEnBray: return "Neufchatel-En-Bray";
                    case fmDieppe: return "Dieppe";
                    case fmBerck: return "Berck";
                    case fmLigescourt: return "Ligescourt";
                    case fmEtaples: return "Etaples";
                    case fmSempy: return "Sempy";
                    case fmBoulogne: return "Boulogne";
                    case fmDesvres: return "Desvres";
                    case fmLumbres: return "Lumbres";
                    case fmStOmer: return "St-Omer";
                    case fmAireSurLaLys: return "Aire-Sur-La-Lys";
                    case fmBruayLaBuissiere: return "Bruay-La-Buissiere";
                    case fmMerville: return "Merville";
                    case fmHazelbrouck: return "Hazelbrouck";
                    case fmLeper: return "Leper";
                    case fmPoperinge: return "Poperinge";
                    case fmDiksmuide: return "Diksmuide";
                    case fmVeurne: return "Veurne";
                    case fmDunkerque: return "Dunkerque";
                    case fmGravelines: return "Gravelines";
                    case fmCalais: return "Calais";
                };
                break;
            case cBattleOfBritain:
                switch (key)
                {
                    case fmDungeness: return "Dungeness";
                    case fmDover: return "Dover";
                    case fmRamsgate: return "Ramsgate";
                    case fmCanterbury: return "Canterbury";
                    case fmRochester: return "Rochester";
                    case fmLondon: return "London";
                    case fmEastbourne: return "Eastbourne";
                    case fmHorsham: return "Horsham";
                };
                break;
            case cNorthAfrica:
                switch (key)
                {
                    case fmSidi_Barrani: return "Sidi Barrani"; break;
                    case fmBuq_Buq: return "Buq Buq"; break;
                    case fmHalfaya_Pass: return "Halfaya Pass"; break;
                    case fmSollum: return "Sollum"; break;
                    case fmFort_Capuzzo: return "Fort Capuzzo"; break;
                    case fmSidi_Omar: return "Sidi Omar"; break;
                    case fmSidi_Azeiz: return "Sidi Azeiz"; break;
                    case fmBardia: return "Bardia"; break;
                    case fmBir_el_Menastir: return "Bir el Menastir"; break;
                    case fmQasr_el_Arid: return "Qasr el Arid"; break;
                    case fmGambut: return "Gambut"; break;
                    case fmSidi_Rezegh: return "Sidi Rezegh"; break;
                    case fmEd_Dedu: return "Ed Dedu"; break;
                    case fmEl_Adem: return "El Adem"; break;
                    case fmTobruk: return "Tobruk"; break;
                    case fmBir_Hacheim: return "Bir Hacheim"; break;
                    case fmAlem_Hamza: return "Alem Hamza"; break;
                    case fmGazala: return "Gazala"; break;
                    case fmTmimi: return "Tmimi"; break;
                    case fmBir_Halegh: return "Bir Halegh"; break;
                    case fmMartuba: return "Martuba"; break;
                    case fmDerna: return "Derna"; break;
                };
                break;
            case cCobra:
                switch (key)
                {
                    case fmWestSeeburg: return "West Seeburg";
                    case fmStHansa: return "S:t Hansa";
                    case fmWestStadt: return "Weststadt";
                    case fmWestigo: return "Westigo";
                    case fmSWestheim: return "Sudwestheim";
                    case fmSudMarckt: return "Sud Marckt";
                    case fmEastUpTrent: return "East-upon-Trent";
                    case fmEastMinor: return "East Minor";
                    case fmEastSherwood: return "East Sherwood";
                    case fmEastLakeCity: return "East Lake City";
                    case fmEastBromTown: return "East Bromtown";
                    case fmStEastman: return "Saint Eastman";
                    case fmSouthKent: return "South Kent";
                };
                break;
        };
        return "Unkown Town";
    }
    private string CampaignPhase()
    {
        switch (CampaignName)
        {
            case cBattleOfFrance: return cBattleOfFrance;
            case cBattleOfBritain:
                if (bobVicSide == LW)
                    if (defSquadron.Contains("RAF")) return "Sealion";
                    else return "Seelöwe";
                if (bobVicSide == RAF)
                    if (defSquadron.Contains("RAF")) return "Fightersweeps over France";
                    else return "Intercept RAF flights";
                if (gameDateTime >= dtFighterBomber) // Night time Blitz, daytime fighterbombers
                    if (defSquadron.Contains("RAF")) return "Fighterbomber Attacks";
                    else return "Störangriffe";
                if (gameDateTime >= dtBlitz)
                    return "Blitz";
                if (gameDateTime >= dtAdlerTag)
                    if (defSquadron.Contains("RAF")) return "Assault on Fighter Command";
                    else return "Adlerangriff";
                if (gameDateTime >= dtCoastalBattles)
                    if (defSquadron.Contains("RAF")) return "Coastal Battles";
                    else return "Kanalkampf";
                if (defSquadron.Contains("RAF")) return "Convoy Battles";
                else return "Kanalkampf";
                break;
            case cNorthAfrica:
                if (gameDateTime >= dtOpThesus)
                    if (defSquadron.Contains("RAF")) return "Axis Op. Theseus";
                    else return "Unternehmen Theseus";
                if (gameDateTime >= dtOpCrusader)
                    if (defSquadron.Contains("RAF")) return "Operation Crusader";
                    else return "Commonwealth Op. Crusader";
                if (gameDateTime >= dtOpSonnenblume)
                    if (defSquadron.Contains("RAF")) return "Axis Op. Sunflower";
                    else return "Unternehmen Sonnenblume";
                if (defSquadron.Contains("RAF")) return "Operation Compass";
                else return "Commonwealth Op. Compass";
                break;
            case cCobra: return "CAS Warfare";
            default: return "";
        };
    }
    internal List<string[]> CampaignBattleSet()
    {
        switch (CampaignName)
        {
            case cBattleOfFrance: return FallGelb;
            case cBattleOfBritain:
                if (bobVicSide == LW) return UntSeelowe;
                else return null;
                break;
            case cNorthAfrica:
                if (gameDateTime >= dtOpThesus) return UntTheseus;
                if (gameDateTime >= dtOpCrusader) return OpCrusader;
                if (gameDateTime >= dtOpSonnenblume) return UntSonnenblume;
                return OpCompass;
                break;
            default: return null;
        };
    }
    private DateTime CampaignStartDate()
    {
        switch (CampaignName)
        {
            case cBattleOfFrance: return dtBattleOfFrance;
            case cBattleOfBritain: return dtBattleOfBritain;
            case cNorthAfrica: return dtOpCompass;
            case cCobra: return new DateTime(1942, 6, 15, 0, 0, 0);
        };
        return gameDateTime;
    }
    private string CampaignCoalition(int army)
    {
        switch (CampaignName)
        {
            case cBattleOfFrance:
                if (army == RAF) return "fr";
                else return "de";
            case cBattleOfBritain:
                if (army == RAF) return "gb";
                else return "de";
            case cNorthAfrica:
                if (army == RAF) return "cw";
                else return "it";
            case cCobra:
                if (army == RAF) return "al";
                else return "ax";
        };
        return "";
    }
    private string CampaignStartFM()
    {
        switch (CampaignName)
        {
            case cBattleOfFrance: return fmEtaples;
            case cNorthAfrica: return fmBardia;
            case cCobra: return (SelectNextMissionMarker(new Point2d(GamePlay.gpPlayer().Place().Pos().x, GamePlay.gpPlayer().Place().Pos().y))).key;
        };
        return "";
    }
    private int CampaignStartInitiative()
    {
        switch (CampaignName)
        {
            case cBattleOfFrance: return LW;
            case cBattleOfBritain: return LW;
            case cNorthAfrica: return RAF;
            case cCobra: return GamePlay.gpPlayer().Army();
        };
        return 0;
    }
    private string VictoryCondition(int army)
    {
        switch (CampaignName)
        {
            case cBattleOfFrance:
                if (army == RAF) return "Recapture France or hold Dunkirk until 4 June 1940";
                else return "Capture Dunkirk before 4 June 1940";
            case cBattleOfBritain:
                if (army == RAF) return "Reduce airforce ratio below 3 to stop operation Sea Lion";
                else return "Keep airforce ratio above 3 to initiate Unternehmen Seelöwe";
            case cNorthAfrica:
                if (army == RAF) return "Capture Derna by 29 Jan 1941";
                else return "Recapture Sidi Barrani or hold Derna by 29 Jan 1941";
            case cCobra: return "Capture All Map";
        };
        return "";
    }
    private string[] FlightSections(int army, int size, string form, int sqnStaffel)
    {   // army defines max, form max per section/flight and iteration used if asking for 3 planes 3 times to be in same sqn/staffel
        string[] Flight = new string[5] { "1", "", "", "", "01" }; // last is 21 in BoB_LW_KG2_I.21
        string value = "";
        // Bomber max 3 +VIC3
        // Zerstörer max 4 +FF
        // Fighter max 4 +FF
        // Recon max 1 +LINEABREAST
        // Transp. max 3 +VIC
        // UK Bomber max 10 +VIC
        // UK Fighter max 6 +VIC3
        // UK Fighter max 4 +FF
        int max = 12;
        if (army == RAF && form == "VIC") max = 40;
        if (army != RAF && form == "VIC") max = 9;
        if (army != RAF && form == "VIC3") max = 9;
        if (size > max) size = max;

        switch (form)
        {
            case "VIC":
                if (army == RAF)
                {   // max 10 but yeah (can go 4x10 in editor)
                    if (size == 2) Flight[0] = "1 2"; // 2-ship flight
                    if (size == 3) Flight[0] = "1 2 3"; // 3-ship flight (single flight)
                    if (size == 4) Flight[0] = "1 2 3 4"; // 4-ship flight (schwarm x3 of staffel)
                    if (size > 4) Flight[0] = "1 2 3 4 5"; // 5-ship flight
                    if (size == 6) Flight[1] = "6";
                    if (size == 7) Flight[1] = "6 7";
                    if (size == 8) Flight[1] = "6 7 8";
                    if (size == 9) Flight[1] = "6 7 8 9";
                    if (size > 9) Flight[1] = "6 7 8 9 10";
                    if (size == 11) Flight[2] = "11";
                    if (size == 12) Flight[2] = "11 12";
                    if (size == 13) Flight[2] = "11 12 13";
                    if (size == 14) Flight[2] = "11 12 13 14";
                    if (size > 14) Flight[2] = "11 12 13 14 15";
                    if (size == 16) Flight[3] = "16";
                    if (size == 17) Flight[3] = "16 17";
                    if (size == 18) Flight[3] = "16 17 18";
                    if (size == 19) Flight[3] = "16 17 18 19";
                    if (size > 19) Flight[3] = "16 17 18 19 20";
                }
                else
                {   // Stuka can go 8 in editor but seems to work as normal staffel of 3x3 kette
                    if (size == 2) Flight[0] = "1 2"; // 2-ship flight
                    if (size > 2) Flight[0] = "1 2 3"; // 3-ship flight
                    if (size == 4) Flight[1] = "4";
                    if (size == 5) Flight[1] = "4 5";
                    if (size > 5) Flight[1] = "4 5 6"; // 2x3-ship staffel
                    if (size == 7) Flight[2] = "7";
                    if (size == 8) Flight[2] = "7 8";
                    if (size > 8) Flight[2] = "7 8 9"; // 3x3-ship staffel = max
                };
                break;
            case "VIC3":
                if (size == 2) Flight[0] = "1 2"; // 2-ship flight
                if (size > 2) Flight[0] = "1 2 3"; // 3-ship flight
                if (size == 4) Flight[1] = "4";
                if (size == 5) Flight[1] = "4 5";
                if (size > 5) Flight[1] = "4 5 6"; // 2x3-ship staffel
                if (size == 7) Flight[2] = "7";
                if (size == 8) Flight[2] = "7 8";
                if (size > 8) Flight[2] = "7 8 9"; // 3x3-ship staffel = max
                if (size == 10) Flight[3] = "10";
                if (size == 11) Flight[3] = "10 11";
                if (size > 11) Flight[3] = "10 11 12";
                break;
            case "VIC6": // RAF 12 must split Flight[0], [1] and [2],[3] in two seperate blocks as VIC3 or fly 2x6 manipulated as VIC6
                if (size == 2) Flight[0] = "1 2";
                if (size == 3) Flight[0] = "1 2 3";
                if (size == 4) Flight[0] = "1 2 3 4";
                if (size == 5) Flight[0] = "1 2 3 4 5";
                if (size > 5) Flight[0] = "1 2 3 4 5 6"; // 2x6-ship flight in x12 squadron
                if (size == 7) Flight[1] = "7";
                if (size == 8) Flight[1] = "7 8";
                if (size == 9) Flight[1] = "7 8 9";
                if (size == 10) Flight[1] = "7 8 9 10";
                if (size == 11) Flight[1] = "7 8 9 10 11";
                if (size > 11) Flight[1] = "7 8 9 10 11 12";
                break;
            case "FINGERFOUR":
                if (size == 2) Flight[0] = "1 2"; // 2-ship flight
                if (size == 3) Flight[0] = "1 2 3"; // 3-ship flight (single flight)
                if (size > 3) Flight[0] = "1 2 3 4"; // 4-ship flight (schwarm x3 of staffel)
                if (size == 5) Flight[1] = "5";
                if (size == 6) Flight[1] = "5 6";
                if (size == 7) Flight[1] = "5 6 7";
                if (size > 7) Flight[1] = "5 6 7 8";
                if (size == 9) Flight[2] = "9";
                if (size == 10) Flight[2] = "9 10";
                if (size == 11) Flight[2] = "9 10 11";
                if (size > 11) Flight[2] = "9 10 11 12";
                break;
            default:
                break;
        };

        double sections = 0;
        if (Flight[0].Length > 0) sections += Math.Pow(2, 0);
        if (Flight[1].Length > 0) sections += Math.Pow(2, 1);
        if (Flight[2].Length > 0) sections += Math.Pow(2, 2);
        if (Flight[3].Length > 0) sections += Math.Pow(2, 3); // BoB_LW_AufklGr10.08, 1 plane in 4th section
        // BoB_LW_AufklGr_14.0F, 1 plane in each of the 4 sections = 1 +2 +4 +8 = 15 = 0xF
        sections.ToString();
        Flight[4] = sqnStaffel.ToString() + String.Format("{0:X}", (int)sections);

        return Flight;

    }

    // flyables in campaign
    private static List<string> RAFFighterSet = new List<string>
    {	"Aircraft.HurricaneMkI_dH5-20",
        "Aircraft.HurricaneMkI_dH5-20_100oct",
		"Aircraft.SpitfireMkI",
        "Aircraft.SpitfireMkI_100oct",
    	"Aircraft.HurricaneMkI",
    	"Aircraft.HurricaneMkI_100oct",
		"Aircraft.SpitfireMkIa",
        "Aircraft.SpitfireMkIa_100oct",
		"Aircraft.SpitfireMkIIa",
        "Aircraft.BeaufighterMkIF",
        "Aircraft.HurricaneMkI_FB",
    };
    private static List<string> RAFBomberSet = new List<string> { "Aircraft.BlenheimMkIV" };

    private static List<string> LWFighterSet = new List<string>
    {   "Aircraft.Bf-109E-1"
        ,"Aircraft.Bf-109E-1B"
        ,"Aircraft.Bf-110C-2"
		,"Aircraft.Bf-109E-3"
		,"Aircraft.Bf-109E-3B"
		,"Aircraft.Bf-110C-4"
		,"Aircraft.Bf-109E-4"
		,"Aircraft.Bf-109E-4B"
		,"Aircraft.Bf-110C-7"
    };
    private static List<string> LWBomberSet = new List<string> { "Aircraft.Ju-87B-2", "Aircraft.Ju-88A-1", "Aircraft.He-111P-2", "Aircraft.He-111H-2" };
    private static List<string> RAFighterSet = new List<string> { "Aircraft.G50" };
    private static List<string> RABomberSet = new List<string> { "Aircraft.BR-20M" };

    private static List<string> RedTankList = new List<string>
    {   "Armor.Guy_Mk_I gb"		// .50 Vickers MG, 5t/15mm 4x4, 1939
        ,"Armor.Vickers_Mk_VIB gb"	// .50 Vickers MG, 5t/14mm Track, 1936
        ,"Armor.Cruiser_Mk_IV gb"	// QF 2pdr (40mm) Gun, 14t/30mm, 1940
        ,"Armor.Valentine_I gb"	// QF 2pdr (40mm) Gun, 16t/65mm, 1940
        ,"Armor.Matilda_2A gb"		// 2 pdr (40mm) Gun, 25t/78mm, 1939
    };
    private static List<string> BlueTankList = new List<string>
    {     //" Armor.7TP de"	// only 20 used
          //," Armor.Hotchkiss_H39 de" // Panzerkampfwagen 38H 735(f) not frontline use
          //," Armor.Krupp_L2H43_Protze_Flak30 de"
          " Armor.SdKfz_222 de"	// 20mm KwK30, 4t/14mm 4x4, 1935
          ," Armor.Pz_35t de"		// 37mm KwK34, 10t/25mm, 1936
          ," Armor.SdKfz_231_6Rad de" // 20mm KwK30, 8t/15mm 6x4, 1932
          ," Armor.Pz_38t de"		// 37mm KwK38, 10t/30mm, 1939
          ," Armor.Pz_IIC de"		// 20mm KwK30, 7t/13mm, 1936
          ," Armor.StuG_IIIB de"	// 75mm StuK37, 24t/50mm, 1940
          ," Armor.Pz_IIIF de"		// 37mm KwK36, 23t/70mm, 1939
          ," Armor.Pz_IVD de"		// 75mm KwK37, 25t/80mm, 1939
    };
    private static List<string> RedVehicleList = new List<string>
    {   "Vehicle.Scammell_Pioneer_R100 gb"
        ,"Vehicle.AEC_Matador gb"
        ,"Vehicle.Morris_CS8_tent gb"
        ,"Vehicle.Morris_CS8_tank gb"
        ,"Vehicle.Morris_CS8 gb"
        ,"Vehicle.Morris_CDSW gb"
        ,"Vehicle.Guy_Quad-Ant gb"
        ,"Vehicle.Ford_V8_E917_tent gb"
        ,"Vehicle.Ford_V8_E917_open gb"
        ,"Vehicle.Bedford_OY_tent gb"
        ,"Vehicle.Bedford_OY_open gb"
        ,"Vehicle.Bedford_MW_tent gb"
        ,"Vehicle.Bedford_MW_tank gb"
        ,"Vehicle.Bedford_MW_open gb"
        ,"Vehicle.Austin_K2_Ambulance gb"
        ,"Vehicle.Austin_10_Tilly gb"
    };

    private static List<string> BlueVehicleList = new List<string>
    {   "Vehicle.Ford_G917 de"
        ,"Vehicle.SdKfz_9 de"
        ,"Vehicle.SdKfz_7 de"
        ,"Vehicle.SdKfz_252 de"
        ,"Vehicle.SdKfz_11 de"
        ,"Vehicle.SdKfz_10_5_Transport de"
        ,"Vehicle.SdKfz_10_4_Transport de"
        ,"Vehicle.SdKfz_10_1 de"
        //,"Vehicle.SdKfz_9_Trailer de"
        ,"Vehicle.Opel_Blitz_tent de"
        ,"Vehicle.Opel_Blitz_radio_transport de"
        ,"Vehicle.Opel_Blitz_med-tent de"
        ,"Vehicle.Opel_Blitz_fuel de"
        ,"Vehicle.Opel_Blitz_cargo_med de"
        ,"Vehicle.Opel_Blitz_cargo de"
        ,"Vehicle.Kubelwagen de"
        ,"Vehicle.Krupp_L2H43_Protze de"
        ,"Vehicle.Horch_108_Typ_1A_open de"
        ,"Vehicle.Horch_108_Typ_1A de"
    };
    private static List<string> RedColumnList = new List<string>
    {   "Vehicle.GB_HAAA_Transport_Column gb"
        ,"Vehicle.GB_Fuel_Column gb"
        ,"Vehicle.GB_Tank_Transport_Column gb"
    };

    private static List<string> BlueColumnList = new List<string>
    {   " Vehicle.GER_HAAA_Transport_Column de"
        ," Vehicle.GER_Bofors_Column de"
        ," Vehicle.GER_Fuel_Column de"
        ," Vehicle.GER_Tank_Transport_Column de"
    };
    private static List<string> RedStationaryList = new List<string>
    {   "Stationary.Austin_10_Tilly gb"
        ,"Stationary.Austin_7 gb"
        ,"Stationary.Austin_K2_Ambulance gb"
        ,"Stationary.Austin_K2_ATV gb"
        ,"Stationary.Albion_AM463 gb"
        ,"Stationary.Bedford_MW_open gb"
        ,"Stationary.Bedford_MW_tank gb"
        ,"Stationary.Bedford_MW_tent gb"
        ,"Stationary.Bedford_OY_open gb"
        ,"Stationary.Bedford_OY_tent gb"
        ,"Stationary.Ford_V8_E917_open gb"
        ,"Stationary.Ford_V8_E917_tent gb"
        ,"Stationary.Guy_Quad-Ant gb"
        ,"Stationary.Morris_CDSW gb"
        ,"Stationary.Morris_CS8 gb"
        ,"Stationary.Morris_CS8_tank gb"
        ,"Stationary.Morris_CS8_tent gb"
        ,"Stationary.MG_TA gb"
        ,"Stationary.AEC_Matador gb"
        //,"Stationary.AEC_Regent_II gb"
        ,"Stationary.Scammell_Pioneer_R100 gb"
        ,"Stationary.Scammell_Pioneer_SV2S gb"
        ,"Stationary.Scammell_Pioneer_TRMU30 gb"
    };

    private static List<string> BlueStationaryList = new List<string>
    {   "Stationary.Ford_G917 de"
        ,"Stationary.Horch_108_Typ_1A de"
        ,"Stationary.Horch_108_Typ_1A_open de"
        ,"Stationary.Horch_830_B1 de"
        ,"Stationary.Krupp_L2H43_Protze de"
        ,"Stationary.Krupp_L2H43_Protze_open de"
        ,"Stationary.Krupp_L2H43_Protze_Kfz69 de"
        ,"Stationary.Kubelwagen de"
        ,"Stationary.Opel_Blitz_cargo de"
        ,"Stationary.Opel_Blitz_cargo_med de"
        ,"Stationary.Opel_Blitz_fuel de"
        ,"Stationary.Opel_Blitz_med-tent de"
        ,"Stationary.Opel_Blitz_radio_transport de"
        ,"Stationary.Opel_Blitz_tent de"
        ,"Stationary.Unic_P107 de"
    };
    private static List<string[]> OpCompass = new List<string[]>
    {   new string[] {fmSidi_Barrani} // battle for first capture all
        ,new string[] {fmBuq_Buq}
        ,new string[] {fmHalfaya_Pass}
        ,new string[] {fmSollum,fmFort_Capuzzo}
        ,new string[] {fmBardia,fmSidi_Omar,fmSidi_Azeiz}
        ,new string[] {fmGambut,fmBir_el_Menastir,fmQasr_el_Arid}
        ,new string[] {fmSidi_Rezegh,fmEd_Dedu}
        ,new string[] {fmEl_Adem}
        ,new string[] {fmBir_Hacheim,fmAlem_Hamza}
        ,new string[] {fmGazala}
        ,new string[] {fmTobruk}
        ,new string[] {fmTmimi}
        ,new string[] {fmMartuba,fmBir_Halegh}
        ,new string[] {fmDerna}
    }; // 14 battles avg. 3 days = 42 days all map, Bardia-Derna is 10 battles and avg 3 days = 30 days match actual 3.jan to 29th pretty well
    private static List<string[]> UntSonnenblume = new List<string[]>
    {   new string[] {fmSidi_Barrani}
        ,new string[] {fmBuq_Buq}
        ,new string[] {fmHalfaya_Pass} // didn't continue until 26.may (Skorpion)
        ,new string[] {fmSollum,fmSidi_Omar,fmFort_Capuzzo} // 18th if 2 per battle
        ,new string[] {fmBardia,fmSidi_Azeiz}
        ,new string[] {fmGambut,fmBir_el_Menastir,fmQasr_el_Arid}
        ,new string[] {fmSidi_Rezegh,fmEl_Adem,fmEd_Dedu}
        ,new string[] {fmTobruk,fmBir_Hacheim,fmAlem_Hamza,fmGazala} // after 10th remove Tobruk and block until 9.dec (2+2 and DAK captures Tobruk!)
        ,new string[] {fmTmimi,fmBir_Halegh,fmMartuba} // 2/13th AUS Bn reached Tmimi 7.apr to block
        ,new string[] {fmDerna} // 6.apr (Sollum by 15th!)
    }; // 9 battles avg. 3 days = 27 days all map, Derna-Sollum is 6 battles and avg 3 days = 18 days but with 2 a battle 12 days match actual 6.apr to 15th pretty well

    // WIP
    private static List<string[]> OpCrusader = new List<string[]>
    {   new string[] {fmSidi_Barrani}
        ,new string[] {fmBuq_Buq}
        ,new string[] {fmHalfaya_Pass}
        ,new string[] {fmSollum,fmFort_Capuzzo}
        ,new string[] {fmSidi_Omar,fmSidi_Azeiz,fmBardia}
        ,new string[] {fmBir_el_Menastir,fmQasr_el_Arid,fmGambut}
        ,new string[] {fmSidi_Rezegh,fmEd_Dedu}
        ,new string[] {fmEl_Adem}
        ,new string[] {fmBir_Hacheim,fmAlem_Hamza}
        ,new string[] {fmGazala}
        ,new string[] {fmTobruk}
        ,new string[] {fmTmimi}
        ,new string[] {fmBir_Halegh,fmMartuba}
        ,new string[] {fmDerna}
    };
    private static List<string[]> UntTheseus = new List<string[]>
    {   new string[] {fmSidi_Barrani} // Axis campaign, runs from last to first
        ,new string[] {fmBuq_Buq}
        ,new string[] {fmHalfaya_Pass} // didn't continue until 26.may (Skorpion)
        ,new string[] {fmSidi_Omar,fmFort_Capuzzo,fmSollum} // 18th if 2 per battle
        ,new string[] {fmSidi_Azeiz,fmBardia}
        ,new string[] {fmBir_el_Menastir,fmQasr_el_Arid,fmGambut}
        ,new string[] {fmEl_Adem,fmEd_Dedu,fmSidi_Rezegh}
        ,new string[] {fmBir_Hacheim,fmAlem_Hamza,fmGazala,fmTobruk} // after 10th remove Tobruk and block until 9.dec (2+2 and DAK captures Tobruk!)
        ,new string[] {fmBir_Halegh,fmMartuba,fmTmimi} // 2/13th AUS Bn reached Tmimi 7.apr to block
        ,new string[] {fmDerna} // 6.apr (Sollum by 15th!)
    }; // 9 battles avg. 3 days = 27 days all map, Derna-Sollum is 6 battles and avg 3 days = 18 days but with 2 a battle 12 days match actual 6.jan to 15th pretty well
    private static List<string[]> UntSeelowe = new List<string[]>
    {   new string[] {fmLondon} // Axis campaign, runs from last to first
        ,new string[] {fmHorsham,fmRochester}
        ,new string[] {fmCanterbury}
        ,new string[] {fmEastbourne,fmDungeness,fmRamsgate,fmDover}
    };
    private static List<string[]> FallGelb = new List<string[]>
    {   new string[] {fmDunkerque} // Axis campaign, runs from last to first
        ,new string[] {fmCalais}
        ,new string[] {fmBoulogne}
        ,new string[] {fmStOmer,fmMerville,fmHazelbrouck,fmPoperinge,fmDiksmuide,fmVeurne,fmLeper}
        ,new string[] {fmGravelines,fmLumbres,fmAireSurLaLys,fmBruayLaBuissiere}
        ,new string[] {fmEtaples,fmLigescourt,fmSempy,fmDesvres,fmBerck} // campaign start 23.may
        ,new string[] {fmAbbeville,fmLeCrotoy} // german start
        ,new string[] {fmAmiens,fmBerteaucourt}
        ,new string[] {fmAuxiLeChateau}
        ,new string[] {fmFrevent,fmHesdin}
        ,new string[] {fmFruges}
        ,new string[] {fmStPolSurTernoise}
        ,new string[] {fmBapaume}
        ,new string[] {fmArras}
    };
}
