public static async Task <Dictionary <string, object> > GetBearingToNearestFriendlyAirbase(Point callerPosition, string group, int flight, int plane, int coalition)
        {
            var command = @"SELECT degrees(ST_AZIMUTH(request.position, airbase.position)) as bearing,
                                      ST_DISTANCE(request.position, airbase.position) as distance,
									  airbase.name
            FROM public.units AS airbase CROSS JOIN LATERAL (
              SELECT requester.position, requester.coalition
              FROM public.units AS requester
              WHERE (requester.pilot ILIKE '" + $"%{group} {flight}-{plane}%" + @"' OR requester.pilot ILIKE '" + $"%{group} {flight}{plane}%" + @"' )
            ) as request
            WHERE (
		      airbase.type = 'Ground+Static+Aerodrome'
			  AND airbase.coalition = "             + $"{coalition}" + @"
              AND airbase.name NOT ILIKE '%FARP%'
            )
            ORDER BY distance
            LIMIT 1";

            Dictionary <string, object> output = null;

            using (var connection = new NpgsqlConnection(ConnectionString()))
            {
                await connection.OpenAsync();

                using (var cmd = new NpgsqlCommand(command, connection))
                {
                    DbDataReader dbDataReader = await cmd.ExecuteReaderAsync();

                    await dbDataReader.ReadAsync();

                    if (dbDataReader.HasRows)
                    {
                        var bearing = Geospatial.TrueToMagnetic(callerPosition, Math.Round(dbDataReader.GetDouble(0)));
                        // West == negative numbers so convert
                        if (bearing < 0)
                        {
                            bearing += 360;
                        }

                        var range = (int)Math.Round(dbDataReader.GetDouble(1) * 0.539957d / 1000); // Nautical Miles
                        var name  = dbDataReader.GetString(2);


                        output = new Dictionary <string, object>
                        {
                            { "name", name },
                            { "bearing", (int)Math.Round(bearing) },
                            { "range", range }
                        };
                    }
                    dbDataReader.Close();
                }
            }
            return(output);
        }
예제 #2
0
        private async Task TransmitHeadingToNextWaypoint(string comment)
        {
            var nextWayPoint = _wayPoints.First();

            var wH = (int)Geospatial.BearingTo(_sender.Position.Coordinate,
                                               new Coordinate(nextWayPoint.Latitude, nextWayPoint.Longitude));

            var magneticHeading = Regex.Replace(Geospatial.TrueToMagnetic(_sender.Position, wH).ToString("000"),
                                                "\\d{1}", " $0");

            _lastInstruction = DateTime.Now;
            await SendMessage($"fly heading {magneticHeading} for {nextWayPoint.Name} {comment}");
        }
예제 #3
0
        public static string BuildResponse(Player sender, Contact contact)
        {
            var bearing  = Regex.Replace(Geospatial.TrueToMagnetic(sender.Position, contact.Bearing).ToString("000"), "\\d{1}", " $0");
            var range    = contact.Range.ToString();
            var altitude = contact.Altitude.ToString("N0");
            var aspect   = GetAspect(contact);
            var name     = AircraftReportingNamePronouncer.PronounceName(contact);

            var response = $"Bra, {bearing}, {range}, {altitude}{aspect}";

            if (name != null)
            {
                response += $", type <break time=\"50\" /> {name}.";
            }

            return(response);
        }
예제 #4
0
        public static async Task <string> Process(IRadioCall radioCall, string voice,
                                                  ConcurrentQueue <byte[]> responseQueue)
        {
            return(await Task.Run(() =>
            {
                try
                {
                    var airfield = Constants.Airfields.First(x => x.Name == radioCall.ReceiverName);
                    var approachRoute = new ApproachController(airfield).GetApproachRoute(radioCall.Sender.Position);

                    var initialTrueBearing = Geospatial.BearingTo(radioCall.Sender.Position.Coordinate,
                                                                  new Coordinate(approachRoute.First().Latitude, approachRoute.First().Longitude));

                    var initialMagneticBearing =
                        Regex.Replace(
                            Geospatial.TrueToMagnetic(radioCall.Sender.Position, initialTrueBearing).ToString("000"),
                            "\\d{1}", " $0");

                    var response =
                        $"fly heading {initialMagneticBearing}, descend and maintain 2,000, reduce speed 2 0 0 knots, for vectors to {approachRoute.Last().Name}, {approachRoute.First().Name}";

                    var currentPosition = new NavigationPoint
                    {
                        Name = "Current Position",
                        Latitude = radioCall.Sender.Position.Coordinate.Latitude,
                        Longitude = radioCall.Sender.Position.Coordinate.Longitude
                    };

                    approachRoute = approachRoute.Prepend(currentPosition).ToList();

                    new AtcProgressChecker(radioCall.Sender, airfield, voice, approachRoute, responseQueue)
                    .CalledInbound();

                    return response;
                }
                catch (InvalidOperationException)
                {
                    return "There are no ATC services currently available at this airfield.";
                }
                catch (NoActiveRunwaysFoundException ex)
                {
                    Logger.Error(ex, "No Active Runways found");
                    return "We could not find any active runways.";
                }
            }));
        }
