Advertisement
Guest User

NTSL Telescience Calculator

a guest
Jan 15th, 2015
715
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.75 KB | None | 0 0
  1. // NTSL Telescience Calculator!
  2. //
  3. // Does all the Telescience work for you,
  4. // without any external program accusations.
  5. // Bruteforces through everything, so is
  6. // guaranteed to be 100% accurate.
  7. //
  8. // Change $opfreq to whatever frequency you
  9. // want to use it on.
  10. //
  11. // Commands:
  12. //
  13. // "reset"
  14. //
  15. // Resets the calibration data for
  16. // this run. This is called the first time
  17. // the program is run.
  18. //
  19. // "help"
  20. //
  21. // Displays (more concise) usage information
  22. // on these commands.
  23. //
  24. // "calibrate <bearing> <elevation> <power>
  25. // <result_x> <result_y> <source_x> <source_y"
  26. //
  27. // Calibrates on the given data. Will report
  28. // on the currently achievable accuracy when
  29. // finished. Result X and Y are where the GPS
  30. // device ended up, and Source X and Y are the
  31. // coordinates of the Telepad.
  32. //
  33. // Because NTSL only accepts a certain amount
  34. // of function calls per run, calibrating will
  35. // require several runs at the start. Just trigger
  36. // it by saying anything to have it continue.
  37. //
  38. // "target <dest_x> <dest_y> <power> <source_x>
  39. // <source_y>"
  40. //
  41. // Computes the Telescience settings needed
  42. // to reach (dest_x, dest_y) with the given
  43. // power, and the given telepad location.
  44. // Will report if unreachable.
  45. //
  46. // "apply <power_offset> <bearing_offset>"
  47. //
  48. // Takes the given offsets as truth and applies
  49. // them. Interoperability!
  50. //
  51. // "get"
  52. //
  53. // Gets the determined offsets. Only works if
  54. // it's calibrated properly!
  55. //
  56. // Be sure to use appropiate precision! This
  57. // means limiting the Elevation to one digit
  58. // after the period, and Bearing to two digits
  59. // after the period.
  60. //
  61. // Made by Braincake, pretty much a direct
  62. // port of the existing C# calculator.
  63.  
  64. $opfreq = 1449;
  65.  
  66. // Don't change this unless they change the NTSL
  67. // function call restrictions
  68. $max_calcs = 30;
  69.  
  70. // Degrees to radians
  71. def toRadian($angle) {
  72. return $angle * (PI/180);
  73. }
  74.  
  75. // Radians to degrees
  76. def toDegree($angle) {
  77. return $angle * (180/PI);
  78. }
  79.  
  80. // Tangent function, in radians
  81. def tan($angle) {
  82. return sin($angle) / cos($angle);
  83. }
  84.  
  85. // Inverse tangent function, in radians
  86. def atan($angle) {
  87. return toRadian(asin($angle / sqrt($angle^2 + 1)));
  88. }
  89.  
  90. // Atan2
  91. def atan2($y, $x) {
  92. if ($x > 0) {
  93. return atan($y / $x);
  94. }
  95. if ($y >= 0 && $x < 0) {
  96. return atan($y / $x) + PI;
  97. }
  98. if ($y < 0 && $x < 0) {
  99. return atan($y / $x) - PI;
  100. }
  101. if ($y > 0 && $x == 0) {
  102. return PI/2;
  103. }
  104. if ($y < 0 && $x == 0) {
  105. return 0-PI/2;
  106. }
  107. }
  108.  
  109. // Modulus function, $a % $b
  110. def mod($a, $b) {
  111. return $a - $b * floor($a / $b);
  112. }
  113.  
  114. // BYOND degree to scientific degree
  115. def toScientific($angle) {
  116. return mod(360 - $angle + 90, 360);
  117. }
  118.  
  119. // Scientific degree to BYOND degree
  120. def fromScientific($angle) {
  121. return mod(360 - $angle + 90, 360);
  122. }
  123.  
  124. // Sends a message
  125. def send($message) {
  126. broadcast($message, $opfreq, "Telescience", "Calculator");
  127. }
  128.  
  129. // Clear and create the initial offsets
  130. def reset() {
  131. // Boundaries
  132. $pow_min = -4;
  133. $pow_max = 0;
  134. $ha_min = -10;
  135. $ha_max = 10;
  136.  
  137. // Keep track
  138. $pow_offsets = vector();
  139. $ha_offsets = vector();
  140. $pow = $pow_min;
  141.  
  142. // Fill them
  143. while ($pow <= $pow_max) {
  144. $ha = $ha_min;
  145. while ($ha <= $ha_max) {
  146. push_back($pow_offsets, $pow);
  147. push_back($ha_offsets, $ha);
  148. $ha += 1;
  149. }
  150. $pow += 1;
  151. }
  152.  
  153. // Store them, overwrite existing
  154. mem("pow_offsets", $pow_offsets);
  155. mem("ha_offsets", $ha_offsets);
  156. mem("total_offsets", 105);
  157.  
  158. // Done, report
  159. send("Offsets initialized!");
  160. }
  161.  
  162. // Apply specified calibration settings
  163. def calibrate($bearing, $elevation, $power, $result_x, $result_y, $source_x, $source_y) {
  164. // Retrieve remaining offsets
  165. $old_pow_offsets = mem("pow_offsets");
  166. $old_ha_offsets = mem("ha_offsets");
  167. $old_total_offsets = mem("total_offsets");
  168.  
  169. // Keep track of the new stuff
  170. $new_pow_offsets = vector();
  171. $new_ha_offsets = vector();
  172. $new_total_offsets = 0;
  173. $index = 1;
  174. $count = 1;
  175.  
  176. // Do we need to continue a computation?
  177. if (mem("continue")) {
  178. $new_pow_offsets = mem("temp_pow_offsets");
  179. $new_ha_offsets = mem("temp_ha_offsets");
  180. $new_total_offsets = mem("temp_total_offsets");
  181. $index = mem("temp_index");
  182. }
  183.  
  184. // Bruteforce through them
  185. while ($index <= $old_total_offsets) {
  186. // Are we at the quota yet?
  187. if ($count > $max_calcs) {
  188. // Store the temporary information, then break
  189. mem("temp_pow_offsets", $new_pow_offsets);
  190. mem("temp_ha_offsets", $new_ha_offsets);
  191. mem("temp_total_offsets", $new_total_offsets);
  192. mem("temp_index", $index);
  193. mem("continue", 1);
  194. break;
  195. }
  196.  
  197. // Get some information
  198. $current_pow_offset = at($old_pow_offsets, $index);
  199. $current_ha_offset = at($old_ha_offsets, $index);
  200.  
  201. // Assume that this offset is true, then run the numbers
  202.  
  203. // Get the actual bearing
  204. $actual_bearing = mod($bearing + $current_ha_offset, 360);
  205.  
  206. // Convert it to scientific radians
  207. $actual_ha = toRadian(toScientific($actual_bearing));
  208.  
  209. // Convert the elevation to scientific radians
  210. $actual_va = toRadian($elevation);
  211.  
  212. // Get the actual velocity
  213. $actual_vel = $power + $current_pow_offset;
  214.  
  215. // Compute the range, G = 10
  216. $range = $actual_vel^2 * sin(toDegree(2 * $actual_va)) / 10;
  217.  
  218. // Compute delta X and Y
  219. $delta_x = $range * cos(toDegree($actual_ha));
  220. $delta_y = $range * sin(toDegree($actual_ha));
  221.  
  222. // Compute destination X and Y
  223. $dest_x = round($source_x + $delta_x);
  224. $dest_y = round($source_y + $delta_y);
  225.  
  226. // Check if this matches the provided coordinates
  227. if ($dest_x == $result_x && $dest_y == $result_y) {
  228. // We got a match! Add it
  229. push_back($new_pow_offsets, $current_pow_offset);
  230. push_back($new_ha_offsets, $current_ha_offset);
  231. $new_total_offsets += 1;
  232. }
  233.  
  234. // Next iteration
  235. $index += 1;
  236. $count += 1;
  237. }
  238.  
  239. // If we're really done, store everything and report
  240. if ($index > $old_total_offsets) {
  241. mem("pow_offsets", $new_pow_offsets);
  242. mem("ha_offsets", $new_ha_offsets);
  243. mem("total_offsets", $new_total_offsets);
  244. mem("continue", 0);
  245.  
  246. // Report
  247. $report = tostring($new_total_offsets) + " offsets left! ";
  248. if ($new_total_offsets == 0) {
  249. $report += "Impossible, please reset!";
  250. mem("reset", 0);
  251. }
  252. if ($new_total_offsets == 1) {
  253. $report += "Perfectly accurate!";
  254. }
  255. if ($new_total_offsets > 1) {
  256. $report += "Not quite accurate yet!";
  257. }
  258. send($report);
  259. }
  260. }
  261.  
  262. // Computes the bearing and elevation required for the given destination
  263. def target($dest_x, $dest_y, $power, $source_x, $source_y) {
  264. // Retrieve the best offsets
  265. $pow_offsets = mem("pow_offsets");
  266. $ha_offsets = mem("ha_offsets");
  267. $pow_offset = at($pow_offsets, 1);
  268. $ha_offset = at($ha_offsets, 1);
  269.  
  270. // Compute delta X and Y
  271. $delta_x = $dest_x - $source_x;
  272. $delta_y = $dest_y - $source_y;
  273.  
  274. // Compute the distance we need
  275. $dist = sqrt($delta_x^2 + $delta_y^2);
  276.  
  277. // Get the actual power
  278. $actual_pow = $power + $pow_offset;
  279.  
  280. // Get the maximum distance achievable
  281. $max_range = $actual_pow^2 * sin(2 * 45) / 10;
  282.  
  283. // Check
  284. if ($dist > $max_range) {
  285. send("That target is out of range!");
  286. } else {
  287. // Compute the bearing we need
  288. $atan2_result = atan2($delta_y, $delta_x);
  289. $bearing = mod(toDegree($atan2_result), 360);
  290.  
  291. // Convert it
  292. $bearing = fromScientific($bearing);
  293.  
  294. // Modify it with the offset
  295. $bearing -= $ha_offset;
  296.  
  297. // Round it to two decimals
  298. $bearing = round($bearing * 100) / 100;
  299.  
  300. // Compute the vertical angle we need
  301. $elevation = 0.5 * asin(10 * $dist / $actual_pow^2);
  302.  
  303. // Round it as well
  304. $elevation = round($elevation * 10) / 10;
  305.  
  306. // All done! Report it
  307. $report = "Bearing = " + tostring($bearing) + " , Elevation = " + tostring($elevation);
  308. send($report);
  309. }
  310. }
  311.  
  312. // Applies a given power and bearing offset
  313. def apply($pow_offset, $ha_offset) {
  314. $pow_offsets = vector($pow_offset);
  315. $ha_offsets = vector($ha_offset);
  316. $total_offsets = 1;
  317. mem("reset", 1);
  318. mem("pow_offsets", $pow_offsets);
  319. mem("ha_offsets", $ha_offsets);
  320. mem("total_offsets", $total_offsets);
  321. send("Applied given offsets! Assuming they were accurate, you can now target!");
  322. }
  323.  
  324. // Gets the offsets and displays them
  325. def get() {
  326. $total_offsets = mem("total_offsets");
  327. if ($total_offsets == 1) {
  328. $pow_offsets = mem("pow_offsets");
  329. $ha_offsets = mem("ha_offsets");
  330. $pow_offset = at($pow_offsets, 1);
  331. $ha_offset = at($ha_offsets, 1);
  332. $report = "Power offset: " + tostring($pow_offset) + " , Bearing offset: " + tostring($ha_offset);
  333. send($report);
  334. } else {
  335. send("We're not accurate enough to have proper offsets!");
  336. }
  337. }
  338.  
  339. // Turn a list of <command, num1, num2, ...> into a number vector
  340. def tonums($command_vec) {
  341. $index = 2;
  342. $total = length($command_vec);
  343. $result = vector();
  344. while ($index <= $total) {
  345. $textv = at($command_vec, $index);
  346. $numv = tonum($textv);
  347. push_back($result, $numv);
  348. $index += 1;
  349. }
  350. return $result;
  351. }
  352.  
  353. // Initialisation
  354. if (!mem("init")) {
  355. mem("continue", 0);
  356. mem("reset", 0);
  357. mem("init", 1);
  358. }
  359.  
  360. // Command processing
  361. if ($freq == $opfreq) {
  362. // If we're still computing, make a nice progress report, then continue
  363. if (mem("continue")) {
  364. $report = "Still computing, currently at ";
  365. $total = mem("total_offsets");
  366. $current = mem("temp_index");
  367. $percent = round($current / $total * 100);
  368. $report += tostring($percent) + "%!";
  369. send($report);
  370. $params = mem("calibrate_params");
  371. $bearing = at($params, 1);
  372. $elevation = at($params, 2);
  373. $power = at($params, 3);
  374. $result_x = at($params, 4);
  375. $result_y = at($params, 5);
  376. $source_x = at($params, 6);
  377. $source_y = at($params, 7);
  378. calibrate($bearing, $elevation, $power, $result_x, $result_y, $source_x, $source_y);
  379. } else {
  380. // Check for commands
  381. $commanded = 0;
  382. $words = explode($content, " ");
  383. $first = at($words, 1);
  384. $first = lower($first);
  385. if ($first == "reset") {
  386. reset();
  387. mem("reset", 1);
  388. $commanded = 1;
  389. }
  390. if ($first == "help") {
  391. send("NTSL Telescience Calculator! To view this line, use 'help'. To reset the calibration, use 'reset'. To calibrate, use 'calibrate bearing elevation power result_x result_y source_x source_y'. To compute, use 'target dest_x dest_y power source_x source_y'. To transfer, use 'apply power_offset bearing_offset'. Have fun!");
  392. $commanded = 1;
  393. }
  394. if ($first == "calibrate") {
  395. if (mem("reset")) {
  396. send("Calibrating!");
  397. $params = tonums($words);
  398. mem("calibrate_params", $params);
  399. $bearing = at($params, 1);
  400. $elevation = at($params, 2);
  401. $power = at($params, 3);
  402. $result_x = at($params, 4);
  403. $result_y = at($params, 5);
  404. $source_x = at($params, 6);
  405. $source_y = at($params, 7);
  406. calibrate($bearing, $elevation, $power, $result_x, $result_y, $source_x, $source_y);
  407. } else {
  408. send("You should reset before calibrating!");
  409. }
  410. $commanded = 1;
  411. }
  412. if ($first == "target") {
  413. if (mem("reset")) {
  414. $params = tonums($words);
  415. $dest_x = at($params, 1);
  416. $dest_y = at($params, 2);
  417. $power = at($params, 3);
  418. $source_x = at($params, 4);
  419. $source_y = at($params, 5);
  420. target($dest_x, $dest_y, $power, $source_x, $source_y);
  421. } else {
  422. send("You should calibrate properly first!");
  423. }
  424. $commanded = 1;
  425. }
  426. if ($first == "apply") {
  427. $params = tonums($words);
  428. $pow_offset = at($params, 1);
  429. $ha_offset = at($params, 2);
  430. apply($dest_x, $dest_y, $power, $source_x, $source_y);
  431. $commanded = 1;
  432. }
  433. if ($first == "get") {
  434. if (mem("reset")) {
  435. get();
  436. } else {
  437. send("You should initialize first!");
  438. }
  439. $commanded = 1;
  440. }
  441.  
  442. // Display generic help if the command is unknown
  443. if (!$commanded) {
  444. send("Unknown command! Use 'help' for a list of commands and their usage!");
  445. }
  446. }
  447. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement