1
0
Fork 0

- Update. Radar2 is now devived frm the last f-14b radar version. Added a

standalone screen and HUD diamond as target marker.
This commit is contained in:
abory 2009-05-24 13:32:52 +00:00
parent 52471e4666
commit d8461ddec7
6 changed files with 7979 additions and 216 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View file

@ -0,0 +1,47 @@
AC3Db
MATERIAL "ac3dmat1" rgb 0 0 0 amb 0 0 0 emis 0.522 1 0.227 spec 0 0 0 shi 0 trans 0.008
OBJECT world
kids 1
OBJECT poly
name "lock-1"
loc 0 1.36774e-11 -1.77806e-10
crease 45.000000
numvert 8
0 4.5369e-05 -0.00476376
0 0.00476376 -4.53695e-05
0 -4.5369e-05 0.00476376
0 -0.00476376 4.53701e-05
0 4.57806e-05 -0.00384497
0 0.00384497 -4.57813e-05
0 -4.57806e-05 0.00384498
0 -0.00384497 4.57811e-05
numsurf 4
SURF 0x30
mat 0
refs 4
0 1 1
1 0 1
5 0 0
4 0 0
SURF 0x30
mat 0
refs 4
1 0 1
2 0 0
6 0 0
5 0 0
SURF 0x30
mat 0
refs 4
2 0 0
3 1 0
7 0 0
6 0 0
SURF 0x30
mat 0
refs 4
3 1 0
0 1 1
4 0 0
7 0 0
kids 0

View file

