/* * acm : an aerial combat simulator for X * Copyright (C) 1991,1992,1997 Riley Rainey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 dated June, 1991. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA. */ #include "pm.h" #include "alarm.h" #include extern double strtod(const char *, char **); struct _navaid_t *vhf_navaid[VOR_CHANNEL_COUNT]; static char *bad_freq = "*****"; static navaid_t *test_navaid = NULL; #ifdef MAG_VAR double mag_var = DEGtoRAD(MAG_VAR); #else double mag_var = DEGtoRAD(8.0); /* eight degrees east */ #endif void InitNavaid(navaid_t * n); char *PrintableVHFFreq(freq_t f, char *s); extern alarm_id_t addAlarm(double delta, void (*proc) (char *, char *), char *arg1, char *arg2); extern double heading(VPoint * x); double magHeading(craft * c) { register double h = c->curHeading + mag_var; return (h < 0.0) ? h + 2.0 * pi : h; } /* * Search for a NAVAID receivable at the frequency specified * by the supplied radio receiver. * * Return 1 for success (r->station is set to the NAVAID). * Return 0 if no station was found. */ int radioReceptionCheck(craft * c, radio_t * r) { navaid_t *n; VPoint p; for (n = test_navaid; n; n = n->next) { if (r->frequency == n->frequency) { if (n->flags & NAVAID_LOC) { VTransform(&c->Sg, &n->lt, &p); #ifdef DEBUG printf("tested: %s %f %f %f\n", n->id, p.x, p.y, p.z); #endif if (p.x > 0.0 && fabs(p.y / p.x) < 1.192) { #ifdef DEBUG printf("locked: %s %f %f %f\n", n->id, p.x, p.y, p.z); #endif r->station = n; return 1; } } else { r->station = n; return 1; } } } return 0; } void radioFrequencyChanged(craft * c, radio_t * r) { r->station = NULL; radioReceptionCheck(c, r); PrintableVHFFreq(r->frequency, r->freq_readout); strcpy(r->dme_readout, "DME ----"); } void initRadio(craft * c, radio_t * r) { r->frequency = r->standby_frequency = 0; r->obs_setting = 0; radioFrequencyChanged(c, r); } void freeAllNavaids (void) { navaid_t *n = test_navaid, *p; while (n) { p = n; n = n->next; free (p); } } int AddNavaid(char *ident, char *type, WorldCoordinates * w, char *magvar, double freq) { navaid_t *n; char var[3]; double mvar; n = (navaid_t *) malloc(sizeof(navaid_t)); strncpy(var, magvar, 2); var[2] = '\0'; mvar = strtod(var, (char **) NULL); mvar = (magvar[2] == 'E') ? -mvar : mvar; n->bearing = n->magvar = DEGtoRAD(mvar); strncpy(n->id, ident, 4); n->loc = *w; GenerateWorldToLocalMatrix(w, &n->lt); VRotate(&n->lt, ZRotation, n->magvar); DISWorldCoordinatesToGeocentric(w, (dis_world_coordinates *) & n->Sg); if (strcmp(type, "VORTAC") == 0) { n->flags = NAVAID_VOR | NAVAID_DME; } else if (strcmp(type, "TACAN") == 0) { n->flags = NAVAID_VOR | NAVAID_DME; } else if (strcmp(type, "VOR/DME") == 0) { n->flags = NAVAID_VOR | NAVAID_DME; } else if (strcmp(type, "VOR") == 0) { n->flags = NAVAID_VOR; } else if (strcmp(type, "NDB") == 0) { n->flags = NAVAID_NDB; } else { free(n); return -1; } if (n->flags & NAVAID_VOR) { n->frequency = (int) ((freq - 108.00) * 20.0 + 0.5); } else { n->frequency = -(int) (freq + 0.5); } n->next = test_navaid; test_navaid = n; return 0; } int AddILS(char *ident, char *type, WorldCoordinates * w, WorldCoordinates * gsw, char *magvar, double freq, double loc_width, double loc_bearing, double gs_angle) { navaid_t *n; char var[3]; double mvar; n = (navaid_t *) malloc(sizeof(navaid_t)); strncpy(var, magvar, 2); var[2] = '\0'; mvar = strtod(var, (char **) NULL); mvar = (magvar[2] == 'E') ? -mvar : mvar; n->magvar = DEGtoRAD(mvar); strncpy(n->id, ident, 4); n->bearing = DEGtoRAD(loc_bearing); n->loc = *w; GenerateWorldToLocalMatrix(w, &n->lt); VRotate(&n->lt, ZRotation, -n->bearing + n->magvar - M_PI); DISWorldCoordinatesToGeocentric(w, (dis_world_coordinates *) & n->Sg); n->gs_loc = *gsw; GenerateWorldToLocalMatrix(gsw, &n->gst); VRotate(&n->gst, ZRotation, -n->bearing + n->magvar - M_PI); n->slope = DEGtoRAD(gs_angle); n->beam_width = DEGtoRAD(loc_width); if (strcmp(type, "ILS") == 0) { n->flags = NAVAID_LOC | NAVAID_GS; } else if (strcmp(type, "ILS/DME") == 0) { n->flags = NAVAID_LOC | NAVAID_GS | NAVAID_DME; } else if (strcmp(type, "LOCALIZER") == 0) { n->flags = NAVAID_LOC; } else if (strcmp(type, "LOC/GS") == 0) { n->flags = NAVAID_LOC | NAVAID_GS; } else if (strcmp(type, "LOC/DME") == 0) { n->flags = NAVAID_LOC | NAVAID_DME; } else { free(n); return -1; } n->frequency = (int) ((freq - 108.00) * 20.0 + 0.5); n->next = test_navaid; test_navaid = n; return 0; } void InitNavaid(navaid_t * n) { VMatrix m; VPoint p; VIdentMatrix(&m); VSetPoint(p, 1.0, 0.0, 0.0); switch (n->flags & (NAVAID_VOR | NAVAID_LOC | NAVAID_GS)) { case NAVAID_VOR: case NAVAID_LOC: break; case (NAVAID_LOC | NAVAID_GS): VRotate(&m, ZRotation, n->bearing); VRotate(&m, YRotation, n->slope); n->gst = m; break; } } double glideSlopeOffset(navaid_t * n, craft * c) { VPoint p; VTransform(&c->Sg, &n->gst, &p); return -(atan(-p.z / p.x) - n->slope); } double radial(navaid_t * n, craft * c, VPoint * vec) { VTransform(&c->Sg, &n->lt, vec); return heading(vec); } char * PrintableVHFFreq(freq_t f, char *s) { if (f > VOR_CHANNEL_COUNT) { fprintf(stderr, "invalid frequency passed to PrintableVHFFreq\n"); return bad_freq; } sprintf(s, "%5d", 10800 + 5 * f); s[6] = '\0'; s[5] = s[4]; s[4] = s[3]; s[3] = '.'; return s; } char * PrintableTACANChannel(freq_t f, char *s) { if (f > VOR_CHANNEL_COUNT) { fprintf(stderr, "invalid frequency passed to PrintableTACANChannel\n"); return bad_freq; } sprintf(s, "%d%c", f / 2 + 17, (f % 2) ? 'Y' : 'X'); return s; } /* ARGSUSED */ void DMECheckAlarm(char *arg1, char *arg2) { int i; craft *c; VPoint p; navaid_t *n; alarm_id_t id; for (i = 0, c = ptbl; i < MAXPLAYERS; ++i, ++c) { /* Ensure that we're still receiving the same station */ if (c->hsiSelect) { radioReceptionCheck(c, c->hsiSelect); } if ((c->type == CT_PLANE) && c->hsiSelect->station) { n = c->hsiSelect->station; p.x = c->Sg.x - n->Sg.x; p.y = c->Sg.y - n->Sg.y; p.z = c->Sg.z - n->Sg.z; sprintf(c->hsiSelect->dme_readout, "DME %.1f", METERStoFEET(mag(p)) / NM); } } id = addAlarm(5.0, DMECheckAlarm, (char *) NULL, (char *) NULL); }