Official Fulqrum Publishing forum

Official Fulqrum Publishing forum (http://forum.fulqrumpublishing.com/index.php)
-   FMB, Mission & Campaign builder Discussions (http://forum.fulqrumpublishing.com/forumdisplay.php?f=203)
-   -   Organising flights in a multisquad campaign. (http://forum.fulqrumpublishing.com/showthread.php?t=30979)

5./JG27.Farber 04-07-2012 10:51 PM

Organising flights in a multisquad campaign.
 
Well our campaign is nearly ready and everyday the "grail patch" draws closer. The big question still remains. How to coordinate (especially red players) into action realistically during our missions. We could simply direct the squadrons in the air and then use one of the following:


Obviously the most realistic method would be have a fighter command to plot and direct red squadrons where they are needed. However I dont see anyone comming forward to do this. This thread wexplains how it might happen: http://forum.1cpublishing.eu/showthread.php?t=30918

Triggers are the next obvious solution. However Triggers are a dead cert! There is no room for error which is unrealistic. Also the Orange writing is a massive immertion killer.

The third option is a brief. This is ok for blue on the attack. However red may feel cheated by a brief if they dont get into action and or lose out in the mission.

The forth option is let radar and the game call out the action and squadrons conduct themselves.



What do you (especially those willing to take pat) think. We are open to all ideas however keep them short and simple - no essays please. I look forward to reading your responses.

FG28_Kodiak 04-08-2012 09:06 AM

Quote:

Originally Posted by 5./JG27.Farber (Post 406774)
Triggers are the next obvious solution. However Triggers are a dead cert! There is no room for error which is unrealistic. Also the Orange writing is a massive immertion killer.

In my Coops i use triggers, but without Orange writing, i simulate a radio message.
Code:

if ("EnterAreaM8".Equals(shortName))
        {
            int i = 0;

            AiActor actor = GamePlay.gpActorByName("0:BoB_LW_JG51_III.000");
         

            (actor as AiAircraft).SayToGroup(actor.Group() as AiAirGroup, "Enemy_planes");

            Timeout(i += 2, () =>
            {
                (actor as AiAircraft).SayToGroup(actor.Group() as AiAirGroup, "In_square");
            });

            Timeout(i += 2, () =>
            {
                (actor as AiAircraft).SayToGroup(actor.Group() as AiAirGroup, "M");
            });
            Timeout(i += 2, () =>
            {
                (actor as AiAircraft).SayToGroup(actor.Group() as AiAirGroup, "n8");
            });

            GamePlay.gpGetTrigger(shortName).Enable = false;
        }


5./JG27.Farber 04-08-2012 11:10 AM

Could a trigger have a chance of success? Or is it like a switch - on/off. Can a message in chat be sent to a specific Squadron or just one team?

bolox 04-08-2012 11:31 AM

triggers can be made to do 'random' things
Code:

// Script that triggered an accidental damage to the player plane
// Autor: FG28_Kodiak

using System;
using maddox.game;
using maddox.game.world;

    public class Mission : maddox.game.AMission
    {
               
                    AiAircraft PlayerPlane;

   
   
        public override void OnTrigger(int missionNumber, string shortName, bool active)
        {
            if (("trigger01".Equals(shortName) || "trigger02".Equals(shortName))  && active)
            {
                DoDamage();
            }
            GamePlay.gpGetTrigger(shortName).Enable = false;
        }
   
   
        private void DoDamage()
        {
                PlayerPlane = (AiAircraft)GamePlay.gpPlayer().Place();             
                   
                Random RandomIncident = new Random();
           
                            switch (RandomIncident.Next(1,9))
                                                    {
                                                        case 1:
                                                                        PlayerPlane.hitNamed(part.NamedDamageTypes.ControlsElevatorDisabled);
                                                                        GamePlay.gpHUDLogCenter("Elevator Disabled");
                                                                    break;
                                                                    case 2:
                                                                        PlayerPlane.hitNamed(part.NamedDamageTypes.ControlsAileronsDisabled);
                                                                        GamePlay.gpHUDLogCenter("Ailerons Disabled");
                                                                    break;
                                                                    case 3:
                                                                        PlayerPlane.hitNamed(part.NamedDamageTypes.ControlsRudderDisabled);
                                                                        GamePlay.gpHUDLogCenter("Rudder Disabled");
                                                                    break;
                                                                    case 4:
                                                                        PlayerPlane.hitNamed(part.NamedDamageTypes.Eng0PropBlade0Broken);
                                                                        GamePlay.gpHUDLogCenter("PropBlade Broken");
                                                                    break;
                                                                    case 5:
                                                                        PlayerPlane.hitNamed(part.NamedDamageTypes.Eng0TotalFailure);
                                                                        GamePlay.gpHUDLogCenter("Engine Failure");
                                                                    break;
                                                                    case 6:
                                                                        PlayerPlane.hitNamed(part.NamedDamageTypes.Eng0OilSecondariesFire);
                                                                                    GamePlay.gpHUDLogCenter("Oil is on fire");
                                                                    break;
                                                                    case 7:
                                                                                    PlayerPlane.hitNamed(part.NamedDamageTypes.HydraulicsPumpFailure);
                                                                        GamePlay.gpHUDLogCenter("Hydraulics Pump failure");
                                                                    break;
                                                                    case 8:
                                                                                    PlayerPlane.hitNamed(part.NamedDamageTypes.UndercarriageDownLockFailureL);
                                                                        GamePlay.gpHUDLogCenter("UndercarriageDownLock Left failure");
                                                                    break;
                                                                    case 9:
                                                                                    PlayerPlane.hitNamed(part.NamedDamageTypes.Eng0Plug00Failure);
                                                                                    PlayerPlane.hitNamed(part.NamedDamageTypes.Eng0Plug01Failure);
                                                                                    PlayerPlane.hitNamed(part.NamedDamageTypes.Eng0Plug05Failure);
                                                                        GamePlay.gpHUDLogCenter("Engine Plug 0,1,5 failure");
                                                                    break;
                                                    }               
               
        }
 
        public override void OnAircraftLanded(int missionNumber, string shortName, AiAircraft aircraft)
        {
            GamePlay.gpHUDLogCenter("Excellent!");
        }
   
        public override void OnAircraftCrashLanded(int missionNumber, string shortName, AiAircraft aircraft)
        {
            GamePlay.gpHUDLogCenter("Congratulation You are alive ;-)");
        }

   
    }

message can be sent to pretty much anyone you like as i understand it- but Kodiak will be able to answer that much better than me (and probably a better way of doing the random:o )

41Sqn_Banks 04-08-2012 11:33 AM

The best would be IMHO to react on Radar messages. However I didn't find a way so far to react on them in the script.

Osprey 04-08-2012 12:02 PM

I think the main problem with radar is that it tells the RAF the type. In reality FC RDF plotters would only be able to give location, height, heading and approximate numbers eg.

"30 plus, 10 miles North of Calais at Angels 12, Heading 300"

Ground control (who the flight lead was in contact with) would give a vector and height for interception. This often took the form of a normal conversation when single pilots were sent to intercept single enemies. eg. "climb to 10,000ft, heading south-south west, you should see him on your 2 o'clock by now"

So what would be immense is to have the script loop the list to find all RAF flight leads (which have at least a single wingman) and then load a custom menu for that pilot. The custom menu would have a ground control option to locate the enemy and firing it would give him a height, position, heading and number in the chat, vocally or on the orange HUD. Since this would be by request to that flight leader only then I don't see a problem with that. It is then up to him to direct his squadron to the enemy.

It is possible to create a menu, to get the enemy, to get the flight position of the pilot.
I would code this but I'm shite at it, I have the idea but not the technical ability :(

I'm not a fan of randomness, RDF was excellent and pretty much directed the RAF into position - there are hundreds of accounts from both sides about this. I only just read about how Brian Kingcombe would scramble away inland from the enemy who were 15kft, he'd climb to 20kft, turn around and shallow dive south to meet them at speed. Anyway, replication would be ace.

FG28_Kodiak 04-08-2012 02:07 PM

An other way to get the Enemy location via script.
In this script i check the distance between red Airgroups and blue Airgroups. And if it lower as a given value, there will a Voice Message being generated to the ally Airgroups which are in range to the enemy. The script is not fully tested yet, i am to busy at the moment (home renovation :rolleyes:). Feel free to expand it, the voice files (use the filename without .ogg) are located in ..\Steam\SteamApps\common\il-2 sturmovik cliffs of dover\parts\bob\speech, you can add for example the type of the Enemy Aircrafts, their Numbers etc. The timedelay between the checks should be larger as in my example to avoid overlaping of the messages.


Code:

using System;
using System.Collections;
using System.Collections.Generic;
using maddox.game;
using maddox.game.world;
using maddox.GP;


public class Mission : AMission
{

    public void sendMessagesToAirgroup(AiAirGroup from, double maxDistance)
    {

        AiAirGroup[] EnemyAirgroups;
        Point3d StartPos = new Point3d(from.Pos().x, from.Pos().y, 1.0);

        EnemyAirgroups = GamePlay.gpAirGroups((from.Army() == 1) ? 2 : 1);

        int i = 0;

        foreach (AiAirGroup aag in EnemyAirgroups)
        {
            Point3d enemyPosition = new Point3d(aag.Pos().x, aag.Pos().y, 1.0);

            if (from.Pos().distance(ref enemyPosition) < maxDistance)
            {
               
                string sectorName = GamePlay.gpSectorName(aag.Pos().x, aag.Pos().y);

                string[] splittet = sectorName.Split(',');
                string alpha = splittet[0];
                string number = "n" + splittet[1];

                AiAircraft LeaderPlane = (from.GetItems()[0] as AiAircraft);

                Timeout(i, () =>
                {
                    (LeaderPlane as AiAircraft).SayToGroup(from as AiAirGroup, "Enemy_planes");
                });


                Timeout(i += 2, () =>
                {
                    LeaderPlane.SayToGroup(from, "In_square");
                });

                Timeout(i += 2, () =>
                {
                    LeaderPlane.SayToGroup(from, alpha);
                });
                Timeout(i += 2, () =>
                {
                    LeaderPlane.SayToGroup(from, number);
                });

                i += 2;
            }
        }
    }


    public override void OnTickGame()
    {
        base.OnTickGame();

        if (Time.tickCounter() % 600 == 299)
        {
            foreach(AiAirGroup aag in GamePlay.gpAirGroups(1))
                sendMessagesToAirgroup(aag, 100000.0);
       
        }
    }
}


_79_dev 04-08-2012 02:53 PM

That looks interesting, Kodiak. Do I just copy that script over existing one? Do I need any extra functions to invoke messages? Where do I edit distaff value between Airgroups? .... If You answer I will test it as soon as possible...

FG28_Kodiak 04-08-2012 02:56 PM

Only copy the sendMessagesToAirgroup to your code, in OnTickGame you will see the example how to use it
sendMessagesToAirgroup(aag, 100000.0);
bold is the distance.

salmo 04-08-2012 02:59 PM

Some more radar speech code that might be useful. I use sayMessageTo to voice to everyone in the army, not just the airgroup, and have converted altitude to use 'angels' & 'metres' (depending on the army) with custom functions.

Interestingly, both (actor as AiAircraft).getParameter(part.ParameterTypes.Z_Alt itudeMSL, -1); and (actor as AiAircraft).getParameter(part.ParameterTypes.Z_Alt itudeAGL, -1); both fail to get the airgroup altitude in a multi-player server environment, so you need to use the Pos().z & convert the z offset to metres.

Code removed by author

Osprey 04-08-2012 03:19 PM

Now this stuff looks very promising.

I'm going to crack open VS express and have a bigger look. I can't write the stuff but adapting it may be easier.

5./JG27.Farber 04-08-2012 04:36 PM

Kodiak thats great. Were gonna give it a whirl on our server today. I have some ideas for expansion. Could there be some kind of delay between requesting the information and recieving it, say 4 mins? This would simulate the request going to and from the lines of communication. Also. What if some radars are knocked out or damaged? Can this be simulated also?

P.S. I know how you feel with the renovation, Ive been doing it for 4 months now. It will be finished this week. What a grind.

FG28_Kodiak 04-08-2012 06:00 PM

you wanna ask the operators with the mission menu? and than after 4min you will get the response? This is possible without problem.
Okay for clearance, when we use "radars" will you give the messages to the Airgroups in range of a spezific radarstation or to all. So if you hit the 'radarbutton' then you get Information of all Enemies Airgoups in range of any available radarstation or only from this you are in Range?

_79_dev 04-08-2012 06:40 PM

i gave it a go : this is my script

PHP Code:

//$reference IL2ClodCommanderStats.dll
// v.1_0. script by FG28_Kodiak, ZaltysZ, Oreva, Small_Bee, RAF238thWildWillie
using System;
using System.Diagnostics;
using System.Collections;
using maddox.GP;
using maddox.game;
using maddox.game.world;
using part;
using System.Collections.Generic;
using IL2ClodCommanderStats;


public class 
Mission AMission
{
    
#region Stats Initialization
    // For Connection to the IL2 Clod Commander Application
    // This allows you to store stats on players within Cliffs of Dover
    //  Change the following to meet your needs
    //
    
private static string serverName "5./JG27 SERVER";
    private static 
string serverIP "127.0.0.1";
    
    
// Password is not used currently
    
private static string serverPassword "password";
    private static 
Int32  serverPort 27015;
    private 
StatsRecording stats = new StatsRecording(serverNameserverIPserverPasswordserverPort);
    private 
Dictionary<StringAiActorallActors = new Dictionary<StringAiActor>();
    private List<
ServerCommandnewCmds = new List<ServerCommand>();
    private 
Stopwatch MissionTimer = new Stopwatch();
    
#endregion

    
int LastMissionLoaded 0;

    
double initTime;
    
    
    
////////////////setting chat messages
    
private void sendChatMessage(string msgparams object[] args)
    {
        
GamePlay.gpLogServer(nullmsgargs);
    }


    private 
void sendChatMessage(Player playerstring msgparams object[] args)
    {
        if (
player != null)
            
GamePlay.gpLogServer(new Player[] { player }, msgargs);
    }


    private 
void sendChatMessage(int armystring msgparams object[] args)
    {
        List<
PlayerConsignees = new List<Player>();

        if (
GamePlay.gpPlayer() != null)
            
Consignees.Add(GamePlay.gpPlayer());
        if (
GamePlay.gpRemotePlayers() != null)
            
Consignees.AddRange(GamePlay.gpRemotePlayers());

        if (
army == -1)
            
GamePlay.gpLogServer(nullmsgargs);
        else if (
Consignees.Exists(item => item.Army() == army))
            
GamePlay.gpLogServer(Consignees.FindAll(item => item.Army() == army).ToArray(), msgargs);
    }
    
////////////////testing voice messages
    
     
public void sendMessagesToAirgroup(AiAirGroup fromdouble maxDistance)
    {

        
AiAirGroup[] EnemyAirgroups;
        
Point3d StartPos = new Point3d(from.Pos().xfrom.Pos().y1.0);

        
EnemyAirgroups GamePlay.gpAirGroups((from.Army() == 1) ? 1);

        
int i 0;

        foreach (
AiAirGroup aag in EnemyAirgroups)
        {
            
Point3d enemyPosition = new Point3d(aag.Pos().xaag.Pos().y1.0);

            if (
from.Pos().distance(ref enemyPosition) < maxDistance)
            {
                
                
string sectorName GamePlay.gpSectorName(aag.Pos().xaag.Pos().y);

                
string[] splittet sectorName.Split(',');
                
string alpha splittet[0];
                
string number "n" splittet[1];

                
AiAircraft LeaderPlane = (from.GetItems()[0] as AiAircraft);

                
Timeout(i, () =>
                {
                    (
LeaderPlane as AiAircraft).SayToGroup(from as AiAirGroup"Enemy_planes");
                });


                
Timeout(+= 2, () =>
                {
                    
LeaderPlane.SayToGroup(from"In_square");
                });

                
Timeout(+= 2, () =>
                {
                    
LeaderPlane.SayToGroup(fromalpha);
                });
                
Timeout(+= 2, () =>
                {
                    
LeaderPlane.SayToGroup(fromnumber);
                });

                
+= 2;
            }
        }
    }


    public 
override void OnTickGame()
    {
        
base.OnTickGame();

        if (
Time.tickCounter() % 600 == 299)
        {
            foreach(
AiAirGroup aag in GamePlay.gpAirGroups(1))
                
sendMessagesToAirgroup(aag100000.0);
        
        }
    


    
// loading sub-missions
    
    
          #region Stats Timer
          
if (MissionTimer.Elapsed.TotalSeconds >= 5// 5 seconds
        
{
            
MissionTimer.Restart(); // stopwatch reset to 0 and restart
            
if (stats != null )
            {
               
newCmds stats.getCommands();
               if (
newCmds != null && newCmds.Count 0)
                   
ProcessCommands(newCmds);
            }
        }
        
#endregion
    ///////////////////////
    // server info every 5 min
    
     
if (Time.tickCounter() % 9000 == 1800)  
       
       {

       
sendChatMessage((-1), "PLEAS VISIT www.5jg27.net TO CHECK STATS");

        }
    
    
    
// load ground objects
       
if (Time.tickCounter() % 2592000 == 300)  
       {
           
GamePlay.gpPostMissionLoad("missions/Multi/Dogfight/kanalkampf/kanalkampf_ground.mis");
    
       }

// loads Mission1
       
if (Time.tickCounter() % 2592000 == 12600)  
       {
           
GamePlay.gpPostMissionLoad("missions/Multi/Dogfight/kanalkampf/kanalkampf_Air1Red1Blue1.mis");
                      
       }

// loads Rescue
       
if (Time.tickCounter() % 2592000 == 95000)  
       {
           
GamePlay.gpPostMissionLoad("missions/Multi/Dogfight/kanalkampf/kanalkampf_Airsearescue.mis");
                      
       }
    

// loads Mission2
       
if (Time.tickCounter() % 2592000 == 66600)  
       {
           
GamePlay.gpPostMissionLoad("missions/Multi/Dogfight/kanalkampf/kanalkampf_Air2Red2.mis");
           
           
       }

// loads Mission3
       
if (Time.tickCounter() % 2592000 == 144000)  
       {
           
GamePlay.gpPostMissionLoad("missions/Multi/Dogfight/kanalkampf/kanalkampf_Air3Blue2.mis");
          
           
       }
       


    }
 
////////////////////////////////////////////////////////////////////////////////////////////////////

//

// Base Scripts for Missions
  
private bool isAiControlledPlane (AiAircraft aircraft
  {
        if (
aircraft == null
        { 
            return 
false;
        }

        
Player [] players GamePlay.gpRemotePlayers ();
        foreach (
Player p in players
        {    
            if (
!= null && (p.Place () is AiAircraft) && (p.Place () as AiAircraft) == aircraft)
            { 
                return 
false;
            }
        }

        return 
true;
    }

    private 
void destroyPlane (AiAircraft aircraft) {
        if (
aircraft != null) { 
            
aircraft.Destroy ();
        }
    }

    private 
void explodeFuelTank (AiAircraft aircraft
  {
        if (
aircraft != null
        { 
            
aircraft.hitNamed (part.NamedDamageTypes.FuelTank0Exploded);
        }
    }

    private 
void destroyAiControlledPlane (AiAircraft aircraft) {
        if (
isAiControlledPlane (aircraft)) {
            
destroyPlane (aircraft);
        }
    }

    private 
void damageAiControlledPlane (AiActor actor) {
        if (
actor == null || !(actor is AiAircraft)) { 
            return;
        }

        
AiAircraft aircraft = (actor as AiAircraft);

        if (!
isAiControlledPlane (aircraft)) {
            return;
        }

        if (
aircraft == null) { 
            return;
        }

        
aircraft.hitNamed (part.NamedDamageTypes.ControlsElevatorDisabled);
        
aircraft.hitNamed (part.NamedDamageTypes.ControlsAileronsDisabled);
        
aircraft.hitNamed (part.NamedDamageTypes.ControlsRudderDisabled);
        
aircraft.hitNamed (part.NamedDamageTypes.FuelPumpFailure);

        
int iNumOfEngines = (aircraft.Group() as AiAirGroup).aircraftEnginesNum();
        for (
int i 0iNumOfEnginesi++)
        {
            
aircraft.hitNamed((part.NamedDamageTypes)Enum.Parse(typeof(part.NamedDamageTypes), "Eng" i.ToString() + "TotalFailure"));
        }

        
/***Timeout (240, () =>
                {explodeFuelTank (aircraft);}
            );
         * ***/

        
Timeout (300, () =>
                {
destroyPlane (aircraft);}
            );
    }

  public 
override void Init(maddox.game.ABattle battleint missionNumber)
  {
        
base.Init(battlemissionNumber);
        
MissionNumberListener = -1//Listen to events of every mission
  
}

//////////////////////////////////////////
// Methods for Stats (You can add any code you may need after the Stats Region
//////////////////////////////////////////

    
public override void OnBattleStarted()
    {
        
base.OnBattleStarted();
        
#region Stats
           
MissionTimer.Start(); // start the stopwatch
        #endregion
    
}

    private 
void sendScreenMessageTo(int armystring msgobject[] parms)
    {
        List<
PlayerPlayers = new List<Player>();

        
// on Dedi the server or for singleplayertesting
        
if (GamePlay.gpPlayer() != null)
        {
            if (
GamePlay.gpPlayer().Army() == army || army == -1)
                
Players.Add(GamePlay.gpPlayer());
        }
        if (
GamePlay.gpRemotePlayers() != null || GamePlay.gpRemotePlayers().Length 0)
        {
            foreach (
Player p in GamePlay.gpRemotePlayers())
            {
                if (
p.Army() == army || army == -1)
                    
Players.Add(p);
            }
        }
        if (
Players != null && Players.Count 0)
            
GamePlay.gpHUDLogCenter(Players.ToArray(), msgparms);
    }

    private 
void ProcessCommands(List<ServerCommandnewCmds)
    {
        try
        {
            foreach (
ServerCommand sc in newCmds)
            {
                if (
sc.CommandType.Equals("HUDmsg"))
                {
                    if (
sc.ToWho.Equals("All"))
                        
GamePlay.gpHUDLogCenter(sc.Command);
                  else if (
sc.ToWho.Equals("Red"))
                    {
                        
sendScreenMessageTo(1sc.Commandnull);
                    }
                    else if (
sc.ToWho.Equals("Blue"))
                    {
                        
sendScreenMessageTo(2sc.Commandnull);
                    }
                    else
                    {
                        if (
GamePlay.gpRemotePlayers() != null || GamePlay.gpRemotePlayers().Length 0)
                        {

                            foreach (
Player p in GamePlay.gpRemotePlayers())
                            {
                                if (
p.Name() == sc.ToWho)
                                    
GamePlay.gpLogServer(new Player[] { }, sc.Commandnull);
                            }
                        }
                        
// Message is for a specific player based on player name in string sc.ToWho
                    
}
                }
            }
        }
        catch (
Exception ex)
        {
            
System.Console.WriteLine("Stats.ProcessCommands - Exception: " ex);
        }
    }
 
    public 
override void OnActorCreated(int missionNumberstring shortNameAiActor actor)
    {
        
#region stats
        
base.OnActorCreated(missionNumbershortNameactor);
        
// Add actor to list of all Actors
        
if (!allActors.ContainsKey(shortName))
           
allActors.Add(shortNameactor);
        try
        {
            
stats.newActor(shortNameactor);
        }
        catch (
Exception ex)
        {
            
System.Console.WriteLine("Stats.OnActorCreated - Exception: " ex);
        }
        
#endregion
    
}


    public 
override void OnPersonHealth(maddox.game.world.AiPerson personmaddox.game.world.AiDamageInitiator initiatorfloat deltaHealth)
    {
        
#region stats
        
base.OnPersonHealth(personinitiatordeltaHealth);
        try
        {
            
stats.playerHealth(personinitiatordeltaHealth);
        }
        catch (
Exception ex)
        {
            
System.Console.WriteLine("Stats.OnPersonHealth - Exception: " ex);
        }
        
#endregion

    
}

    public 
override void OnPersonParachuteFailed(maddox.game.world.AiPerson person)
    {
        
#region stats
        
base.OnPersonParachuteFailed(person);
        try
        {
            
stats.personParachute("Failed"person);
        }
        catch (
Exception ex)
        {
            
System.Console.WriteLine("Stats.OnPersonParachuteFailed - Exception: " ex);
        }
        
#endregion
    
}

    public 
override void OnPersonParachuteLanded(maddox.game.world.AiPerson person)
    {
        
#region stats
        
base.OnPersonParachuteLanded(person);
        try
        {
            
stats.personParachute("Landed"person);
        }
        catch (
Exception ex)
        {
            
System.Console.WriteLine("Stats.OnPersonParachuteLanded - Exception: " ex);
        }
        
#endregion
    
}

    public 
override void OnPlayerArmy(maddox.game.Player playerint army)
    {
        
#region stats
        
base.OnPlayerArmy(playerarmy);
        try
        {
            
stats.playerArmy(playerarmy);
        }
        catch (
Exception ex)
        {
            
System.Console.WriteLine("Stats.OnPlayerArmy - Exception: " ex);
        }
        
#endregion

    
}

    public 
override void OnPlayerConnected(maddox.game.Player player)
    {
        
#region stats
        
base.OnPlayerConnected(player);
        try
        {
            
stats.pilotInfo(player);
        }
        catch (
Exception ex)
        {
            
System.Console.WriteLine("Stats.OnPlayerConnected - Exception: " ex);
        }

        
#endregion
        // Your code here
    
}
    public 
override void OnPlayerDisconnected(maddox.game.Player playerstring diagnostic)
    {
        
#region stats
        
base.OnPlayerDisconnected(playerdiagnostic);
        try
        {
            
stats.playerDisconnect(playerdiagnostic);
        }
        catch (
Exception ex)
        {
            
System.Console.WriteLine("Stats.OnPlayerDisconnected - Exception: " ex);
        }

        
#endregion
        // Your code here
    
}
    
    public 
override void OnPlaceEnter(Player playerAiActor actorint placeIndex)
    {
        
#region stats
        
base.OnPlaceEnter(playeractorplaceIndex);
        try
        {
            
Point2d actorPos = new Point2d(actor.Pos().xactor.Pos().y);
            
String startingGrid GamePlay.gpSectorName(actorPos.xactorPos.y).ToString();
            
stats.sortieBegin(playeractorplaceIndexactorPosstartingGrid);
        }
        catch (
Exception ex)
        {
            
System.Console.WriteLine("Stats.OnPlaceEnter - Exception: " ex);
        }
        
#endregion
        //add your code here
    
}


    public 
override void OnPlaceLeave(Player playerAiActor actorint placeIndex)
    {
        
#region stats
        
base.OnPlaceLeave(playeractorplaceIndex);
        try
        {
            
stats.sortieEnd(playeractorplaceIndex);
        }
        catch (
Exception ex)
        {
            
System.Console.WriteLine("Stats.OnPlaceLeave - Exception: " ex);
        }

        
#endregion
        //add your code here
        
Timeout(1, () =>
                { 
damageAiControlledPlane(actor); }
            );
    }

    public 
override void OnAircraftCrashLanded (int missionNumberstring shortNameAiAircraft aircraft)
    {
        
#region stats
        
base.OnAircraftCrashLanded (missionNumbershortNameaircraft);
        try
        {
            
Point2d actorPos = new Point2d(aircraft.Pos().xaircraft.Pos().y);
            
String gridRef GamePlay.gpSectorName(actorPos.xactorPos.y).ToString();
            
stats.aircraftLanded("CrashLanded"shortNameaircraftactorPosgridRef);
            
System.Console.WriteLine("Stats.OnAircraftCrashLanded - ("+shortName+")");
        }
        catch (
Exception ex)
        {
            
System.Console.WriteLine("Stats.OnAircraftCrashLanded - Exception: " ex);
        }
        
#endregion
        //add your code here
        
Timeout (300, () =>
            { 
destroyPlane(aircraft); }
            );
      }

    public 
override void OnAircraftTookOff(int missionNumberstring shortNameAiAircraft aircraft)
    {
        
#region stats
        
base.OnAircraftTookOff(missionNumbershortNameaircraft);
        try
        {
            
stats.aircraftTakeoff(shortNameaircraft);
        }
        catch (
Exception ex)
        {
            
System.Console.WriteLine("Stats.OnAircraftTookOff - Exception: " ex);
        }
        
#endregion
        //add your code here
    
}
          
    public 
override void OnAircraftLanded (int missionNumberstring shortNameAiAircraft aircraft)
    {
          
#region stats
          
base.OnAircraftLanded(missionNumbershortNameaircraft);
            try
            {
              
Point2d actorPos = new Point2d(aircraft.Pos().xaircraft.Pos().y);
             
String gridRef GamePlay.gpSectorName(actorPos.xactorPos.y).ToString();
             
stats.aircraftLanded("Landed"shortNameaircraftactorPosgridRef);
            }
            catch (
Exception ex)
            {
            
System.Console.WriteLine("Stats.OnAircraftTookOff - Exception: " ex);
            }
          
#endregion
          //add your code here

          
Timeout(300, () =>
            { 
destroyPlane(aircraft); }
            );
    }

    public 
override void OnActorDamaged(int missionNumberstring shortNameAiActor actorAiDamageInitiator initiatorNamedDamageTypes damageType)
    {
        
#region stats
        
base.OnActorDamaged(missionNumbershortNameactorinitiatordamageType);
        try
        {
            
stats.missionActorDamaged(shortNameactorinitiatordamageType);
        }
        catch (
Exception ex)
        {
            
System.Console.WriteLine("Stats.OnActorDamaged - Exception: " ex);
        }
        
#endregion
        //add your code here

    
}

    public 
override void OnAircraftDamaged(int missionNumberstring shortNameAiAircraft aircraftAiDamageInitiator initiatorNamedDamageTypes damageType)
    {
        
#region stats
        
base.OnAircraftDamaged(missionNumbershortNameaircraftinitiatordamageType);
        try
        {
            
stats.missionAircraftDamaged(shortNameaircraftinitiatordamageType);
        }
        catch (
Exception ex)
        {
            
System.Console.WriteLine("Stats.OnAircraftDamaged - Exception: " ex);
        }
        
#endregion
        //add your code here

    
}
    public 
override void OnAircraftLimbDamaged(int missionNumberstring shortNameAiAircraft aircraftAiLimbDamage limbDamage)
    {
        
#region stats
        
base.OnAircraftLimbDamaged(missionNumbershortNameaircraftlimbDamage);
        try
        {
            
stats.aircraftLimbDamaged(shortNameaircraftlimbDamage);
        }
        catch (
Exception ex)
        {
            
System.Console.WriteLine("Stats.OnAircraftLimbDamaged - Exception: " ex);
        }
        
#endregion
        //add your code here
    
}
    public 
override void OnAircraftCutLimb(int missionNumberstring shortNameAiAircraft aircraftAiDamageInitiator initiatorLimbNames limbName)
    {
        
#region stats
        
base.OnAircraftCutLimb(missionNumbershortNameaircraftinitiatorlimbName);
        try
        {
            
stats.missionAircraftCutLimb(shortNameaircraftinitiatorlimbName);
        }
        catch (
Exception ex)
        {
            
System.Console.WriteLine("Stats.OnAircraftCutLimb - Exception: " ex);
        }
        
#endregion
        //add your code here
    
}

    public 
override void OnActorDead(int missionNumberstring shortNameAiActor actor, List<DamagerScoredamages)
    {
        
#region stats
        
base.OnActorDead(missionNumbershortNameactordamages);
        try
        {
             
stats.missionActorDead(shortNameactordamages); 
        }
        catch (
Exception ex)
        {
            
System.Console.WriteLine("Stats.OnActorDead - Exception: " ex);
        }
        
#endregion
        //add your code here

    
}

    public 
override void OnActorDestroyed(int missionNumberstring shortNameAiActor actor)
    {
        
#region stats
        
base.OnActorDestroyed(missionNumbershortNameactor);
        try
        {
            
stats.actorDestroyed(shortNameactor);
        }
        catch (
Exception ex)
        {
            
System.Console.WriteLine("Stats.OnActorDestroyed - Exception: " ex);
        }
        
#endregion
        //add your code here

    
}
    public 
override void OnAircraftKilled(int missionNumberstring shortNameAiAircraft aircraft)
    {
        
#region stats
        
base.OnAircraftKilled(missionNumbershortNameaircraft);
        try
        {
            
stats.aircraftKilled(shortNameaircraft);
        }
        catch (
Exception ex)
        {
            
System.Console.WriteLine("Stats.OnAircraftKilled - Exception: " ex);
        }
        
#endregion
        //add your code here

    
}

    public 
override void OnBattleStoped()
    {
        
#region stats
        
base.OnBattleStoped();
        try
        {
            
stats.battleStopped();
            
// Loop through list of AiActors and destroy them all
            
List<stringkeys = new List<string>(allActors.Keys);
            for (
int i 0keys.Counti++)
            {
                
AiActor a allActors[keys[i]];
                
AiAircraft aircraft as AiAircraft;
                if (
aircraft != null)
                {
                    
aircraft.Destroy();
                }
                else
                {
                    
AiGroundActor aiGroundActor as AiGroundActor;
                    if (
aiGroundActor != null)
                    {
                        
aiGroundActor.Destroy();
                    }
                    else
                    {
                        
System.Console.WriteLine("Stats.OnBattleStoped - Unknown Actor (" a.Name()+") ShortName ("+keys[i]+")");
                    }
                }
            }
            
stats.disconnectStats();
        }
        catch (
Exception ex)
        {
            
System.Console.WriteLine("Stats.OnBattleStoped - Exception: " ex);
        }
        
#endregion
        //add your code here
    
}
//////////////////////////////////////////////////////////////////////////////////////////////////


 


console gives that every 20-30sec

PHP Code:

at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsgIMessage retMsg)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageDatamsgDataInt32 type)
at maddox.game.IBattle.OnTickGame()
at maddox.game.GameDef.tickGame()
at uRQMLX6vlhrpBgfbWjC.eBu9gE6TS67VJSjj97t.Hwe9ADXhn0AxpFMw7lv0(Object )
at uRQMLX6vlhrpBgfbWjC.eBu9gE6TS67VJSjj97t.8An9qLaqwNd()
at 93bAC3gAbOoH4F4mw53.Pljjc2gU48bdLjaViwW.Af3oASrUh27g1Z9hCmya(Object )
at 93bAC3gAbOoH4F4mw53.Pljjc2gU48bdLjaViwW.9B8JM8x755B(Boolean Boolean )
=================================================
=================================================
System.NullReferenceExceptionObject reference not set to an instance of an object.
Server stack trace:
at Mission.sendMessagesToAirgroup(AiAirGroup fromDouble maxDistance)
at Mission.OnTickGame()
at maddox.game.ABattle.OnTickGame()
at maddox.game.world.Strategy.OnTickGame()
at System.Runtime.Remoting.Messaging.StackBuilderSink._PrivateProcessMessage(IntPtr mdObject[] argsObject serverInt32 methodPtrBoolean fExecuteInContextObject[]& outArgs)
at System.Runtime.Remoting.Messaging.StackBuilderSink.SyncProcessMessage(IMessage msgInt32 methodPtrBoolean fExecuteInContext)
Exception rethrown at [0]:
at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsgIMessage retMsg)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageDatamsgDataInt32 type)
at maddox.game.IBattle.OnTickGame()
at maddox.game.GameDef.tickGame()
at uRQMLX6vlhrpBgfbWjC.eBu9gE6TS67VJSjj97t.Hwe9ADXhn0AxpFMw7lv0(Object )
at uRQMLX6vlhrpBgfbWjC.eBu9gE6TS67VJSjj97t.8An9qLaqwNd()
at 93bAC3gAbOoH4F4mw53.Pljjc2gU48bdLjaViwW.Af3oASrUh27g1Z9hCmya(Object )
at 93bAC3gAbOoH4F4mw53.Pljjc2gU48bdLjaViwW.9B8JM8x755B(Boolean Boolean )
================================================= 

is that because there is no airgroups loaded yet?

FG28_Kodiak 04-08-2012 07:26 PM

Quote:

Originally Posted by _79_dev (Post 406972)
is that because there is no airgroups loaded yet?

Yepp:
Added
if (EnemyAirgroups == null) return;
to method sendMessagesToAirgroup
and
if (GamePlay.gpAirGroups(1) != null)
in OnTickGame
to avoid exception

Code:

using System;
using System.Collections;
using System.Collections.Generic;
using maddox.game;
using maddox.game.world;
using maddox.GP;


public class Mission : AMission
{

    public void sendMessagesToAirgroup(AiAirGroup from, double maxDistance)
    {

        AiAirGroup[] EnemyAirgroups;
        Point3d StartPos = new Point3d(from.Pos().x, from.Pos().y, 1.0);

        EnemyAirgroups = GamePlay.gpAirGroups((from.Army() == 1) ? 2 : 1);
        if (EnemyAirgroups == null) return;

        int i = 0;

        foreach (AiAirGroup aag in EnemyAirgroups)
        {
            Point3d enemyPosition = new Point3d(aag.Pos().x, aag.Pos().y, 1.0);

            if (from.Pos().distance(ref enemyPosition) < maxDistance)
            {
               
                string sectorName = GamePlay.gpSectorName(aag.Pos().x, aag.Pos().y);

                string[] splittet = sectorName.Split(',');
                string alpha = splittet[0];
                string number = "n" + splittet[1];

                AiAircraft LeaderPlane = (from.GetItems()[0] as AiAircraft);

                Timeout(i, () =>
                {
                    (LeaderPlane as AiAircraft).SayToGroup(from as AiAirGroup, "Enemy_planes");
                });


                Timeout(i += 2, () =>
                {
                    LeaderPlane.SayToGroup(from, "In_square");
                });

                Timeout(i += 2, () =>
                {
                    LeaderPlane.SayToGroup(from, alpha);
                });
                Timeout(i += 2, () =>
                {
                    LeaderPlane.SayToGroup(from, number);
                });

                i += 2;
            }
        }
    }


    public override void OnTickGame()
    {
        base.OnTickGame();

        if (Time.tickCounter() % 600 == 299)
        {
            if (GamePlay.gpAirGroups(1) != null)
                foreach(AiAirGroup aag in GamePlay.gpAirGroups(1))
                    sendMessagesToAirgroup(aag, 100000.0);
       
        }
    }
}


5./JG27.Farber 04-08-2012 11:26 PM

Quote:

Originally Posted by FG28_Kodiak (Post 406962)
you wanna ask the operators with the mission menu? and than after 4min you will get the response? This is possible without problem.
Okay for clearance, when we use "radars" will you give the messages to the Airgroups in range of a spezific radarstation or to all. So if you hit the 'radarbutton' then you get Information of all Enemies Airgoups in range of any available radarstation or only from this you are in Range?

Hmm if the radar closest gave the information that would be good otherwise it is as if the aircraft has the radar, or maybe not? :confused:

How would you ask the radar? :confused:

FG28_Kodiak 04-09-2012 03:54 AM

via MissionMenu.

csThor 04-09-2012 07:55 AM

If my input is allowed. I agree with Kodiak about the menu thing. Think of it as a Squadron Leader "registering" with a certain Sector Station Ops Room to receive RADAR information. That could be easily done either by making this selection available in the menu (i.e. Select Sector -> Biggin Hill, Kenley, Tangmere etc - if you want more structure and accept a slightly higher workload for the squadron leader) or simply via a distance check for the airgroup (if it's supposed to be easier).

I do, however, suggest to take a look at how the Squad Select Series at Warbirds and the Friday Squad Ops at Aces High II operate. They appoint a CO prior to a run and he has to devise a general plan. Since we lack the numbers they can (theoretically) operate with there would, of course, be some adaptations necessary. My suggestion would be:

1.) Select one squad for CO duty prior to the run. Rotate this position within the squad pool after each run.
2.) Give the CO a number of targets he can choose from. For example a mission set in August 1940 would give the Luftwaffe CO a list of primary airfields of which he has to hit a certain number (depending on number of players, I guess no more than two for CloD) plus a list of secondary targets which may give the LW additional points. This way you create a more realistic Fog of War situation in which the RAF doesn't know which targets will be hit by the LW in advance.

For the RAF this CO duty is, of course, not that important. Later it will certainly become more important once we move to theaters which include offensive ops by both sides.

_79_dev 04-09-2012 08:22 AM

Kodiak, Your script for generating voice messages due to distance from blue Airgroup seems to be working fine on server console, however I can't test it physically my self cause I am on holidays and using IPod at the moment (can't run Cliffs of Dover on iPod...yet). If someone can give us a hand pleas go to 5jg27.net there is direct connect button to server.

Just one more question, by the look at the script It supose to give radio messages every x amount of seconds or do I have to go to TAB menu to ask for message? (just getting confused here)

FG28_Kodiak 04-09-2012 09:19 AM

At the moment with time amount, but it's no problem doing this via menu. But at the moment there is the problem with the missionmenu for the red side on dediserver, so it's better to wait for the patch, and hope the patch solving this problem.
How many of this Sector Station Ops Room where available at BoB? How many radars and other observers was attached to one station?

Osprey 04-09-2012 09:43 AM

Hi Kodiak, whilst Farber has done the vast majority of the work and it is a JG27 campaign, I am providing a large number of his enemy fighters for it (looking forward to that :) ) and I have been working with him on how this runs (though the buck stops with him).

Quote:

Originally Posted by FG28_Kodiak (Post 406962)
you wanna ask the operators with the mission menu? and than after 4min you will get the response? This is possible without problem.
Okay for clearance, when we use "radars" will you give the messages to the Airgroups in range of a spezific radarstation or to all. So if you hit the 'radarbutton' then you get Information of all Enemies Airgoups in range of any available radarstation or only from this you are in Range?

Quote:

Originally Posted by 5./JG27.Farber (Post 407013)
Hmm if the radar closest gave the information that would be good otherwise it is as if the aircraft has the radar, or maybe not? :confused:

How would you ask the radar? :confused:

Yes, mission menu! This is what I suggested in the first place. The flight leaders select #1

http://i7.photobucket.com/albums/y29...eselection.png

Everyone else selects something else, therefore this means not everyone gets the menu option and have to be organised by the squadron leader. Only 3 or 4 people on RAF would even have this ability so their workload goes up and the pressure for their team to stay together in flight becomes very important.

The information provided should be:
1. Location
2. Approximate numbers (30+??)
3. Height
4. Heading

The flight lead has to then direct his crew to intercept. If this can be provided vocally then that is even better.

Fighter Command had a WHOLE picture of the area via the plotting room bunker. This would receive all radar information from the RDF stations and observer corps, then scramble accordingly. @FARBER I imagine that for the purposes of campaign, that this event, ie "501 squadron scramble" could be handle by trigger. That way we start at the right time from the right place. I wouldn't want to be on some random patrol for ages because I don't know what's going on and then find ourselves 180 miles away with 1/2 tank of fuel left. Sorry to talk mission but I would suggest participating RAF squadrons being "At Readiness" with kites ready to scramble waiting for the off would be most realistic.

4 minutes delay
This 4 minutes delay for response is interesting since information cannot be absolutely up to date. I'm trying to find out the delay between RDF station and reporting to the squadrons. 4 mins seems a long time, you could cross the Channel in that time. An alternative suggestion is that the flight leaders have a time delay between plot requests of a few minutes, so once they request and get feedback they cannot select again until that time has expired - this would add in the random factor for LW course changes and human error until visual confirmation, it would stop a flight leader from just hammering the button!


This is why I love this stuff, because you learn so much about it all as you go :) I read that Ground Controlled Interception didn't occur until later because the RDF stations needed to scan the whole sky, therefore a squadron was scrambled and vectored to an interception position and that was it, though it was accurate. There was no 'within range of a station' since the entire coast was covered as one. It's really this we need to replicate. The difficulty would be that since we don't have the whole of 11 group in the mission then the Luftwaffe could 'slip the net' so we probably could do with a bit more reliability.
Here's a nice overview
http://www.radarpages.co.uk/mob/gci/gci.htm


Quote:

Originally Posted by csThor (Post 407042)
If my input is allowed. I agree with Kodiak about the menu thing. Think of it as a Squadron Leader "registering" with a certain Sector Station Ops Room to receive RADAR information. That could be easily done either by making this selection available in the menu (i.e. Select Sector -> Biggin Hill, Kenley, Tangmere etc - if you want more structure and accept a slightly higher workload for the squadron leader) or simply via a distance check for the airgroup (if it's supposed to be easier).

I do, however, suggest to take a look at how the Squad Select Series at Warbirds and the Friday Squad Ops at Aces High II operate. They appoint a CO prior to a run and he has to devise a general plan. Since we lack the numbers they can (theoretically) operate with there would, of course, be some adaptations necessary. My suggestion would be:

1.) Select one squad for CO duty prior to the run. Rotate this position within the squad pool after each run.
2.) Give the CO a number of targets he can choose from. For example a mission set in August 1940 would give the Luftwaffe CO a list of primary airfields of which he has to hit a certain number (depending on number of players, I guess no more than two for CloD) plus a list of secondary targets which may give the LW additional points. This way you create a more realistic Fog of War situation in which the RAF doesn't know which targets will be hit by the LW in advance.

For the RAF this CO duty is, of course, not that important. Later it will certainly become more important once we move to theaters which include offensive ops by both sides.

I see where you are coming from but I wouldn't want to sit out and direct anyone, and if you have a list of targets which the LW can hit then chances of even meeting in the sky are slim - which is the whole point. I don't care for tactics, winning or losing, I'm interested in experiencing the same as squadrons did in the BoB (minus the death).

Osprey 04-09-2012 09:48 AM

Quote:

Originally Posted by FG28_Kodiak (Post 407056)
At the moment with time amount, but it's no problem doing this via menu. But at the moment there is the problem with the missionmenu for the red side on dediserver, so it's better to wait for the patch, and hope the patch solving this problem.
How many of this Sector Station Ops Room where available at BoB? How many radars and other observers was attached to one station?


DANG! So the custom menu code is not available on dedicated servers? I must admit, I couldn't get it to work but I put it down to me being rubbish. Is there a way you can fire an event to the server to obtain that radar information?

Please view my above post for further context, they are just ideas.

Osprey 04-09-2012 09:57 AM

About the 4 minutes delay. It appears to be bang on because the RDF data went through a filter station (where people examined the plotted information) before being passed to the FC bunker - this website is definitely worth a read.

http://www.ventnorradar.co.uk/CH.htm

"The edited data was assembled as markers on a large plotting table and this showed the situation as it had been something like four minutes previously : since then the bombers would have flown about another fifteen miles"

This is interesting too. Vector was only confirmed with the second reading.
"Repeated plots became the direction of travel (vector) with the height and estimated number of aircraft repeatedly confirmed"

CH was blind past the coast and then the OC was used. But was the delay resolved for the BoB???
"With the separate raids thus identified, the information was passed to an Operations room staff who could then make the tactical decisions regarding the deployment and vectoring of the defending aircraft, either those already in the air or presently on the ground, towards their ever moving targets. It was found that those best equipped to calculate the required courses were recuperating experienced pilots as they were able to better visulise the everchanging relationships between defending and attacking aircraft. However, once the enemy aircraft had crossed the coast the CH RDF could no longer detect them and then the Royal Observer Corps reports to the Filter Room became the sole means of tracking the enemy."

"The system of having to use correction charts before reporting plots to the Filter Room contributed to the four minute delay and and sometimes of course the human factor introduced errors. This problem was solved by 'The Calculator'. Designed and installed by the Post Office ( which later constructed the Colossi computers for Bletchley Park) and using relays and uniselectors, this little known and uncelebrated early form of computer automatically added the correction factors to the input plots and displayed the results visually as the grid reference. The machine could also correct heights in the same way and a mechanically linked teleprinter could send the data by telephone line to the remote Filter Room. Ventnor was equipped with its first calculator in June 1940 and received its second in April 1941."

csThor 04-09-2012 10:07 AM

Quote:

Originally Posted by Osprey (Post 407062)
I see where you are coming from but I wouldn't want to sit out and direct anyone, and if you have a list of targets which the LW can hit then chances of even meeting in the sky are slim - which is the whole point.

Err ... no. The CO position is essentially a pre-flight position and is not meant to be RAF Fighter Command CO or commanding General of a german Fliegerkorps during the game. Once the planning is done the CO reverts to flying as usual. I don't know what number of players and squads you're planning with but given the obvious limitations on player numbers and ability to display a lot of aircraft I guess we're talking about maybe forty to fifty people at best so the target area and the target selection will always be within the confines of this limit. Going back to my example of an August 1940 mission I'd envision the german task to hit at least one of the primary targets (i.e. Biggin Hill, Kenley, Croydon) and also offers secondary targets such as radar stations, harbors and secondary airfields.

And just to make that absolutely clear I am not talking about using the whole width of the map if it doesn't reflect the number of players engaged. Right now that is simply not possible from the technical side as we don't see 128 player servers working and being filled to that point (plus a load of AI for the bombers which few people fly, anyway). The target zone would be limited to one of the areas assigned to the german Luftflotten (Luftflotte 3 = west of Seine, Luftflotte 2 = east of Seine). This way both RAF and LW would meet in one area and not play chicken with each other.

Quote:

Originally Posted by Osprey (Post 407062)
I don't care for tactics, winning or losing, I'm interested in experiencing the same as squadrons did in the BoB (minus the death).

The problem is you can't exclude tactics if you want that immersion. The Luftwaffe's bombers would be jubilant if they could fly unmolested. ;)