@ -0,0 +1,58 @@
<?xml version="1.0"?>
<!-- Additional Radar features in the HUD -->
<PropertyList>
<path>hud.ac</path>
<animation>
<type>select</type>
<object-name>hud</object-name>
<condition>
<equals>
<property>sim/current-view/name</property>
<value>Cockpit View</value>
</equals>
<property>sim/hud/visibility[1]</property>
</condition>
</animation>
<!-- Diamond -->
<animation>
<type>select</type>
<object-name>lock-1</object-name>
<condition>
<property>instrumentation/radar2/hud/target-display</property>
<not><property>instrumentation/radar/radar-standby</property></not>
<property>instrumentation/radar2/hud/target-clamped-blinker/state</property>
</condition>
</animation>
<animation>
<type>rotate</type>
<object-name>lock-1</object-name>
<property>instrumentation/radar2/hud/target-total-angle</property>
<axis><x>-1</x></axis>
</animation>
<animation>
<type>translate</type>
<object-name>lock-1</object-name>
<property>instrumentation/radar2/hud/target-total-deviation</property>
<factor>1</factor>
<axis>
<z>1</z>
</axis>
</animation>
<animation><!-- post-rotate in inverse direction to keep the diamond vertical -->
<type>rotate</type>
<object-name>lock-1</object-name>
<property>instrumentation/radar2/hud/target-total-angle</property>
<axis><x>1</x></axis>
</animation>
</PropertyList>

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,259 +1,330 @@
##### radar2.nas Multiplayer radar and ECM/RWR system. # Radar2 and RWR routines.
# Alexis Bory, 2008. # Alexis Bory (xiii)
# Cycles through the list of multiplayers and tankers, then triggers
# radar or ECM/RWR computations if those features are enabled in our aircraft -set.xml file.
# Needs radardist.nas for some visibilty computations based on radardist radar and RCS database. # Every 0.05 seconde:
# watch_aimp_models() has to be periodicaly called from one of our aircraft # [1] Generates a sweep scan pattern and when sweep direction changes, scans
# nasal files. Do not forget to init both scripts. # /AI/models for (aircrafts), (carriers), multiplayers. Creates a list of
# these targets, whenever they are in radar overall range and are valid.
# [2] RWR (Radar Warning Receiver) signals are then computed. RWR is included
# within the radar stuff to avoid redundancy.
# [3] At each loop the targets list is scanned and each target bearing is checked
# against the radar beam heading. If the target is within the radar beam, its
# display properties are updated. Two different displays are possible:
# B-scan like and PPI like.
# The target distance is then scored so the radar system can autotrack the
# nearest target.
# Every 0.1 seconde:
# [4] Computes HUD marker position and closure rate for the nearest target.
# Input properties: var ElapsedSec = props.globals.getNode("sim/time/elapsed-sec");
# ----------------- var DisplayRdr = props.globals.getNode("instrumentation/radar/display-rdr");
# instrumentation/radar/enabled (bool) (radar display) var AzField = props.globals.getNode("instrumentation/radar/az-field");
# instrumentation/ecm/enabled (bool) (RWR display) var RangeSelected = props.globals.getNode("instrumentation/radar/range-selected");
# At least one of these true. var RadarStandby = props.globals.getNode("instrumentation/radar/radar-standby");
# /instrumentation/radar/range : fixed limit to any computation (both radar and ECM/RWR) var RadarStandbyMP = props.globals.getNode("sim/multiplay/generic/int[2]");
# /instrumentation/radar/radar2-range : our own and current display range. var SwpMarker = props.globals.getNode("instrumentation/radar2/sweep-marker-norm", 1);
# TODO: /instrumentation/radar/symbols-enabled (bool) as we could also display raw spots on the screen. var SwpDisplayWidth = props.globals.getNode("instrumentation/radar2/sweep-width-m");
# /instrumentation/radar/radar-standby (int), shall be transmited via sim/multiplay/generic/int[2] var RngDisplayWidth = props.globals.getNode("instrumentation/radar2/range-width-m");
# (until we get a good definition of radar and related properties that could be added to the var PpiDisplayRadius = props.globals.getNode("instrumentation/radar2/radius-ppi-display-m");
# standard set of MP transmited parameters). With this property set to 1, your radar [1] is not var HudEyeDist = props.globals.getNode("instrumentation/radar2/hud-eye-dist-m");
# updated anymore but continue to show targets as they where before entering standby [2] it var HudRadius = props.globals.getNode("instrumentation/radar2/hud-radius-m");
# enter silent mode and do not trigger any alert on other players using a RWR. var HudTgtHDisplay = props.globals.getNode("instrumentation/radar2/hud/target-display", 1);
# /instrumentation/ecm/on-off (bool) (disable RWR computations) var HudTgt = props.globals.getNode("instrumentation/radar2/hud/target", 1);
var HudTgtTDev = props.globals.getNode("instrumentation/radar2/hud/target-total-deviation", 1);
var HudTgtTDeg = props.globals.getNode("instrumentation/radar2/hud/target-total-angle", 1);
var HudTgtClosureRate = props.globals.getNode("instrumentation/radar2/hud/closure-rate", 1);
var OurAlt = props.globals.getNode("position/altitude-ft");
var OurHdg = props.globals.getNode("orientation/heading-deg");
var OurRoll = props.globals.getNode("orientation/roll-deg");
var OurPitch = props.globals.getNode("orientation/pitch-deg");
var EcmOn = props.globals.getNode("instrumentation/ecm/on-off", 1);
var EcmAlert1 = props.globals.getNode("instrumentation/ecm/alert-type1", 1);
var EcmAlert2 = props.globals.getNode("instrumentation/ecm/alert-type2", 1);
# Output properties: var az_fld = AzField.getValue();
# ------------------ var l_az_fld = 0;
# /instrumentation/ecm/alert-type1 (bool) alert type 1: at least one weak scan detected. var r_az_fld = 0;
# /instrumentation/ecm/alert-type1 (bool) alert type 2: at least one strong scan detected. var swp_marker = nil; # Scan azimuth deviation, normalized (-1 --> 1).
# /ai/models/multiplayer[n]/radar/carrier (bool) var swp_deg = nil; # Scan azimuth deviation, in degree.
# /ai/models/multiplayer[n]/radar/display (bool) var swp_deg_last = 0; # Used to get sweep direction.
# /ai/models/multiplayer[n]/radar/ecm-signal (double) var swp_spd = 1.7;
# /ai/models/multiplayer[n]/radar/ecm-signal-norm (int) var swp_dir = nil; # Sweep direction, 0 to left, 1 to right.
# 0 = none, 1 = strong, 2 = weak, used as a translate prop in the xml animation. var swp_dir_last = 0;
# /ai/models/multiplayer[n]/radar/ecm_type_num (int) var swp_diplay_width = SwpDisplayWidth.getValue(); # Length of the max azimuth range on the screen.
# used for RWR which recognize and display the radar type # used for the B-scan display and sweep markers.
var rng_diplay_width = SwpDisplayWidth.getValue(); # Length of the max range vertical width on the
# screen. used for the B-scan display.
var ppi_diplay_radius = PpiDisplayRadius.getValue(); # Length of the radial size
# of the PPI like display.
var hud_eye_dist = HudEyeDist.getValue(); # Distance eye <-> HUD plane.
var hud_radius = HudRadius.getValue(); # Used to clamp the nearest target marker.
var range_radar2 = 0;
var my_radarcorr = 0;
var wcs_mode = "rws"; #FIXME should handled as properties choice, not harcoded.
var tmp_nearest_rng = nil;
var tmp_nearest_u = nil;
var nearest_rng = 0;
var nearest_u = nil;
var our_true_heading = 0;
var our_alt = 0;
var watch_i = 0;
var list_count = 0;
var radar_able = nil;
var ecm_able = nil;
var impact_able = nil;
var synbols_enabled = nil;
var my_radarcorr = 0;
var Mp = props.globals.getNode("ai/models"); var Mp = props.globals.getNode("ai/models");
var watch_list = []; var tgts_list = [];
var cnt = 0; # Counter used for the scan sweep pattern
# Our aircraft controls. var cnt_hud = 0; # Counter used for the HUD update
var OurRadarStandby = props.globals.getNode("instrumentation/radar/radar-standby", 1);
var RangeRadar = props.globals.getNode("instrumentation/radar/range");
var RangeRadar2 = props.globals.getNode("instrumentation/radar/radar2-range");
var EcmOn = props.globals.getNode("instrumentation/ecm/on-off", 1);
var OurAlt = props.globals.getNode("position/altitude-ft");
# ECM warnings. # ECM warnings.
var EcmAlert1 = props.globals.getNode("instrumentation/ecm/alert-type1", 1); var ecm_alert1 = 0;
var EcmAlert2 = props.globals.getNode("instrumentation/ecm/alert-type2", 1); var ecm_alert2 = 0;
var ecm_alert1 = 0; var ecm_alert1_last = 0;
var ecm_alert2 = 0; var ecm_alert2_last = 0;
var ecm_alert1_last = 0; var u_ecm_signal = 0;
var ecm_alert2_last = 0; var u_ecm_signal_norm = 0;
var u_radar_standby = 0;
var u_ecm_type_num = 0;
init = func() {
var init = func {
var our_ac_name = getprop("sim/aircraft"); var our_ac_name = getprop("sim/aircraft");
# Check which feature are enabled for our aircraft to avoid computing useless things. radardist.init();
radar_able = props.globals.getNode("instrumentation/radar/enabled").getValue(); my_radarcorr = radardist.my_maxrange( our_ac_name ); # Kilometers
ecm_able = props.globals.getNode("instrumentation/ecm/enabled").getValue();
# TODO: synbols_enabled = props.globals.getNode("instrumentation/radar/symbols_enabled"); settimer(rdr_loop, 0.5);
# Get our radar max range.
if (radar_able) {
my_radarcorr = radardist.my_maxrange( our_ac_name ); # in kilometers
}
if ( OurRadarStandby.getValue() == nil ) {
OurRadarStandby.setBoolValue(0);
}
} }
# Main loop ###############
# Main loop. var rdr_loop = func() {
var watch_aimp_models = func { var display_rdr = DisplayRdr.getBoolValue();
# Cycle through an ordered list of multiplayers and tankers. if ( display_rdr ) {
if ( watch_i == 0 ) { az_scan();
list_count = get_list(); } elsif ( size(tgts_list) > 0 ) {
foreach( u; tgts_list ) {
u.set_display(0);
}
} }
var target_type = watch_list[watch_i][0]; if (cnt_hud == 0.1) {
var target_index = watch_list[watch_i][1]; RadarStandbyMP.setIntValue(RadarStandby.getValue()); # Tell over MP if
var target_string = "ai/models/" ~ target_type ~ "[" ~ target_index ~ "]"; # our radar is scaning or is in stanby.
target_process( target_string ); hud_nearest_tgt();
if ( watch_i == ( list_count - 1 )) { cnt_hud = 0;
watch_i = 0;
} else { } else {
watch_i += 1; cnt_hud += 0.05;
} }
settimer(rdr_loop, 0.05);
} }
var az_scan = func() {
# Antena az scan.
var fld_frac = az_fld / 120;
var fswp_spd = swp_spd / fld_frac;
swp_marker = math.sin(cnt * fswp_spd) * fld_frac;
SwpMarker.setValue(swp_marker);
swp_deg = az_fld / 2 * swp_marker;
swp_dir = swp_deg < swp_deg_last ? 0 : 1;
if ( az_fld == nil ) { az_fld = 74 }
l_az_fld = - az_fld / 2;
r_az_fld = az_fld / 2;
var get_list = func { var fading_speed = 0.015;
watch_list = [];
var raw_list = Mp.getChildren();
foreach( var c; raw_list ) {
var type = c.getName();
# TODO: watch for AI carriers instead of only reconize mp-carriers.
if (type == "multiplayer" or type == "tanker") {
append(watch_list, [type, c.getIndex()]);
}
}
return size(watch_list);
}
our_true_heading = OurHdg.getValue();
our_alt = OurAlt.getValue();
if (swp_dir != swp_dir_last) {
# Antena scan direction change. Max every 2 seconds. Reads the whole MP_list.
# TODO: Transient move for the sweep marker when changing az scan field.
az_fld = AzField.getValue();
range_radar2 = RangeSelected.getValue();
if ( range_radar2 == 0 ) { range_radar2 = 0.00000001 }
# Reset nearest_range score
nearest_u = tmp_nearest_u;
nearest_rng = tmp_nearest_rng;
tmp_nearest_rng = nil;
tmp_nearest_u = nil;
tgts_list = [];
var raw_list = Mp.getChildren();
var target_process = func ( target ) { foreach( var c; raw_list ) {
var TNode = props.globals.getNode(target); # FIXME: At that time a multiplayer node may have been deleted while still
var TRadar = TNode.getNode("radar"); # existing as a displayable target in the radar targets nodes.
var TRadarStandby = TNode.getNode("sim/multiplay/generic/int[2]"); var type = c.getName();
# This propery used by ECM over MP should be standardized, if (!c.getNode("valid", 1).getValue()) {
# like "ai/models/multiplayer[0]/radar/radar-standby" continue;
var THeading = TNode.getNode("orientation/true-heading-deg");
var TInRange = TRadar.getNode("in-range");
if ( TInRange == nil ) { return }
var TCarrier = TRadar.getNode("carrier", 1);
var TDisplay = TRadar.getNode("display", 1);
var TEcmSignal = TRadar.getNode("ecm-signal", 1);
var TEcmSignalNorm = TRadar.getNode("ecm-signal-norm", 1);
var TEcmTypeNum = TRadar.getNode("ecm_type_num", 1);
# Set variables.
var t_carrier = 0;
var t_display = 0;
var t_ecm_signal = 0;
var t_ecm_signal_norm = 0;
var t_radar_standby = 0;
var t_ecm_type_num = 0;
if ( TRadarStandby != nil ) {
t_radar_standby = TRadarStandby.getValue();
if ( t_radar_standby == nil ) {
t_radar_standby = 0;
} elsif ( t_radar_standby != 1 ) {
t_radar_standby = 0;
}
}
var our_radar_standby = OurRadarStandby.getValue();
var t_in_range = TInRange.getValue();
if ( t_in_range ) {
var TPosition = TNode.getNode("position");
var TRange = TRadar.getNode("range-nm");
var t_range = TRange.getValue();
var TBearing = TRadar.getNode("bearing-deg");
var t_bearing = TBearing.getValue();
var TAlt = TPosition.getNode("altitude-ft");
var t_alt = TAlt.getValue();
var TDrawRangeNm = TRadar.getNode("draw-range-nm", 1);
var TRoundedAlt = TRadar.getNode("rounded-alt-ft", 1);
var t_heading = THeading.getValue();
var range_radar = RangeRadar.getValue();
var range_radar2 = 0;
if ( RangeRadar2 != nil ) { range_radar2 = RangeRadar2.getValue(); }
var TPath = TNode.getNode("sim/model/path");
var TACType = TNode.getNode("sim/model/ac-type");
if (( t_bearing == nil ) or ( t_alt == nil ) or ( TPath == nil )) {
return;
}
var t_ac_type = "none";
if ( TACType != nil ) { t_ac_type = TACType.getValue() }
if ( t_ac_type == "MP-Nimitz" or t_ac_type == "MP-Eisenhower") {
t_carrier = 1;
}
# TODO: add AWAKS and ATC.
var our_alt = OurAlt.getValue();
var horizon = radardist.radar_horizon( our_alt, t_alt );
# RADAR stuff.
# Check if mp within our radar field (hard coded 74°) and if detectable.
if ( radar_able and t_range <= range_radar2 and !our_radar_standby ) {
var true_heading = getprop("orientation/heading-deg");
var deviation_deg = deviation_normdeg(true_heading, t_bearing);
if ( deviation_deg > -37 and deviation_deg < 37 and radardist.radis(target, my_radarcorr) and t_range < horizon ) {
# Compute mp position in our radar display. (Horizontal situation)
if ( range_radar2 == 0 ) { range_radar2 = 0.00000001 }
var factor_range_radar = 0.15 / range_radar2;
var draw_radar = factor_range_radar * t_range;
TDrawRangeNm.setValue(draw_radar);
# Compute first digit of mp altitude rounded to nearest thousand. (labels).
var rounded_alt = rounding1000(t_alt) / 1000;
TRoundedAlt.setValue(rounded_alt);
t_display = 1;
} }
} var HaveRadarNode = c.getNode("radar");
# ECM/RWR stuff. if (type == "multiplayer" or type == "tanker" and HaveRadarNode != nil) {
# Test if target has a radar. Computes if we are illuminated. var u = Target.new(c);
ecm_on = EcmOn.getValue(); u_ecm_signal = 0;
if ( ecm_able and ecm_on and t_radar_standby == 0 ) { u_ecm_signal_norm = 0;
# TODO: overide display when alert. u_radar_standby = 0;
t_path = TPath.getValue(); u_ecm_type_num = 0;
var t_name = radardist.get_aircraft_name(target); if ( u.Range != nil) {
var t_maxrange = radardist.my_maxrange(t_name); # in kilometer, 0 is unknown or no radar. var u_rng = u.get_range();
if ( t_maxrange > 0 and t_range < horizon ) { if (u_rng < range_radar2 ) {
# Test if we are in its radar field (hard coded 74°) or if we have a carrier. u.get_deviation(our_true_heading);
# Compute the signal strength. if ( u.deviation > l_az_fld and u.deviation < r_az_fld ) {
var t_reciprocal_bearing = geo.normdeg(t_bearing + 180); append(tgts_list, u);
var our_deviation_deg = deviation_normdeg(t_heading, t_reciprocal_bearing); } else {
if ( our_deviation_deg < 0 ) { our_deviation_deg *= -1 } u.set_display(0);
if ( our_deviation_deg < 37 or t_carrier == 1 ) { }
t_ecm_signal = ( (((-our_deviation_deg/20)+2.5)*(!t_carrier )) + (-t_range/20) + 2.6 + (t_carrier*1.8)); } else {
t_ecm_type_num = radardist.get_ecm_type_num(t_name); u.set_display(0);
}
ecm_on = EcmOn.getBoolValue();
# Test if target has a radar. Compute if we are illuminated. This propery used by ECM
# over MP, should be standardized, like "ai/models/multiplayer[0]/radar/radar-standby".
if ( ecm_on) {
rwr(u); # TODO: override display when alert.
}
} }
} }
# Compute global threat situation for undiscriminant warning lights
# and discrete (normalized) definition of threat strength.
if ( t_ecm_signal > 1 and t_ecm_signal < 3 ) {
EcmAlert1.setBoolValue(1);
ecm_alert1 = 1;
t_ecm_signal_norm = 2;
} elsif ( t_ecm_signal >= 3 ) {
EcmAlert2.setBoolValue(1);
ecm_alert2 = 1;
t_ecm_signal_norm = 1;
}
} }
}
# Outputs: # Summarize ECM alerts.
if ( ! our_radar_standby ) {
# If stanby: stop updating but do not erase targets positions.
TCarrier.setBoolValue(t_carrier);
TDisplay.setBoolValue(t_display);
}
if ( watch_i == 0 ) {
if ( ecm_alert1 == 0 and ecm_alert1_last == 0 ) { EcmAlert1.setBoolValue(0) } if ( ecm_alert1 == 0 and ecm_alert1_last == 0 ) { EcmAlert1.setBoolValue(0) }
if ( ecm_alert2 == 0 and ecm_alert1_last == 0 ) { EcmAlert2.setBoolValue(0) } if ( ecm_alert2 == 0 and ecm_alert1_last == 0 ) { EcmAlert2.setBoolValue(0) }
# Avoid alert blinking at each loop. ecm_alert1_last = ecm_alert1; # And avoid alert blinking at each loop.
ecm_alert1_last = ecm_alert1;
ecm_alert2_last = ecm_alert2; ecm_alert2_last = ecm_alert2;
ecm_alert1 = 0; ecm_alert1 = 0;
ecm_alert2 = 0; ecm_alert2 = 0;
}
foreach( u; tgts_list ) {
var u_display = 0;
var u_fading = u.get_fading() - fading_speed;
if ( u_fading < 0 ) { u_fading = 0 }
if (( swp_dir and swp_deg_last < u.deviation and u.deviation <= swp_deg )
or ( ! swp_dir and swp_deg <= u.deviation and u.deviation < swp_deg_last )) {
u.get_bearing();
u.get_heading();
var horizon = u.get_horizon( our_alt );
var u_rng = u.get_range();
if ( u_rng < horizon and radardist.radis(u.string, my_radarcorr)) {
# Compute mp position in our B-scan like display. (Bearing/horizontal + Range/Vertical).
u.set_relative_bearing( swp_diplay_width / az_fld * u.deviation );
var factor_range_radar = rng_diplay_width / range_radar2; # Length of the distance range on the B-scan screen.
u.set_ddd_draw_range_nm( factor_range_radar * u_rng );
u_fading = 1;
u_display = 1;
# Compute mp position in our PPI like display.
factor_range_radar = ppi_diplay_radius / range_radar2; # Length of the radius range on the PPI like screen.
u.set_tid_draw_range_nm( factor_range_radar * u_rng );
# Compute first digit of mp altitude rounded to nearest thousand. (labels).
u.set_rounded_alt( rounding1000( u.get_altitude() ) / 1000 );
# Compute closure rate in Kts.
u.get_closure_rate();
# Check if u = nearest echo.
if ( tmp_nearest_rng == nil or u_rng < tmp_nearest_rng) {
tmp_nearest_u = u;
tmp_nearest_rng = u_rng;
}
}
u.set_display(u_display);
}
u.set_fading(u_fading);
} }
TEcmSignal.setValue(t_ecm_signal); swp_deg_last = swp_deg;
TEcmSignalNorm.setIntValue(t_ecm_signal_norm); swp_dir_last = swp_dir;
TEcmTypeNum.setIntValue(t_ecm_type_num); cnt += 0.05;
}
var hud_nearest_tgt = func() {
# Computes nearest_u position in the HUD
if ( nearest_u != nil ) {
if ( wcs_mode == "tws-auto" and nearest_u.get_display() and nearest_u.deviation > l_az_fld and nearest_u.deviation < r_az_fld ) {
var u_target = nearest_u.type ~ "[" ~ nearest_u.index ~ "]";
var our_pitch = OurPitch.getValue();
var u_dev_rad = (90 - nearest_u.get_deviation(our_true_heading)) * D2R;
var u_elev_rad = (90 - nearest_u.get_total_elevation(our_pitch)) * D2R;
# Deviation length on the HUD (at level flight), 0.6686m = distance eye <-> virtual HUD screen.
var h_dev = 0.6686 / ( math.sin(u_dev_rad) / math.cos(u_dev_rad) );
var v_dev = 0.6686 / ( math.sin(u_elev_rad) / math.cos(u_elev_rad) );
# Angle between HUD center/top <-> HUD center/target position.
# -90° left, 0° up, 90° right, +/- 180° down.
var dev_deg = math.atan2( h_dev, v_dev ) * R2D;
# Correction with own a/c roll.
var combined_dev_deg = dev_deg - OurRoll.getValue();
# Lenght HUD center <-> target pos on the HUD:
var combined_dev_length = math.sqrt((h_dev*h_dev)+(v_dev*v_dev));
# Clamp so the target follow the HUD limits.
if ( combined_dev_length > hud_radius ) {
combined_dev_length = hud_radius;
Clamp_Blinker.blink();
} else {
Clamp_Blinker.cont();
}
# Clamp closure rate from -200 to +1,000 Kts.
var cr = nearest_u.ClosureRate.getValue();
if (cr < -200) { cr = 200 } elsif (cr > 1000) { cr = 1000 }
HudTgtClosureRate.setValue(cr);
HudTgtTDeg.setValue(combined_dev_deg);
HudTgtTDev.setValue(combined_dev_length);
HudTgtHDisplay.setBoolValue(1);
HudTgt.setValue(u_target);
return;
}
}
HudTgtClosureRate.setValue(0);
HudTgtTDeg.setValue(0);
HudTgtTDev.setValue(0);
HudTgtHDisplay.setBoolValue(0);
}
# HUD clamped target blinker
Clamp_Blinker = aircraft.light.new("instrumentation/radar2/hud/target-clamped-blinker", [0.1, 0.1]);
setprop("instrumentation/radar2/hud/target-clamped-blinker/enabled", 1);
# ECM: Radar Warning Receiver
rwr = func(u) {
var u_name = radardist.get_aircraft_name(u.string);
var u_maxrange = radardist.my_maxrange(u_name); # in kilometer, 0 is unknown or no radar.
var horizon = u.get_horizon( our_alt );
var u_rng = u.get_range();
var u_carrier = u.check_carrier_type();
if ( u.get_rdr_standby() == 0 and u_maxrange > 0 and u_rng < horizon ) {
# Test if we are in its radar field (hard coded 74°) or if we have a MPcarrier.
# Compute the signal strength.
var our_deviation_deg = deviation_normdeg(u.get_heading(), u.get_reciprocal_bearing());
if ( our_deviation_deg < 0 ) { our_deviation_deg *= -1 }
if ( our_deviation_deg < 37 or u_carrier == 1 ) {
u_ecm_signal = (((-our_deviation_deg/20)+2.5)*(!u_carrier )) + (-u_rng/20) + 2.6 + (u_carrier*1.8);
u_ecm_type_num = radardist.get_ecm_type_num(u_name);
}
} else {
u_ecm_signal = 0;
}
# Compute global threat situation for undiscriminant warning lights
# and discrete (normalized) definition of threat strength.
if ( u_ecm_signal > 1 and u_ecm_signal < 3 ) {
EcmAlert1.setBoolValue(1);
ecm_alert1 = 1;
u_ecm_signal_norm = 2;
} elsif ( u_ecm_signal >= 3 ) {
EcmAlert2.setBoolValue(1);
ecm_alert2 = 1;
u_ecm_signal_norm = 1;
}
u.EcmSignal.setValue(u_ecm_signal);
u.EcmSignalNorm.setIntValue(u_ecm_signal_norm);
u.EcmTypeNum.setIntValue(u_ecm_type_num);
} }
# Utilities. # Utilities.
var deviation_normdeg = func(our_heading, target_bearing) { var deviation_normdeg = func(our_heading, target_bearing) {
var dev_norm = our_heading - target_bearing; var dev_norm = our_heading - target_bearing;
while (dev_norm < -180) dev_norm += 360; while (dev_norm < -180) dev_norm += 360;
while (dev_norm > 180) dev_norm -= 360; while (dev_norm > 180) dev_norm -= 360;
return(dev_norm); return(dev_norm);
} }
var rounding1000 = func(n) { var rounding1000 = func(n) {
var a = int( n / 1000 ); var a = int( n / 1000 );
var l = ( a + 0.5 ) * 1000; var l = ( a + 0.5 ) * 1000;
@ -261,4 +332,221 @@ var rounding1000 = func(n) {
return( n ); return( n );
} }
# Controls
var radar_range_control = func(n) {
# FIXME: Radar props should provide their own ranges instead of being hardcoded.
# 5, 10, 20, 50, 100, 200
var range_radar = RangeSelected.getValue();
if ( n == 1 ) {
if ( range_radar == 5 ) {
range_radar = 10;
} elsif ( range_radar == 10 ) {
range_radar = 20;
} elsif ( range_radar == 20 ) {
range_radar = 50;
} elsif ( range_radar == 50 ) {
range_radar = 100;
} else {
range_radar = 150;
}
} else {
if ( range_radar == 150 ) {
range_radar = 100;
} elsif ( range_radar == 100 ) {
range_radar = 50;
} elsif ( range_radar == 50 ) {
range_radar = 20;
} elsif ( range_radar == 20 ) {
range_radar = 10;
} else {
range_radar = 5;
}
}
RangeSelected.setValue(range_radar);
}
radar_mode_sel = func(mode) {
# FIXME: Modes props should provide their own data instead of being hardcoded.
foreach (var n; props.globals.getNode("instrumentation/radar/mode").getChildren()) {
n.setBoolValue(n.getName() == mode);
wcs_mode = mode;
}
if ( wcs_mode == "rws" ) {
AzField.setValue(120);
swp_diplay_width = 0.0844;
} else {
AzField.setValue(60);
swp_diplay_width = 0.0422;
}
}
radar_mode_toggle = func() {
# FIXME: Modes props should provide their own data instead of being hardcoded.
# Toggles between the available modes.
foreach (var n; props.globals.getNode("instrumentation/radar/mode").getChildren()) {
if ( n.getBoolValue() ) { wcs_mode = n.getName() }
}
if ( wcs_mode == "rws" ) {
setprop("instrumentation/radar/mode/rws", 0);
setprop("instrumentation/radar/mode/tws-auto", 1);
wcs_mode = "tws-auto";
AzField.setValue(60);
swp_diplay_width = 0.0422;
} elsif ( wcs_mode == "tws-auto" ) {
setprop("instrumentation/radar/mode/tws-auto", 0);
setprop("instrumentation/radar/mode/rws", 1);
wcs_mode = "pulse-srch";
AzField.setValue(120);
swp_diplay_width = 0.0844;
}
}
setlistener("sim/signals/fdm-initialized", init);
# Target class
var Target = {
new : func (c) {
var obj = { parents : [Target]};
obj.RdrProp = c.getNode("radar");
obj.Heading = c.getNode("orientation/true-heading-deg");
obj.Alt = c.getNode("position/altitude-ft");
obj.AcType = c.getNode("sim/model/ac-type");
obj.type = c.getName();
obj.index = c.getIndex();
obj.string = "ai/models/" ~ obj.type ~ "[" ~ obj.index ~ "]";
obj.shortstring = obj.type ~ "[" ~ obj.index ~ "]";
obj.InstrTgts = props.globals.getNode("instrumentation/radar2/targets", 1);
obj.TgtsFiles = obj.InstrTgts.getNode(obj.shortstring, 1);
obj.Range = obj.RdrProp.getNode("range-nm");
obj.Bearing = obj.RdrProp.getNode("bearing-deg");
obj.Elevation = obj.RdrProp.getNode("elevation-deg");
obj.BBearing = obj.TgtsFiles.getNode("bearing-deg", 1);
obj.BHeading = obj.TgtsFiles.getNode("true-heading-deg", 1);
obj.RangeScore = obj.TgtsFiles.getNode("range-score", 1);
obj.RelBearing = obj.TgtsFiles.getNode("ddd-relative-bearing", 1);
obj.Carrier = obj.TgtsFiles.getNode("carrier", 1);
obj.EcmSignal = obj.TgtsFiles.getNode("ecm-signal", 1);
obj.EcmSignalNorm = obj.TgtsFiles.getNode("ecm-signal-norm", 1);
obj.EcmTypeNum = obj.TgtsFiles.getNode("ecm_type_num", 1);
obj.Display = obj.TgtsFiles.getNode("display", 1);
obj.Fading = obj.TgtsFiles.getNode("ddd-echo-fading", 1);
obj.DddDrawRangeNm = obj.TgtsFiles.getNode("ddd-draw-range-nm", 1);
obj.TidDrawRangeNm = obj.TgtsFiles.getNode("tid-draw-range-nm", 1);
obj.RoundedAlt = obj.TgtsFiles.getNode("rounded-alt-ft", 1);
obj.TimeLast = obj.TgtsFiles.getNode("closure-last-time", 1);
obj.RangeLast = obj.TgtsFiles.getNode("closure-last-range-nm", 1);
obj.ClosureRate = obj.TgtsFiles.getNode("closure-rate-kts", 1);
obj.TimeLast.setValue(ElapsedSec.getValue());
if ( obj.Range != nil) {
obj.RangeLast.setValue(obj.Range.getValue());
} else {
obj.RangeLast.setValue(0);
}
obj.RadarStandby = c.getNode("sim/multiplay/generic/int[2]");
obj.deviation = nil;
return obj;
},
get_heading : func {
var n = me.Heading.getValue();
me.BHeading.setValue(n);
return n;
},
get_bearing : func {
var n = me.Bearing.getValue();
me.BBearing.setValue(n);
return n;
},
set_relative_bearing : func(n) {
me.RelBearing.setValue(n);
},
get_reciprocal_bearing : func {
return geo.normdeg(me.get_bearing() + 180);
},
get_deviation : func(true_heading_ref) {
me.deviation = - deviation_normdeg(true_heading_ref, me.get_bearing());
return me.deviation;
},
get_altitude : func {
return me.Alt.getValue();
},
get_total_elevation : func(own_pitch) {
me.deviation = - deviation_normdeg(own_pitch, me.Elevation.getValue());
return me.deviation;
},
get_range : func {
return me.Range.getValue();
},
get_horizon : func(own_alt) {
var tgt_alt = me.get_altitude();
if ( tgt_alt != nil ) {
if ( own_alt < 0 ) { own_alt = 0.001 }
if ( debug.isnan(tgt_alt)) {
return(0);
}
if ( tgt_alt < 0 ) { tgt_alt = 0.001 }
return radardist.radar_horizon( own_alt, tgt_alt );
} else {
return(0);
}
},
check_carrier_type : func {
var type = "none";
var carrier = 0;
if ( me.AcType != nil ) { type = me.AcType.getValue() }
if ( type == "MP-Nimitz" or type == "MP-Eisenhower" or type == "MP-Vinson") { carrier = 1 }
# This works only after the mp-carrier model has been loaded. Before that it is seen like a common aircraft.
me.Carrier.setBoolValue(carrier);
return carrier;
},
get_rdr_standby : func {
var s = 0;
if ( me.RadarStandby != nil ) {
s = me.RadarStandby.getValue();
if (s == nil) { s = 0 } elsif (s != 1) { s = 0 }
}
return s;
},
get_display : func() {
return me.Display.getValue();
},
set_display : func(n) {
me.Display.setBoolValue(n);
},
get_fading : func() {
var fading = me.Fading.getValue();
if ( fading == nil ) { fading = 0 }
return fading;
},
set_fading : func(n) {
me.Fading.setValue(n);
},
set_ddd_draw_range_nm : func(n) {
me.DddDrawRangeNm.setValue(n);
},
set_hud_draw_horiz_dev : func(n) {
me.HudDrawHorizDev.setValue(n);
},
set_tid_draw_range_nm : func(n) {
me.TidDrawRangeNm.setValue(n);
},
set_rounded_alt : func(n) {
me.RoundedAlt.setValue(n);
},
get_closure_rate : func() {
var dt = ElapsedSec.getValue() - me.TimeLast.getValue();
var rng = me.Range.getValue();
var t_distance = me.RangeLast.getValue() - rng;
var cr = t_distance/dt*3600;
me.ClosureRate.setValue(cr);
me.RangeLast.setValue(rng);
return(cr);
},
list : [],
};