radarTool.nas 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. var RadarTool = {
  2. ##############################################################################################
  3. # This function will explore the proprty tree and create new contact in the raw_selection.
  4. ##############################################################################################
  5. get_elevation : func(lat,lon){
  6. #first looking if the tile is loaded
  7. me.local_ground_alt = geo.elevation(lat, lon);
  8. #if geo is nil, the tile is not loaded. There is no fucking way to get the ground elevation (except what I'm about to do)
  9. if(me.local_ground_alt == nil){
  10. #finding the closest navaid and take its altitude
  11. me.navaid_vector = findNavaidsWithinRange(lat,lon,100);
  12. me.local_ground_alt = me.navaid_vector[0].elevation;
  13. }
  14. return me.local_ground_alt;
  15. },
  16. scan_update_tgt_list_func:func(){
  17. if(scan_update_tgt_list){
  18. me.temp_raw_list = me.Mp.getChildren();
  19. foreach(var c ; me.temp_raw_list)
  20. {
  21. # FIXME: At that time a multiplayer node may have been deleted while still
  22. # existing as a displayable target in the radar targets nodes.
  23. # FIXED, with janitor. 5H1N0B1
  24. var type = me.type_selector(c);
  25. if(c.getNode("valid") == nil or c.getNode("valid").getValue() != 1)
  26. {
  27. continue;
  28. }
  29. # the 2 following line are needed : If not, it would detects our own missiles...
  30. # this will come soon
  31. # var HaveRadarNode = c.getNode("radar");
  32. #print(me.check_selected_type(c));
  33. #if(type == "multiplayer"
  34. # or (type == "tanker" and HaveRadarNode != nil)
  35. # or (type == "aircraft" and me.showAI == 1)
  36. # or type == "carrier"
  37. # or type == "ship"
  38. # or (type == "missile" and HaveRadarNode != nil))
  39. #
  40. var Tree_Name = c.getName();
  41. #print("folderName:" ~ c.getName());
  42. #print("type:" ~ type);
  43. if(me.check_selected_type(c))
  44. {
  45. # creation of the tempo object Target
  46. var u = Target.new(c,me.myTree.getPath());
  47. folderName = c.getName();
  48. #print("test : " ~ c.pathNode.getValue());
  49. #print("folderName:" ~ folderName);
  50. # important Shinobi:
  51. # expand this so multiplayer that is on sea or ground is also set correct.
  52. # also consider if doppler do not see them that they are either SURFACE or MARINE, depending on if they have alt = ~ 0
  53. # notice that GROUND_TARGET is set inside Target.new().
  54. u.setType(armament.AIR);
  55. #print("Update Type of " ~ u.get_Callsign());
  56. #printf("Elevation of the tile :%f00" , me.get_elevation(u.get_Latitude(), u.get_Longitude()));
  57. #print("Target Altitude:" ~u.get_altitude()*FT2M);
  58. #var ground_alt = geo.elevation(u.get_Latitude(), u.get_Longitude());
  59. me.type_ground_alt = me.get_elevation(u.get_Latitude(), u.get_Longitude());#= ground_alt==nil?0:ground_alt;
  60. # We are testing if it is near the ground
  61. if(me.type_ground_alt!=nil){
  62. if(abs(me.type_ground_alt - u.get_altitude()*FT2M) < 20 or u.get_altitude()*FT2M < 50) { # in meters
  63. #print("It is close to the ground");
  64. me.info = geodinfo(u.get_Latitude(), u.get_Longitude());
  65. if (me.info != nil and me.info[1] != nil) {
  66. #print("The ground underneath the aircraft is ", me.info[1].solid == 1 ? "solid." : "water.");
  67. #debug.dump(me.info);
  68. if(me.info[1].solid == 1){
  69. #print("SURFACE");
  70. u.setType(armament.SURFACE);
  71. u.skipDoppler = 0;
  72. }else{
  73. #print("MARINE");
  74. u.setType(armament.MARINE);
  75. u.skipDoppler = 1;
  76. }
  77. #if we can't get the geoinfo it is because the terrain didn't load. So doing a default altitude check to choose
  78. }elsif(u.get_altitude()*FT2M < 50){
  79. #print("MARINE");
  80. u.setType(armament.MARINE);
  81. u.skipDoppler = 1;
  82. }else{
  83. #print("SURFACE");
  84. u.setType(armament.SURFACE);
  85. u.skipDoppler = 0;
  86. }
  87. }
  88. }else{
  89. print("Tiles not loaded for target load moar" ~ u.get_Callsign() ~ " at " ~ u.get_range() ~"nm");
  90. }
  91. if(u.get_type() == armament.AIR){
  92. # now we test the model name to guess what type it is:
  93. me.pathNode = c.getNode("sim/model/path");
  94. if (me.pathNode != nil) {
  95. me.path = me.pathNode.getValue();
  96. me.model = split(".", split("/", me.path)[-1])[0];
  97. u.set_model(me.model);#used for RCS
  98. }
  99. u.skipDoppler = 0;
  100. }
  101. #Testing if ORDNANCE
  102. if (c.getNode("missile") != nil and c.getNode("missile").getValue()) {
  103. u.setType(armament.ORDNANCE);
  104. u.skipDoppler = 0;
  105. # print("missile:"~ folderName ~":"~ "armament.ORDNANCE");
  106. }
  107. if (c.getNode("munition") != nil and c.getNode("munition").getValue()) {
  108. u.setType(armament.ORDNANCE);
  109. # u.skipDoppler = 0;
  110. # print("munition:" ~ folderName ~":"~ "armament.ORDNANCE");
  111. }
  112. #Testing Ground Target
  113. if(u.get_Callsign() == "GROUND_TARGET"){
  114. u.setType(armament.SURFACE);
  115. }
  116. #print(folderName ~ " type:" ~ u.get_type()~ " Skipping Doppler: " ~ u.skipDoppler);
  117. # if(Tree_Name != "munition"){
  118. # print("Test Important:");
  119. me.update_array(u,me.raw_selection);
  120. me.update_array(u,completeList);
  121. # }
  122. }
  123. }
  124. }
  125. scan_update_tgt_list = 0;
  126. },
  127. ##############################################################################################
  128. # Checking if behind terrain or Not
  129. ##############################################################################################
  130. isNotBehindTerrain: func(SelectedObject){
  131. if(SelectedObject.get_Callsign()=="GROUND_TARGET"){return 1;}
  132. isVisible = 0;
  133. # As the script is relatively ressource consuming, then, we do a maximum of test before doing it
  134. # if(me.get_check())
  135. # {
  136. SelectCoord = SelectedObject.get_Coord();
  137. SelectCoord.set_alt(SelectCoord.alt()+1);
  138. # Because there is no terrain on earth that can be between these 2
  139. if(me.our_alt < 8900 and SelectCoord.alt() < 8900)
  140. {
  141. if (pickingMethod == 1) {
  142. var myPos = geo.aircraft_position();
  143. var xyz = {"x":myPos.x(), "y":myPos.y(), "z":myPos.z()};
  144. var dir = {"x":SelectCoord.x()-myPos.x(), "y":SelectCoord.y()-myPos.y(), "z":SelectCoord.z()-myPos.z()};
  145. # Check for terrain between own aircraft and other:
  146. v = get_cart_ground_intersection(xyz, dir);
  147. if (v == nil) {
  148. return 1;
  149. #printf("No terrain, planes has clear view of each other");
  150. } else {
  151. var terrain = geo.Coord.new();
  152. terrain.set_latlon(v.lat, v.lon, v.elevation);
  153. var maxDist = myPos.direct_distance_to(SelectCoord);
  154. var terrainDist = myPos.direct_distance_to(terrain);
  155. if (terrainDist < maxDist-1) {
  156. #print("terrain found between the planes");
  157. return 0;
  158. } else {
  159. #print("The planes has clear view of each other");
  160. return 1;
  161. }
  162. }
  163. } else {
  164. # Temporary variable
  165. # A (our plane) coord in meters
  166. a = me.MyCoord.x();
  167. b = me.MyCoord.y();
  168. c = me.MyCoord.z();
  169. # B (target) coord in meters
  170. d = SelectCoord.x();
  171. e = SelectCoord.y();
  172. f = SelectCoord.z();
  173. x = 0;
  174. y = 0;
  175. z = 0;
  176. RecalculatedL = 0;
  177. difa = d - a;
  178. difb = e - b;
  179. difc = f - c;
  180. # direct Distance in meters
  181. myDistance = SelectCoord.direct_distance_to(me.MyCoord);
  182. Aprime = geo.Coord.new();
  183. # Here is to limit FPS drop on very long distance
  184. L = 500;
  185. if(myDistance > 50000)
  186. {
  187. L = myDistance / 15;
  188. }
  189. step = L;
  190. maxLoops = int(myDistance / L);
  191. isVisible = 1;
  192. # This loop will make travel a point between us and the target and check if there is terrain
  193. for(var i = 0 ; i < maxLoops ; i += 1)
  194. {
  195. L = i * step;
  196. K = (L * L) / (1 + (-1 / difa) * (-1 / difa) * (difb * difb + difc * difc));
  197. DELTA = (-2 * a) * (-2 * a) - 4 * (a * a - K);
  198. if(DELTA >= 0)
  199. {
  200. # So 2 solutions or 0 (1 if DELTA = 0 but that 's just 2 solution in 1)
  201. x1 = (-(-2 * a) + math.sqrt(DELTA)) / 2;
  202. x2 = (-(-2 * a) - math.sqrt(DELTA)) / 2;
  203. # So 2 y points here
  204. y1 = b + (x1 - a) * (difb) / (difa);
  205. y2 = b + (x2 - a) * (difb) / (difa);
  206. # So 2 z points here
  207. z1 = c + (x1 - a) * (difc) / (difa);
  208. z2 = c + (x2 - a) * (difc) / (difa);
  209. # Creation Of 2 points
  210. Aprime1 = geo.Coord.new();
  211. Aprime1.set_xyz(x1, y1, z1);
  212. Aprime2 = geo.Coord.new();
  213. Aprime2.set_xyz(x2, y2, z2);
  214. # Here is where we choose the good
  215. if(math.round((myDistance - L), 2) == math.round(Aprime1.direct_distance_to(SelectCoord), 2))
  216. {
  217. Aprime.set_xyz(x1, y1, z1);
  218. }
  219. else
  220. {
  221. Aprime.set_xyz(x2, y2, z2);
  222. }
  223. AprimeLat = Aprime.lat();
  224. Aprimelon = Aprime.lon();
  225. AprimeTerrainAlt = geo.elevation(AprimeLat, Aprimelon);
  226. if(AprimeTerrainAlt == nil)
  227. {
  228. AprimeTerrainAlt = 0;
  229. }
  230. if(AprimeTerrainAlt > Aprime.alt())
  231. {
  232. isVisible = 0;
  233. }
  234. }
  235. }
  236. }
  237. }
  238. else
  239. {
  240. isVisible = 1;
  241. }
  242. # }
  243. return isVisible;
  244. },
  245. ##############################################################################################
  246. # Checking if the target is beyond horizon
  247. ##############################################################################################
  248. NotBeyondHorizon: func(SelectedObject){
  249. me.MyCoord = geo.aircraft_position();
  250. me.our_alt = me.MyCoord.alt();
  251. if(SelectedObject.get_Callsign()=="GROUND_TARGET"){return 1;}
  252. # if distance is beyond the earth curve
  253. var horizon = SelectedObject.get_horizon(me.our_alt);
  254. var u_rng = me.targetRange(SelectedObject);
  255. #print("u_rng : " ~ u_rng ~ ", Horizon : " ~ horizon);
  256. var InHorizon = (u_rng < horizon);
  257. return InHorizon;
  258. },
  259. doppler: func(SelectedObject){
  260. #if it is a radiating stuff, skip doppler
  261. #print("In the doppler");
  262. if(pylons.fcs.getSelectedWeapon() != nil){
  263. #print("pylons.fcs.getSelectedWeapon() != nil");
  264. if(pylons.fcs.getSelectedWeapon().type != "30mm Cannon"){
  265. #print("pylons.fcs.getSelectedWeapon().guidance:" ~pylons.fcs.getSelectedWeapon().guidance);
  266. if(pylons.fcs.getSelectedWeapon().guidance =="radiation"){
  267. #print( "Using anti radiation missile. Is target radiating :" ~ SelectedObject.isRadiating(me.MyCoord));
  268. if(SelectedObject.isRadiating(me.MyCoord)){
  269. return 1;
  270. }
  271. }
  272. }
  273. }
  274. # Test to check if the target can hide bellow us
  275. # Or Hide using anti doppler movements
  276. var InDoppler = 0;
  277. var groundNotbehind = me.isGroundNotBehind(SelectedObject);
  278. if(groundNotbehind)
  279. {
  280. InDoppler = 1;
  281. }
  282. if(me.HaveDoppler and (abs(SelectedObject.get_closure_rate_from_Coord(me.MyCoord)) > me.DopplerSpeedLimit))
  283. {
  284. InDoppler = 1;
  285. }
  286. if(SelectedObject.get_Callsign() == "GROUND_TARGET" or SelectedObject.check_carrier_type())
  287. {
  288. InDoppler = 1;
  289. }
  290. return InDoppler;
  291. },
  292. ##############################################################################################
  293. # Checking if ground isn't behind : this is done for non doppler radar that should be blind
  294. # or also a way to blind a doppler radar
  295. ##############################################################################################
  296. isGroundNotBehind: func(SelectedObject){
  297. var myPitch = SelectedObject.get_Elevation_from_Coord(me.MyCoord);
  298. var GroundNotBehind = 1; # sky is behind the target (this don't work on a valley)
  299. if(myPitch < 0 and me.NotBeyondHorizon(SelectedObject))
  300. {
  301. # the aircraft is bellow us, the ground could be bellow
  302. # Based on earth curve. Do not work with mountains
  303. # The script will calculate what is the ground distance for the line (us-target) to reach the ground,
  304. # If the earth was flat. Then the script will compare this distance to the horizon distance
  305. # If our distance is greater than horizon, then sky behind
  306. # If not, we cannot see the target unless we have a doppler radar
  307. var distHorizon = me.MyCoord.alt() / math.tan(abs(myPitch * D2R)) * M2NM;
  308. var horizon = SelectedObject.get_horizon( me.our_alt);
  309. var TempBool = (distHorizon > horizon);
  310. GroundNotBehind = (distHorizon > horizon);
  311. }
  312. return GroundNotBehind;
  313. },
  314. ##############################################################################################
  315. # Checking azimuth
  316. ##############################################################################################
  317. inAzimuth: func(SelectedObject,ExceptGroundTarget = 1){
  318. if(SelectedObject.get_Callsign()=="GROUND_TARGET" and ExceptGroundTarget){return 1;}
  319. # Check if it's in Azimuth.
  320. # first we check our heading+ center az deviation + the sweep if the radar is mechanical
  321. tempAz = me.az_fld;
  322. var inMyAzimuth = 0;
  323. var myHeading = math.mod(me.fieldazCenter + me.OurHdg, 360);
  324. if(me.haveSweep)
  325. {
  326. myHeading = math.mod(myHeading + me.SwpMarker * (0.0844 / me.swp_diplay_width) * tempAz / 4, 360);
  327. mydeviation = SelectedObject.get_deviation(myHeading, me.MyCoord);
  328. #print("Heading:"~ myHeading ~" My deviation:"~ mydeviation);
  329. inMyAzimuth = (abs(mydeviation) < (tempAz / 4));
  330. }
  331. else
  332. {
  333. mydeviation = SelectedObject.get_deviation(myHeading, me.MyCoord);
  334. inMyAzimuth = (abs(mydeviation)<(tempAz/2));
  335. }
  336. return inMyAzimuth;
  337. },
  338. ##############################################################################################
  339. # Don't know what this. With canvas this should be deleted
  340. ##############################################################################################
  341. #The goal of this function is to make the xml radar screen work. It is useless with Canvas
  342. calculateScreen: func(SelectedObject){
  343. # swp_diplay_width = Global
  344. # az_fld = Global
  345. # ppi_diplay_radius = Global
  346. SelectedObject.check_carrier_type();
  347. mydeviation = SelectedObject.get_deviation(me.OurHdg, me.MyCoord);
  348. #print("My Radar deviation %f", mydeviation);
  349. var u_rng = me.targetRange(SelectedObject);
  350. # compute mp position in our B-scan like display. (Bearing/horizontal + Range/Vertical).
  351. SelectedObject.set_relative_bearing(me.swp_diplay_width / me.az_fld * mydeviation,me.UseATree);
  352. var factor_range_radar = me.rng_diplay_width / me.rangeTab[me.rangeIndex]; # length of the distance range on the B-scan screen.
  353. SelectedObject.set_ddd_draw_range_nm(factor_range_radar * u_rng,me.UseATree);
  354. u_fading = 1;
  355. u_display = 1;
  356. # Compute mp position in our PPI like display.
  357. factor_range_radar = me.ppi_diplay_radius / me.rangeTab[me.rangeIndex]; # Length of the radius range on the PPI like screen.
  358. SelectedObject.set_tid_draw_range_nm(factor_range_radar * u_rng,me.UseATree);
  359. # Compute first digit of mp altitude rounded to nearest thousand. (labels).
  360. SelectedObject.set_rounded_alt(rounding1000(SelectedObject.get_altitude()) / 1000,me.UseATree);
  361. # Compute closure rate in Kts.
  362. #SelectedObject.get_closure_rate_from_Coord(me.MyCoord) * MPS2KT;
  363. # Check if u = nearest echo.
  364. if(SelectedObject.get_Callsign() == getprop("/ai/closest/callsign"))
  365. {
  366. #print(u.get_Callsign());
  367. tmp_nearest_u = SelectedObject;
  368. tmp_nearest_rng = u_rng;
  369. }
  370. SelectedObject.set_display(u_display, me.UseATree);
  371. SelectedObject.set_fading(u_fading, me.UseATree);
  372. },
  373. ##############################################################################################
  374. # Checking the elevation
  375. ##############################################################################################
  376. inElevation: func(SelectedObject){
  377. if(SelectedObject.get_Callsign()=="GROUND_TARGET"){return 1;}
  378. # Moving the center of this field will be ne next option
  379. var tempAz = me.vt_az_fld;
  380. var myElevation = SelectedObject.get_total_elevation_from_Coord(me.OurPitch, me.MyCoord);
  381. var IsInElevation = (abs(myElevation) < (tempAz / 2));
  382. return IsInElevation;
  383. },
  384. ##############################################################################################
  385. # Checking the Range
  386. ##############################################################################################
  387. InRange: func(SelectedObject){
  388. if(SelectedObject.get_Callsign()=="GROUND_TARGET"){return 1;}
  389. # Check if it's in range
  390. IsInRange = 0;
  391. var myRange = me.targetRange(SelectedObject);
  392. if(myRange != 0)
  393. {
  394. #print(SelectedObject.get_Callsign() ~": Range (NM) : " ~myRange);
  395. IsInRange = ( myRange <= me.rangeTab[me.rangeIndex]);
  396. }
  397. return IsInRange;
  398. },
  399. ##############################################################################################
  400. # Checking the heat (n1 rotation) need improvement (like heat attenuation)
  401. ##############################################################################################
  402. heat_sensor: func(SelectedObject){
  403. myEngineTree = SelectedObject.get_engineTree();
  404. # If MP or AI has an engine tree, we will check for each engine n1>30 or rpm>1000
  405. if(myEngineTree != nil)
  406. {
  407. var engineList = myEngineTree.getChildren();
  408. foreach(var currentEngine ; engineList)
  409. {
  410. var HaveN1node = currentEngine.getNode("n1");
  411. var HaveRPMnode = currentEngine.getNode("rpm");
  412. if(HaveN1node != nil)
  413. {
  414. n1value = HaveN1node.getValue();
  415. if(n1value != nil and n1value > 30)
  416. {
  417. #print("N1 detected");
  418. return 1;
  419. }
  420. }
  421. if(HaveRPMnode != nil)
  422. {
  423. RpMvalue = HaveRPMnode.getValue();
  424. if(RpMvalue != nil and RpMvalue > 1000)
  425. {
  426. #print("RPM detected");
  427. return 1;
  428. }
  429. }
  430. }
  431. }
  432. # Here we could add a velocity test : if speed >mach 1, we can imagine that friction provides heat
  433. },
  434. ##############################################################################################
  435. #Detection of the link16 : Should allow us to see it as a friend and avoiding shooting it
  436. ##############################################################################################
  437. IsFriendlink16: func(SelectedObject){
  438. cs = SelectedObject.get_Callsign();
  439. rn = SelectedObject.get_range();
  440. if (getprop("link16/wingman-1")==cs or getprop("link16/wingman-2")==cs or getprop("link16/wingman-3")==cs or getprop("link16/wingman-4")==cs or getprop("link16/wingman-5")==cs or getprop("link16/wingman-6")==cs or getprop("link16/wingman-7")==cs or getprop("link16/wingman-8")==cs or getprop("link16/wingman-9")==cs or rn > 150) {
  441. return 1;
  442. }else{
  443. return 0;
  444. }
  445. },
  446. ##############################################################################################
  447. #Transponder detection : if transponder still on, the target will be easy to detect
  448. ##############################################################################################
  449. HasTransponderOn: func(SelectedObject){
  450. trAct = SelectedObject.propNode.getNode("instrumentation/transponder/transmitted-id");
  451. rn = SelectedObject.get_range();
  452. if(SelectedObject.propNode.getName() != "multiplayer" and rn < 55) {
  453. return 1;#non MP always has transponder on.
  454. } elsif (trAct != nil and trAct.getValue() != -9999 and rn < 55) {
  455. return 1; # transponder on
  456. }else{
  457. return 0;
  458. }
  459. },
  460. targetRange: func(SelectedObject){
  461. me.MyCoord = geo.aircraft_position();
  462. # This is a way to shortcurt the issue that some of node have : in-range =0
  463. # So by giving the second fucntion our coord, we just have to calculate it
  464. var myRange = 0;
  465. # myRange = SelectedObject.get_range();
  466. # if(myRange == 0)
  467. # {
  468. myRange = SelectedObject.get_range_from_Coord(me.MyCoord);
  469. #print("Pouet");
  470. # }
  471. #print("targetRange : " ~ SelectedObject.get_Callsign() ~" longitude : " ~ SelectedObject.get_Longitude() ~ " latitude : " ~ SelectedObject.get_Latitude() ~" result="~myRange);
  472. return myRange;
  473. },
  474. targetBearing: func(SelectedObject){
  475. # This is a way to shortcurt the issue that some of node have : bearing =0
  476. # So by giving the second fucntion our coord, we just have to calculate it
  477. var myBearing = 0;
  478. myBearing = SelectedObject.get_bearing();
  479. if(myBearing == 0)
  480. {
  481. myBearing = SelectedObject.get_bearing_from_Coord(me.MyCoord);
  482. }
  483. return myBearing;
  484. },
  485. TargetWhichRadarAzimut: func(SelectedObject){
  486. if(SelectedObject.type == armament.SURFACE or SelectedObject.type == armament.MARINE) {
  487. return 180;
  488. }else{
  489. return 60;
  490. }
  491. }
  492. }