Osprey 04-09-2012 10:13 AM

Sort of reminds me of the USL in that there was a known mission and both sides planned for it plus if someone knew what was going to happen though then it sort of spoils it for them.

Although it would be nice, I wouldn't expect Farber to have to tail a bomber with flaps down lol I can live without that total repetition!

csThor 04-09-2012 11:31 AM

Never heard anything about the USL so I can't compare but essentially I envision a system in which the RAF will not know what the LW will attack until the action is underway. It's not that I want the LW to announce its targets before flying ... that would make the whole system pointless (all that will be known in advance is the area of operations - ergo whether the west or the east of the Channel map will be used).
Tactically the squadrons should be given not more than a general task but not told "you must do close escort for the bombers". All these considerations should be up to the squad.

5./JG27.Farber 04-09-2012 04:11 PM

Quote:

Originally Posted by csThor (Post 407071)
I don't know what number of players and squads you're planning with but given the obvious limitations on player numbers and ability to display a lot of aircraft I guess we're talking about maybe forty to fifty people at best....

We had around 70 last time at the peak if I recall. Were hoping to fill the server. :-P

Good Post Osprey. Heh 4 minutes hey? Good guess then. You guys can sit on the ground in readyness, no problem.

FG28_Kodiak 04-09-2012 06:37 PM

