radar2.nas 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237
  1. print("*** LOADING radar2.nas ... ***");
  2. ################################################################################
  3. #
  4. # m2005-5's RADAR SETTINGS
  5. #
  6. ################################################################################
  7. # Radar
  8. # Fabien BARBIER (5H1N0B1) September 2015
  9. # inspired by Alexis Bory (xiii)
  10. #var UPDATE_PERIOD = 0.1; # update interval for engine init() functions
  11. var ElapsedSec = props.globals.getNode("sim/time/elapsed-sec");
  12. var wcs_mode = "rws" ; # FIXME should handled as properties choice, not harcoded.
  13. var tmp_nearest_rng = nil;
  14. var tmp_nearest_u = nil;
  15. var nearest_rng = 0;
  16. var nearest_u = nil;
  17. var missileIndex = 0;
  18. var MytargetVariable = nil;
  19. var completeList = [];
  20. var tempo = nil;
  21. #var LoopElapsed =0;
  22. #This is done for detecting a terrain between aircraft and target. Since 2017.2.1, a new method allow to do the same, faster, and with more precision. (See isNotBehindTerrain function)
  23. var versionString = getprop("sim/version/flightgear");
  24. var version = split(".", versionString);
  25. var major = num(version[0]);
  26. var minor = num(version[1]);
  27. var pica = num(version[2]);
  28. var pickingMethod = 0;
  29. if ((major == 2017 and minor == 2 and pica >= 1) or (major == 2017 and minor > 2) or major > 2017) {
  30. pickingMethod = 1;
  31. }
  32. #print("Version is "~ versionString ~ " So Picking method : "~pickingMethod);
  33. var weaponRadarNames = {
  34. #
  35. # this should match weaponNames in ext_stores.nas
  36. # Its a list of folders inside ai/models that has weapons.
  37. #
  38. "AGM65": nil,
  39. "AIM-54": nil,
  40. "aim-7": nil,
  41. "aim-9": nil,
  42. "AIM120": nil,
  43. "GBU12": nil,
  44. "GBU16": nil,
  45. "MATRA-R530": nil,
  46. "MatraMica": nil,
  47. "MatraMicaIR": nil,
  48. "MatraR550Magic2": nil,
  49. "Meteor": nil,
  50. "R74": nil,
  51. "SCALP": nil,
  52. "SeaEagle": nil,
  53. "Exocet": nil,
  54. };
  55. listOfGroundTargetNames = ["groundvehicle"];
  56. listOfShipNames = ["carrier", "ship"];
  57. listOfAIRadarEchoes = ["multiplayer", "tanker", "aircraft", "carrier", "ship", "missile", "groundvehicle", "Mig-28", "F-16"];
  58. listOfAIRadarEchoes2 = keys(weaponRadarNames);
  59. listOfGroundVehicleModels = ["buk-m2", "MIM104D", "depot", "truck", "tower", "germansemidetached1","GROUND_TARGET"];
  60. #listOfGroundVehicleModels = ["GROUND_TARGET"];
  61. listOfShipModels = ["frigate", "missile_frigate", "USS-LakeChamplain", "USS-NORMANDY", "USS-OliverPerry", "USS-SanAntonio"];
  62. #
  63. listOfShipModels_hash = {
  64. "carrier":"MARINE",
  65. "ship" :"MARINE",
  66. "frigate":"MARINE",
  67. "missile_frigate":"MARINE",
  68. "USS-LakeChamplain":"MARINE",
  69. "USS-NORMANDY":"MARINE",
  70. "USS-OliverPerry":"MARINE",
  71. "USS-SanAntonio":"MARINE",
  72. "san_antonio":"MARINE",
  73. "oliver_perry":"MARINE",
  74. "normandy":"MARINE",
  75. "lake_champlain":"MARINE",
  76. };
  77. listOfGroundTargetNames_hash = {
  78. "groundvehicle":armament.SURFACE,
  79. "buk-m2":armament.SURFACE,
  80. "MIM104D":armament.SURFACE,
  81. "depot":armament.SURFACE,
  82. "truck":armament.SURFACE,
  83. "tower":armament.SURFACE,
  84. "germansemidetached1":armament.SURFACE,
  85. "GROUND_TARGET":armament.SURFACE,
  86. "Mig-28":armament.AIR,
  87. "F-16":armament.AIR,
  88. };
  89. var shouldHaveRadarNodearray = ["tanker","aircraft","missile"];
  90. #
  91. #WTF ?
  92. foreach(var addMe ; listOfAIRadarEchoes2) {
  93. append(listOfAIRadarEchoes, addMe);
  94. }
  95. var scan_update_tgt_list = 1;
  96. # use listeners to define when to update the radar return list.
  97. setlistener("/ai/models/model-added", func(v){
  98. if (!scan_update_tgt_list) {
  99. scan_update_tgt_list = 1;
  100. }
  101. });
  102. setlistener("/ai/models/model-removed", func(v){
  103. if (!scan_update_tgt_list) {
  104. scan_update_tgt_list = 1;
  105. }
  106. });
  107. var extraUpdate = func {
  108. # need this to get targets type reevaluated once in a while.
  109. scan_update_tgt_list = 1;
  110. settimer(extraUpdate,7.5);
  111. }
  112. extraUpdate();
  113. var link16_array = [];
  114. var updatelink16 = func(){
  115. #print("Link16");
  116. link16_array = [];
  117. var mylink16 = props.globals.getNode("/link16");
  118. if(mylink16 != nil){
  119. var mylink16_raw_list = mylink16.getChildren();
  120. foreach(var callsign_Ally ; mylink16_raw_list)
  121. {
  122. append(link16_array,callsign_Ally.getValue());
  123. #print("Toto:"~callsign_Ally.getValue());
  124. }
  125. }
  126. mirage2000.myRadar3.ContactsList = [];
  127. mirage2000.myRadar3.tgts_list = [];
  128. mirage2000.myRadar3.Target_Index = -1;
  129. #settimer(updatelink16,60);
  130. }
  131. #settimer(updatelink16,10);
  132. # radar : check : InRange, inAzimuth, inElevation, NotBeyondHorizon, doppler, isNotBehindTerrain
  133. # rwr : check : InhisRange (radardist), inHisElevation, inHisAzimuth, NotBeyondHorizon, isNotBehindTerrain
  134. # heat : check : InRange, inAzimuth, inElevation, NotBeyondHorizon, heat_sensor, isNotBehindTerrain
  135. # laser : check : InRange, inAzimuth, inElevation, NotBeyondHorizon, isNotBehindTerrain
  136. # cam : check : InRange, inAzimuth, inElevation, NotBeyondHorizon, isNotBehindTerrain
  137. # transponder : check : radar, transponderOn (not yet implemented)
  138. #var Mp = props.globals.getNode("ai/models");
  139. # radar class
  140. var Radar = {
  141. new: func(
  142. NewRangeTab = nil, # array with all the different possible range
  143. NewRangeIndex = nil, # range indexshould not be greater than NewRangeTab
  144. NewTypeTarget = nil, # array of different kind of object that can be seen.
  145. NewRadarType = nil, # array that indicate wich type of detector we have "radar","laser",
  146. NewshowAI = nil, # show or not AI. (It will be depreciated)
  147. NewUnfocused_az_fld = nil, # total angle of radar
  148. Newfocused_az_fld = nil, # total angle of focused radar
  149. NewFieldAzimuthCenter = nil, # 0-360.For rear radar. 0 is the default value.
  150. NewVerticalAzimuth = nil, # 0-180
  151. NewhaveSweep = nil, # boolean 1 or 0. Has a Sweep or not
  152. NewHaveDoppler = nil, # boolean 1 or 0. Has a Doppler or not
  153. newDopplerSpeedLimit = nil, # value in kts. This the min speed a doppler radar can detect. the less it is, more your doppler radar is recent and precise
  154. NewMyTimeLimit = nil,
  155. NewJanitorTime = nil, # time a target will disapear from the radar
  156. NewAutoUpdate = nil, # boolean 1 or 0. When to 1, it runs the update function in the init loop.
  157. NewElectricalPath = nil, # path of the property that allow the radar to be feed by electricity
  158. path = nil, # general path of the radar. it where we should have multiple targets array, targets[0], targets[1] where the number is the number of detection means present on the aircraft
  159. forcePath = nil, # force the full tree. That prevent to use targets[1] when targets[0] is existing already.
  160. NewSourcePath = nil)
  161. {
  162. # if we want to use a different source than AI
  163. var m = { parents : [Radar,RadarTool] };
  164. # variable that can be passed in parameters
  165. m.rangeTab = (NewRangeTab == nil) ? [10, 20, 40, 60, 160] : NewRangeTab; # radar Ranges in nm
  166. m.rangeIndex = (NewRangeIndex == nil) ? 0 : math.mod(NewRangeIndex, size(m.rangeTab)); # tab starts at index 1 so here it's 20
  167. m.HaveDoppler = (NewHaveDoppler == nil) ? 1 : NewHaveDoppler;
  168. m.DopplerSpeedLimit = (newDopplerSpeedLimit == nil) ? 50 : newDopplerSpeedLimit; # in Knot
  169. m.MyTimeLimit = (NewMyTimeLimit == nil) ? 2 : NewMyTimeLimit; # in seconds
  170. m.janitorTime = (NewJanitorTime == nil) ? 5 : NewJanitorTime;
  171. m.haveSweep = (NewhaveSweep == nil) ? 1 : NewhaveSweep;
  172. m.typeTarget = (NewTypeTarget == nil) ? listOfAIRadarEchoes : NewTypeTarget;
  173. m.showAI = (NewshowAI == nil) ? 1 : NewshowAI;
  174. m.radarHeading = 0; # in this we fix the radar position in the nose. We will change it to make rear radar or RWR etc
  175. m.unfocused_az_fld = (NewUnfocused_az_fld == nil) ? 120 : NewUnfocused_az_fld;
  176. m.focused_az_fld = (Newfocused_az_fld == nil) ? 60 : Newfocused_az_fld;
  177. m.vt_az_fld = (NewVerticalAzimuth == nil) ? 120 : NewVerticalAzimuth;
  178. m.fieldazCenter = (NewFieldAzimuthCenter == nil) ? 0 : NewFieldAzimuthCenter;
  179. m.AutoUpdate = (NewAutoUpdate == nil) ? 1 : NewAutoUpdate;
  180. # m.ElectricalPath = (NewElectricalPath == nil) ? "/systems/electrical/outputs/radar" : NewElectricalPath;
  181. m.detectionTypetab = (NewRadarType == nil) ? "radar" : NewRadarType; # old : m.detectionTypetab = ["radar","laser"];
  182. m.source = (NewSourcePath == nil) ? "ai/models" : NewSourcePath;
  183. m.Mp = props.globals.getNode(m.source);
  184. #m.detectionTypeIndex = 0;
  185. # variables that need to be initialised
  186. m.loop_running = 0;
  187. m.LoopElapsed = 0;
  188. m.MyCoord = geo.aircraft_position(); # this is when the radar is on our own aircraft. This part have to change if we want to put the radar on a missile/AI
  189. m.az_fld = m.unfocused_az_fld;
  190. #m.vt_az_fld = m.az_fld;
  191. m.raw_selection = [];
  192. # for Target Selection
  193. m.tgts_list = [];
  194. m.ContactsList = [];
  195. m.Target_Index = -1 ; # for Target Selection
  196. m.Target_Callsign = nil;
  197. m.radarMaxSize = 20;
  198. m.selectedArmament= nil; #Actually useless : The idea is to allow the radar to occult everything that is not for the current loaded weapon
  199. # source behavior
  200. m.OurHdg = 0;
  201. m.OurPitch = 0;
  202. m.our_alt = 0;
  203. m.Check_List = [];
  204. m.TimeWhenUpdate = 0;
  205. # sweep : if have no sweep, we do not have to call internal very specific properties (This is one of the last part to tune)
  206. m.SwpMarker = 0;
  207. m.sweep_frequency = 0;
  208. m.SwpDisplayWidth = 0;
  209. m.PpiDisplayRadius =0;
  210. m.swp_diplay_width = 0;
  211. m.rng_diplay_width = 0;
  212. m.ppi_diplay_radius = 0;
  213. m.isdeleting = 0;
  214. m.tempo_Index = 0;
  215. if(m.haveSweep == 1)
  216. {
  217. m.sweepProperty = "instrumentation/radar2/sweep-marker-norm";
  218. m.sweep_frequency = m.MyTimeLimit / 4; # in seconds
  219. m.SwpDisplayWidth = props.globals.getNode("instrumentation/radar2/sweep-width-m");
  220. m.PpiDisplayRadius = props.globals.getNode("instrumentation/radar2/radius-ppi-display-m");
  221. m.swp_diplay_width = m.SwpDisplayWidth.getValue(); # length of the max azimuth range on the screen
  222. m.rng_diplay_width = m.SwpDisplayWidth.getValue(); # length of the max range vertical width on the
  223. m.ppi_diplay_radius = m.PpiDisplayRadius.getValue(); # length of the radial size
  224. }
  225. # separate each "targets" Properties in case of multidetection systems
  226. m.tree = (path == nil) ? "instrumentation/radar2/" : path;
  227. var n = props.globals.getNode(m.tree, 1);
  228. for(var i = 0 ; 1 ; i += 1)
  229. {
  230. if(n.getChild("targets", i, 0) == nil)
  231. {
  232. break;
  233. }
  234. }
  235. m.myTree = forcePath==nil?n.getChild("targets", i, 1):props.globals.getNode(forcePath, 1);
  236. m.UseATree = 1;
  237. #print(m.myTree.getPath());
  238. # update interval for engine init() functions
  239. m.updating_now = 0;
  240. m.UPDATE_PERIOD = 0.05;
  241. #Some are not need there
  242. m.input = {
  243. pitch: "/orientation/pitch-deg",
  244. roll: "/orientation/roll-deg",
  245. hdg: "/orientation/heading-magnetic-deg",
  246. hdgReal: "/orientation/heading-deg",
  247. hdgBug: "/autopilot/settings/heading-bug-deg",
  248. hdgDisplay: "/instrumentation/efis/mfd/true-north",
  249. speed_n: "velocities/speed-north-fps",
  250. speed_e: "velocities/speed-east-fps",
  251. speed_d: "velocities/speed-down-fps",
  252. alpha: "/orientation/alpha-deg",
  253. beta: "/orientation/side-slip-deg",
  254. gload: "/accelerations/pilot-g",
  255. ias: "/velocities/airspeed-kt",
  256. mach: "/velocities/mach",
  257. gs: "/velocities/groundspeed-kt",
  258. vs: "/velocities/vertical-speed-fps",
  259. alt: "/position/altitude-ft",
  260. alt_instru: "/instrumentation/altimeter/indicated-altitude-ft",
  261. rad_alt: "position/altitude-agl-ft", #"/instrumentation/radar-altimeter/radar-altitude-ft",
  262. wow_nlg: "/gear/gear[1]/wow",
  263. gearPos: "/gear/gear[1]/position-norm",
  264. airspeed: "/velocities/airspeed-kt",
  265. target_spd: "/autopilot/settings/target-speed-kt",
  266. acc: "/fdm/jsbsim/accelerations/udot-ft_sec2",
  267. acc_yas: "/fdm/yasim/accelerations/a-x",
  268. NavFreq: "/instrumentation/nav/frequencies/selected-mhz",
  269. destRunway: "/autopilot/route-manager/destination/runway",
  270. destAirport:"/autopilot/route-manager/destination/airport",
  271. distNextWay:"/autopilot/route-manager/wp/dist",
  272. NextWayNum :"/autopilot/route-manager/current-wp",
  273. NextWayTrueBearing:"/autopilot/route-manager/wp/true-bearing-deg",
  274. NextWayBearing:"/autopilot/route-manager/wp/bearing-deg",
  275. AutopilotStatus:"/autopilot/locks/AP-status",
  276. currentWp : "/autopilot/route-manager/current-wp",
  277. ILS_valid :"/instrumentation/nav/data-is-valid",
  278. NavHeadingRunwayILS:"/instrumentation/nav/heading-deg",
  279. ILS_gs_in_range :"/instrumentation/nav/gs-in-range",
  280. ILS_gs_deg: "/instrumentation/nav/gs-direct-deg",
  281. NavHeadingNeedleDeflectionILS:"/instrumentation/nav/heading-needle-deflection-norm",
  282. MasterArm :"/controls/armament/master-arm",
  283. TimeToTarget :"/sim/dialog/groundtTargeting/time-to-target",
  284. AbsoluteElapsedtime : "sim/time/elapsed-sec",
  285. };
  286. foreach(var name; keys(m.input))
  287. m.input[name] = props.globals.getNode(m.input[name], 1);
  288. # return our new object
  289. return m;
  290. },
  291. ############### LOOP MANAGEMENT ##################
  292. # creates an engine update loop (optional)
  293. ##################################################
  294. init: func(){
  295. if(me.loop_running)
  296. {
  297. return;
  298. }
  299. me.loop_running = 1;
  300. # init Radar Distance
  301. # launch only On time : this is an auto updated loop.
  302. if(me.haveSweep == 1)
  303. {
  304. me.maj_sweep();
  305. }
  306. var loop_Update = func() {
  307. #rwr stuff
  308. if (rwr.rwr != nil) {
  309. if (size(rwrList)>0) {
  310. rwr.rwr.update(rwrList,"normal");
  311. } else {
  312. rwr.rwr.update(rwrList16,"normal");
  313. }
  314. }
  315. var radarWorking = getprop(me.ElectricalPath);
  316. radarWorking = (radarWorking == nil) ? 1 : radarWorking;
  317. # if(radarWorking > 0 and me.AutoUpdate)
  318. {
  319. setprop("sim/multiplay/generic/int[10]",0);
  320. #me.update();
  321. #These line bellow are error management.
  322. var UpdateErr = [];
  323. # print("Calling radar");
  324. call(me.scan_update_tgt_list_func,[],me,nil,UpdateErr);
  325. call(me.update,[],me,nil,UpdateErr);
  326. if(size(UpdateErr) > 0)
  327. {
  328. print("We have Radar update Errors, but radar still running");
  329. foreach(var myErrors ; UpdateErr)
  330. {
  331. print(myErrors);
  332. }
  333. }
  334. # print("Radar refreshing done");
  335. }else{
  336. setprop("sim/multiplay/generic/int[10]",1);
  337. me.ContactsList = [];
  338. me.tgts_list = [];
  339. me.Target_Index = -1;
  340. setprop("sim/multiplay/generic/string[10]", "");
  341. }
  342. #me.Global_janitor();
  343. # RWR launch
  344. RWR_APG.run();
  345. if(me.isdeleting == 0){settimer(loop_Update, me.UPDATE_PERIOD)};
  346. };
  347. if(me.isdeleting == 0){settimer(loop_Update, me.UPDATE_PERIOD)};
  348. var loop_Sweep = func() {
  349. if(me.haveSweep ==1){me.maj_sweep();}
  350. settimer(loop_Sweep, 0.05);
  351. };
  352. if(me.isdeleting == 0){settimer(loop_Sweep,0.05);}
  353. },
  354. delete: func(){
  355. me.AutoUpdate = 0;
  356. me.isdeleting = 1;
  357. tmp_nearest_rng = nil;
  358. tmp_nearest_u = nil;
  359. nearest_rng = 0;
  360. nearest_u = nil;
  361. missileIndex = 0;
  362. MytargetVariable = nil;
  363. completeList = [];
  364. me.ContactsList = [];
  365. #rwr Stuff
  366. rwrList = [];
  367. rwrList16 = [];
  368. },
  369. ############
  370. # UPDATE #
  371. ############
  372. ## How the radar should work :
  373. ## 1 - use the tree via getNode
  374. ## 2 - ARRAY1 : Stock contact in an array. This array should never be deleted and contact never be removed from it.
  375. ## 3 - ARRAY1 : Update this array (new coord etc all data of the contact), and above all, update if "Display" or not.
  376. ## 4 - ARRAY2 : Stock only "Display" Contact. This array can be tempo and contact can/have to be REMOVED once it is not "Display"
  377. ## 5 - ARRAY3 : Stock Contact contact that can be targeted. Contact must not be deleted. (in case of a firing missile, the contact stocked here is the
  378. # one that is updated. If we lose this contact, we cannont have action on the missile anymore (lost of the contact or anything else)
  379. ## 6 - ARRAY3 : Update this array (new coord etc all data of the contact), and above all, update if "Display" or not.
  380. ## 7 - ARRAY4 : Stock and update array with "Display" target. <-This is for target selection. Unavailable Target => must be REMOVED
  381. ## 8 - ARRAY5 : Stock and update selected Target. Put the tag Painted on it. (Use an array here allow multiple selection and firing all the target in the same time)
  382. ## Schematic :
  383. ## PROPERTY TREE "Display"
  384. ## =============> ARRAY1 =========> ARRAY2
  385. ## |
  386. ## | Target stock "Display"
  387. ## =============>ARRAY3 ==========> ARRAY4
  388. ## |
  389. ## | Painted/selected
  390. ## ====================> ARRAY5
  391. ## STOCRAGE ARRAY : functions : add, update
  392. ## ARRAY1, ARRAY3
  393. ##
  394. ## DIPLAY ARRAY : functions : add, update, remove
  395. ## ARRAY2, ARRAY4, ARRAY5
  396. ## Simplification : Only use ARRAY1, ARRAY2 and ARRAY5
  397. update: func(tempCoord = nil, tempHeading = nil, tempPitch = nil) {
  398. #Double Run prevention
  399. if(me.updating_now == 1){return;}else{me.updating_now = 1;}
  400. #Interval calculation
  401. me.LoopElapsed = me.input.AbsoluteElapsedtime.getValue() - me.TimeWhenUpdate;
  402. # This is to know when was the last time we called the update
  403. me.TimeWhenUpdate = me.input.AbsoluteElapsedtime.getValue();
  404. # First update Coord, Alt, heeading and Pitch.
  405. # The code pout the aircraft properties if nothing has been passed in parameters
  406. # Coord update ! Should be filled with altitude
  407. if(tempCoord == nil){me.MyCoord = geo.aircraft_position();}else{me.MyCoord = tempCoord;}
  408. # Altitude update (in meters)
  409. me.our_alt = me.MyCoord.alt();
  410. # Heading Update (should be the airplane heading, not the radar look direction)
  411. if(tempHeading == nil){me.OurHdg = me.input.hdgReal.getValue();}else{me.OurHdg = tempHeading;}
  412. # Pitch Update (should be the airplane heading, not the radar look direction)
  413. if(tempPitch == nil){me.OurPitch = me.input.pitch.getValue();}else{me.OurPitch = tempPitch;}
  414. # Variable initialized
  415. # This is the return array. Made First for Canvas, but can be usefull to a lot of other things
  416. # var CANVASARRAY = [];
  417. #This is the missile index. It is reset on each loop.
  418. me.missileIndex = 0;
  419. # var raw_list = me.Mp.getChildren();
  420. foreach(me.update_u ; me.raw_selection)
  421. {
  422. # set Check_List to void
  423. me.Check_List = [];
  424. # this function do all the checks and put all result of each
  425. # test on an array[] named Check_List
  426. me.go_check(me.update_u);
  427. #Displaying Check
  428. # then a function just check it all
  429. #print("Update targetList" ~ me.update_u.get_Callsign());
  430. #print("get_type()" ~ me.update_u.get_type());
  431. if(me.get_check() and me.update_u.isValid())
  432. {
  433. #Is in Range : Should be added to the main ARRAY1 (Here : ContactsList)
  434. # var HaveRadarNode = c.getNode("radar");
  435. #Update ContactList : Only updated when target is valid
  436. #Should return an Index, in order to take the object from the table and not the property tree
  437. if(me.UseATree){
  438. me.update_u.create_tree(me.MyCoord, me.OurHdg);
  439. me.update_u.set_all(me.MyCoord);
  440. me.calculateScreen(me.update_u);
  441. }
  442. me.update_array(me.update_u,me.ContactsList);
  443. me.update_u.set_display(1);
  444. # for Target Selection
  445. # here we disable the capacity of targeting a missile.
  446. if(me.update_u.get_type != armament.ORDNANCE and !contains(weaponRadarNames, me.update_u.get_Callsign) and !me.update_u.isFriend())
  447. {
  448. #tgts_list => ARRAY4
  449. me.TargetList_Update(me.update_u);
  450. me.TargetList_AddingTarget(me.update_u);
  451. #We should UPDATE tgts_list here
  452. if(size(me.tgts_list)>me.Target_Index){
  453. #This shouldn't be here. See how to delete it
  454. if(me.update_u.getUnique() == me.tgts_list[me.Target_Index].getUnique() and me.update_u.getUnique() == me.Target_Callsign
  455. and me.az_fld == me.focused_az_fld){
  456. #print("Picasso painting");
  457. me.update_u.setPainted(1);
  458. armament.contact = me.tgts_list[me.Target_Index];
  459. #print(armament.contact.get_type());
  460. }
  461. }else{
  462. me.next_Target_Index();
  463. }
  464. }
  465. me.displayTarget();
  466. }
  467. else
  468. {
  469. #me.tempo_Index = me.find_index_inArray(u,me.ContactsList);
  470. #if(me.tempo_Index != nil){me.ContactsList[me.tempo_Index].set_display(1,me.myTree);}
  471. #Here we shouldn't see the target anymore. It should disapear. So for that, we are calling the Tempo_Janitor
  472. if(me.update_u.get_Validity() == 1)
  473. {
  474. if(me.input.AbsoluteElapsedtime.getValue() - me.update_u.get_TimeLast() > me.MyTimeLimit)
  475. {
  476. me.Tempo_janitor(me.update_u);
  477. }
  478. }
  479. }
  480. }
  481. me.ContactsList = me.decrease_life(me.ContactsList);
  482. if (armament.contact != nil and armament.contact.get_display() and getprop("controls/armament/master-arm") and armament.contact.get_Callsign() != nil and armament.contact.get_Callsign() != "" and armament.contact.isPainted()) {
  483. #print("armament.contact.get_Callsign"~armament.contact.get_Callsign());
  484. setprop("sim/multiplay/generic/string[10]", left(md5(armament.contact.get_Callsign()), 4));
  485. } else {
  486. setprop("sim/multiplay/generic/string[10]", "");
  487. }
  488. me.updating_now = 0;
  489. },
  490. maj_sweep: func(){
  491. var x = (getprop("sim/time/elapsed-sec") / (me.sweep_frequency)) * (0.0844 / me.swp_diplay_width); # shorten the period time when illuminating a target
  492. #print("SINUS (X) = "~math.sin(x);
  493. me.SwpMarker = (math.sin(3.14 * x) * (me.swp_diplay_width / 0.0844)); # shorten the period amplitude when illuminating
  494. setprop(me.sweepProperty,me.SwpMarker);
  495. },
  496. TargetList_Update: func(SelectedObject){
  497. forindex(i; me.tgts_list){
  498. #print("Target list update");
  499. if(me.tgts_list[i].get_Callsign()==SelectedObject.get_Callsign()){
  500. me.tgts_list[i].update(SelectedObject);
  501. return i;
  502. }
  503. }
  504. return nil;
  505. },
  506. TargetList_AddingTarget: func(SelectedObject){
  507. # This is selectioned target management.
  508. if(me.TargetList_LookingForATarget(SelectedObject) == 0)
  509. {
  510. append(me.tgts_list, SelectedObject);
  511. }
  512. },
  513. TargetList_RemovingTarget: func(SelectedObject){
  514. # This is selectioned target management.
  515. if(me.TargetList_LookingForATarget(SelectedObject) > 5)
  516. {
  517. # Then kill it
  518. var TempoTgts_list = [];
  519. foreach(var TempTarget ; me.tgts_list)
  520. {
  521. if(TempTarget.get_shortring() != SelectedObject.get_shortring())
  522. {
  523. append(TempoTgts_list, TempTarget);
  524. }else{
  525. #TempTarget.setPainted(0);
  526. }
  527. }
  528. #me.tgts_list = TempoTgts_list;
  529. }
  530. },
  531. TargetList_LookingForATarget: func(SelectedObject){
  532. # This is selectioned target management.
  533. # Target list janitor
  534. foreach(var TempTarget ; me.tgts_list)
  535. {
  536. if(TempTarget.get_shortring() == SelectedObject.get_shortring())
  537. {
  538. return TempTarget.get_TimeLast();
  539. }
  540. }
  541. return 0;
  542. },
  543. get_check: func(){
  544. # This function allow to display multi check
  545. me.checked = 1;
  546. me.CheckTable = ["InRange:", "inAzimuth:", "inElevation:", "Horizon:", "RCS","Doppler:", "NotBtBehindTerrain:"];
  547. var i = 0;
  548. foreach(myCheck ; me.Check_List)
  549. {
  550. if(i<size(me.CheckTable)){
  551. #print("i : "~ i ~"|" ~ me.CheckTable[i] ~ " " ~ myCheck);
  552. }else{
  553. #print("i : "~ i ~"|myCheck : " ~ myCheck);
  554. }
  555. i +=1;
  556. me.checked = (myCheck and me.checked);
  557. }
  558. return me.checked;
  559. },
  560. #function in order to make it work with unified missile method in FG
  561. type_selector: func(SelectedObject){
  562. me.type_selector_selectedType = SelectedObject.getName();
  563. #Overwrite selectedType if missile
  564. me.type_selector_TestIfMissileNode = SelectedObject.getNode("missile");
  565. if(me.type_selector_TestIfMissileNode != nil) {
  566. if(me.type_selector_TestIfMissileNode.getValue()){
  567. #print("It is a missile");
  568. me.type_selector_selectedType = "missile";
  569. }
  570. }
  571. return me.type_selector_selectedType;
  572. },
  573. check_selected_type: func(SelectedObject)
  574. {
  575. me.check_selected_type_result = 0;
  576. #Variable for the selection Type test
  577. me.check_selected_type_selectedType = SelectedObject.getName();
  578. me.check_selected_type_selectedType = me.type_selector(SelectedObject);
  579. #print("MY type IS : "~selectedType);
  580. #variable for the RadarNode test
  581. var shouldHaveRadarNode = ["tanker","aircraft","missile"];
  582. var HaveRadarNode = SelectedObject.getNode("radar");
  583. #We test the type of target
  584. foreach(myType;me.typeTarget)
  585. {
  586. if(myType == me.check_selected_type_selectedType){
  587. me.check_selected_type_result = 1;
  588. }
  589. }
  590. #We test if they have a radar Node (they should all have one, but unconventionnal model like ATC or else could have these issue)
  591. foreach(myType;shouldHaveRadarNode)
  592. {
  593. if(myType == me.check_selected_type_selectedType and HaveRadarNode == nil){
  594. me.check_selected_type_result = 0;
  595. }
  596. }
  597. return me.check_selected_type_result;
  598. },
  599. go_check: func(SelectedObject){
  600. #if radar : check : InRange, inAzimuth, inElevation, NotBeyondHorizon, doppler, isNotBehindTerrain
  601. #if Rwr : check : InhisRange (radardist), inHisElevation, inHisAzimuth, NotBeyondHorizon, isNotBehindTerrain
  602. #if heat : check : InRange, inAzimuth, inElevation, NotBeyondHorizon, heat_sensor, isNotBehindTerrain
  603. #if laser : check : InRange, inAzimuth, inElevation, NotBeyondHorizon, isNotBehindTerrain
  604. #if cam : check : InRange, inAzimuth, inElevation, NotBeyondHorizon, isNotBehindTerrain
  605. # Need to add the fonction flare_sensivity : is there flare near aircraft and should we get fooled by it
  606. append(me.Check_List, me.InRange(SelectedObject));
  607. if(me.Check_List[0] == 0)
  608. {
  609. return;
  610. }
  611. append(me.Check_List, me.inAzimuth(SelectedObject));
  612. if(me.Check_List[1] == 0)
  613. {
  614. return;
  615. }
  616. append(me.Check_List, me.inElevation(SelectedObject));
  617. if(me.Check_List[2] == 0)
  618. {
  619. return;
  620. }
  621. append(me.Check_List, me.NotBeyondHorizon(SelectedObject));
  622. if(me.Check_List[3] == 0)
  623. {
  624. return;
  625. }
  626. append(me.Check_List, rcs.inRadarRange(SelectedObject, 60, 3.2));# Radar RDY: 60 NM for 3.2 RCS
  627. if(me.Check_List[4] == 0)
  628. {
  629. return;
  630. }
  631. #me.heat_sensor(SelectedObject);
  632. if( me.detectionTypetab=="laser" or SelectedObject.skipDoppler == 1)
  633. {
  634. #print("Skip Doppler");
  635. append(me.Check_List, 1);
  636. }else{
  637. append(me.Check_List, me.doppler(SelectedObject));
  638. }
  639. if(me.Check_List[5] == 0)
  640. {
  641. return;
  642. }
  643. # Has to be last coz it will call the get_checked function
  644. append(me.Check_List, me.isNotBehindTerrain(SelectedObject));
  645. },
  646. Tempo_janitor:func(SelectedObject){
  647. SelectedObject.set_nill();
  648. me.TargetList_RemovingTarget(SelectedObject);
  649. },
  650. Global_janitor: func(){
  651. #Action on tree. Too complicated. has to be corrected or removed
  652. # This function is made to remove all persistent non relevant data on radar2 tree
  653. #var myRadarNode = props.globals.getNode("instrumentation/radar2/targets", 1);
  654. var raw_list = me.myTree.getChildren();
  655. foreach(var Tempo_TgtsFiles ; raw_list)
  656. {
  657. #print(Tempo_TgtsFiles.getName());
  658. if(Tempo_TgtsFiles.getNode("display", 1).getValue() != nil)
  659. {
  660. var myTime = Tempo_TgtsFiles.getNode("closure-last-time", 1);
  661. if(getprop("sim/time/elapsed-sec") - myTime.getValue() > me.janitorTime)
  662. {
  663. var Property_list = Tempo_TgtsFiles.getChildren();
  664. foreach(var myProperty ; Property_list )
  665. {
  666. #print(myProperty.getName());
  667. if(myProperty.getName() != "closure-last-time")
  668. {
  669. myProperty.setValue("");
  670. }
  671. }
  672. }
  673. }
  674. }
  675. },
  676. #increase radar distance
  677. switch_distance_ics: func(){
  678. me.rangeIndex = math.mod(me.rangeIndex + 1, size(me.rangeTab));
  679. },
  680. #decrease radar distance
  681. switch_distance_dcs: func(){
  682. me.rangeIndex = math.mod(me.rangeIndex - 1, size(me.rangeTab));
  683. },
  684. #get radar distance
  685. get_radar_distance: func(){
  686. return me.rangeTab[me.rangeIndex];
  687. },
  688. radar_mode_toggle: func(){
  689. # FIXME: Modes props should provide their own data instead of being hardcoded.
  690. # Toggles between the available modes.
  691. foreach(var n ; props.globals.getNode("instrumentation/radar/mode").getChildren())
  692. {
  693. if(n.getBoolValue())
  694. {
  695. wcs_mode = n.getName();
  696. }
  697. }
  698. if(wcs_mode == "rws")
  699. {
  700. setprop("instrumentation/radar/mode/rws", 0);
  701. setprop("instrumentation/radar/mode/tws-auto", 1);
  702. wcs_mode = "tws-auto";
  703. me.az_fld=me.focused_az_fld;
  704. me.vt_az_fld=me.focused_az_fld;
  705. me.swp_diplay_width = 0.0422;
  706. #me.tgts_list = [];
  707. }
  708. elsif(wcs_mode == "tws-auto")
  709. {
  710. setprop("instrumentation/radar/mode/tws-auto", 0);
  711. setprop("instrumentation/radar/mode/rws", 1);
  712. wcs_mode = "pulse-srch";
  713. me.az_fld=me.unfocused_az_fld;
  714. me.vt_az_fld=me.unfocused_az_fld;
  715. me.swp_diplay_width = 0.0844;
  716. }
  717. me.displayTarget();
  718. return me.az_fld;
  719. },
  720. next_loop: func(index,factor){
  721. var number = 0;
  722. for(i=1;i<size(me.tgts_list);i = i + 1){
  723. number = math.mod(index + (i * factor), size(me.tgts_list));
  724. if(me.tgts_list[number].get_display() == 1){ return number;}
  725. }
  726. return index;
  727. },
  728. next_Target_Index: func(){
  729. #Stuff to un paint previous target
  730. if (size(me.tgts_list) > 0) {me.tgts_list[me.Target_Index].setPainted(0);}
  731. #Stuff to decrease the index
  732. me.Target_Index = me.next_loop(me.Target_Index, 1);
  733. #Stuff to do with new index
  734. if (size(me.tgts_list) > 0) {
  735. me.Target_Callsign = me.tgts_list[me.Target_Index].getUnique();
  736. if(me.az_fld == me.focused_az_fld){me.tgts_list[me.Target_Index].setPainted(1);} #If it require a focus, paint it
  737. screen.log.write("Target is :" ~ me.tgts_list[me.Target_Index].get_Callsign() ~ " Painted :" ~ me.tgts_list[me.Target_Index].isPainted(), 0.0, 0.5, 1.0);
  738. print("Target is :" ~ me.tgts_list[me.Target_Index].get_Callsign() ~ " Painted :" ~ me.tgts_list[me.Target_Index].isPainted());
  739. } else {
  740. me.Target_Callsign = nil;
  741. }
  742. },
  743. previous_Target_Index: func(){
  744. #Stuff to un paint previous target
  745. if (size(me.tgts_list) > 0) {me.tgts_list[me.Target_Index].setPainted(0);}
  746. #Stuff to decrease the index
  747. me.Target_Index = me.next_loop(me.Target_Index, -1);
  748. #Stuff to do with new index
  749. if (size(me.tgts_list) > 0) {
  750. me.Target_Callsign = me.tgts_list[me.Target_Index].getUnique();
  751. if(me.az_fld == me.focused_az_fld){me.tgts_list[me.Target_Index].setPainted(1);} #If it require a focus, paint it
  752. screen.log.write("Target is :" ~ me.tgts_list[me.Target_Index].get_Callsign() ~ " Painted :" ~ me.tgts_list[me.Target_Index].isPainted(), 0.0, 0.5, 1.0);
  753. print("Target is :" ~ me.tgts_list[me.Target_Index].get_Callsign() ~ " Painted :" ~ me.tgts_list[me.Target_Index].isPainted());
  754. } else {
  755. me.Target_Callsign = nil;
  756. }
  757. },
  758. displayTarget: func(){
  759. # 60 here is the illuminating or selecting cone. This has to be reworked
  760. # 1 To not to depend of a written value. 2 To take account that some radar do not need focus to get target
  761. # perhaps introduce a "selecting" target variable
  762. # This is very mirage specific. We should find a way to remove it
  763. if(size(me.tgts_list) != 0 and me.az_fld == me.focused_az_fld and me.tgts_list != nil)
  764. {
  765. if( me.Target_Index < 0)
  766. {
  767. me.Target_Index = size(me.tgts_list) - 1;
  768. me.Target_Callsign = nil;
  769. # setprop("/ai/closest/range", 0);
  770. return;#me.Target_Index = size(me.tgts_list) - 1;
  771. }
  772. if( me.Target_Index > size(me.tgts_list) - 1)
  773. {
  774. me.Target_Index = 0;
  775. me.Target_Callsign = nil;
  776. # setprop("/ai/closest/range", 0);
  777. return;#me.Target_Index = 0;
  778. }
  779. if (me.Target_Callsign != me.tgts_list[me.Target_Index].getUnique()) {
  780. me.Target_Callsign = nil;
  781. me.Target_Callsign = nil;
  782. # setprop("/ai/closest/range", 0);
  783. return;
  784. }
  785. var MyTarget = me.tgts_list[ me.Target_Index];
  786. # me.tgts_list[ me.Target_Index].setPainted(1);#That sucks for mica
  787. # closeRange = me.targetRange(MyTarget);
  788. # heading = MyTarget.get_heading();
  789. # altitude = MyTarget.get_altitude();
  790. # speed = MyTarget.get_Speed();
  791. # callsign = MyTarget.get_Callsign();
  792. # longitude = MyTarget.get_Longitude();
  793. # latitude = MyTarget.get_Latitude();
  794. # bearing = me.targetBearing(MyTarget);
  795. # if(speed == nil)
  796. # {
  797. # speed = 0;
  798. # }
  799. #It shouldn't be use anymore
  800. # setprop("/ai/closest/range", closeRange);
  801. # setprop("/ai/closest/bearing", bearing);
  802. # setprop("/ai/closest/heading", heading);
  803. # setprop("/ai/closest/altitude", altitude);
  804. # setprop("/ai/closest/speed", speed);
  805. # setprop("/ai/closest/callsign", callsign);
  806. # setprop("/ai/closest/longitude", longitude);
  807. # setprop("/ai/closest/latitude", latitude);
  808. }else{
  809. if(me.az_fld != me.focused_az_fld){
  810. if (size(me.tgts_list) > 0) {
  811. # me.tgts_list[me.Target_Index].setPainted(0);
  812. # armament.contact = nil;
  813. }
  814. }
  815. # setprop("/ai/closest/range", 0);
  816. }
  817. },
  818. ###########################################################################
  819. ### Update element of the actual diplayed array
  820. update_Element_of_array: func(SelectedObject,myArray){
  821. #print("Normal Update bellow");
  822. forindex(i; myArray){
  823. if(myArray[i].getUnique()==SelectedObject.getUnique()){
  824. myArray[i].update(SelectedObject);
  825. return myArray;
  826. }
  827. }
  828. return myArray;
  829. },
  830. ### add element to the array
  831. add_Element_to_Array: func(SelectedObject,myArray){
  832. append(myArray,SelectedObject);
  833. return myArray;
  834. },
  835. ### update array : update element, or add it if there aren't present
  836. update_array: func(SelectedObject,myArray){
  837. tempo = nil;
  838. if(size(myArray) > 0){
  839. myArray = me.update_Element_of_array(SelectedObject,myArray);
  840. tempo = me.find_index_inArray(SelectedObject,myArray);
  841. }
  842. if(tempo == nil){;
  843. myArray = me.add_Element_to_Array(SelectedObject,myArray);
  844. }
  845. return myArray;
  846. },
  847. find_index_inArray: func(SelectedObject,myArray){
  848. forindex(i; myArray){
  849. #print("myArray[i].getUnique() : " ~ myArray[i].getUnique() ~" And SelectedObject.getUnique() : "~SelectedObject.getUnique());
  850. if(myArray[i].getUnique()==SelectedObject.getUnique()){return i;}
  851. }
  852. return nil;
  853. },
  854. update_array_no_life_reset: func(SelectedObject,myArray){
  855. tempo = nil;
  856. if(size(myArray) > 0){
  857. #The idea is to keep the values of the variables and not reseting them
  858. #This way it does not impact the radar
  859. myIndex = me.find_index_inArray(SelectedObject,myArray);
  860. if(myIndex != nil and myArray[myIndex].Display_Node != nil){
  861. var mypaint = myArray[myIndex].isPainted();
  862. var myDisplay = myArray[myIndex].get_display();
  863. var myLife = myArray[myIndex].life;
  864. }
  865. me.update_array(SelectedObject,myArray);
  866. if(myIndex != nil and myArray[myIndex].Display_Node != nil){
  867. myArray[myIndex].setPainted(mypaint);
  868. myArray[myIndex].set_display(myDisplay, me.UseATree);
  869. myArray[myIndex].life = myLife;
  870. }
  871. }else{
  872. me.update_array(SelectedObject,myArray);
  873. }
  874. return myArray;
  875. },
  876. #############################################################################
  877. #decrease life of element. < 0 then it's not displayed anymore
  878. #should call a remove_element function to remove element from array
  879. decrease_life: func(myArray){
  880. var i = 0;
  881. foreach(contact;myArray){
  882. contact.life = contact.life - me.LoopElapsed;
  883. #print("Elapsed = " ~ me.LoopElapsed ~" Then " ~ contact.get_Callsign() ~ " 's life : "~ contact.life);
  884. if(contact.life<3){
  885. #print("Elapsed = " ~ me.LoopElapsed ~" Then " ~ contact.get_Callsign() ~ " 's life : "~ contact.life);
  886. contact.set_display(0, me.UseATree);
  887. contact.setPainted(0);
  888. }
  889. }
  890. return myArray;
  891. },
  892. #This function should sort and suppr
  893. sorting_and_suppr: func(myArray){
  894. #print("Test2 : size : " ~ size(me.ContactsList));
  895. for(var i=0;i<size(myArray)-1;i = i + 1){
  896. #print("Test3");
  897. for(var j=0;j<size(myArray)-1;j = j + 1){
  898. #print(myArray[i].get_Callsign() ~ " : " ~ myArray[i].life ~ " vs " ~ myArray[j].get_Callsign() ~ " : " ~ myArray[j].life);
  899. if(myArray[i].life<myArray[j].life){
  900. var u = myArray[i];
  901. myArray[i] = myArray[j];
  902. myArray[j] = u;
  903. }
  904. }
  905. }
  906. },
  907. cut_array : func(ChoosenSize, Myarray){
  908. var tempArray = [];
  909. for(var i=0;i<size(Myarray)-1;i = i + 1){
  910. if(i>ChoosenSize){
  911. append(tempArray, Myarray[i]);
  912. }
  913. }
  914. return tempArray;
  915. },
  916. GetTarget: func(){
  917. if(me.tgts_list == nil)
  918. {
  919. return nil;
  920. }
  921. if(size(me.tgts_list) <= 0)
  922. {
  923. return nil;
  924. }
  925. if(me.Target_Index < 0)
  926. {
  927. return nil;#me.Target_Index = size(me.tgts_list) - 1;
  928. }
  929. if(me.Target_Index > size(me.tgts_list) - 1)
  930. {
  931. return nil;#me.Target_Index = 0;
  932. }
  933. if (me.Target_Callsign == me.tgts_list[me.Target_Index].getUnique()) {
  934. #me.tgts_list[me.Target_Index].setPainted(1); <- The fuck is that doing here
  935. return me.tgts_list[me.Target_Index];
  936. } else {
  937. me.Target_Callsign = nil;
  938. return nil;
  939. }
  940. #return me.tgts_list[me.Target_Index];
  941. },
  942. #toggle_Type: func(){
  943. # me.detectionTypeIndex = math.mod(me.detectionTypeIndex + 1, size(me.detectionTypetab));
  944. # setprop("/sim/messages/atc", "Toggle Detection Type : "~ me.detectionTypetab[me.detectionTypeIndex]);
  945. #},
  946. myRadarList : [],
  947. };
  948. # Utilities.
  949. var deviation_normdeg = func(our_heading, target_bearing){
  950. var dev_norm = our_heading - target_bearing;
  951. while(dev_norm < -180)
  952. {
  953. dev_norm += 360;
  954. }
  955. while(dev_norm > 180)
  956. {
  957. dev_norm -= 360;
  958. }
  959. return(dev_norm);
  960. }
  961. var rounding1000 = func(n){
  962. var a = int(n / 1000);
  963. var l = (a + 0.5) * 1000;
  964. n = (n >= l) ? ((a + 1) * 1000) : (a * 1000);
  965. return(n);
  966. }
  967. #RWR stuff, thank to Leto
  968. var rwrList = [];
  969. var rwrList16 = [];
  970. var RWR_APG = {
  971. # parents : [RWR_APG,RadarTool],
  972. run: func () {
  973. me.parents = [RadarTool];
  974. rwrList = [];
  975. rwrList16 = [];
  976. me.MyCoord = geo.aircraft_position();
  977. # printf("clist %d", size(completeList));
  978. #Sound of Lock
  979. #setprop("sound/rwr-lck", 0);
  980. me.myCallsign = getprop("sim/multiplay/callsign");
  981. me.myCallsign = size(me.myCallsign) < 8 ? me.myCallsign : left(me.myCallsign,7);
  982. me.act_lck = 0;
  983. foreach(me.u;completeList) {
  984. me.cs = me.u.get_Callsign();
  985. # print("Will test : "~ me.u.get_Callsign()~" as Type: " ~ me.u.type);
  986. me.rn = me.u.get_range();
  987. me.l16 = 0;
  988. if (me.u.isFriend() or me.rn > 150) {
  989. me.l16 = 1;
  990. }
  991. me.lck = me.u.propNode.getNode("sim/multiplay/generic/string[10]");
  992. if (me.lck != nil and me.lck.getValue() != nil and me.lck.getValue() != "" and size(""~me.lck.getValue())==4 and left(md5(me.myCallsign),4) == me.lck.getValue()) {
  993. me.act_lck = 1;
  994. }
  995. me.bearing = geo.aircraft_position().course_to(me.u.get_Coord());
  996. me.trAct = me.u.propNode.getNode("instrumentation/transponder/transmitted-id");
  997. me.show = 0;
  998. me.heading = me.u.get_heading();
  999. me.inv_bearing = me.bearing+180;
  1000. me.deviation = me.inv_bearing - me.heading;
  1001. me.dev = math.abs(geo.normdeg180(me.deviation));
  1002. if (me.u.get_display()) {
  1003. me.show = 1;#in radar cone
  1004. } elsif(me.HasTransponderOn(me.u)){
  1005. # transponder on
  1006. me.show = 1;
  1007. }else{
  1008. me.rdrAct = me.u.propNode.getNode("sim/multiplay/generic/int[10]");
  1009. me.rwrTargetAzimuth = me.TargetWhichRadarAzimut(me.u);
  1010. #print(me.rwrTargetAzimuth);
  1011. #if (((me.rdrAct != nil and me.rdrAct.getValue()!=1) or me.rdrAct == nil) and math.abs(geo.normdeg180(me.deviation)) < me.rwrTargetAzimuth and me.NotBeyondHorizon(me.u) and me.isNotBehindTerrain(me.u) ) {
  1012. if (((me.rdrAct != nil and me.rdrAct.getValue()!=1) or me.rdrAct == nil) < me.rwrTargetAzimuth and me.NotBeyondHorizon(me.u) and me.isNotBehindTerrain(me.u) ) {
  1013. # we detect its radar is pointed at us and active
  1014. me.show = 1;
  1015. }
  1016. }
  1017. #if(!me.u.isValid()){me.show = 0;}
  1018. #print("should show : " ~ me.u.get_Callsign()~" as Type: " ~ me.u.type ~ " Show : "~ me.show ~ " Name:"~me.u.propNode.getName()~" Model:"~me.u.get_model() ~
  1019. #" ModelType:"~me.u.ModelType ~ " isValid:"~me.u.isValid());
  1020. if (me.show == 1) {
  1021. me.threat = 0;
  1022. if (me.u.get_model() != "missile_frigate" and me.u.propNode.getName() != "carrier" and me.u.get_model() != "fleet" and me.u.get_model() != "buk-m2" and me.u.get_model() != "MIM104D") {
  1023. me.threat += ((180-me.dev)/180)*0.30;
  1024. me.spd = (60-me.u.get_Speed())/60;
  1025. me.threat -= me.spd>0?me.spd:0;
  1026. } elsif (me.u.get_model == "missile_frigate" or me.u.get_model == "fleet") {
  1027. me.threat += 0.30;
  1028. } else {
  1029. me.threat += 0.30;
  1030. }
  1031. me.danger = 50;
  1032. if (me.u.get_model() == "missile_frigate" or me.u.get_model() == "fleet") {
  1033. me.danger = 75
  1034. } elsif (me.u.get_model() == "buk-m2") {
  1035. me.danger = 35;
  1036. } elsif (me.u.propNode.getName() == "carrier") {
  1037. me.danger = 60;
  1038. }
  1039. # if (me.u.get_model() == "MIM104D") {
  1040. # printf("%d %d %d %d %d", me.rdrAct != nil and me.rdrAct.getValue()!=1, me.rdrAct == nil, me.dev < me.rwrTargetAzimuth, me.NotBeyondHorizon(me.u), me.isNotBehindTerrain(me.u));
  1041. # }
  1042. me.threat += ((me.danger-me.rn)/me.danger)>0?((me.danger-me.rn)/me.danger)*0.60:0;
  1043. me.clo = me.u.get_closure_rate_from_Coord(me.MyCoord);
  1044. me.threat += me.clo>0?(me.clo/500)*0.10:0;
  1045. if (me.threat > 1) me.threat = 1;
  1046. #printf("%s threat:%.2f range:%d dev:%d", me.u.get_Callsign(),me.threat,me.u.get_range(),me.dev);
  1047. if (me.threat <= 0) continue;
  1048. #printf("%s threat:%.2f range:%d dev:%d", u.get_Callsign(),threat,u.get_range(),dev);
  1049. if (!me.l16) {
  1050. append(rwrList,[me.u,me.threat]);
  1051. } else {
  1052. append(rwrList16,[me.u,me.threat]);
  1053. }
  1054. } else {
  1055. #printf("%s ----", u.get_Callsign());
  1056. }
  1057. }
  1058. setprop("sound/rwr-lck", me.act_lck);
  1059. },
  1060. };