예제 #5
0
        private static async Task <string> NamedAirbase(IRadioCall radioCall)
        {
            string response;
            var    braData = await GameQuerier.GetBearingToNamedAirbase(radioCall.Sender.Position,
                                                                        radioCall.Sender.Group, radioCall.Sender.Flight, radioCall.Sender.Plane, radioCall.AirbaseName);

            if (braData != null)
            {
                var bearing =
                    Regex.Replace(Geospatial.TrueToMagnetic(radioCall.Sender.Position, braData["bearing"]).ToString("000"),
                                  "\\d{1}", " $0");
                var range = braData["range"];
                response = $"{AirbasePronouncer.PronounceAirbase(radioCall.AirbaseName)} bearing {bearing}, {range} miles";
            }
            else
            {
                response = $"I Could not find {AirbasePronouncer.PronounceAirbase(radioCall.AirbaseName)}.";
            }

            return(response);
        }
예제 #6
0
        private static async Task <string> NearestAirbase(IRadioCall radioCall)
        {
            string response;
            var    braData = await GameQuerier.GetBearingToNearestFriendlyAirbase(radioCall.Sender.Position,
                                                                                  radioCall.Sender.Group, radioCall.Sender.Flight, radioCall.Sender.Plane, (int)radioCall.Sender.Coalition);

            if (braData != null)
            {
                var bearing =
                    Regex.Replace(Geospatial.TrueToMagnetic(radioCall.Sender.Position, (int)braData["bearing"]).ToString("000"),
                                  "\\d{1}", " $0");
                var range = braData["range"];
                response = $"{AirbasePronouncer.PronounceAirbase((string) braData["name"])} bearing {bearing}, {(int) range} miles";
            }
            else
            {
                response = "I Could not find any friendly airbases.";
            }

            return(response);
        }
예제 #7
0
        public static async Task <string> Process(BearingToFriendlyPlayerRadioCall radioCall)
        {
            string response;

            if (radioCall.FriendlyPlayer == null)
            {
                return("I could not understand the friendly's callsign");
            }

            var contact = await GameQuerier.GetFriendlyPlayer(radioCall.Sender.Group, radioCall.Sender.Flight, radioCall.Sender.Plane,
                                                              radioCall.FriendlyPlayer.Group, radioCall.FriendlyPlayer.Flight, radioCall.FriendlyPlayer.Plane);

            if (contact != null)
            {
                var bearing  = Regex.Replace(Geospatial.TrueToMagnetic(radioCall.Sender.Position, contact.Bearing).ToString("000"), "\\d{1}", " $0");
                var range    = contact.Range.ToString();
                var altitude = (int)contact.Altitude;
                int angels;
                if (altitude < 1000)
                {
                    angels = 1;
                }
                else
                {
                    angels = (altitude % 1000 >= 500 ? altitude + 1000 - altitude % 1000 : altitude - altitude % 1000) / 1000;
                }

                response = $"Bra, {bearing}, {range}, angels {angels}.";
            }
            else
            {
                response = $"I cannot find {radioCall.Sender.Group} {radioCall.Sender.Flight} {radioCall.Sender.Plane}.";
            }

            return(response);
        }
예제 #8
0
        private async Task CheckInbound()
        {
            await PerformCheck(async() =>
            {
                Logger.Debug($"{_sender.Id} - {_sender.Callsign}: Inbound Progress Check");
                var nextWayPoint = _wayPoints.First();

                Logger.Debug(
                    $"{_sender.Id} is {nextWayPoint.DistanceTo(_sender.Position.Coordinate)} KM from {nextWayPoint.Name}");

                // THINK ABOUT: Change this fixed value to a relative ratio based on the distances?
                if (nextWayPoint.DistanceTo(_sender.Position.Coordinate) < 1)
                {
                    if (nextWayPoint.Name.Contains("Entry"))
                    {
                        await _atcState.FireAsync(Trigger.TurnBase);
                    }
                    else
                    {
                        await _atcState.FireAsync(Trigger.StartInbound);
                    }

                    return;
                }

                // No point with last minute instructions when we are sending them to initial soon anyway
                if (nextWayPoint.DistanceTo(_sender.Position.Coordinate) < 2.5)
                {
                    return;
                }

                if (_sender.Heading == null)
                {
                    Logger.Debug($"{_sender.Id} - {_sender.Callsign}: heading was null");
                    return;
                }

                Logger.Debug($"{_sender.Id} - {_sender.Callsign}: Time between two transmissions ok");

                var sH = (int)_sender.Heading;
                var wH = (int)Geospatial.BearingTo(_sender.Position.Coordinate,
                                                   new Coordinate(nextWayPoint.Latitude, nextWayPoint.Longitude));

                var headingDiff = Math.Min((wH - sH) < 0 ? wH - sH + 360 : wH - sH,
                                           (sH - wH) < 0 ? sH - wH + 360 : sH - wH);

                Logger.Debug(
                    $"{_sender.Id} - {_sender.Callsign}: Headings: Waypoint {wH}, Player {sH}, diff {headingDiff}");

                Logger.Debug(
                    $"{_sender.Id} - {_sender.Callsign}: {(DateTime.Now - _lastInstruction).TotalSeconds} since last transmission");
                if ((DateTime.Now - _lastInstruction).TotalMilliseconds < _transmissionInterval)
                {
                    Logger.Debug(
                        $"{_sender.Id} - {_sender.Callsign}: Time between two transmissions too low, returning");
                    return;
                }

                if (headingDiff <= 5)
                {
                    return;
                }

                var magneticHeading = Regex.Replace(Geospatial.TrueToMagnetic(_sender.Position, wH).ToString("000"),
                                                    "\\d{1}", " $0");
                _lastInstruction = DateTime.Now;
                await SendMessage($"fly heading {magneticHeading}");
            });
        }