Ok example for the mission menu:
Select red side then TAB->4 at moment the "radar" is not functional, menu at the moment is an example, so feel free to comment :rolleyes:

for rest i must first read the posts above :rolleyes:

Code:

using System;
using System.Collections;
using System.Collections.Generic;
using maddox.game;
using maddox.game.world;
using maddox.GP;


public class Mission : AMission
{
    #region class Menu
   
    internal class Menu
    {
        internal class MenuEntry
        {
            internal string MenuName { get; set; }
            internal bool active { get; set; }
        }

        internal List<MenuEntry> menuEntries = new List<MenuEntry>();

        public void AddMenuEntry(string description, bool active)
        {
            MenuEntry NewMenuEntry = new MenuEntry();

            NewMenuEntry.MenuName = description;
            NewMenuEntry.active = active;

            menuEntries.Add(NewMenuEntry);
        }

        public string[] GetMenuDescriptions()
        {
            List<string> Descriptions = new List<string>();

            menuEntries.ForEach(item =>
            {
                Descriptions.Add(item.MenuName);
            });

            return Descriptions.ToArray();
        }

        public bool[] GetActives()
        {
            List<bool> Actives = new List<bool>();

            menuEntries.ForEach(item =>
            {
                Actives.Add(item.active);
            });

            return Actives.ToArray();
        }

        public bool IsValid()
        {
            if (menuEntries == null || menuEntries.Count < 1)
                return false;
            else
                return true;

        }

    }

    #endregion


    internal class Pilot
    {
        public Player player { get; set; }
        public LocalHeadquarters connectedHeadquarter;

        public Pilot(Player player)
        {
            this.player = player;
        }
    }


    internal List<Pilot> PilotsInGame = new List<Pilot>();


    internal class LocalHeadquarters
    {
        public string Name { get; set; }
        public Point2d LocationCoords { get; set; }
        public List<string> AttachedRadarStations = new List<string>();

        public LocalHeadquarters(string name, double x, double y)
        {
            this.Name = name;
            this.LocationCoords = new Point2d(x, y);
        }
    }


    List<LocalHeadquarters> Headquarters = new List<LocalHeadquarters>{
        {new LocalHeadquarters("Alpha", 100.0, 100.0)},
        {new LocalHeadquarters("Beta", 200.0, 200.0)},
        {new LocalHeadquarters("Gamma", 300.0, 300.0)},
        {new LocalHeadquarters("Delta", 400.0, 400.0)}};



    public override void OnPlaceEnter(Player player, AiActor actor, int placeIndex)
    {
        base.OnPlaceEnter(player, actor, placeIndex);


        if (!PilotsInGame.Exists(item => item.player == player))
        {
            PilotsInGame.Add(new Pilot(player));
        }


        PilotsInGame.ForEach(item =>
            {
                GamePlay.gpLogServer(null, "Spieler: {0}", new[] {item.player.Name() });
            });

        SetMainMenu(player);
    }
   
   
    public void SetMainMenu(Player player)
    {
        if (player.Army() == 1) // red Side
            GamePlay.gpSetOrderMissionMenu(player, false, 0, new string[] { "Radaroperations" }, new bool[] { true });
        else
            GamePlay.gpSetOrderMissionMenu(player, false, 0, new string[] { "Not Available" }, new bool[] { true });
    }


    public void SetRadarMenu(Player player)
    {
        string headQuarter = "Select Headquarter";
        string connectedTo = "";

        if (PilotsInGame.Exists(item => item.player == player))
        {
            int i = PilotsInGame.FindIndex(item => item.player == player);

            if (PilotsInGame[i].connectedHeadquarter != null)
                connectedTo = string.Format(" (connected: {0})", PilotsInGame[i].connectedHeadquarter.Name);
        }
        headQuarter += connectedTo;

        GamePlay.gpSetOrderMissionMenu(player, true, 100, new string[] { headQuarter, "Get Radar Information" }, new bool[] { true, true });

    }


    public void SetConnectToHeadquarterMenu(Player player)
    {
        Menu NewMenu = new Menu();
        LocalHeadquarters headQuarter = null;

        if (PilotsInGame.Exists(item => item.player == player))
        {
            int i = PilotsInGame.FindIndex(item => item.player == player);
            headQuarter = PilotsInGame[i].connectedHeadquarter;
        }

        Headquarters.ForEach(item =>
        {
            if (headQuarter != null && item == headQuarter)
            {
                NewMenu.AddMenuEntry(item.Name + " *", true);
            }
            else
                NewMenu.AddMenuEntry(item.Name, true);
        });

        if (NewMenu.IsValid())
            GamePlay.gpSetOrderMissionMenu(player, true, 101, NewMenu.GetMenuDescriptions() , NewMenu.GetActives());
        else
            GamePlay.gpSetOrderMissionMenu(player, true, 101, new string[]{ "Not available" }, new bool[]{true});
    }


    public void SetHeadQuarter(Player player, int menuItemIndex)
    {
        if (PilotsInGame.Exists(item => item.player == player))
            PilotsInGame[PilotsInGame.FindIndex(item => item.player == player)].connectedHeadquarter = Headquarters[menuItemIndex-1];

    }


    public override void OnOrderMissionMenuSelected(Player player, int ID, int menuItemIndex)
    {


        if (ID == 0)
        { // main menu
            if (menuItemIndex == 1)
            {
                SetRadarMenu(player);
            }
            //if (menuItemIndex == 2)
            //{


            //}
            //if (menuItemIndex == 3)
            //{


            //}
        }


        if (ID == 100)
        {
            //Radar Menu
            if (menuItemIndex == 1)
            {
                SetConnectToHeadquarterMenu(player);
            }

            if (menuItemIndex == 2)
            {
                SetMainMenu(player);
            }


            if (menuItemIndex == 0)
                SetMainMenu(player);
        }

        if (ID == 101)
        {
            //Radar Menu
            if (menuItemIndex == 0)
                SetRadarMenu(player);
            else
            {
                SetHeadQuarter(player, menuItemIndex);
                SetRadarMenu(player);
            }
        }
    }
}


5./JG27.Farber 04-09-2012 08:50 PM

The menu works. I can attach myself to one of the radaroperators, Alpha, Beta, Gamma and Delta.

I can also see the request option.

FG28_Kodiak 04-09-2012 09:09 PM

Any wishes for the captions of the menus?

_79_dev 04-09-2012 09:51 PM

I am trying my best but I can't get to work voice messages script invoked by time for some reason.
I persume that it will be adopted for this menu script... Is it correct?

5./JG27.Farber 04-09-2012 10:18 PM

Quote:

Originally Posted by FG28_Kodiak (Post 407237)
Any wishes for the captions of the menus?

Select Ground Control Frequency? Or Select Frequency?

Channel 1,2,3,4?

Make Request?


Would be nice if when you asked for information the voice actor acknoledged and said, "Roger, Standby "players callsign letter""


What do the channels actually mean/do/will do?

FG28_Kodiak 04-10-2012 04:40 AM

@_79_dev
Yes would be the better way, the first example was only for showing the possibilies.

@5./JG27.Farber
Quote:

..voice actor acknoledged and said, "Roger, Standby "players callsign letter"
If there are ogg files present it's possible, but i must first look for it. May be there is a way to create own ogg files for this, but not tested it at the moment.
Quote:

What do the channels actually mean/do/will do?
Plan is to attach sectors (channel 1: C1..D4 etc.) to be observed to a "channel or headquarter", if the player make a request, he get the information for each enemy Airgroup in these sectors. The number of available "channels" depens of the distance to them, if two in range the player can select one of the two, if none of them in range, no radar information is present etc. May be the player is transfered to an other "headquarter" when leaving the Area from another. There are many possibilities.

bolox 04-10-2012 05:59 AM

Quote:

Originally Posted by FG28_Kodiak (Post 407316)
May be there is a way to create own ogg files for this, but not tested it at the moment.

I have tried this with no success (probably me being stupid :rolleyes:)
http://forum.1cpublishing.eu/showthread.php?t=30245
Would open up some nice possibilities if can be done- Desastersoft seems to have added 8 sound files for their demo (hidden away in //...steamapps/.../desastersoft/wick vs dundas/sounds)

FG28_Kodiak 04-10-2012 09:07 AM

Have tried it also but not very intensive :grin:, no result.

Another possibility should be the Soundplayer integrated in System.Media. But i don't think it work on Multiplayer, scripts are serverbased. For singleplayer missions it should work.
But we only interested in Multiplayer :cool:

5./JG27.Farber 04-11-2012 07:17 AM

By the callsign letter, this is the one you choose in game. I choose "Falke" for farber for example. I have heard the computer call it to me, or is this only in offline?

FG28_Kodiak 04-11-2012 08:01 AM

I can get the airgroup callsign via script, but must test if this is able for a single player.

Osprey 04-11-2012 10:49 AM

I've been absent, but Kodiak this is very promising stuff!! :)

I'd like to help with this, I have ideas but I'm at work so I will post later on.

~S~ and many thanks!

5./JG27.Farber 04-11-2012 12:25 PM

Quote:

Originally Posted by FG28_Kodiak (Post 407647)
I can get the airgroup callsign via script, but must test if this is able for a single player.

You mean multiplayer? :-P

FG28_Kodiak 04-11-2012 01:28 PM

Yep a single player in multiplayer :-P

FG28_Kodiak 04-11-2012 02:32 PM

Ok Problem, there are callsighn?? ogg present, but if i try to play them via SayToGroup nothing happens. :(
So it seems it's better to wait for the next patch, hope the problem is solved.

Osprey 04-11-2012 03:45 PM

I think that customising sounds to individuals may be a step too far for now, the existing sounds seem to have most of the comments needed to piece together a decent instruction. I'll write up some design/requirements and example scenarios in which existing logic could be used to create those instructions. I think we could start with some basic vocal instruction and extend the logic in pieces to improve the description as that is proven out.

I need a chat with Farber about his requirements from a German pilot perspective. We need to be careful here, and I'm not trying to gain advantage for the RAF BUT it should be noted that in 1940 it was not possible for German fighter pilots to talk on radios to German bomber crews because they had completely different sets and 'crystals'. This is explained in Ulrich Stienhilpers book "Spitfire on my Tail" who was responsible for radio comms for his squadron. Of course I am open to correction on this, and I'm keen to learn about any use of German radar in directing fighter squadrons - again I don't think there was any, they used radar for attack eg finding ships to target in the Channel.

5./JG27.Farber 04-11-2012 03:51 PM

No, fighters could not communicate with bombers and niether will we, as most if not all will be AI.

FG28_Kodiak 04-11-2012 04:23 PM

Argh sometimes i could the devs ... :grin:

Callsigns work, the oggs are called callsign1 .. etc. but you must write CallSign1 in code :rolleyes:

Osprey 04-11-2012 04:36 PM

You can't use a variable or parameter?

FG28_Kodiak 04-11-2012 04:49 PM

Yes i can, but i must it 'translate' it somewhere. :rolleyes:

Ok try of a 'connect' - communication (use the mission-menu ;)):

Code:

using System;
using System.Collections;
using System.Collections.Generic;
using maddox.game;
using maddox.game.world;
using maddox.GP;


public class Mission : AMission
{
    #region class Menu
   
    internal class Menu
    {
        internal class MenuEntry
        {
            internal string MenuName { get; set; }
            internal bool active { get; set; }
        }

        internal List<MenuEntry> menuEntries = new List<MenuEntry>();

        public void AddMenuEntry(string description, bool active)
        {
            MenuEntry NewMenuEntry = new MenuEntry();

            NewMenuEntry.MenuName = description;
            NewMenuEntry.active = active;

            menuEntries.Add(NewMenuEntry);
        }

        public string[] GetMenuDescriptions()
        {
            List<string> Descriptions = new List<string>();

            menuEntries.ForEach(item =>
            {
                Descriptions.Add(item.MenuName);
            });

            return Descriptions.ToArray();
        }

        public bool[] GetActives()
        {
            List<bool> Actives = new List<bool>();

            menuEntries.ForEach(item =>
            {
                Actives.Add(item.active);
            });

            return Actives.ToArray();
        }

        public bool IsValid()
        {
            if (menuEntries == null || menuEntries.Count < 1)
                return false;
            else
                return true;

        }

    }

    #endregion


    internal class Pilot
    {
        public Player player { get; set; }
        public LocalHeadquarters connectedHeadquarter;

        public Pilot(Player player)
        {
            this.player = player;
        }
    }


    internal List<Pilot> PilotsInGame = new List<Pilot>();


    internal class LocalHeadquarters
    {
        public string Name { get; set; }
        public Point2d LocationCoords { get; set; }
        public string Callsign { get; set; }
        public List<string> AttachedSectors = new List<string>();

        public LocalHeadquarters(string name, string callsign, double x, double y)
        {
            this.Name = name;
            this.Callsign = callsign;
            this.LocationCoords = new Point2d(x, y);
        }
    }


    List<LocalHeadquarters> Headquarters = new List<LocalHeadquarters>{
        {new LocalHeadquarters("Luton", "CallSign24", 100.0, 100.0)},
        {new LocalHeadquarters("RadPoe", "CallSign32", 200.0, 200.0)},
        {new LocalHeadquarters("Forest", "CallSign15", 300.0, 300.0)},
        {new LocalHeadquarters("Bearskin", "CallSign5", 400.0, 400.0)}};



    public override void OnPlaceEnter(Player player, AiActor actor, int placeIndex)
    {
        base.OnPlaceEnter(player, actor, placeIndex);


        if (!PilotsInGame.Exists(item => item.player == player))
        {
            PilotsInGame.Add(new Pilot(player));
        }

        GamePlay.gpLogServer(null, "Callsign: {0}", new[] { (actor as AiAircraft).CallSign() });

        SetMainMenu(player);
    }


    private void connectToHeadquarterSpeech(AiAircraft aircraft, LocalHeadquarters localHQ)
    {
        double initTime = 0.0;

        aircraft.SayToGroup(aircraft.AirGroup(), "Hello_guys");

        Timeout(initTime += 2, () =>
            {
                aircraft.SayToGroup(aircraft.AirGroup(), "This_is");
            });

        Timeout(initTime += 2, () =>
        {
            aircraft.SayToGroup(aircraft.AirGroup(), localHQ.Callsign);
        });

       
        // to is missing as ogg


        Timeout(initTime += 2, () =>
        {
            aircraft.SayToGroup(aircraft.AirGroup(), aircraft.CallSign());
        });

       

        Timeout(initTime += 2, () =>
        {
            aircraft.SayToGroup(aircraft.AirGroup(), "leader__");
        });


    }


   
    public void SetMainMenu(Player player)
    {
        if (player.Army() == 1) // red Side
            GamePlay.gpSetOrderMissionMenu(player, false, 0, new string[] { "Radaroperations" }, new bool[] { true });
        else
            GamePlay.gpSetOrderMissionMenu(player, false, 0, new string[] { "Not Available" }, new bool[] { true });
    }


    public void SetRadarMenu(Player player)
    {
        string headQuarter = "Select Headquarter";
        string connectedTo = "";

        if (PilotsInGame.Exists(item => item.player == player))
        {
            int i = PilotsInGame.FindIndex(item => item.player == player);

            if (PilotsInGame[i].connectedHeadquarter != null)
                connectedTo = string.Format(" (connected: {0})", PilotsInGame[i].connectedHeadquarter.Name);
        }
        headQuarter += connectedTo;

        GamePlay.gpSetOrderMissionMenu(player, true, 100, new string[] { headQuarter, "Get Radar Information" }, new bool[] { true, true });

    }


    public void SetConnectToHeadquarterMenu(Player player)
    {
        Menu NewMenu = new Menu();
        LocalHeadquarters headQuarter = null;

        if (PilotsInGame.Exists(item => item.player == player))
        {
            int i = PilotsInGame.FindIndex(item => item.player == player);
            headQuarter = PilotsInGame[i].connectedHeadquarter;
        }

        Headquarters.ForEach(item =>
        {
            if (headQuarter != null && item == headQuarter)
            {
                NewMenu.AddMenuEntry(item.Name + " *", true);
            }
            else
                NewMenu.AddMenuEntry(item.Name, true);
        });

        if (NewMenu.IsValid())
            GamePlay.gpSetOrderMissionMenu(player, true, 101, NewMenu.GetMenuDescriptions() , NewMenu.GetActives());
        else
            GamePlay.gpSetOrderMissionMenu(player, true, 101, new string[]{ "Not available" }, new bool[]{true});
    }


    public void SetHeadQuarter(Player player, int menuItemIndex)
    {
        if (PilotsInGame.Exists(item => item.player == player))
        {
            int i = PilotsInGame.FindIndex(item => item.player == player);
            PilotsInGame[i].connectedHeadquarter = Headquarters[menuItemIndex-1];
            if (player.Place() != null)
                connectToHeadquarterSpeech((player.Place() as AiAircraft), PilotsInGame[i].connectedHeadquarter);
        }

    }


    public override void OnOrderMissionMenuSelected(Player player, int ID, int menuItemIndex)
    {


        if (ID == 0)
        { // main menu
            if (menuItemIndex == 1)
            {
                SetRadarMenu(player);
            }
            //if (menuItemIndex == 2)
            //{


            //}
            //if (menuItemIndex == 3)
            //{


            //}
        }


        if (ID == 100)
        {
            //Radar Menu
            if (menuItemIndex == 1)
            {
                SetConnectToHeadquarterMenu(player);
            }

            if (menuItemIndex == 2)
            {
                SetMainMenu(player);
            }


            if (menuItemIndex == 0)
                SetMainMenu(player);
        }

        if (ID == 101)
        {
            //Radar Menu
            if (menuItemIndex == 0)
                SetRadarMenu(player);
            else
            {
                SetHeadQuarter(player, menuItemIndex);
                SetRadarMenu(player);
            }
        }
    }
}


Osprey 04-11-2012 04:54 PM

Oooo you're working ahead of me :) This looks interesting, when I get back from football I'll run it up in VS and try it in a dedicated server. Do I need any special map set up so it knows about the sectors?

FG28_Kodiak 04-11-2012 04:57 PM

Do you will script this by your own? - No problem i 've some other scriptwork to do. :rolleyes:
At the moment it's only a test for communication, nor other features like sectors implemented.

Osprey 04-11-2012 07:05 PM

No no, I am rubbish at writing the code myself because I am not trained properly. I can only read it and understand it usually, and write basic logic.

I would just like to offer help with getting this working, I think a lot of people would find 'realistic radar' quite useful :)

_79_dev 04-11-2012 08:15 PM

Latest script for menu is up on server, ready to be tested... thanks Kodiak... Conect here http://www.5jg27.net/

FG28_Kodiak 04-12-2012 04:14 AM

Quote:

Originally Posted by Osprey (Post 407808)
I would just like to offer help with getting this working, I think a lot of people would find 'realistic radar' quite useful :)

A great help would be looking what oggs (and sequence) are usefull for communication. So i can 'translate' it direct in code.

salmo 04-12-2012 06:07 AM

Kodiak,
Here's the speech file (text) with all the ogg phrases in various languages. http://www.freefilehosting.net/speech I'm trying to concatonate various phrases into sentences, without success at the moment. There must be a way, since the inj-game radar speech uses almost complete sentences from the ogg phrases.

FG28_Kodiak 04-12-2012 06:38 AM

Quote:

Originally Posted by salmo (Post 407985)
Kodiak,
Here's the speech file (text) with all the ogg phrases in various languages. http://www.freefilehosting.net/speech I'm trying to concatonate various phrases into sentences, without success at the moment. There must be a way, since the inj-game radar speech uses almost complete sentences from the ogg phrases.

I think it depens of the length of a speech file, at the moment i use 3 sec. but the speech files have different lenghts, so it would better to use the exact lenghts + few miliseconds. Your speech.txt is the file for the subtitles, could be usefull, thanks. ;)

Osprey 04-12-2012 07:11 AM

Quote:

Originally Posted by FG28_Kodiak (Post 407979)
A great help would be looking what oggs (and sequence) are usefull for communication. So i can 'translate' it direct in code.

I can give you a solution to a minor problem, in one of your scripts you said in comments that there was no "to.ogg" - just use the "2.ogg" instead since it is phonetically the same.


