diff --git a/Aircraft/Instruments-3d/rwr/rwr.nas b/Aircraft/Instruments-3d/rwr/rwr.nas
new file mode 100644
index 000000000..adbdfcf9b
--- /dev/null
+++ b/Aircraft/Instruments-3d/rwr/rwr.nas
@@ -0,0 +1,220 @@
+# Radar2 and RWR routines.
+
+# Alexis Bory (xiii)
+
+# Every 0.05 seconde:
+# [1] Scans /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 signal values
+#     are writen under /instrumentation/radar2/targets for interoperabilty purposes.
+# [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 for the nearest target.
+
+var OurAlt            = props.globals.getNode("position/altitude-ft");
+var OurHdg            = props.globals.getNode("orientation/heading-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);
+
+var our_alt           = 0;
+var Mp = props.globals.getNode("ai/models");
+var tgts_list         = [];
+var ecm_alert1        = 0;
+var ecm_alert2        = 0;
+var ecm_alert1_last   = 0;
+var ecm_alert2_last   = 0;
+var u_ecm_signal      = 0;
+var u_ecm_signal_norm = 0;
+var u_radar_standby   = 0;
+var u_ecm_type_num    = 0;
+
+init = func() {
+	radardist.init();
+	settimer(rwr_loop, 0.5);
+}
+
+# Main loop ###############
+var rwr_loop = func() {
+	ecm_on = EcmOn.getBoolValue();
+	if ( ecm_on) {
+		our_alt = OurAlt.getValue();
+		tgts_list = [];
+		var raw_list = Mp.getChildren();
+		foreach( var c; raw_list ) {
+			var type = c.getName();
+			if (!c.getNode("valid", 1).getValue()) {
+				continue;
+			}
+			var HaveRadarNode = c.getNode("radar");
+			if (type == "multiplayer" or type == "tanker" and HaveRadarNode != nil) {
+				var u = Threat.new(c);
+				u_ecm_signal      = 0;
+				u_ecm_signal_norm = 0;
+				u_radar_standby   = 0;
+				u_ecm_type_num    = 0;
+				if ( u.Range != nil) {
+					# 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".
+					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);
+				}
+			}
+		}
+
+		# Summarize ECM alerts.
+		if ( ecm_alert1 == 0 and ecm_alert1_last == 0 ) { EcmAlert1.setBoolValue(0) }
+		if ( ecm_alert2 == 0 and ecm_alert1_last == 0 ) { EcmAlert2.setBoolValue(0) }
+		ecm_alert1_last = ecm_alert1; # And avoid alert blinking at each loop.
+		ecm_alert2_last = ecm_alert2;
+		ecm_alert1 = 0;
+		ecm_alert2 = 0;
+	} elsif ( size(tgts_list) > 0 ) {
+		foreach( u; tgts_list ) {
+			u.EcmSignal.setValue(0);
+			u.EcmSignalNorm.setIntValue(0);
+			u.EcmTypeNum.setIntValue(0);
+		}
+	}
+	settimer(rwr_loop, 0.05);
+}
+
+
+
+# Utilities.
+var deviation_normdeg = func(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;
+	return(dev_norm);
+}
+
+
+setlistener("sim/signals/fdm-initialized", init);
+
+# Target class
+var Threat = {
+	new : func (c) {
+		var obj = { parents : [Threat]};
+		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.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_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;
+	},
+	list : [],
+};
+
+