Really sorry I did nothing yesterday. I am changing ISP and since I told them I have been getting cut off every night :(

I have been looking at these and have some ideas on what needs to be said by the radio operator. For instance, I'm interested in the Point3D position of both aircraft, therefore for example

if(pilot.height < aiairgroup.height)
{
//use "climb.ogg" & "2.ogg" angels i;
}
else
{
//use "descend.ogg & "2.ogg" angels i;
}

There are also direction oggs such as "turn right.ogg" but I don't know how sophisticated this can be. Unless it is easy to work out interception vectors then that is probably too much work or a longer term project. It is not needed for now

I would like to know more about the sectors and how you intend to have this working. I have some input for this. There are a few important behaviour requirements for this if possible, briefly:

1. No aircraft reported under 600m (Chain Home Low min operating height)
2. RDF range as far as the French coast (and into France some 50 miles in the Pas De Calais area) A range map is available on Wikipedia

I have an idea for a 4 minute delay but it's probably complicated and not the first thing to implement. It would involve the radar constantly working behind in the script and storing 4 minute old data in variables, then releasing that to the user on request instead of current data. Perhaps if the RDF event fired every minute transparently and the resulting information string stored and passed on every minute into a new variable until the 4th minute, then this was accessed and played to the player. (hope that makes sense)

Speak later ~S~

41Sqn_Banks 04-12-2012 07:22 AM

Quote:

Originally Posted by FG28_Kodiak (Post 407991)
I think it depens of the length of a speech file, at the moment i use 3 sec. but the speech files have different lenghts, so it would better to use the exact lenghts + few miliseconds. Your speech.txt is the file for the subtitles, could be usefull, thanks. ;)

Wouldn't it be possible to open the ogg files with a .Net media class not to play it but only to read the length?

By this one could write a function that takes a array/list of strings that contains the names of the ogg files that should be played in a row.

FG28_Kodiak 04-12-2012 07:42 AM

Quote:

Really sorry I did nothing yesterday. I am changing ISP and since I told them I have been getting cut off every night.
No problem with that, at the moment i am busy, also.


Ok to sectors how i will use them.

If a Battle Area is available you get the sector of a Actor with:
GamePlay.gpSectorName(x, y)
for exampe i get "D,1" as a string.
Then i look if there is a HQ which is ' responsible' for this sector, each HQ gets a List with Sectors (its the job of the missionbuilder which sectors are stored in the Lists). If the player is connected to this HQ he became a response like
"Mason Leader Enemy Bombers are in sector D 1", the rest depends on what is possible like Angels 12, Heading 320 etc.
if he is not connected to that HQ he get no message, or
"Mason Leader no enemy in sectors".

To which 'HQ' the player can connect depens of the range to the next HQs.


On German side may be i introduce a "Fliegerleitoffizier" which give targets to german stukas or bombers. Like "ship convoi in sector D,1 destroy.."

5./JG27.Farber 04-12-2012 09:33 AM

Nice. :-P

FG28_Kodiak 04-12-2012 09:34 AM

Quote:

Originally Posted by 41Sqn_Banks (Post 407999)
Wouldn't it be possible to open the ogg files with a .Net media class not to play it but only to read the length?

By this one could write a function that takes a array/list of strings that contains the names of the ogg files that should be played in a row.

Good idea will try it.

FG28_Kodiak 04-12-2012 09:39 AM

So added sectors to headquarters, for testing i use a simple chat message, at the moment.

Code:

using System;
using System.Collections;
using System.Collections.Generic;
using maddox.game;
using maddox.game.world;
using maddox.GP;


public class Mission : AMission
{
    #region class Menu
   
    internal class Menu
    {
        internal class MenuEntry
        {
            internal string MenuName { get; set; }
            internal bool active { get; set; }
        }

        internal List<MenuEntry> menuEntries = new List<MenuEntry>();

        public void AddMenuEntry(string description, bool active)
        {
            MenuEntry NewMenuEntry = new MenuEntry();

            NewMenuEntry.MenuName = description;
            NewMenuEntry.active = active;

            menuEntries.Add(NewMenuEntry);
        }

        public string[] GetMenuDescriptions()
        {
            List<string> Descriptions = new List<string>();

            menuEntries.ForEach(item =>
            {
                Descriptions.Add(item.MenuName);
            });

            return Descriptions.ToArray();
        }

        public bool[] GetActives()
        {
            List<bool> Actives = new List<bool>();

            menuEntries.ForEach(item =>
            {
                Actives.Add(item.active);
            });

            return Actives.ToArray();
        }

        public bool IsValid()
        {
            if (menuEntries == null || menuEntries.Count < 1)
                return false;
            else
                return true;

        }

    }

    #endregion


    internal class Pilot
    {
        public Player player { get; set; }
        public LocalHeadquarters connectedHeadquarter;

        public Pilot(Player player)
        {
            this.player = player;
        }
    }


    internal List<Pilot> PilotsInGame = new List<Pilot>();


    internal class LocalHeadquarters
    {
        public string Name { get; set; }
        public Point2d LocationCoords { get; set; }
        public string Callsign { get; set; }
        private List<string> AttachedSectors = new List<string>();
       
        public LocalHeadquarters(string name, string callsign, double x, double y, params string[] sectors)
        {
            this.Name = name;
            this.Callsign = callsign;
            this.LocationCoords = new Point2d(x, y);

            if (sectors != null)
                AttachedSectors.AddRange(sectors);
        }

        public bool observeSector(string sectorName)
        {
            if (AttachedSectors.Exists(item => item.Equals(sectorName)))
                return true;
            else
                return false;
        }
    }


    List<LocalHeadquarters> Headquarters = new List<LocalHeadquarters>{
        {new LocalHeadquarters("Luton", "CallSign24", 100.0, 100.0, "A,1","A,2","A,3","B,1","B,2","B,3")},
        {new LocalHeadquarters("RadPoe", "CallSign32", 200.0, 200.0, "C,1","C,2","C,3","D,1","D,2","D,3")},
        {new LocalHeadquarters("Forest", "CallSign15", 300.0, 300.0, "E,1","E,2","E,3","F,1","F,2","F,3")},
        {new LocalHeadquarters("Bearskin", "CallSign5", 400.0, 400.0, "G,1","G,2","G,3")}};



    public void checkSectors(Player player)
    {

        if (PilotsInGame.Exists(item => item.player == player))
        {
            int i = PilotsInGame.FindIndex(item => item.player == player);

            if (PilotsInGame[i].connectedHeadquarter != null)
            {
                if (Headquarters.Exists(hq => hq == PilotsInGame[i].connectedHeadquarter))
                {
                    LocalHeadquarters localHQ = PilotsInGame[i].connectedHeadquarter;
                    AiAirGroup[] EnemyAirgroups = GamePlay.gpAirGroups((player.Army() == 1) ? 2 : 1);

                    if (EnemyAirgroups != null)
                    {
                        bool foundEnemy = false;
                       
                        foreach (AiAirGroup aag in EnemyAirgroups)
                        {
                            string sectorName = GamePlay.gpSectorName(aag.Pos().x, aag.Pos().y);

                            if (localHQ.observeSector(sectorName) && aag.Pos().z > 600.00)
                            {
                                foundEnemy = true;
                                string type = "";

                                if (aag.isAircraftType(AircraftType.Bomber) || aag.isAircraftType(AircraftType.DiveBomber))
                                    type = "Bombers";
                                else if (aag.isAircraftType(AircraftType.Fighter))
                                    type = "Fighters";


                                GamePlay.gpLogServer(new[] { player }, "Enemy {0} in Sector: {1}", new[] { type, sectorName });
                            }
                        }
                        if(!foundEnemy)
                            GamePlay.gpLogServer(new[] { player }, "No Enemy in Range", null);

                    }
                }
            }
        }
    }


    public override void OnPlaceEnter(Player player, AiActor actor, int placeIndex)
    {
        base.OnPlaceEnter(player, actor, placeIndex);


        if (!PilotsInGame.Exists(item => item.player == player))
        {
            PilotsInGame.Add(new Pilot(player));
        }

        SetMainMenu(player);
    }


    private void connectToHeadquarterSpeech(AiAircraft aircraft, LocalHeadquarters localHQ)
    {
        double initTime = 0.0;

        aircraft.SayToGroup(aircraft.AirGroup(), "Hello_guys");

        Timeout(initTime += 2, () =>
            {
                aircraft.SayToGroup(aircraft.AirGroup(), "This_is");
            });

        Timeout(initTime += 2, () =>
        {
            aircraft.SayToGroup(aircraft.AirGroup(), localHQ.Callsign);
        });

       
        // to is missing as ogg


        Timeout(initTime += 2, () =>
        {
            aircraft.SayToGroup(aircraft.AirGroup(), aircraft.CallSign());
        });

       

        Timeout(initTime += 2, () =>
        {
            aircraft.SayToGroup(aircraft.AirGroup(), "leader__");
        });


    }


   
    public void SetMainMenu(Player player)
    {
        if (player.Army() == 1) // red Side
            GamePlay.gpSetOrderMissionMenu(player, false, 0, new string[] { "Radaroperations" }, new bool[] { true });
        else
            GamePlay.gpSetOrderMissionMenu(player, false, 0, new string[] { "Not Available" }, new bool[] { true });
    }


    public void SetRadarMenu(Player player)
    {
        string headQuarter = "Select Headquarter";
        string connectedTo = "";

        if (PilotsInGame.Exists(item => item.player == player))
        {
            int i = PilotsInGame.FindIndex(item => item.player == player);

            if (PilotsInGame[i].connectedHeadquarter != null)
                connectedTo = string.Format(" (connected: {0})", PilotsInGame[i].connectedHeadquarter.Name);
        }
        headQuarter += connectedTo;

        GamePlay.gpSetOrderMissionMenu(player, true, 100, new string[] { headQuarter, "Get Radar Information" }, new bool[] { true, true });

    }


    public void SetConnectToHeadquarterMenu(Player player)
    {
        Menu NewMenu = new Menu();
        LocalHeadquarters headQuarter = null;

        if (PilotsInGame.Exists(item => item.player == player))
        {
            int i = PilotsInGame.FindIndex(item => item.player == player);
            headQuarter = PilotsInGame[i].connectedHeadquarter;
        }

        Headquarters.ForEach(item =>
        {
            if (headQuarter != null && item == headQuarter)
            {
                NewMenu.AddMenuEntry(item.Name + " *", true);
            }
            else
                NewMenu.AddMenuEntry(item.Name, true);
        });

        if (NewMenu.IsValid())
            GamePlay.gpSetOrderMissionMenu(player, true, 101, NewMenu.GetMenuDescriptions() , NewMenu.GetActives());
        else
            GamePlay.gpSetOrderMissionMenu(player, true, 101, new string[]{ "Not available" }, new bool[]{true});
    }


    public void SetHeadQuarter(Player player, int menuItemIndex)
    {
        if (PilotsInGame.Exists(item => item.player == player))
        {
            int i = PilotsInGame.FindIndex(item => item.player == player);
            PilotsInGame[i].connectedHeadquarter = Headquarters[menuItemIndex-1];
            if (player.Place() != null)
                connectToHeadquarterSpeech((player.Place() as AiAircraft), PilotsInGame[i].connectedHeadquarter);
        }

    }


    public override void OnOrderMissionMenuSelected(Player player, int ID, int menuItemIndex)
    {


        if (ID == 0)
        { // main menu
            if (menuItemIndex == 1)
            {
                SetRadarMenu(player);
            }
            //if (menuItemIndex == 2)
            //{


            //}
            //if (menuItemIndex == 3)
            //{


            //}
        }


        if (ID == 100)
        {
            //Radar Menu
            if (menuItemIndex == 1)
            {
                SetConnectToHeadquarterMenu(player);
            }

            if (menuItemIndex == 2)
            {
                checkSectors(player);
                SetMainMenu(player);
            }
            if (menuItemIndex == 0)
                SetMainMenu(player);
        }

        if (ID == 101)
        {
            //Radar Menu
            if (menuItemIndex == 0)
                SetRadarMenu(player);
            else
            {
                SetHeadQuarter(player, menuItemIndex);
                SetRadarMenu(player);
            }
        }
    }
}

Example mission:
Three planes in sectors (at beginning all in sectors from RadPoe) one figther, one Bomber and a Bf110 below 600m (this should not be 'found' at the beginning)
Code:

[PARTS]
  core.100
  bob.100
[MAIN]
  MAP Land$Online_Cobra_(8x8)
  BattleArea 8704 14465 64640 59199 10000
  TIME 12
  WeatherIndex 0
  CloudsHeight 1000
  BreezeActivity 10
  ThermalActivity 10
  player BoB_RAF_F_FatCat_Early.000
[GlobalWind_0]
  Power 3.000 0.000 0.000
  BottomBound 0.00
  TopBound 1500.00
  GustPower 5
  GustAngle 45
[splines]
[AirGroups]
  BoB_RAF_F_FatCat_Early.01
  BoB_LW_LG2_I.02
  BoB_LW_LG2_I.04
  BoB_LW_LG2_I.11
[BoB_RAF_F_FatCat_Early.01]
  Flight0  1
  Class Aircraft.SpitfireMkIIa
  Formation VIC3
  CallSign 26
  Fuel 100
  Weapons 1
  Skill 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3
  Person0_0 0 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3 1
[BoB_RAF_F_FatCat_Early.01_Way]
  TAKEOFF 40128.00 20864.00 0 0
[BoB_LW_LG2_I.02]
  Flight1  11
  Class Aircraft.Bf-109E-4
  Formation FINGERFOUR
  CallSign 26
  Fuel 100
  Weapons 1
  Skill 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3
[BoB_LW_LG2_I.02_Way]
  NORMFLY 31360.00 43456.00 1000.00 300.00
  NORMFLY 31360.00 21696.00 1000.00 300.00
  NORMFLY 22464.00 21440.00 1000.00 300.00
  NORMFLY 22272.00 43008.00 1000.00 300.00
[BoB_LW_LG2_I.04]
  Flight2  21
  Class Aircraft.He-111H-2
  Formation FINGERFOUR
  CallSign 26
  Fuel 100
  Weapons 1
  Skill 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3
[BoB_LW_LG2_I.04_Way]
  NORMFLY 33536.56 29249.82 2500.00 300.00
  NORMFLY 45119.69 29953.77 2500.00 300.00
  NORMFLY 54143.01 37825.18 2500.00 300.00
  NORMFLY 61502.45 49920.27 2500.00 300.00
[BoB_LW_LG2_I.11]
  Flight0  1
  Class Aircraft.Bf-110C-4
  Formation FINGERFOUR
  CallSign 26
  Fuel 100
  Weapons 1
  Skill 0.3 0.3 0.3 0.3 0.3 0.3 0.3 0.3
[BoB_LW_LG2_I.11_Way]
  NORMFLY 40448.00 44097.40 500.00 300.00
  NORMFLY 32960.00 32129.40 500.00 300.00
  NORMFLY 27008.00 26817.40 1000.00 300.00
  NORMFLY 17664.00 22529.40 1000.00 300.00
[CustomChiefs]
[Stationary]
[Buildings]
[BuildingsLinks]


5./JG27.Farber 04-12-2012 05:32 PM

I tested your mission. It works fine. However its like the aircraft has radar.

Could the command sectors be tied to an ingame object? Then it could take its readings from there instead of mesuring from the aircraft. Also this means radar can be destroyed.

Could radar tell the difference between fighters and bombers?

Osprey 04-12-2012 06:08 PM

It was going to be one of my suggestions, however I have grave reservations about the ability to destroy radar. Although yes, a tactical war campaign that is perfectly sensible the impact would be:

1. Not historical. During the entire BoB, RDF was lost for under 2 hours in one sector only.
2. Lost RDF means that, on such a large map, that you are unlikely to meet each other in the sky, which is the whole point.

If it came to that, the first thing one would do would be to send out the entire squadron to each station and strike the object with 1 jabo. Job done. In reality an entire bombing group had little success. When we had Radar in the USL I made it so that it wasn't worth the attempt since it would detract from the historical nature of the missions that were developed.

FG28_Kodiak 04-12-2012 06:12 PM

Hm a sector is 10*10Km or more, so i don't think its to easy, and if no symbols in options a pilot must know where he is himself :rolleyes:, and there will be a time delay between request and answer, and a delay before a pilot can request again, so a player could not ask every 5 seconds. (not implemented yet).

But i can create Radars, each radar then has it's sectors to observe and is attached to a HQ. If a radar is destroyed the HQ is blind in this sectors.
Must test if a radar is an Actor, so i can 'see' if it is destroyed (the destroy with bombs ;)).

5./JG27.Farber 04-12-2012 06:20 PM

Quote:

Originally Posted by Osprey (Post 408163)
It was going to be one of my suggestions, however I have grave reservations about the ability to destroy radar. Although yes, a tactical war campaign that is perfectly sensible the impact would be:

1. Not historical. During the entire BoB, RDF was lost for under 2 hours in one sector only.
2. Lost RDF means that, on such a large map, that you are unlikely to meet each other in the sky, which is the whole point.

Radar stations were knocked out in BoB. It is well documented. You wont be able to miss 100+ aircraft :)
Mobile units were used when this happened and were not as effective due to their short hieght which effect wave length and the distance they could "see".

Quote:

Originally Posted by FG28_Kodiak (Post 408165)
Hm a sector is 10*10Km or more, so i don't think its to easy, and if no symbols in options a pilot must know where he is himself :rolleyes:, and there will be a time delay between request and answer, and a delay before a pilot can request again, so a player could not ask every 5 seconds. (not implemented yet).

But i can create Radars, each radar then has it's sectors to observe and is attached to a HQ. If a radar is destroyed the HQ is blind in this sectors.
Must test if a radar is an Actor, so i can 'see' if it is destroyed (the destroy with bombs ;)).

The English Radar 1, it is one object made of 4 towers, it would make the ideal actor. It can assigned a side (red/blue) and be destroyed with bombs. ;)

Osprey 04-13-2012 06:46 AM

One 250kg bomb from a single fight will knock out that radar. The towers in the BoB weren't destroyed anywhere despite several attempts by entire bomber squadrons. There were a couple of single events where radar was damaged, one because a bomb happened to land on one of the essential buildings in the complex.

I'm really not sure where this is going, what is the bigger objective of the campaign? I am seeing long term a tactical reason for this. From my perspective I honestly don't care if you bomb the crap out of every target as long as we get to meet you in the skies in the same interception fashion as the boys of the day did, but if you knock out our eyes then that won't happen - you can come in from anywhere, anytime across a big map.

5./JG27.Farber 04-13-2012 08:45 AM

Dont worry Osprey, it will be fine. I cant give to much away ;)

Osprey 04-13-2012 11:02 AM

Forgive my panickyness......

FG28_Kodiak 04-13-2012 12:27 PM

Ok Problem, this Radars are not normal Actors, so i can't register their creation nor their destroying via script, must add TGroundDestroyed-Triggers to every radar. More unconfortable for mission-builder. :rolleyes:

41Sqn_Banks 04-13-2012 12:56 PM

Quote:

Originally Posted by FG28_Kodiak (Post 408467)
Ok Problem, this Radars are not normal Actors, so i can't register their creation nor their destroying via script, must add TGroundDestroyed-Triggers to every radar. More unconfortable for mission-builder. :rolleyes:

Didn't know that TGroundDestroyed is fired for "strange actors", thanks for the info, comes handy for IL2DCE.

You could parse the mission file OnBattleStart (or one of the init events before) and create a mission file that contains triggers for each radar station and then postload the trigger file (remember to set MissionNumberListener = -1;). The script has to know the path to the mission file though.

FG28_Kodiak 04-13-2012 01:04 PM

Yes i could, but would :rolleyes: :grin:

Gib ihnen den kleinen Finger ... :rolleyes:

FG28_Kodiak 04-14-2012 06:03 PM

1 Attachment(s)
Ok added the possibility to destroy Radars so the HQ gets blind in attached sectors.
For triggers i scan the mis file for the Radarstations:
Code:

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using maddox.game;
using maddox.game.world;
using maddox.GP;


public class Mission : AMission
{

    private static string userdocpath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
    private static string FILE_PATH = userdocpath + @"\1C SoftClub\il-2 sturmovik cliffs of dover\missions\";
    private static string MISSION_FILE = FILE_PATH + @"RadarTest\RadarTest.mis";


    private List<string> getRadarCreationStrings(string filename)
    {
        List<string> list = new List<string>();
       
        using (StreamReader reader = new StreamReader(filename))
        {
            string line;
            while ((line = reader.ReadLine()) != null)
            {
                if (line.Contains("Stationary.Radar"))
                {
                    list.Add(line);
                }
            }
        }
        return list;
    }



    private ISectionFile createRadarTriggers()
    {
        ISectionFile trigger = GamePlay.gpCreateSectionFile();

        List<string> Radarstations = getRadarCreationStrings(MISSION_FILE);

        if (Radarstations.Count > 0)
        {
            int i = 0;
            Radarstations.ForEach(item =>
                {
                    item = item.TrimStart(' ');
                    string[] splittet = item.Split(' ');
                    //Radar02Destroyed TGroundDestroyed 50 23438 20849 750
                    string keyTr, valueTr;

                    keyTr = "Radar" + string.Format("{0:00}", i) +"Destroyed";
                    valueTr = " TGroundDestroyed 50 " + splittet[3] + " " + splittet[4] + " 500"; //TGroundDestroyedTrigger 50% destroyed in radius 500m
                    trigger.add("Trigger", keyTr, valueTr);

                    Headquarters.ForEach(hq => { hq.AddTriggerToObserver(splittet[0], keyTr); });
                    i++;
                });
        }
        return trigger;
    }


    public override void OnBattleStarted()
    {
        base.OnBattleStarted();
        MissionNumberListener = -1;
        GamePlay.gpPostMissionLoad(createRadarTriggers());             
       
    }


    #region class Menu
   
    internal class Menu
    {
        internal class MenuEntry
        {
            internal string MenuName { get; set; }
            internal bool active { get; set; }
        }

        internal List<MenuEntry> menuEntries = new List<MenuEntry>();

        public void AddMenuEntry(string description, bool active)
        {
            MenuEntry NewMenuEntry = new MenuEntry();

            NewMenuEntry.MenuName = description;
            NewMenuEntry.active = active;

            menuEntries.Add(NewMenuEntry);
        }

        public string[] GetMenuDescriptions()
        {
            List<string> Descriptions = new List<string>();

            menuEntries.ForEach(item =>
            {
                Descriptions.Add(item.MenuName);
            });

            return Descriptions.ToArray();
        }

        public bool[] GetActives()
        {
            List<bool> Actives = new List<bool>();

            menuEntries.ForEach(item =>
            {
                Actives.Add(item.active);
            });

            return Actives.ToArray();
        }

        public bool IsValid()
        {
            if (menuEntries == null || menuEntries.Count < 1)
                return false;
            else
                return true;

        }

    }

    #endregion


    internal class Pilot
    {
        public Player player { get; set; }
        public LocalHeadquarters connectedHeadquarter;

        public Pilot(Player player)
        {
            this.player = player;
        }
    }


    internal List<Pilot> PilotsInGame = new List<Pilot>();


    internal class LocalHeadquarters
    {
        public string Name { get; set; }
        public Point2d LocationCoords { get; set; }
        public string Callsign { get; set; }
        private List<ObserverStation> AttachedObservers = new List<ObserverStation>();

        public LocalHeadquarters(string name, string callsign, double x, double y, params ObserverStation[] observerStations)
        {
            this.Name = name;
            this.Callsign = callsign;
            this.LocationCoords = new Point2d(x, y);

            if (observerStations != null)
                AttachedObservers.AddRange(observerStations);
        }

        public bool ObserveSector(string sectorName)
        {

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

            if (AttachedObservers.Count > 0)
            {
                AttachedObservers.ForEach(item =>
                    {
                        if (item.IsActive)
                            AttachedSectors.AddRange(item.observedSectors);
                    });
            }
           
            if (AttachedSectors.Exists(item => item.Equals(sectorName)))
                return true;
            else
                return false;
        }

        public List<ObserverStation> GetObservers()
        {

            return AttachedObservers;
        }


        public string GetNotObservedSectors()
        {
            string sectorList = "";

            if (AttachedObservers.Exists(item => item.IsActive == false))
            {
                AttachedObservers[AttachedObservers.FindIndex(item => item.IsActive == false)].observedSectors.ForEach(sector =>
                    {
                        sectorList += sector + " ";
                    });

                sectorList = sectorList.Replace(',', '/');
                sectorList = sectorList.TrimEnd(' ');
            }
            return sectorList;
        }


        public void SetObserverInactive(string triggerName)
        {
           
            if (AttachedObservers.Exists(item => item.TriggerName == triggerName))
            {
                AttachedObservers[AttachedObservers.FindIndex(item => item.TriggerName == triggerName)].IsActive = false;
            }
        }


        public void AddTriggerToObserver(string staticName, string triggerName)
        {
            if (AttachedObservers.Exists(item => item.StaticName == staticName))
            {
                AttachedObservers[AttachedObservers.FindIndex(item => item.StaticName == staticName)].TriggerName = triggerName;
            }
        }
    }


    internal class ObserverStation
    {
        public bool IsActive { get; set; }
        public string StaticName { get; set; }
        public string TriggerName { get; set; }

        public List<string> observedSectors = new List<string>();

        public ObserverStation(string staticName, params string[] sectorNames)
        {
            this.StaticName = staticName;
            this.IsActive = true;

            if (sectorNames != null)
                observedSectors.AddRange(sectorNames);
        }


        public void SetTriggerName(string triggerName)
        {
            this.TriggerName = triggerName;
        }

    }


    List<LocalHeadquarters> Headquarters = new List<LocalHeadquarters>{
        {new LocalHeadquarters("Luton", "CallSign24", 100.0, 100.0, new ObserverStation( "Static0","A,1","A,2","A,3"), new ObserverStation( "Static1","B,1","B,2","B,3"))},
        {new LocalHeadquarters("RadPoe", "CallSign32", 200.0, 200.0, new ObserverStation( "Static2","C,1","C,2","C,3"), new ObserverStation( "Static3","D,1","D,2","D,3"))},
        {new LocalHeadquarters("Forest", "CallSign15", 300.0, 300.0, new ObserverStation( "Static4","E,1","E,2","E,3"), new ObserverStation( "Static5","F,1","F,2","F,3"))}
    };


    public void checkSectors(Player player)
    {

        if (PilotsInGame.Exists(item => item.player == player))
        {
            int i = PilotsInGame.FindIndex(item => item.player == player);

            if (PilotsInGame[i].connectedHeadquarter != null)
            {
                if (Headquarters.Exists(hq => hq == PilotsInGame[i].connectedHeadquarter))
                {
                    LocalHeadquarters localHQ = PilotsInGame[i].connectedHeadquarter;
                    AiAirGroup[] EnemyAirgroups = GamePlay.gpAirGroups((player.Army() == 1) ? 2 : 1);

                    if (EnemyAirgroups != null)
                    {
                        bool foundEnemy = false;
                       
                        foreach (AiAirGroup aag in EnemyAirgroups)
                        {
 
                            string sectorName = GamePlay.gpSectorName(aag.Pos().x, aag.Pos().y);

                            if (localHQ.ObserveSector(sectorName) && aag.Pos().z > 600.00)
                            {
                                foundEnemy = true;
                                string type = "";

                                if (aag.isAircraftType(AircraftType.Bomber) || aag.isAircraftType(AircraftType.DiveBomber))
                                    type = "Bombers";
                                else if (aag.isAircraftType(AircraftType.Fighter))
                                    type = "Fighters";

                                GamePlay.gpLogServer(new[] { player }, "{0} Enemy {1} in Sector: {2}", new object[] { aag.NOfAirc, type, sectorName });
                            }
                        }


                        if (localHQ.GetNotObservedSectors() != "")
                        {
                            GamePlay.gpLogServer(null, "Attention Informations for Sectors {0} not available!", new[] { localHQ.GetNotObservedSectors() });
                            if (!foundEnemy)
                                GamePlay.gpLogServer(new[] { player }, "No Enemy in other available Sectors spottet", null);
                       
                        }
                        else if(!foundEnemy)
                            GamePlay.gpLogServer(new[] { player }, "No Enemy in Range", null);

                    }
                }
            }
        }
    }


    public override void OnPlaceEnter(Player player, AiActor actor, int placeIndex)
    {
        base.OnPlaceEnter(player, actor, placeIndex);


        if (!PilotsInGame.Exists(item => item.player == player))
        {
            PilotsInGame.Add(new Pilot(player));
        }

     
        SetMainMenu(player);
    }


    private void connectToHeadquarterSpeech(AiAircraft aircraft, LocalHeadquarters localHQ)
    {
        double initTime = 0.0;

       
        aircraft.SayToGroup(aircraft.AirGroup(), "Hello_guys");

        Timeout(initTime += 2, () =>
            {
                aircraft.SayToGroup(aircraft.AirGroup(), "This_is");
            });

        Timeout(initTime += 2, () =>
        {
            aircraft.SayToGroup(aircraft.AirGroup(), localHQ.Callsign);
        });


        Timeout(initTime += 2, () =>
        {
            aircraft.SayToGroup(aircraft.AirGroup(), "n2"); // to is missing as ogg
        });
       


        Timeout(initTime += 2, () =>
        {
            aircraft.SayToGroup(aircraft.AirGroup(), aircraft.CallSign());
        });

       

        Timeout(initTime += 2, () =>
        {
            aircraft.SayToGroup(aircraft.AirGroup(), "leader__");
        });


    }


   
    public void SetMainMenu(Player player)
    {
        if (player.Army() == 1) // red Side
            GamePlay.gpSetOrderMissionMenu(player, false, 0, new string[] { "Radaroperations" }, new bool[] { true });
        else
            GamePlay.gpSetOrderMissionMenu(player, false, 0, new string[] { "Not Available" }, new bool[] { true });
    }


    public void SetRadarMenu(Player player)
    {
        string headQuarter = "Select Headquarter";
        string connectedTo = "";

        if (PilotsInGame.Exists(item => item.player == player))
        {
            int i = PilotsInGame.FindIndex(item => item.player == player);

            if (PilotsInGame[i].connectedHeadquarter != null)
                connectedTo = string.Format(" (connected: {0})", PilotsInGame[i].connectedHeadquarter.Name);
        }
        headQuarter += connectedTo;

        GamePlay.gpSetOrderMissionMenu(player, true, 100, new string[] { headQuarter, "Get Radar Information" }, new bool[] { true, true });

    }


    public void SetConnectToHeadquarterMenu(Player player)
    {
        Menu NewMenu = new Menu();
        LocalHeadquarters headQuarter = null;

        if (PilotsInGame.Exists(item => item.player == player))
        {
            int i = PilotsInGame.FindIndex(item => item.player == player);
            headQuarter = PilotsInGame[i].connectedHeadquarter;
        }

        Headquarters.ForEach(item =>
        {
            if (headQuarter != null && item == headQuarter)
            {
                NewMenu.AddMenuEntry(item.Name + " *", true);
            }
            else
                NewMenu.AddMenuEntry(item.Name, true);
        });

        if (NewMenu.IsValid())
            GamePlay.gpSetOrderMissionMenu(player, true, 101, NewMenu.GetMenuDescriptions() , NewMenu.GetActives());
        else
            GamePlay.gpSetOrderMissionMenu(player, true, 101, new string[]{ "Not available" }, new bool[]{true});
    }


    public void SetHeadQuarter(Player player, int menuItemIndex)
    {
        if (PilotsInGame.Exists(item => item.player == player))
        {
            int i = PilotsInGame.FindIndex(item => item.player == player);
            PilotsInGame[i].connectedHeadquarter = Headquarters[menuItemIndex-1];
            if (player.Place() != null)
                connectToHeadquarterSpeech((player.Place() as AiAircraft), PilotsInGame[i].connectedHeadquarter);
        }

    }


    public override void OnOrderMissionMenuSelected(Player player, int ID, int menuItemIndex)
    {
        if (ID == 0)
        { // main menu
            if (menuItemIndex == 1)
            {
                SetRadarMenu(player);
            }
        }


        if (ID == 100)
        {
            //Radar Menu
            if (menuItemIndex == 1)
            {
                SetConnectToHeadquarterMenu(player);
            }

            if (menuItemIndex == 2)
            {
                checkSectors(player);
                SetMainMenu(player);
            }
            if (menuItemIndex == 0)
                SetMainMenu(player);
        }

        if (ID == 101)
        {
            //Radar Menu
            if (menuItemIndex == 0)
                SetRadarMenu(player);
            else
            {
                SetHeadQuarter(player, menuItemIndex);
                SetRadarMenu(player);
            }
        }
    }


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

       
        if (shortName.StartsWith("Radar") && shortName.EndsWith("Destroyed"))
        {
            GamePlay.gpLogServer(null, "Radar destroyed", null);

            Headquarters.ForEach(item =>
                {
                    item.SetObserverInactive(shortName);
                });
        }
    }

}

Example in the attached file. Change the MISSION_FILE variable in the cs to your needs, please.

5./JG27.Farber 04-15-2012 04:29 PM

I tested it.

Luton is the only station that picks up the bombers. I assume Luton is the station which gets bombed. It continues to function after been blown to pieces.

The other stations pick up nothing.

I altered the mission slightly. I airspawned myself in ad crashlanded near the towers.

Tab menu is disabled on killed.

FG28_Kodiak 04-15-2012 05:14 PM

Luton has two radarstations attached one for sectors A1..A3 and one for B1..B3, the Bombers destroyed this for A1..A3, so there should no informations from these sectors be available. But this is not the case?
Do you changed the MISSION_FILE variable to your needs? If it is not found there are no triggers for the Radars are generated, which are needed to register the destroying of it.
My testversion is in ..\Documents\1C SoftClub\il-2 sturmovik cliffs of dover\missions\RadarTest


It's normal that the mission menu is vanished after death or parachute.

5./JG27.Farber 04-15-2012 06:32 PM

I will test again.

I did not change anything, only where I spawned.

5./JG27.Farber 04-15-2012 06:53 PM

ok I tested it. Luton channel still works when the radar is destroyed. Is this becase each channel has two radars? :confused:

I changed the flight path of the bombers to go accross all radars. This works and you have to change channel to keep up with them. :-P

FG28_Kodiak 04-15-2012 09:00 PM

Which path do you have the mission?
Is there a message "Radar destroyed" in the chat bar, if the radar is hit? If not the missionpath is wrong, if yes i there is a bug elsewhere :rolleyes:

Memo to myself: Add a message if the mission file is not found ;)

5./JG27.Farber 04-15-2012 09:21 PM

Ahh ok, I dont script. Sorry, I ddint realise it was s o specific.

Yes now in the right directory it works! A message comes up saying Radar Destroyed. When you ask for information after this it says, No enemy in other available sectors spottet. Maybe after its destroyed and a request is made it should read - Negative, Radar Blind?

So we just add grids in the .cs file for the grids we want it to be able to see?

Could radar actually tell the difference between fighters and bombers? Maybe it should say aircraft?

FG28_Kodiak 04-16-2012 04:23 AM

Quote:

So we just add grids in the .cs file for the grids we want it to be able to see?
If you look at the code you will find
Code:

List<LocalHeadquarters> Headquarters = new List<LocalHeadquarters>{
        {new LocalHeadquarters("Luton", "CallSign24", 100.0, 100.0, new ObserverStation( "Static0","A,1","A,2","A,3"), new ObserverStation( "Static1","B,1","B,2","B,3"))},
        {new LocalHeadquarters("RadPoe", "CallSign32", 200.0, 200.0, new ObserverStation( "Static2","C,1","C,2","C,3"), new ObserverStation( "Static3","D,1","D,2","D,3"))},
        {new LocalHeadquarters("Forest", "CallSign15", 300.0, 300.0, new ObserverStation( "Static4","E,1","E,2","E,3"), new ObserverStation( "Static5","F,1","F,2","F,3"))}
    };

there you can add/remove the observed sectors from a "Radarstation".

Code:

new LocalHeadquarters("Luton", "CallSign24", 100.0, 100.0, ..
Here you can modify the Headquarter, first the name of it, second its callsign, third and fourth the Position of it (needed later for "in range communication"). The next parameters are the attached Radarstations to this sectors.
Code:

new ObserverStation( "Static0","A,1","A,2","A,3")
first parameter is the name of the object from the mis-file, the next parameters are the sectors which are observed, you can add so many sectors you like.
You can also add so many Radarstations to a HQ you need.



The message texts are only placeholders at the moment.

5./JG27.Farber 04-16-2012 07:08 AM

Very good explination, thank you Kodiak!

ok, so now we have a working example, how about 4 min delay and 4 min lock out? ;)

FG28_Kodiak 04-16-2012 07:41 AM

Working on it. Time delay is no problem.
i've added number, course and height information to the messages. May be i will add a message for Intercept course to the nearest or biggest enemy group, or make it able to select the target via mission menu and then get the course settings. :rolleyes:

5./JG27.Farber 04-16-2012 07:49 AM

I dont think Radar could give much details, other than, aircraft 10+,30+,50+ location and heading. Thats it I think.

FG28_Kodiak 04-16-2012 10:59 AM

Other question, which mile the RAF use
1.609,3426m = 1mile?

At the moment i generate messages like
6 Enemy in Sector: A,3 heading 180
7906m 350° from Smalltown
but i will
7 miles North from Smaltown (Smalltown only a example, i added Landmarks to the script).
but i wanna know the compass terms like N, NE, E, SE, S, SW, W, NW are enough or are more needed NNW, NNE, etc? And the heading was it geografical or magnetic?

bolox 04-16-2012 12:37 PM

correct- RAF used 'English' miles upto Sept '45 when they converted to Nautical miles (knots), involving the change of every asi:!:

AFAIK headings were usually given as 'vectors' in degrees (10 deg increments)
I THINK this was magnetic.
(there was a second format using 'bearing' and iirc this used the other North, however i may be mixing the 2 up)
need to find reference to this

FG28_Kodiak 04-20-2012 06:00 AM

1 Attachment(s)
Ok new version to test:
Added Landmarks to the mission, now you get messages like
27 Enemy 15 miles West from Calais at Angels 13, Heading 320
18 Enemy 13 miles South East from New Romney at Angels 8, Heading 0
in the chatbar

To do:
-Add more 'fuzzy' to the messages but at moment i don't know how exact the british radar was.
-merge the Airgroups better if they are in 'pulks'.

Code:

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using maddox.game;
using maddox.game.world;
using maddox.GP;


public class Mission : AMission
{

    private static string userdocpath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
    private static string CLODO_FILE_PATH = userdocpath + @"\1C SoftClub\il-2 sturmovik cliffs of dover\";
    private static string FILE_PATH = @"missions\RadarTest\Radar.mis"; // adjust to your needs
    private static string MISSION_FILE = CLODO_FILE_PATH + FILE_PATH;

    List<LocalHeadquarters> Headquarters = new List<LocalHeadquarters>{
        {new LocalHeadquarters("Luton (Ash)", "CallSign24", 242928.64, 251773.16,
            new ObserverStation( "Static0","AN,16","AN,17","AN,18","AN,19","AO,16","AO,17","AO,18","AO,19","AP,16","AP,17","AP,18","AP,19","AQ,16","AQ,17","AQ,18","AQ,19"), //Dover
            new ObserverStation( "Static2","AL,20","AL,21","AL,22","AM,20","AM,21","AM,22","AN,20","AN,21","AN,22","AO,20","AO,21","AO,22"))}, // Dunkirk
        {new LocalHeadquarters("RadPoe (Woodchurch)", "CallSign32", 208162.91, 227726.61,
            new ObserverStation( "Static1","AJ,15","AJ,16","AJ,17","AJ,18","AK,15","AK,16","AK,17","AK,18","AL,15","AL,16","AL,17","AL,18","AM,15","AM,16","AM,17","AM,18"), //Rye
            new ObserverStation( "Royal Observer Corps I","AK,19","AK,20","AK,21","AL,19","AL,20","AL,21","AM,19","AM,20","AM,21"))}, // fake simulation of Royal Observer Corps, none destructable
        //{new LocalHeadquarters("Forest (Woodchurch)", "CallSign15", 208162.91, 227726.61, new ObserverStation( "Static4","E,1","E,2","E,3"), new ObserverStation( "Static5","F,1","F,2","F,3"))}
    };


    LandMarkHandling LandMarks = new LandMarkHandling(
        new LandMark("Dover", 245577.51, 234521.20),
        new LandMark("Folkestone", 235333.17, 229568.64),
        new LandMark("St.Magarets's at Cliffe", 250423.81, 238001.64),
        new LandMark("Deal", 250985.14, 244801.80),
        new LandMark("Dymchurch", 223734.62, 222437.79),
        new LandMark("New Romney", 220005.71, 218110.40),
        new LandMark("Rye", 205758.66, 213525.22),
        new LandMark("Hastings", 195366.28, 203132.83),
        new LandMark("Eastbourne", 174755.54, 191963.14),
        new LandMark("Brighton", 144909.86, 197927.40),
        new LandMark("Calais", 284654.87, 215707.54)
        );


    Random random = new Random();


    internal class LandMark
    {
        public string LandMarkName { get; set; }
        public Point2d LandMarkPosition { get; set; }

        public LandMark(string landMarkName, double x, double y)
        {
            this.LandMarkName = landMarkName;
            this.LandMarkPosition = new Point2d(x, y);
        }
    }


    internal class LandMarkHandling
    {
        List<LandMark> LandMarkList = new List<LandMark>();

        public LandMarkHandling(params LandMark[] mark)
        {
            if (mark != null)
                LandMarkList.AddRange(mark);
        }


        public LandMark getNearestLandMarkTo(Point3d position)
        {

            if (!(LandMarkList.Count > 0))
                return null;

            LandMark NearestLandMark = null;
            Point2d currentPosition = new Point2d(position.x, position.y);

            LandMarkList.ForEach(item =>
            {
                if (NearestLandMark != null)
                {
                    if (NearestLandMark.LandMarkPosition.distance(ref currentPosition) > item.LandMarkPosition.distance(ref currentPosition))
                        NearestLandMark = item;
                }
                else NearestLandMark = item;
            });

            return NearestLandMark;
        }
    }


    private List<string> getRadarCreationStrings(string filename)
    {
        List<string> list = new List<string>();
       
        if (!File.Exists(filename))
            GamePlay.gpLogServer(new Player[] { GamePlay.gpPlayer() }, "Missionfile {0} not found! Please check settings", new object[] { FILE_PATH });

        using (StreamReader reader = new StreamReader(filename))
        {
            string line;
            while ((line = reader.ReadLine()) != null)
            {
                if (line.Contains("Stationary.Radar"))
                {
                    list.Add(line);
                }
            }
        }
        return list;
    }

   
    private ISectionFile createRadarTriggers()
    {
        ISectionFile trigger = GamePlay.gpCreateSectionFile();

        List<string> Radarstations = getRadarCreationStrings(MISSION_FILE);

        if (Radarstations.Count > 0)
        {
            int i = 0;
            Radarstations.ForEach(item =>
                {
                    item = item.TrimStart(' ');
                    string[] splittet = item.Split(' ');
                    string keyTr, valueTr;

                    keyTr = "Radar" + string.Format("{0:00}", i) +"Destroyed";
                    valueTr = " TGroundDestroyed 50 " + splittet[3] + " " + splittet[4] + " 100"; //TGroundDestroyedTrigger 50% destroyed in radius 100m
                    trigger.add("Trigger", keyTr, valueTr);

                    Headquarters.ForEach(hq => { hq.AddTriggerToObserver(splittet[0], keyTr); });
                    i++;
                });
        }
        return trigger;
    }


    #region CourseCalculations


    private int ToAngels(double altitude)
    {
        double altAngels = (altitude / 0.3048) / 1000;

        if (altAngels > 1)
            altAngels = Math.Round(altAngels, MidpointRounding.AwayFromZero);
        else
            altAngels = 1;

        return (int)altAngels;
    }


    private int ToMiles(double distance)
    {
        double distanceMiles = 0;
        distanceMiles = Math.Round(((distance / 1609.3426)), 0, MidpointRounding.AwayFromZero);  // distance in Miles

        return (int)distanceMiles;
    }


    private string degreesToWindRose(double degrees)
    {
        String[] directions = { "North", "North East", "East", "South East", "South", "South West", "West", "North West", "North" };
        return directions[(int)Math.Round((((double)degrees % 360) / 45))];
    }

    // to get the correct bearing its nessesary to make a litte enter the matrix operation.
    // the Vector2d.direction() (same as atan2) has 0° at the x-axis and goes counter clockwise, but we need 0° at the y-axis
    // and clockwise direction
    // so to convert it we need
    // |0 1| |x|  |0*x + 1*y|    |y|
    // |  | | | = |        | =  | |  // ok not very surprising ;)
    // |1 0| |y|  |1*x + 0*y|    |x|

    private double calculateBearingDegree(Vector3d vector)
    {
        Vector2d matVector = new Vector2d(vector.y, vector.x);
        // the value of direction is in rad so we need *180/Pi to get the value in degrees
        return matVector.direction() * 180.0 / Math.PI;
    }


    private double calculateBearingDegree(Vector2d vector)
    {
        Vector2d newVector = new Vector2d(vector.y, vector.x);

        return newVector.direction() * 180.0 / Math.PI;
    }


    private double calculateBearingFromOrigin(Point2d targetLocation, Point2d originLocation)
    {

        double deltaX = targetLocation.x - originLocation.x;
        double deltaY = targetLocation.y - originLocation.y;

        double bearing = Math.Atan2(deltaX, deltaY);
        bearing = bearing * (180.0 / Math.PI);

        return (bearing > 0.0 ? bearing : (360.0 + bearing));
    }


    private double calculateBearingFromOrigin(Point3d targetLocation, Point3d originLocation)
    {

        double deltaX = targetLocation.x - originLocation.x;
        double deltaY = targetLocation.y - originLocation.y;


        double bearing = Math.Atan2(deltaX, deltaY);
        bearing = bearing * (180.0 / Math.PI);

        return (bearing > 0.0 ? bearing : (360.0 + bearing));
    }


    private int getDegreesIn10Step(double degrees)
    {
        degrees = Math.Round((degrees / 10), MidpointRounding.AwayFromZero) * 10;

        return (int) degrees;
    }



    #endregion


    internal class LocalHeadquarters
    {
        public string Name { get; set; }
        public Point2d LocationCoords { get; set; }
        public string Callsign { get; set; }
        private List<ObserverStation> AttachedObservers = new List<ObserverStation>();

        public LocalHeadquarters(string name, string callsign, double x, double y, params ObserverStation[] observerStations)
        {
            this.Name = name;
            this.Callsign = callsign;
            this.LocationCoords = new Point2d(x, y);

            if (observerStations != null)
                AttachedObservers.AddRange(observerStations);
        }


        public bool ObserveSector(string sectorName)
        {

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

            if (AttachedObservers.Count > 0)
            {
                AttachedObservers.ForEach(item =>
                {
                    if (item.IsActive)
                        AttachedSectors.AddRange(item.observedSectors);
                });
            }

            if (AttachedSectors.Exists(item => item.Equals(sectorName)))
                return true;
            else
                return false;
        }

        public List<ObserverStation> GetObservers()
        {

            return AttachedObservers;
        }



        public List<string> GetObservedSectors()
        {
            List<string> sectorList = new List<string>();

            AttachedObservers.ForEach(item =>
                {
                    if (item.IsActive)
                    {
                        item.observedSectors.ForEach(sector =>
                            {
                                if (!sectorList.Exists(newsector => sector == newsector))
                                    sectorList.Add(sector);
                            });
                    };
                });
            return sectorList;
        }


        public List<string> GetLostObservedSectors()
        {

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

            AttachedObservers.ForEach(item =>
            {
                if (!item.IsActive)
                {
                    item.observedSectors.ForEach(sector =>
                    {
                        if (!sectorList.Exists(newsector => sector == newsector))
                            sectorList.Add(sector);
                    });
                };
            });

            if (sectorList.Count > 0)
            {
                List<string> CurrentObservedSectors = GetObservedSectors();

                if (CurrentObservedSectors.Count > 0)
                {
                    CurrentObservedSectors.ForEach(item =>
                        {
                            if (sectorList.Exists(sector => sector == item))
                            {
                                sectorList.RemoveAll(sector => sector == item);
                            }
                        });

                }

            }
            return sectorList;
        }


        public void SetObserverInactive(string triggerName)
        {

            if (AttachedObservers.Exists(item => item.TriggerName == triggerName))
            {
                AttachedObservers[AttachedObservers.FindIndex(item => item.TriggerName == triggerName)].IsActive = false;
            }
        }


        public void AddTriggerToObserver(string staticName, string triggerName)
        {
            if (AttachedObservers.Exists(item => item.StaticName == staticName))
            {
                AttachedObservers[AttachedObservers.FindIndex(item => item.StaticName == staticName)].TriggerName = triggerName;
            }
        }
    }


    internal class ObserverStation
    {
        public bool IsActive { get; set; }
        public string StaticName { get; set; }
        public string TriggerName { get; set; }

        public List<string> observedSectors = new List<string>();

        public ObserverStation(string staticName, params string[] sectorNames)
        {
            this.StaticName = staticName;
            this.IsActive = true;

            if (sectorNames != null)
                observedSectors.AddRange(sectorNames);
        }


        public ObserverStation(string staticName, string triggerName, params string[] sectorNames)
        {
            this.StaticName = staticName;
            this.TriggerName = triggerName;
            this.IsActive = true;

            if (sectorNames != null)
                observedSectors.AddRange(sectorNames);
        }


        public void SetTriggerName(string triggerName)
        {
            this.TriggerName = triggerName;
        }

    }


    internal class Pilot
    {
        public Player player { get; set; }
        public LocalHeadquarters connectedHeadquarter;
        public DateTime TimeStamp { get; set; }

        public Pilot(Player player)
        {
            this.player = player;
        }
    }


    internal List<Pilot> PilotsInGame = new List<Pilot>();


    public void checkSectors(Player player)
    {
 
        if (PilotsInGame.Exists(item => item.player == player))
        {
            int i = PilotsInGame.FindIndex(item => item.player == player);

            if (PilotsInGame[i].connectedHeadquarter != null)
            {
                if (Headquarters.Exists(hq => hq == PilotsInGame[i].connectedHeadquarter))
                {
                    LocalHeadquarters localHQ = PilotsInGame[i].connectedHeadquarter;

                    AiAirGroup[] EnemyAirgroups = base.GamePlay.gpAirGroups((player.Army() == 1) ? 2 : 1);

                    if (EnemyAirgroups != null)
                    {
                        bool foundEnemy = false;

                        Dictionary<string, int> Messages = new Dictionary<string, int>();

                        foreach (AiAirGroup aag in EnemyAirgroups)
                        {
                            string sectorName = GamePlay.gpSectorName(aag.Pos().x, aag.Pos().y);
                           
                            if (localHQ.ObserveSector(sectorName) && aag.Pos().z > 600.00)
                            {
                                foundEnemy = true;
                                string message ="";

                                Point3d destinationPoint = aag.Pos();
                                LandMark NearestLandMark = LandMarks.getNearestLandMarkTo(aag.Pos());
                                Point2d AirgroupPos = new Point2d(aag.Pos().x, aag.Pos().y);
                                Vector2d AirgroupVector = new Vector2d(aag.Vwld().x, aag.Vwld().y);

                                if (NearestLandMark != null)
                                    message = string.Format("Enemy {0} miles {1} from {2} at Angels {3}, Heading {4}", ToMiles(NearestLandMark.LandMarkPosition.distance(ref AirgroupPos)), degreesToWindRose(calculateBearingFromOrigin(AirgroupPos, NearestLandMark.LandMarkPosition)), NearestLandMark.LandMarkName, ToAngels(aag.Pos().z), getDegreesIn10Step(calculateBearingDegree(AirgroupVector)));
                                else
                                    message = string.Format("Enemy in Sector: {1} heading {2}", sectorName, getDegreesIn10Step(calculateBearingDegree(AirgroupVector)));
                                 
                                int nrOfAircraft;
                               
                                if (Messages.TryGetValue(message, out nrOfAircraft))
                                {
                                    Messages[message] = nrOfAircraft + aag.NOfAirc;
                                }
                                else
                                {
                                    Messages.Add(message, aag.NOfAirc);
                                }
                            }
                        }

                        Timeout(3, () =>
                            {
                               
                                foreach (var msg in Messages)
                                {
                                    GamePlay.gpLogServer(new[] { player }, "{0} {1}", new object[] { msg.Value, msg.Key });
                                }

                                if (localHQ.GetLostObservedSectors().Count > 0)
                                {
                                    string lostSectors = "";

                                    localHQ.GetLostObservedSectors().ForEach(item =>
                                        {
                                            lostSectors += item + " ";
                                        });

                                    lostSectors = lostSectors.TrimEnd(' ');

                                    GamePlay.gpLogServer(null, "Radar blind for Sectors {0}!", new[] { lostSectors });
                                    if (!foundEnemy)
                                        GamePlay.gpLogServer(new[] { player }, "No Enemy in other available Sectors spottet", null);
                                }
                                else if (!foundEnemy)
                                    GamePlay.gpLogServer(new[] { player }, "No Enemy in Range", null);
                            });
                    }
                }
            }
        }
    }


    private void connectToHeadquarterSpeech(AiAircraft aircraft, LocalHeadquarters localHQ)
    {
        double initTime = 0.0;
       
        aircraft.SayToGroup(aircraft.AirGroup(), "Hello_guys");

        Timeout(initTime += 2, () =>
            {
                aircraft.SayToGroup(aircraft.AirGroup(), "This_is");
            });

        Timeout(initTime += 2, () =>
        {
            aircraft.SayToGroup(aircraft.AirGroup(), localHQ.Callsign);
        });

        Timeout(initTime += 2, () =>
        {
            aircraft.SayToGroup(aircraft.AirGroup(), "n2"); // to is missing as ogg
        });

        Timeout(initTime += 2, () =>
        {
            aircraft.SayToGroup(aircraft.AirGroup(), aircraft.CallSign());
        });

        Timeout(initTime += 2, () =>
        {
            aircraft.SayToGroup(aircraft.AirGroup(), "leader__");
        });
    }


    #region mission menus

    #region class Menu

    internal class Menu
    {
        internal class MenuEntry
        {
            internal string MenuName { get; set; }
            internal bool active { get; set; }
        }

        internal List<MenuEntry> menuEntries = new List<MenuEntry>();

        public void AddMenuEntry(string description, bool active)
        {
            MenuEntry NewMenuEntry = new MenuEntry();

            NewMenuEntry.MenuName = description;
            NewMenuEntry.active = active;

            menuEntries.Add(NewMenuEntry);
        }

        public string[] GetMenuDescriptions()
        {
            List<string> Descriptions = new List<string>();

            menuEntries.ForEach(item =>
            {
                Descriptions.Add(item.MenuName);
            });

            return Descriptions.ToArray();
        }

        public bool[] GetActives()
        {
            List<bool> Actives = new List<bool>();

            menuEntries.ForEach(item =>
            {
                Actives.Add(item.active);
            });

            return Actives.ToArray();
        }

        public bool IsValid()
        {
            if (menuEntries == null || menuEntries.Count < 1)
                return false;
            else
                return true;

        }

    }

    #endregion

   
    public void SetMainMenu(Player player)
    {
        if (player.Army() == 1) // red Side
            GamePlay.gpSetOrderMissionMenu(player, false, 0, new string[] { "Radaroperations" }, new bool[] { true });
        else
            GamePlay.gpSetOrderMissionMenu(player, false, 0, new string[] { "Not Available" }, new bool[] { true });
    }


    public void SetRadarMenu(Player player)
    {
        string headQuarter = "Select Headquarter";
        string connectedTo = "";

        if (PilotsInGame.Exists(item => item.player == player))
        {
            int i = PilotsInGame.FindIndex(item => item.player == player);

            if (PilotsInGame[i].connectedHeadquarter != null)
                connectedTo = string.Format(" (connected: {0})", PilotsInGame[i].connectedHeadquarter.Name);
        }
        headQuarter += connectedTo;

        GamePlay.gpSetOrderMissionMenu(player, true, 100, new string[] { headQuarter, "Get Radar Information" }, new bool[] { true, true });

    }


    public void SetConnectToHeadquarterMenu(Player player)
    {
        Menu NewMenu = new Menu();
        LocalHeadquarters headQuarter = null;

        if (PilotsInGame.Exists(item => item.player == player))
        {
            int i = PilotsInGame.FindIndex(item => item.player == player);
            headQuarter = PilotsInGame[i].connectedHeadquarter;
        }

        Headquarters.ForEach(item =>
        {
            if (headQuarter != null && item == headQuarter)
            {
                NewMenu.AddMenuEntry(item.Name + " *", true);
            }
            else
                NewMenu.AddMenuEntry(item.Name, true);
        });

        if (NewMenu.IsValid())
            GamePlay.gpSetOrderMissionMenu(player, true, 101, NewMenu.GetMenuDescriptions() , NewMenu.GetActives());
        else
            GamePlay.gpSetOrderMissionMenu(player, true, 101, new string[]{ "Not available" }, new bool[]{true});
    }


    public void SetHeadQuarter(Player player, int menuItemIndex)
    {
        if (PilotsInGame.Exists(item => item.player == player))
        {
            int i = PilotsInGame.FindIndex(item => item.player == player);
            PilotsInGame[i].connectedHeadquarter = Headquarters[menuItemIndex-1];
            if (player.Place() != null)
                connectToHeadquarterSpeech((player.Place() as AiAircraft), PilotsInGame[i].connectedHeadquarter);
        }

    }


    public override void OnOrderMissionMenuSelected(Player player, int ID, int menuItemIndex)
    {
        if (ID == 0)
        { // main menu
            if (menuItemIndex == 1)
            {
                SetRadarMenu(player);
            }
        }

        if (ID == 100)
        {
            //Radar Menu
            if (menuItemIndex == 1)
            {
                SetConnectToHeadquarterMenu(player);
            }

            if (menuItemIndex == 2)
            {
                checkSectors(player);
                SetMainMenu(player);
            }
            if (menuItemIndex == 0)
                SetMainMenu(player);
        }

        if (ID == 101)
        {
            //Radar Menu
            if (menuItemIndex == 0)
                SetRadarMenu(player);
            else
            {
                SetHeadQuarter(player, menuItemIndex);
                SetRadarMenu(player);
            }
        }
    }

    #endregion


    public override void OnBattleStarted()
    {
        base.OnBattleStarted();
        MissionNumberListener = -1;
        GamePlay.gpPostMissionLoad(createRadarTriggers());
    }


    public override void OnPlaceEnter(Player player, AiActor actor, int placeIndex)
    {
        base.OnPlaceEnter(player, actor, placeIndex);

        if (!PilotsInGame.Exists(item => item.player == player))
        {
            PilotsInGame.Add(new Pilot(player));
        }

        SetMainMenu(player);
    }


    public override void OnTrigger(int missionNumber, string shortName, bool active)
    {
        base.OnTrigger(missionNumber, shortName, active);
       
        if (shortName.StartsWith("Radar") && shortName.EndsWith("Destroyed"))
        {
            GamePlay.gpLogServer(null, "Radar destroyed", null);

            Headquarters.ForEach(item =>
                {
                    item.SetObserverInactive(shortName);
                });
        }
    }

}


csThor 04-20-2012 07:43 AM

I've read something of a 300% inaccuracy but that sounds grossly overstated to me. I do have a suggestion, however, and that pertains to the reported number of planes. IIRC the numbers were never that accurate, mostly it was 10+ or 20+ ... so I wonder if it would be better to use this term (which also adds a bit of insecurity as 10+ can mean 10 or 19) ...

Osprey 04-20-2012 07:43 AM

Quote:

Originally Posted by 5./JG27.Farber (Post 409697)
I dont think Radar could give much details, other than, aircraft 10+,30+,50+ location and heading. Thats it I think.


It could give heading when 2 or more plots were registered. It could easily tell who was friend or foe from the signal and FC (as part of the 4 minute delay) would be able to give an interception vector. You are correct on the aircraft numbers, and this could be implemented with a switch statement in code.

FG28_Kodiak 04-20-2012 08:18 AM

Quote:

Originally Posted by Osprey (Post 411861)
You are correct on the aircraft numbers, and this could be implemented with a switch statement in code.

No switch statement needed a simple Math.Round will do the job too and better :rolleyes:
So how the numbers of aircraft was given

1, 2, 5+ 10+ 15+ 20+ etc?

5./JG27.Farber 04-20-2012 11:59 AM

Bravo Kodiak! This is a real work of art!

Single or few aircraft were hard to detect I belive. Think it would be more:

5+, 10+ 20+ 30+


How did you find the location for each town? Place a static in each town and look in the .mis file?

FG28_Kodiak 04-20-2012 03:50 PM

Quote:

Originally Posted by 5./JG27.Farber (Post 412012)
How did you find the location for each town? Place a static in each town and look in the .mis file?

Yes a neutral missionmarker :rolleyes:

ATAG_Colander 04-20-2012 08:21 PM

Quote:

Originally Posted by csThor (Post 411860)
I've read something of a 300% inaccuracy ...

From what I've read about the Chain Home radar, the altitude was measured comparing the strength of two receivers at different heights in the tower. Because of this, they where measuring angles.

Since the angles where not exact, the altitude error increased with the distance. I think this could be emulated with simple trigonometry using random errors for the angle.

http://theairtacticalassaultgroup.com/banner.png

5./JG27.Farber 04-26-2012 02:03 PM

Is this the final evolution of the script Kodiak? We are eger to implement it and iron out the wrinkles on our own maps. What about the 4 min delay?

Thanks for this,
Farber.

FG28_Kodiak 04-26-2012 02:18 PM

No its not ;)
Current Version, added routine to merge Airgroups better, to avoid 'splittering' added a short time delay (for testing)
To Do: complete the Radar Mission Menu, hope i finish it this weekend, so the script is usable on servers.
Future: Create a DLL and Configuration via XML-file, so the handling will be easier for missionbuilders.
Code:

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using maddox.game;
using maddox.game.world;
using maddox.GP;


public class Mission : AMission
{

    private static string userdocpath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
    private static string CLODO_FILE_PATH = userdocpath + @"\1C SoftClub\il-2 sturmovik cliffs of dover\";
    private static string FILE_PATH = @"missions\RadarTest\Radar.mis"; // adjust to your needs
    private static string MISSION_FILE = CLODO_FILE_PATH + FILE_PATH;

    List<LocalHeadquarters> Headquarters = new List<LocalHeadquarters>{
        {new LocalHeadquarters("Luton (Ash)", "CallSign24", 242928.64, 251773.16,
            new ObserverStation( "Static0","AN,16","AN,17","AN,18","AN,19","AO,16","AO,17","AO,18","AO,19","AP,16","AP,17","AP,18","AP,19","AQ,16","AQ,17","AQ,18","AQ,19"), //Dover
            new ObserverStation( "Static2","AL,20","AL,21","AL,22","AM,20","AM,21","AM,22","AN,20","AN,21","AN,22","AO,20","AO,21","AO,22"))}, // Dunkirk
        {new LocalHeadquarters("RadPoe (Woodchurch)", "CallSign32", 208162.91, 227726.61,
            new ObserverStation( "Static1","AJ,15","AJ,16","AJ,17","AJ,18","AK,15","AK,16","AK,17","AK,18","AL,15","AL,16","AL,17","AL,18","AM,15","AM,16","AM,17","AM,18"), //Rye
            new ObserverStation( "Royal Observer Corps I","AK,19","AK,20","AK,21","AL,19","AL,20","AL,21","AM,19","AM,20","AM,21"))}, // fake simulation of Royal Observer Corps, none destructable
        //{new LocalHeadquarters("Forest (Woodchurch)", "CallSign15", 208162.91, 227726.61, new ObserverStation( "Static4","E,1","E,2","E,3"), new ObserverStation( "Static5","F,1","F,2","F,3"))}
    };


    LandMarkHandling LandMarks = new LandMarkHandling(
        new LandMark("Dover", 245577.51, 234521.20),
        new LandMark("Folkestone", 235333.17, 229568.64),
        new LandMark("St.Magarets's at Cliffe", 250423.81, 238001.64),
        new LandMark("Deal", 250985.14, 244801.80),
        new LandMark("Dymchurch", 223734.62, 222437.79),
        new LandMark("New Romney", 220005.71, 218110.40),
        new LandMark("Rye", 205758.66, 213525.22),
        new LandMark("Hastings", 195366.28, 203132.83),
        new LandMark("Eastbourne", 174755.54, 191963.14),
        new LandMark("Brighton", 144909.86, 197927.40),
        new LandMark("Calais", 284654.87, 215707.54)
        );


    Random random = new Random();


    internal class LandMark
    {
        public string LandMarkName { get; set; }
        public Point2d LandMarkPosition { get; set; }

        public LandMark(string landMarkName, double x, double y)
        {
            this.LandMarkName = landMarkName;
            this.LandMarkPosition = new Point2d(x, y);
        }
    }


    internal class LandMarkHandling
    {
        List<LandMark> LandMarkList = new List<LandMark>();

        public LandMarkHandling(params LandMark[] mark)
        {
            if (mark != null)
                LandMarkList.AddRange(mark);
        }


        public LandMark getNearestLandMarkTo(Point3d position)
        {

            if (!(LandMarkList.Count > 0))
                return null;

            LandMark NearestLandMark = null;
            Point2d currentPosition = new Point2d(position.x, position.y);

            LandMarkList.ForEach(item =>
            {
                if (NearestLandMark != null)
                {
                    if (NearestLandMark.LandMarkPosition.distance(ref currentPosition) > item.LandMarkPosition.distance(ref currentPosition))
                        NearestLandMark = item;
                }
                else NearestLandMark = item;
            });

            return NearestLandMark;
        }
    }


    private List<string> getRadarCreationStrings(string filename)
    {
        List<string> list = new List<string>();
       
        if (!File.Exists(filename))
            GamePlay.gpLogServer(new Player[] { GamePlay.gpPlayer() }, "Missionfile {0} not found! Please check settings", new object[] { FILE_PATH });

        using (StreamReader reader = new StreamReader(filename))
        {
            string line;
            while ((line = reader.ReadLine()) != null)
            {
                if (line.Contains("Stationary.Radar"))
                {
                    list.Add(line);
                }
            }
        }
        return list;
    }

   
    private ISectionFile createRadarTriggers()
    {
        ISectionFile trigger = GamePlay.gpCreateSectionFile();

        List<string> Radarstations = getRadarCreationStrings(MISSION_FILE);

        if (Radarstations.Count > 0)
        {
            int i = 0;
            Radarstations.ForEach(item =>
                {
                    item = item.TrimStart(' ');
                    string[] splittet = item.Split(' ');
                    string keyTr, valueTr;

                    keyTr = "Radar" + string.Format("{0:00}", i) +"Destroyed";
                    valueTr = " TGroundDestroyed 50 " + splittet[3] + " " + splittet[4] + " 100"; //TGroundDestroyedTrigger 50% destroyed in radius 100m
                    trigger.add("Trigger", keyTr, valueTr);

                    Headquarters.ForEach(hq => { hq.AddTriggerToObserver(splittet[0], keyTr); });
                    i++;
                });
        }
        return trigger;
    }


    #region Calculations

    private int ToAngels(double altitude)
    {
        double altAngels = (altitude / 0.3048) / 1000;

        if (altAngels > 1)
            altAngels = Math.Round(altAngels, MidpointRounding.AwayFromZero);
        else
            altAngels = 1;

        return (int)altAngels;
    }


    private int ToMiles(double distance)
    {
        double distanceMiles = 0;
        distanceMiles = Math.Round(((distance / 1609.3426)), 0, MidpointRounding.AwayFromZero);  // distance in Miles

        return (int)distanceMiles;
    }


    private string degreesToWindRose(double degrees)
    {
        String[] directions = { "North", "North East", "East", "South East", "South", "South West", "West", "North West", "North" };
        return directions[(int)Math.Round((((double)degrees % 360) / 45))];
    }

    // to get the correct bearing its nessesary to make a litte enter the matrix operation.
    // the Vector2d.direction() (same as atan2) has 0° at the x-axis and goes counter clockwise, but we need 0° at the y-axis
    // and clockwise direction
    // so to convert it we need
    // |0 1| |x|  |0*x + 1*y|    |y|
    // |  | | | = |        | =  | |  // ok not very surprising ;)
    // |1 0| |y|  |1*x + 0*y|    |x|

    private double calculateBearingDegree(Vector3d vector)
    {
        Vector2d matVector = new Vector2d(vector.y, vector.x);
        // the value of direction is in rad so we need *180/Pi to get the value in degrees
        return matVector.direction() * 180.0 / Math.PI;
    }


    private double calculateBearingDegree(Vector2d vector)
    {
        Vector2d newVector = new Vector2d(vector.y, vector.x);

        return newVector.direction() * 180.0 / Math.PI;
    }


    private double calculateBearingFromOrigin(Point2d targetLocation, Point2d originLocation)
    {

        double deltaX = targetLocation.x - originLocation.x;
        double deltaY = targetLocation.y - originLocation.y;

        double bearing = Math.Atan2(deltaX, deltaY);
        bearing = bearing * (180.0 / Math.PI);

        return (bearing > 0.0 ? bearing : (360.0 + bearing));
    }


    private double calculateBearingFromOrigin(Point3d targetLocation, Point3d originLocation)
    {

        double deltaX = targetLocation.x - originLocation.x;
        double deltaY = targetLocation.y - originLocation.y;


        double bearing = Math.Atan2(deltaX, deltaY);
        bearing = bearing * (180.0 / Math.PI);

        return (bearing > 0.0 ? bearing : (360.0 + bearing));
    }


    private int getDegreesIn10Step(double degrees)
    {
        degrees = Math.Round((degrees / 10), MidpointRounding.AwayFromZero) * 10;

        if ((int)degrees == 360)
            degrees = 0.0;

        return (int) degrees;
    }

    private int noOfAircraft(int number)
    {
        int firstDecimal = 0;
        int higherDecimal = 0;

        higherDecimal = Math.DivRem(number, 10, out firstDecimal);

        if (firstDecimal > 3 && firstDecimal <= 8)
            firstDecimal = 5;
        else if (firstDecimal > 8)
            higherDecimal += 1;

        if (higherDecimal > 0)
            return (int)higherDecimal * 10;
        else
            return (int)firstDecimal;
    }
   
    #endregion


    internal class LocalHeadquarters
    {
        public string Name { get; set; }
        public Point2d LocationCoords { get; set; }
        public string Callsign { get; set; }
        private List<ObserverStation> AttachedObservers = new List<ObserverStation>();

        public LocalHeadquarters(string name, string callsign, double x, double y, params ObserverStation[] observerStations)
        {
            this.Name = name;
            this.Callsign = callsign;
            this.LocationCoords = new Point2d(x, y);

            if (observerStations != null)
                AttachedObservers.AddRange(observerStations);
        }


        public bool ObserveSector(string sectorName)
        {

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

            if (AttachedObservers.Count > 0)
            {
                AttachedObservers.ForEach(item =>
                {
                    if (item.IsActive)
                        AttachedSectors.AddRange(item.observedSectors);
                });
            }

            if (AttachedSectors.Exists(item => item.Equals(sectorName)))
                return true;
            else
                return false;
        }


        public List<ObserverStation> GetObservers()
        {
            return AttachedObservers;
        }


        public List<string> GetObservedSectors()
        {
            List<string> sectorList = new List<string>();

            AttachedObservers.ForEach(item =>
                {
                    if (item.IsActive)
                    {
                        item.observedSectors.ForEach(sector =>
                            {
                                if (!sectorList.Exists(newsector => sector == newsector))
                                    sectorList.Add(sector);
                            });
                    };
                });
            return sectorList;
        }


        public List<string> GetLostObservedSectors()
        {
            List<string> sectorList = new List<string>();

            AttachedObservers.ForEach(item =>
            {
                if (!item.IsActive)
                {
                    item.observedSectors.ForEach(sector =>
                    {
                        if (!sectorList.Exists(newsector => sector == newsector))
                            sectorList.Add(sector);
                    });
                };
            });

            if (sectorList.Count > 0)
            {
                List<string> CurrentObservedSectors = GetObservedSectors();

                if (CurrentObservedSectors.Count > 0)
                {
                    CurrentObservedSectors.ForEach(item =>
                        {
                            if (sectorList.Exists(sector => sector == item))
                            {
                                sectorList.RemoveAll(sector => sector == item);
                            }
                        });

                }

            }
            return sectorList;
        }

        public void SetObserverInactive(string triggerName)
        {

            if (AttachedObservers.Exists(item => item.TriggerName == triggerName))
            {
                AttachedObservers[AttachedObservers.FindIndex(item => item.TriggerName == triggerName)].IsActive = false;
            }
        }


        public void AddTriggerToObserver(string staticName, string triggerName)
        {
            if (AttachedObservers.Exists(item => item.StaticName == staticName))
            {
                AttachedObservers[AttachedObservers.FindIndex(item => item.StaticName == staticName)].TriggerName = triggerName;
            }
        }


        public double GetDistance(Player player)
        {
            Point2d playerLocation = new Point2d(player.Place().Pos().x, player.Place().Pos().y);

            double distance = LocationCoords.distance(ref playerLocation);

            return distance;
        }

    }

    internal class ObserverStation
    {
        public bool IsActive { get; set; }
        public string StaticName { get; set; }
        public string TriggerName { get; set; }

        public List<string> observedSectors = new List<string>();

        public ObserverStation(string staticName, params string[] sectorNames)
        {
            this.StaticName = staticName;
            this.IsActive = true;

            if (sectorNames != null)
                observedSectors.AddRange(sectorNames);
        }


        public ObserverStation(string staticName, string triggerName, params string[] sectorNames)
        {
            this.StaticName = staticName;
            this.TriggerName = triggerName;
            this.IsActive = true;

            if (sectorNames != null)
                observedSectors.AddRange(sectorNames);
        }


        public void SetTriggerName(string triggerName)
        {
            this.TriggerName = triggerName;
        }

    }


    internal class Pilot
    {
        public Player player { get; set; }
        public LocalHeadquarters connectedHeadquarter;
        public DateTime TimeStamp { get; set; }
        public bool RadarUsed { get; set; }

        public Pilot(Player player)
        {
            this.player = player;
            this.RadarUsed = false;
        }
    }


    internal List<Pilot> PilotsInGame = new List<Pilot>();


    public void checkSectors(Player player)
    {
        if (PilotsInGame.Exists(item => item.player == player))
        {
            int i = PilotsInGame.FindIndex(item => item.player == player);

            if (PilotsInGame[i].RadarUsed) return;

            PilotsInGame[i].RadarUsed = true;

            if (PilotsInGame[i].connectedHeadquarter != null)
            {
                if (Headquarters.Exists(hq => hq == PilotsInGame[i].connectedHeadquarter))
                {
                    LocalHeadquarters localHQ = PilotsInGame[i].connectedHeadquarter;
                    Dictionary<AiAirGroup, int> planePulks = getPulks(GamePlay.gpAirGroups((player.Army() == 1) ? 2 : 1), 1600.0); //all Airgroups in 1600m radius count as one

                    Dictionary<string, string> Messages = new Dictionary<string, string>();
                    //List<string> Messages = new List<string>();

                    if (planePulks != null && planePulks.Count > 0)
                    {
                        bool foundEnemy = false;

                        foreach (var kvp in planePulks)
                        {
                            string sectorName = GamePlay.gpSectorName(kvp.Key.Pos().x, kvp.Key.Pos().y);

                            if (localHQ.ObserveSector(sectorName) && kvp.Key.Pos().z > 600.00)
                            {
                                foundEnemy = true;
                                string tmpKey = "";
                                string message = "";
                                Point3d destinationPoint = kvp.Key.Pos();
                                LandMark NearestLandMark = LandMarks.getNearestLandMarkTo(kvp.Key.Pos());
                                Point2d AirgroupPos = new Point2d(kvp.Key.Pos().x, kvp.Key.Pos().y);
                                Vector2d AirgroupVector = new Vector2d(kvp.Key.Vwld().x, kvp.Key.Vwld().y);

                                if (kvp.Value > 3) // only if more than 3 planes in a pulk generate a message
                                {
                                    if (NearestLandMark != null)
                                    {
                                        tmpKey = string.Format("Enemy {0} miles {1} from {2} at Angels {3}, Heading {4}", ToMiles(NearestLandMark.LandMarkPosition.distance(ref AirgroupPos)), degreesToWindRose(calculateBearingFromOrigin(AirgroupPos, NearestLandMark.LandMarkPosition)), NearestLandMark.LandMarkName, ToAngels(kvp.Key.Pos().z), getDegreesIn10Step(calculateBearingDegree(AirgroupVector)));
                                        message = string.Format("{0}+ Enemy {1} miles {2} from {3} at Angels {4}, Heading {5}", noOfAircraft(kvp.Value), ToMiles(NearestLandMark.LandMarkPosition.distance(ref AirgroupPos)), degreesToWindRose(calculateBearingFromOrigin(AirgroupPos, NearestLandMark.LandMarkPosition)), NearestLandMark.LandMarkName, ToAngels(kvp.Key.Pos().z), getDegreesIn10Step(calculateBearingDegree(AirgroupVector)));
                                    }
                                    else
                                    {
                                        tmpKey = string.Format("Enemy in Sector: {0} heading {1}", noOfAircraft(kvp.Value), sectorName, getDegreesIn10Step(calculateBearingDegree(AirgroupVector)));
                                        message = string.Format("{0}+ Enemy in Sector: {1} heading {2}", noOfAircraft(kvp.Value), sectorName, getDegreesIn10Step(calculateBearingDegree(AirgroupVector)));
                                    }
                                    if (!Messages.ContainsKey(tmpKey))
                                    {
                                        Messages.Add(tmpKey, message);
                                    }
                                }
                               
                            }
                        }

                        Timeout(3, () =>
                        {
                            GamePlay.gpLogServer(new[] { player }, "From {0}:", new object[]{localHQ.Name });
                           
                            if (Messages.Count > 0)
                                foreach(var kvp in Messages)
                                {
                                        GamePlay.gpLogServer(new[] { player }, kvp.Value, null);
                                };

                            if (localHQ.GetLostObservedSectors().Count > 0)
                            {
                                string lostSectors = "";

                                localHQ.GetLostObservedSectors().ForEach(item =>
                                {
                                    lostSectors += item + " ";
                                });

                                lostSectors = lostSectors.TrimEnd(' ');
                                GamePlay.gpLogServer(null, "Radar blind for Sectors {0}!", new[] { lostSectors });
                               
                                if (!foundEnemy)
                                    GamePlay.gpLogServer(new[] { player }, "No Enemy in other available Sectors spottet", null);
                            }
                            else if (!foundEnemy)
                                GamePlay.gpLogServer(new[] { player }, "No Enemy in Range", null);
                        });
                    }
                }
            }
            Timeout(13.0, () => // delay for next use
                {
                    PilotsInGame[i].RadarUsed = false;
                });
        }
    }


    private Dictionary<AiAirGroup, int> getPulks(AiAirGroup[] airgroups, double maxdistance)
    {
        Dictionary<AiAirGroup, List<AiAirGroup>> Pulks = new Dictionary<AiAirGroup, List<AiAirGroup>>();

        if (airgroups != null && airgroups.Length > 1)
        {
            Pulks.Add(airgroups[0], new List<AiAirGroup>());  //leaderGroup //'attached' groups (in radius maxdistance)

            for (int i = 1; i < airgroups.Length; i++)
            {
                bool airgroupAdded = false;
                foreach (var kvp in Pulks)
                {
                    Point3d airgroupPos = kvp.Key.Pos();

                    if (airgroups[i].Pos().distance(ref airgroupPos) < maxdistance)
                    {
                        kvp.Value.Add(airgroups[i]);
                        airgroupAdded = true;
                    }
                }
                if (!airgroupAdded)
                    Pulks.Add(airgroups[i], new List<AiAirGroup>());
            }
        }

        Dictionary<AiAirGroup, int> planePulks = new Dictionary<AiAirGroup, int>();

        foreach (var kvp in Pulks)
        {
            int numberOfPlanes = 0;

            numberOfPlanes += kvp.Key.NOfAirc;

            if (kvp.Value.Count > 0)
                kvp.Value.ForEach(item =>
                    {
                        numberOfPlanes += item.NOfAirc;
                    });

            planePulks.Add(kvp.Key, numberOfPlanes);
        }

        return planePulks;
    }


    private void connectToHeadquarterSpeech(AiAircraft aircraft, LocalHeadquarters localHQ)
    {
        double initTime = 0.0;
       
        aircraft.SayToGroup(aircraft.AirGroup(), "Hello_guys");

        Timeout(initTime += 2, () =>
            {
                aircraft.SayToGroup(aircraft.AirGroup(), "This_is");
            });

        Timeout(initTime += 2, () =>
        {
            aircraft.SayToGroup(aircraft.AirGroup(), localHQ.Callsign);
        });

        Timeout(initTime += 2, () =>
        {
            aircraft.SayToGroup(aircraft.AirGroup(), "n2"); // to is missing as ogg
        });

        Timeout(initTime += 2, () =>
        {
            aircraft.SayToGroup(aircraft.AirGroup(), aircraft.CallSign());
        });

        Timeout(initTime += 2, () =>
        {
            aircraft.SayToGroup(aircraft.AirGroup(), "leader__");
        });
    }


    #region mission menus

    #region class Menu

    internal class Menu
    {
        internal class MenuEntry
        {
            internal string MenuName { get; set; }
            internal bool active { get; set; }
        }

        internal List<MenuEntry> menuEntries = new List<MenuEntry>();

        public void AddMenuEntry(string description, bool active)
        {
            MenuEntry NewMenuEntry = new MenuEntry();

            NewMenuEntry.MenuName = description;
            NewMenuEntry.active = active;

            menuEntries.Add(NewMenuEntry);
        }

        public string[] GetMenuDescriptions()
        {
            List<string> Descriptions = new List<string>();

            menuEntries.ForEach(item =>
            {
                Descriptions.Add(item.MenuName);
            });

            return Descriptions.ToArray();
        }

        public bool[] GetActives()
        {
            List<bool> Actives = new List<bool>();

            menuEntries.ForEach(item =>
            {
                Actives.Add(item.active);
            });

            return Actives.ToArray();
        }

        public bool IsValid()
        {
            if (menuEntries == null || menuEntries.Count < 1)
                return false;
            else
                return true;

        }

    }

    #endregion

   
    public void SetMainMenu(Player player)
    {
        if (player.Army() == 1) // red Side
            GamePlay.gpSetOrderMissionMenu(player, false, 0, new string[] { "Radaroperations" }, new bool[] { true });
        else
            GamePlay.gpSetOrderMissionMenu(player, false, 0, new string[] { "Not Available" }, new bool[] { true });
    }


    public void SetRadarMenu(Player player)
    {
        string headQuarter = "Select Headquarter";
        string connectedTo = "";

        if (PilotsInGame.Exists(item => item.player == player))
        {
            int i = PilotsInGame.FindIndex(item => item.player == player);

            if (PilotsInGame[i].connectedHeadquarter != null)
                connectedTo = string.Format(" (connected: {0})", PilotsInGame[i].connectedHeadquarter.Name);
        }
        headQuarter += connectedTo;

        if(PilotsInGame.Exists(item=> item.player == player))
        {
            int i = PilotsInGame.FindIndex(item=> item.player == player);
            if(PilotsInGame[i].RadarUsed)
                GamePlay.gpSetOrderMissionMenu(player, true, 100, new string[] { headQuarter, "Get Radar Information" }, new bool[] { true, false });
            else
                GamePlay.gpSetOrderMissionMenu(player, true, 100, new string[] { headQuarter, "Get Radar Information" }, new bool[] { true, true });
        }
    }


    public void SetConnectToHeadquarterMenu(Player player, double maxdistanceToHq)
    {
        Menu NewMenu = new Menu();
        LocalHeadquarters headQuarter = null;

        if (PilotsInGame.Exists(item => item.player == player))
        {
            int i = PilotsInGame.FindIndex(item => item.player == player);
            headQuarter = PilotsInGame[i].connectedHeadquarter;
        }

        Headquarters.ForEach(item =>
        {
            if (headQuarter != null && item == headQuarter && item.GetDistance(player) < maxdistanceToHq)
            {
                NewMenu.AddMenuEntry(item.Name + " *", true);
            }
            else
                NewMenu.AddMenuEntry(item.Name, true);
        });

        if (NewMenu.IsValid())
            GamePlay.gpSetOrderMissionMenu(player, true, 101, NewMenu.GetMenuDescriptions() , NewMenu.GetActives());
        else
            GamePlay.gpSetOrderMissionMenu(player, true, 101, new string[]{ "Not available" }, new bool[]{true});
    }


    public void SetHeadQuarter(Player player, int menuItemIndex)
    {
        if (PilotsInGame.Exists(item => item.player == player))
        {
            int i = PilotsInGame.FindIndex(item => item.player == player);
            PilotsInGame[i].connectedHeadquarter = Headquarters[menuItemIndex-1];
            if (player.Place() != null)
                connectToHeadquarterSpeech((player.Place() as AiAircraft), PilotsInGame[i].connectedHeadquarter);
        }

    }


    public override void OnOrderMissionMenuSelected(Player player, int ID, int menuItemIndex)
    {
        if (ID == 0)
        { // main menu
            if (menuItemIndex == 1)
            {
                SetRadarMenu(player);
            }
        }

        if (ID == 100)
        {
            //Radar Menu
            if (menuItemIndex == 1)
            {
                SetConnectToHeadquarterMenu(player, 50000.0);
            }

            if (menuItemIndex == 2)
            {
                checkSectors(player);
                SetMainMenu(player);
            }
            if (menuItemIndex == 0)
                SetMainMenu(player);
        }

        if (ID == 101)
        {
            //Radar Menu
            if (menuItemIndex == 0)
                SetRadarMenu(player);
            else
            {
                SetHeadQuarter(player, menuItemIndex);
                SetRadarMenu(player);
            }
        }
    }

    #endregion


    public override void OnBattleStarted()
    {
        base.OnBattleStarted();
        MissionNumberListener = -1;
        GamePlay.gpPostMissionLoad(createRadarTriggers());
    }


    public override void OnPlaceEnter(Player player, AiActor actor, int placeIndex)
    {
        base.OnPlaceEnter(player, actor, placeIndex);

        if (!PilotsInGame.Exists(item => item.player == player))
        {
            PilotsInGame.Add(new Pilot(player));
        }

        SetMainMenu(player);
    }


    public override void OnTrigger(int missionNumber, string shortName, bool active)
    {
        base.OnTrigger(missionNumber, shortName, active);
       
        if (shortName.StartsWith("Radar") && shortName.EndsWith("Destroyed"))
        {
            GamePlay.gpLogServer(null, "Radar destroyed", null);

            Headquarters.ForEach(item =>
                {
                    item.SetObserverInactive(shortName);
                });
        }
    }

}


5./JG27.Farber 04-26-2012 02:24 PM

Speedy reply!

You sir, are a credit to the community and our forth coming campaign!

S! :cool:

von Brühl 04-26-2012 03:31 PM

Quote:

Originally Posted by 5./JG27.Farber (Post 409615)

Could radar actually tell the difference between fighters and bombers? Maybe it should say aircraft?

Ok, you've asked this several times and I haven't seen an answer. Yes, they could, but not in the sense that the radar operator would say "Ooo, look, 15 He-111s just popped up over Calais!" Instead, they would see the size of the return, and plot the speed, maybe see how fast it changed direction/altitude, and determine if it was a bomber or fighter. (Although I've read somewhere it could be fooled with very tight formations) With your 4 minute returns, I think that would give the Home Chain enough time to determine roughly what they were looking at.

Osprey 04-26-2012 06:49 PM

Credit where credit is due Kodiak, this is an epic program that shoud add a big dimension to immersion. ~S~ !!

5./JG27.Farber 04-29-2012 01:57 PM

What pattern would a radar "emit"?

Which pattern is closets to reality?



http://i1020.photobucket.com/albums/...etc/radar3.jpg

http://i1020.photobucket.com/albums/...etc/radar2.jpg

http://i1020.photobucket.com/albums/...etc/radar1.jpg

Osprey 04-29-2012 04:06 PM

Here's the coverage but this is 2D in a 3D world. The stations overlapped to complete the coverage.

http://ww2db.com/images/battle_britain9.jpg


Or are you asking what Kodiak's RDF covers?

5./JG27.Farber 04-29-2012 05:35 PM

No, Kodiaks system covers what you tell it to. I think they were like the third example but more elipse and over lapping like you said... I dont intend to use 20 radar to cover the South East like real BoB, as you reds will have to switch channels constantly and with one shot every four minutes that would not be much good. Also there was Chain Home high and low for different altitudes. So its simpler and better to use high and low combined with say 4 radar operating... Covering an unrealistic area...

Otherwise one radar might only be high or low and only cover 40km wide and 120km long... So you would check in with that radar and be locked out for 4 mins! There would in all likelyness be nothing in that slim sector and therefore the radar would be useless.

So, in clonclusion its better, faster and simpler to let one radar cover a bigger area both high and low... You might argue its unrealistic but any gap in the field is still a gap and an entire air armada can be sailed through a 40km gap! So its more realistc to fudge it. Also Kodiak has included Air Obsever Corps, so any inland grid sqaures can be set to them. Think Ill go with something like picture 2. - but wider with AOC taking up the slck near the cone point.!

FG28_Kodiak 04-29-2012 05:45 PM

You can let them overlapp.
So if one Radarstation is destroyed your HQ lost not all sectors from this observer, only the unique.

FG28_Kodiak 04-29-2012 07:03 PM

So the menu should now work correctly, but i was to busy to test it properly, so i hope you will testing it for me ;)
At the moment i use a time delay from 30sec. for the station answer, and a additional 10sec before the radar can be reused (for testing no problem to change the timings) . Please check the messages, i don't know how the radar communication exactly was, so maybe i must change them.
The communication is only possible if in range to the station for testing 50Km at the moment, you can only choose the HQs in range and you can lost the connection.
Only airgroups larger than 3 are detected, 5+ (4-7), 10+ (8-17planes) 20+(18-27) 30+ (28-37) etc.

Code:

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using maddox.game;
using maddox.game.world;
using maddox.GP;


public class Mission : AMission
{

    private static string userdocpath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
    private static string CLODO_FILE_PATH = userdocpath + @"\1C SoftClub\il-2 sturmovik cliffs of dover\";
    private static string FILE_PATH = @"missions\RadarTest\Radar.mis"; // adjust to your needs
    private static string MISSION_FILE = CLODO_FILE_PATH + FILE_PATH;

    List<LocalHeadquarters> Headquarters = new List<LocalHeadquarters>{
        {new LocalHeadquarters("Luton (Ash)", "CallSign24", 50000.0, 242928.64, 251773.16,
            new ObserverStation( "Static0","AN,16","AN,17","AN,18","AN,19","AO,16","AO,17","AO,18","AO,19","AP,16","AP,17","AP,18","AP,19","AQ,16","AQ,17","AQ,18","AQ,19"), //Dover
            new ObserverStation( "Static2","AL,20","AL,21","AL,22","AM,20","AM,21","AM,22","AN,20","AN,21","AN,22","AO,20","AO,21","AO,22"))}, // Dunkirk
        {new LocalHeadquarters("RadPoe (Woodchurch)", "CallSign32", 50000.0, 208162.91, 227726.61,
            new ObserverStation( "Static1","AJ,15","AJ,16","AJ,17","AJ,18","AK,15","AK,16","AK,17","AK,18","AL,15","AL,16","AL,17","AL,18","AM,15","AM,16","AM,17","AM,18"), //Rye
            new ObserverStation( "Royal Observer Corps I","AK,19","AK,20","AK,21","AL,19","AL,20","AL,21","AM,19","AM,20","AM,21"))}, // fake simulation of Royal Observer Corps, none destructable
        //{new LocalHeadquarters("Forest (Woodchurch)", "CallSign15", 208162.91, 227726.61, new ObserverStation( "Static4","E,1","E,2","E,3"), new ObserverStation( "Static5","F,1","F,2","F,3"))}
    };


    LandMarkHandling LandMarks = new LandMarkHandling(
        new LandMark("Dover", 245577.51, 234521.20),
        new LandMark("Folkestone", 235333.17, 229568.64),
        new LandMark("St.Magarets's at Cliffe", 250423.81, 238001.64),
        new LandMark("Deal", 250985.14, 244801.80),
        new LandMark("Dymchurch", 223734.62, 222437.79),
        new LandMark("New Romney", 220005.71, 218110.40),
        new LandMark("Rye", 205758.66, 213525.22),
        new LandMark("Hastings", 195366.28, 203132.83),
        new LandMark("Eastbourne", 174755.54, 191963.14),
        new LandMark("Brighton", 144909.86, 197927.40),
        new LandMark("Calais", 284654.87, 215707.54)
        );


    Random random = new Random();


    internal class LandMark
    {
        public string LandMarkName { get; set; }
        public Point2d LandMarkPosition { get; set; }

        public LandMark(string landMarkName, double x, double y)
        {
            this.LandMarkName = landMarkName;
            this.LandMarkPosition = new Point2d(x, y);
        }
    }


    internal class LandMarkHandling
    {
        List<LandMark> LandMarkList = new List<LandMark>();

        public LandMarkHandling(params LandMark[] mark)
        {
            if (mark != null)
                LandMarkList.AddRange(mark);
        }


        public LandMark getNearestLandMarkTo(Point3d position)
        {

            if (!(LandMarkList.Count > 0))
                return null;

            LandMark NearestLandMark = null;
            Point2d currentPosition = new Point2d(position.x, position.y);

            LandMarkList.ForEach(item =>
            {
                if (NearestLandMark != null)
                {
                    if (NearestLandMark.LandMarkPosition.distance(ref currentPosition) > item.LandMarkPosition.distance(ref currentPosition))
                        NearestLandMark = item;
                }
                else NearestLandMark = item;
            });

            return NearestLandMark;
        }
    }


    private List<string> getRadarCreationStrings(string filename)
    {
        List<string> list = new List<string>();
       
        if (!File.Exists(filename))
            GamePlay.gpLogServer(new Player[] { GamePlay.gpPlayer() }, "Missionfile {0} not found! Please check settings", new object[] { FILE_PATH });

        using (StreamReader reader = new StreamReader(filename))
        {
            string line;
            while ((line = reader.ReadLine()) != null)
            {
                if (line.Contains("Stationary.Radar"))
                {
                    list.Add(line);
                }
            }
        }
        return list;
    }

   
    private ISectionFile createRadarTriggers()
    {
        ISectionFile trigger = GamePlay.gpCreateSectionFile();

        List<string> Radarstations = getRadarCreationStrings(MISSION_FILE);

        if (Radarstations.Count > 0)
        {
            int i = 0;
            Radarstations.ForEach(item =>
                {
                    item = item.TrimStart(' ');
                    string[] splittet = item.Split(' ');
                    string keyTr, valueTr;

                    keyTr = "Radar" + string.Format("{0:00}", i) +"Destroyed";
                    valueTr = " TGroundDestroyed 50 " + splittet[3] + " " + splittet[4] + " 100"; //TGroundDestroyedTrigger 50% destroyed in radius 100m
                    trigger.add("Trigger", keyTr, valueTr);

                    Headquarters.ForEach(hq => hq.AddTriggerToObserver(splittet[0], keyTr));
                    i++;
                });
        }
        return trigger;
    }


    #region Calculations

    private int ToAngels(double altitude)
    {
        double altAngels = (altitude / 0.3048) / 1000;

        if (altAngels > 1)
            altAngels = Math.Round(altAngels, MidpointRounding.AwayFromZero);
        else
            altAngels = 1;

        return (int)altAngels;
    }


    private int ToMiles(double distance)
    {
        double distanceMiles = 0;
        distanceMiles = Math.Round(((distance / 1609.3426)), 0, MidpointRounding.AwayFromZero);  // distance in Miles

        return (int)distanceMiles;
    }


    private string degreesToWindRose(double degrees)
    {
        String[] directions = { "North", "North East", "East", "South East", "South", "South West", "West", "North West", "North" };
        return directions[(int)Math.Round((((double)degrees % 360) / 45))];
    }

    // to get the correct bearing its nessesary to make a litte enter the matrix operation.
    // the Vector2d.direction() (same as atan2) has 0° at the x-axis and goes counter clockwise, but we need 0° at the y-axis
    // and clockwise direction
    // so to convert it we need
    // |0 1| |x|  |0*x + 1*y|    |y|
    // |  | | | = |        | =  | |  // ok not very surprising ;)
    // |1 0| |y|  |1*x + 0*y|    |x|

    private double calculateBearingDegree(Vector3d vector)
    {
        Vector2d matVector = new Vector2d(vector.y, vector.x);
        // the value of direction is in rad so we need *180/Pi to get the value in degrees
        return matVector.direction() * 180.0 / Math.PI;
    }


    private double calculateBearingDegree(Vector2d vector)
    {
        Vector2d newVector = new Vector2d(vector.y, vector.x);

        return newVector.direction() * 180.0 / Math.PI;
    }


    private double calculateBearingFromOrigin(Point2d targetLocation, Point2d originLocation)
    {

        double deltaX = targetLocation.x - originLocation.x;
        double deltaY = targetLocation.y - originLocation.y;

        double bearing = Math.Atan2(deltaX, deltaY);
        bearing = bearing * (180.0 / Math.PI);

        return (bearing > 0.0 ? bearing : (360.0 + bearing));
    }


    private double calculateBearingFromOrigin(Point3d targetLocation, Point3d originLocation)
    {

        double deltaX = targetLocation.x - originLocation.x;
        double deltaY = targetLocation.y - originLocation.y;


        double bearing = Math.Atan2(deltaX, deltaY);
        bearing = bearing * (180.0 / Math.PI);

        return (bearing > 0.0 ? bearing : (360.0 + bearing));
    }


    private int getDegreesIn10Step(double degrees)
    {
        degrees = Math.Round((degrees / 10), MidpointRounding.AwayFromZero) * 10;

        if ((int)degrees == 360)
            degrees = 0.0;

        return (int) degrees;
    }

    private int noOfAircraft(int number)
    {
        int firstDecimal = 0;
        int higherDecimal = 0;

        higherDecimal = Math.DivRem(number, 10, out firstDecimal);

        if (firstDecimal > 3 && firstDecimal <= 8)
            firstDecimal = 5;
        else if (firstDecimal > 8)
            higherDecimal += 1;

        if (higherDecimal > 0)
            return (int)higherDecimal * 10;
        else
            return (int)firstDecimal;
    }
   
    #endregion


    internal class LocalHeadquarters
    {
        public string Name { get; set; }
        public Point2d LocationCoords { get; set; }
        public string Callsign { get; set; }

        public double MaxRange { get; set; }

        private List<ObserverStation> AttachedObservers = new List<ObserverStation>();

        public LocalHeadquarters(string name, string callsign, double maxRange, double x, double y, params ObserverStation[] observerStations)
        {
            this.Name = name;
            this.Callsign = callsign;
            this.LocationCoords = new Point2d(x, y);
            this.MaxRange = maxRange;

            if (observerStations != null)
                AttachedObservers.AddRange(observerStations);
        }


        public bool CheckInRange(Player player)
        {
            if (player.Place() == null) return false;
           
            bool inRange = false;
            Point2d currentPos = new Point2d(player.Place().Pos().x, player.Place().Pos().y);

            if (LocationCoords.distance(ref currentPos) < MaxRange)
                return true;

            return false;
        }


        public bool ObserveSector(string sectorName)
        {

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

            if (AttachedObservers.Count > 0)
            {
                AttachedObservers.ForEach(item =>
                {
                    if (item.IsActive)
                        AttachedSectors.AddRange(item.observedSectors);
                });
            }

            if (AttachedSectors.Exists(item => item.Equals(sectorName)))
                return true;
            else
                return false;
        }


        public List<ObserverStation> GetObservers()
        {
            return AttachedObservers;
        }


        public List<string> GetObservedSectors()
        {
            List<string> sectorList = new List<string>();

            AttachedObservers.ForEach(item =>
                {
                    if (item.IsActive)
                    {
                        item.observedSectors.ForEach(sector =>
                            {
                                if (!sectorList.Exists(newsector => sector == newsector))
                                    sectorList.Add(sector);
                            });
                    };
                });
            return sectorList;
        }


        public List<string> GetLostObservedSectors()
        {
            List<string> sectorList = new List<string>();

            AttachedObservers.ForEach(item =>
            {
                if (!item.IsActive)
                {
                    item.observedSectors.ForEach(sector =>
                    {
                        if (!sectorList.Exists(newsector => sector == newsector))
                            sectorList.Add(sector);
                    });
                };
            });

            if (sectorList.Count > 0)
            {
                List<string> CurrentObservedSectors = GetObservedSectors();

                if (CurrentObservedSectors.Count > 0)
                {
                    CurrentObservedSectors.ForEach(item =>
                        {
                            if (sectorList.Exists(sector => sector == item))
                            {
                                sectorList.RemoveAll(sector => sector == item);
                            }
                        });

                }

            }
            return sectorList;
        }

        public void SetObserverInactive(string triggerName)
        {

            if (AttachedObservers.Exists(item => item.TriggerName == triggerName))
            {
                AttachedObservers[AttachedObservers.FindIndex(item => item.TriggerName == triggerName)].IsActive = false;
            }
        }


        public void AddTriggerToObserver(string staticName, string triggerName)
        {
            if (AttachedObservers.Exists(item => item.StaticName == staticName))
            {
                AttachedObservers[AttachedObservers.FindIndex(item => item.StaticName == staticName)].TriggerName = triggerName;
            }
        }


        public double GetDistance(Player player)
        {
            Point2d playerLocation = new Point2d(player.Place().Pos().x, player.Place().Pos().y);

            double distance = LocationCoords.distance(ref playerLocation);

            return distance;
        }

    }

    internal class ObserverStation
    {
        public bool IsActive { get; set; }
        public string StaticName { get; set; }
        public string TriggerName { get; set; }

        public List<string> observedSectors = new List<string>();

        public ObserverStation(string staticName, params string[] sectorNames)
        {
            this.StaticName = staticName;
            this.IsActive = true;

            if (sectorNames != null)
                observedSectors.AddRange(sectorNames);
        }


        public ObserverStation(string staticName, string triggerName, params string[] sectorNames)
        {
            this.StaticName = staticName;
            this.TriggerName = triggerName;
            this.IsActive = true;

            if (sectorNames != null)
                observedSectors.AddRange(sectorNames);
        }


        public void SetTriggerName(string triggerName)
        {
            this.TriggerName = triggerName;
        }

    }


    internal class Pilot
    {
        public Player player { get; set; }
        public LocalHeadquarters ConnectedHeadquarter;
        public DateTime TimeStamp { get; set; }
        public bool RadarUsed { get; set; }

        public Pilot(Player player)
        {
            this.player = player;
            this.RadarUsed = false;
        }
    }


    internal List<Pilot> PilotsInGame = new List<Pilot>();


    public void checkSectors(Player player)
    {

        double timeDelay = 0.0;
       
        if (PilotsInGame.Exists(item => item.player == player))
        {
            int i = PilotsInGame.FindIndex(item => item.player == player);

            if (PilotsInGame[i].RadarUsed) return;
           
           

            if (PilotsInGame[i].ConnectedHeadquarter != null && PilotsInGame[i].ConnectedHeadquarter.CheckInRange(player))
            {
                PilotsInGame[i].RadarUsed = true;

                if (Headquarters.Exists(hq => hq == PilotsInGame[i].ConnectedHeadquarter))
                {
                    LocalHeadquarters localHQ = PilotsInGame[i].ConnectedHeadquarter;

                    Timeout(timeDelay += 2.0, () =>
                        {
                            GamePlay.gpLogServer(new[]{player},"From {0} to {1}:", new object[]{localHQ.Name, player.Name()});
                            GamePlay.gpLogServer(new[] { player }, "Collecting available informations - stay patient", null);
                        });

                    Dictionary<AiAirGroup, int> planePulks = getPulks(GamePlay.gpAirGroups((player.Army() == 1) ? 2 : 1), 1600.0); //all Airgroups in 1600m radius count as one

                    Dictionary<string, string> Messages = new Dictionary<string, string>();
                 

                    if (planePulks != null && planePulks.Count > 0)
                    {
                        bool foundEnemy = false;

                        foreach (var kvp in planePulks)
                        {
                            string sectorName = GamePlay.gpSectorName(kvp.Key.Pos().x, kvp.Key.Pos().y);

                            if (localHQ.ObserveSector(sectorName) && kvp.Key.Pos().z > 600.00)
                            {
                                foundEnemy = true;
                                string tmpKey = "";
                                string message = "";
                                Point3d destinationPoint = kvp.Key.Pos();
                                LandMark nearestLandMark = LandMarks.getNearestLandMarkTo(kvp.Key.Pos());
                                Point2d airgroupPos = new Point2d(kvp.Key.Pos().x, kvp.Key.Pos().y);
                                Vector2d airgroupVector = new Vector2d(kvp.Key.Vwld().x, kvp.Key.Vwld().y);

                                if (kvp.Value > 3) // only if more than 3 planes in a pulk generate a message
                                {
                                    if (nearestLandMark != null)
                                    {
                                        tmpKey = string.Format("Enemy {0} miles {1} from {2} at Angels {3}, Heading {4}", ToMiles(nearestLandMark.LandMarkPosition.distance(ref airgroupPos)), degreesToWindRose(calculateBearingFromOrigin(airgroupPos, nearestLandMark.LandMarkPosition)), nearestLandMark.LandMarkName, ToAngels(kvp.Key.Pos().z), getDegreesIn10Step(calculateBearingDegree(airgroupVector)));
                                        message = string.Format("{0}+ Enemy {1} miles {2} from {3} at Angels {4}, Heading {5}", noOfAircraft(kvp.Value), ToMiles(nearestLandMark.LandMarkPosition.distance(ref airgroupPos)), degreesToWindRose(calculateBearingFromOrigin(airgroupPos, nearestLandMark.LandMarkPosition)), nearestLandMark.LandMarkName, ToAngels(kvp.Key.Pos().z), getDegreesIn10Step(calculateBearingDegree(airgroupVector)));
                                    }
                                    else
                                    {
                                        tmpKey = string.Format("Enemy in Sector: {0} heading {1}", noOfAircraft(kvp.Value), sectorName, getDegreesIn10Step(calculateBearingDegree(airgroupVector)));
                                        message = string.Format("{0}+ Enemy in Sector: {1} heading {2}", noOfAircraft(kvp.Value), sectorName, getDegreesIn10Step(calculateBearingDegree(airgroupVector)));
                                    }
                                    if (!Messages.ContainsKey(tmpKey))
                                    {
                                        Messages.Add(tmpKey, message);
                                    }
                                }
                               
                            }
                        }

                        Timeout(timeDelay += 28, () =>
                        {
                            GamePlay.gpLogServer(new[] { player }, "From {0}:", new object[]{localHQ.Name });
                           
                            if (Messages.Count > 0)
                                foreach(var kvp in Messages)
                                {
                                        GamePlay.gpLogServer(new[] { player }, kvp.Value, null);
                                };

                            if (localHQ.GetLostObservedSectors().Count > 0)
                            {
                                string lostSectors = "";

                                localHQ.GetLostObservedSectors().ForEach(item =>
                                {
                                    lostSectors += item + " ";
                                });

                                lostSectors = lostSectors.TrimEnd(' ');
                                GamePlay.gpLogServer(null, "Radar blind for Sectors {0}!", new[] { lostSectors });
                               
                                if (!foundEnemy)
                                    GamePlay.gpLogServer(new[] { player }, "No Enemy in other available Sectors spottet", null);
                            }
                            else if (!foundEnemy)
                                GamePlay.gpLogServer(new[] { player }, "No Enemy in Range", null);
                        });
                    }
                }
            }
            else
            {
                GamePlay.gpLogServer(new[] { player }, "Connection to HQ lost (out of Range)", null);
            }




            Timeout(timeDelay += 10.0, () => // delay for next use
                {
                    PilotsInGame[i].RadarUsed = false;
                });
        }
    }


    private Dictionary<AiAirGroup, int> getPulks(AiAirGroup[] airgroups, double maxdistance)
    {
        Dictionary<AiAirGroup, List<AiAirGroup>> Pulks = new Dictionary<AiAirGroup, List<AiAirGroup>>();

        if (airgroups != null && airgroups.Length > 1)
        {
            Pulks.Add(airgroups[0], new List<AiAirGroup>());  //leaderGroup //'attached' groups (in radius maxdistance)

            for (int i = 1; i < airgroups.Length; i++)
            {
                bool airgroupAdded = false;
                foreach (var kvp in Pulks)
                {
                    Point3d airgroupPos = kvp.Key.Pos();

                    if (airgroups[i].Pos().distance(ref airgroupPos) < maxdistance)
                    {
                        kvp.Value.Add(airgroups[i]);
                        airgroupAdded = true;
                    }
                }
                if (!airgroupAdded)
                    Pulks.Add(airgroups[i], new List<AiAirGroup>());
            }
        }

        Dictionary<AiAirGroup, int> planePulks = new Dictionary<AiAirGroup, int>();

        foreach (var kvp in Pulks)
        {
            int numberOfPlanes = 0;

            numberOfPlanes += kvp.Key.NOfAirc;

            if (kvp.Value.Count > 0)
                kvp.Value.ForEach(item =>
                    {
                        numberOfPlanes += item.NOfAirc;
                    });

            planePulks.Add(kvp.Key, numberOfPlanes);
        }

        return planePulks;
    }


    private void connectToHeadquarterSpeech(AiAircraft aircraft, LocalHeadquarters localHQ)
    {
        double initTime = 0.0;
       
        aircraft.SayToGroup(aircraft.AirGroup(), "Hello_guys");

        Timeout(initTime += 2, () =>
            {
                aircraft.SayToGroup(aircraft.AirGroup(), "This_is");
            });

        Timeout(initTime += 2, () =>
        {
            aircraft.SayToGroup(aircraft.AirGroup(), localHQ.Callsign);
        });

        Timeout(initTime += 2, () =>
        {
            aircraft.SayToGroup(aircraft.AirGroup(), "n2"); // to is missing as ogg
        });

        Timeout(initTime += 2, () =>
        {
            aircraft.SayToGroup(aircraft.AirGroup(), aircraft.CallSign());
        });

        Timeout(initTime += 2, () =>
        {
            aircraft.SayToGroup(aircraft.AirGroup(), "leader__");
        });
    }


    #region mission menus

    #region class Menu

    internal class Menu
    {
        internal class MenuEntry
        {
            internal string MenuName { get; set; }
            internal bool active { get; set; }
        }

        internal List<MenuEntry> menuEntries = new List<MenuEntry>();

        public void AddMenuEntry(string description, bool active)
        {
            MenuEntry NewMenuEntry = new MenuEntry();

            NewMenuEntry.MenuName = description;
            NewMenuEntry.active = active;

            menuEntries.Add(NewMenuEntry);
        }

        public string[] GetMenuDescriptions()
        {
            List<string> Descriptions = new List<string>();

            menuEntries.ForEach(item =>
            {
                Descriptions.Add(item.MenuName);
            });

            return Descriptions.ToArray();
        }

        public bool[] GetActives()
        {
            List<bool> Actives = new List<bool>();

            menuEntries.ForEach(item =>
            {
                Actives.Add(item.active);
            });

            return Actives.ToArray();
        }

        public bool IsValid()
        {
            if (menuEntries == null || menuEntries.Count < 1)
                return false;
            else
                return true;

        }

    }

    #endregion

   
    public void SetMainMenu(Player player)
    {
        if (player.Army() == 1) // red Side
            GamePlay.gpSetOrderMissionMenu(player, false, 0, new string[] { "Fighter Command HQs" }, new bool[] { true });
        //else // blue Side
        //    GamePlay.gpSetOrderMissionMenu(player, false, 0, new string[] { "Nothing Available" }, new bool[] { true });
    }


    public void SetRadarMenu(Player player)
    {
        if (player.Army() != 1) return;
       
        string headQuarter = "Select Headquarter";
        string connectedTo = "";

        if (PilotsInGame.Exists(item => item.player == player))
        {
            int i = PilotsInGame.FindIndex(item => item.player == player);

            if (PilotsInGame[i].ConnectedHeadquarter != null)
                connectedTo = string.Format(" (connected: {0})", PilotsInGame[i].ConnectedHeadquarter.Name);
        }
        headQuarter += connectedTo;

        if(PilotsInGame.Exists(item=> item.player == player))
        {
            int i = PilotsInGame.FindIndex(item=> item.player == player);
            if (PilotsInGame[i].ConnectedHeadquarter == null)
                GamePlay.gpSetOrderMissionMenu(player, true, 100, new string[] { headQuarter, "Get Radar Information" }, new bool[] { true, false });
            else if (PilotsInGame[i].RadarUsed)
                GamePlay.gpSetOrderMissionMenu(player, true, 100, new string[] { headQuarter, "Get Radar Information" }, new bool[] { false, false });
            else
                GamePlay.gpSetOrderMissionMenu(player, true, 100, new string[] { headQuarter, "Get Radar Information" }, new bool[] { true, true });
        }
    }


    public void SetConnectToHeadquarterMenu(Player player)
    {

        Menu NewMenu = new Menu();
        LocalHeadquarters headQuarter = null;
        int i = -1;

        if (PilotsInGame.Exists(item => item.player == player))
        {
            i = PilotsInGame.FindIndex(item => item.player == player);
            headQuarter = PilotsInGame[i].ConnectedHeadquarter;
        }

        if (i < 0 && PilotsInGame[i].RadarUsed == true) return;


        Headquarters.ForEach(item =>
        {
            if (headQuarter != null && item == headQuarter && headQuarter.CheckInRange(player))
            {
                NewMenu.AddMenuEntry(item.Name + " *", true);
            }
            else if (item.CheckInRange(player))
                NewMenu.AddMenuEntry(item.Name, true);
        });

        if (NewMenu.IsValid())
            GamePlay.gpSetOrderMissionMenu(player, true, 101, NewMenu.GetMenuDescriptions() , NewMenu.GetActives());
        else
            GamePlay.gpSetOrderMissionMenu(player, true, 101, new string[]{ "None available" }, new bool[]{false});
    }


    public void SetHeadQuarter(Player player, int menuItemIndex)
    {
        if (PilotsInGame.Exists(item => item.player == player))
        {
            int i = PilotsInGame.FindIndex(item => item.player == player);

            if (Headquarters[menuItemIndex - 1].CheckInRange(player) && !PilotsInGame[i].RadarUsed)
            {
                PilotsInGame[i].ConnectedHeadquarter = Headquarters[menuItemIndex - 1];
                if (player.Place() != null)
                {
                  // connectToHeadquarterSpeech((player.Place() as AiAircraft), PilotsInGame[i].ConnectedHeadquarter);
                    Timeout(2.0, () =>
                        {
                            GamePlay.gpLogServer(new[] { player }, "From {0} to {1}:", new object[] { PilotsInGame[i].ConnectedHeadquarter.Name, player.Name() });
                            GamePlay.gpLogServer(new[] { player }, "You are welcome!", null);
                        });
                }
            }
            PilotsInGame[i].RadarUsed = false;
        }

    }




    public void MenuPartRadarOperations(Player player, int id, int menuItemIndex)
    {
        if (id == 100)
        {
            if (PilotsInGame.Exists(item => item.player == player))
            {
                if (!PilotsInGame[PilotsInGame.FindIndex(item => item.player == player)].RadarUsed)
                {
                    //Radar Menu
                    if (menuItemIndex == 1)
                    {
                        SetConnectToHeadquarterMenu(player);
                    }

                    if (menuItemIndex == 2)
                    {

                        checkSectors(player);
                        SetMainMenu(player);
                    }
                }
                else
                {
                    SetMainMenu(player);
                }
            }
        }

        if (id == 101)
        {
            //Radar Menu
            if (menuItemIndex == 0)
                SetRadarMenu(player);
            else
            {
                SetHeadQuarter(player, menuItemIndex);
                SetRadarMenu(player);
            }
        }
    }
       
   






    public override void OnOrderMissionMenuSelected(Player player, int ID, int menuItemIndex)
    {
        base.OnOrderMissionMenuSelected(player, ID, menuItemIndex);

       
        if (ID == 0)
        { // main menu
            if (menuItemIndex == 1)
            {
                SetRadarMenu(player);
            }
        }


        MenuPartRadarOperations(player, ID, menuItemIndex);

    }

    #endregion


    public override void OnBattleStarted()
    {
        base.OnBattleStarted();
        MissionNumberListener = -1;
        GamePlay.gpPostMissionLoad(createRadarTriggers());
    }


    public override void OnPlaceEnter(Player player, AiActor actor, int placeIndex)
    {
        base.OnPlaceEnter(player, actor, placeIndex);

        if (!PilotsInGame.Exists(item => item.player == player))
        {
            PilotsInGame.Add(new Pilot(player));
        }

        SetMainMenu(player);
    }


    public override void OnTrigger(int missionNumber, string shortName, bool active)
    {
        base.OnTrigger(missionNumber, shortName, active);
       
        if (shortName.StartsWith("Radar") && shortName.EndsWith("Destroyed"))
        {
            GamePlay.gpLogServer(null, "Radar destroyed", null);

            Headquarters.ForEach(item =>
                {
                    item.SetObserverInactive(shortName);
                });
        }
    }

}


5./JG27.Farber 04-29-2012 07:37 PM

Sounds good. We will test if for you. :-P

Thanks Kodiak, you really are a diamond!


All times are GMT. The time now is 07:40 PM.

Powered by vBulletin® Version 3.8.4
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Copyright © 2007 Fulqrum Publishing. All rights reserved.