Precise slither

Simplified client for slither.io

当前为 2025-04-26 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Precise slither
  3. // @namespace precise_slither
  4. // @version 0.3
  5. // @description Simplified client for slither.io
  6. // @author Sr_2_0
  7. // @match *://slither.com/io
  8. // @match *://slither.io/
  9. // @grant none
  10. // @license MIT
  11. // ==/UserScript==
  12.  
  13. (function() {
  14. 'use strict';
  15.  
  16. // you can change these values
  17. const myNick_29 = 'tt'; // allowed characters: !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ (maximum lenght 24)
  18. const mySkin_29 = 1; // 0 - 65
  19. const useCustomSkin_29 = false; // true false
  20. const myCustomSkin_29 = [39, 28, 28, 29, 17, 0, 19, 30, 30, 30, 30, 7, 7, 13]; // use these numbers when building: 28 - 35, 37, 39, 41, 17 - 27, 8 - 16, 0 - 7 (maximum array lenght 227)
  21. const myCosmetic_29 = 255; // 255, 24 - 31, 16 - 23, 8 - 15, 0 - 7 (255 - without cosmetic)
  22. const serverIpAndPortForInputField_29 = '57.129.37.42:444';
  23. const maxFps_29 = 40;
  24.  
  25. // rewrite original slither client
  26. document.getElementsByTagName('html')[0].innerHTML = `
  27. <head>
  28. <title>precise slither</title>
  29. </head>
  30. <body>
  31. </body>
  32. `;
  33.  
  34. let ws_29;
  35.  
  36. let myId_29 = -1;
  37. let myIdWas_29 = false;
  38.  
  39. let snakes_29 = [];
  40. let preys_29 = [];
  41. let sectors_29 = [];
  42. let foods_29 = [];
  43. let foods_c_29 = 0;
  44.  
  45. let grd_29 = 16384;
  46. let mscps_29 = 0;
  47. let fmlts_29 = [];
  48. let fpsls_29 = [];
  49. let sector_size_29 = 480;
  50. let spangdv_29 = 4.8;
  51. let nsp1_29 = 4.25;
  52. let nsp2_29 = .5;
  53. let nsp3_29 = 12;
  54. let mamu_29 = .033;
  55. let mamu2_29 = .028;
  56. let cst_29 = .43;
  57. let protocol_version_29 = 2;
  58.  
  59. let real_flux_grd_29 = grd_29;
  60. let rfgrdForMinimap_29 = real_flux_grd_29;
  61.  
  62. let playersInfo_29 = "";
  63.  
  64. let minimapObjs_29 = [];
  65.  
  66. let myValidNick_29;
  67. let myValidSkin_29;
  68. let myCustomSkinData_29 = [];
  69. let myValidCosmetic_29;
  70.  
  71. let vfr_29 = 0;
  72. let vfrb_29 = 0;
  73. let fr_29 = 0;
  74. let lfr_29 = 0;
  75.  
  76. let ltm_29 = Date.now();
  77.  
  78. let last_ping_mtm_29 = 0;
  79. let wfpr_29 = false;
  80. let lastPings_29 = [];
  81. let lastPingsIndex_29 = 0;
  82. let avgPing_29 = 70;
  83.  
  84. let last_accel_mtm_29 = 0;
  85. let lstSnddAclState_29 = false;
  86. let acceleration_29 = false;
  87.  
  88. let last_e_mtm_29 = 0;
  89. let prevComndForEang_29 = -1;
  90. let whereMouseX_29 = -1;
  91. let whereMouseY_29 = -1;
  92.  
  93. let oefTimerId_29;
  94. let oefTimerStarted_29 = false;
  95.  
  96. let lastStartOtrisTime_29;
  97.  
  98. let currentFps_29 = 0;
  99. let currentFpsLastShowTime_29 = 0;
  100.  
  101. let gameExists_29 = false;
  102. let wantCloseCurrentGame_29 = false;
  103. let wantNewGame_29 = false;
  104. let buttonFunctionality_29 = true;
  105.  
  106. let xx_29 = 0;
  107. let yy_29 = 0;
  108. let cm1_29;
  109.  
  110. const pi2_29 = 2 * Math.PI;
  111.  
  112. function prepareNewGame_29() {
  113. gameExists_29 = true;
  114. myIdWas_29 = false;
  115. snakes_29 = [];
  116. preys_29 = [];
  117. sectors_29 = [];
  118. foods_29 = [];
  119. foods_c_29 = 0;
  120. xx_29 = 0;
  121. yy_29 = 0;
  122. playersInfo_29 = "";
  123. minimapObjs_29 = [];
  124. last_ping_mtm_29 = 0;
  125. wfpr_29 = false;
  126. lastPings_29 = [];
  127. lastPingsIndex_29 = 0;
  128. avgPing_29 = 70;
  129. last_accel_mtm_29 = 0;
  130. lstSnddAclState_29 = false;
  131. acceleration_29 = false;
  132. last_e_mtm_29 = 0;
  133. prevComndForEang_29 = -1;
  134. whereMouseX_29 = -1;
  135. whereMouseY_29 = -1;
  136. connect_29();
  137. }
  138.  
  139. function decodeSecret_29(sv, idba) {
  140. function qff9x_29(b) {
  141. eval(b);
  142. if (0 < idba.length) {
  143. b = 0;
  144. for (let d, a, e, c = 0; c < idba.length; c++) {
  145. d = 65,
  146. a = idba[c],
  147. 97 <= a && (d += 32, a -= 32),
  148. a -= 65,
  149. 0 == c && (b = 2 + a),
  150. e = a + b,
  151. e %= 26,
  152. b += 3 + a,
  153. idba[c] = e + d;
  154. }
  155. }
  156. };
  157. let a = "", b;
  158. for (let d = 0, e = 23, f = 0, g = 0; g < sv.length; ) {
  159. b = sv[g],
  160. g++,
  161. 96 >= b && (b += 32),
  162. b = (b - 97 - e) % 26,
  163. 0 > b && (b += 26),
  164. d *= 16,
  165. d += b,
  166. e += 17,
  167. 1 == f ? (a += String.fromCharCode(d), f = d = 0) : f++;
  168. }
  169. qff9x_29(a);
  170. for (a = 0; a < sv.length; a++)
  171. if (b = sv[a], 65 > b || 122 < b)
  172. return !1;
  173. return !0;
  174. };
  175.  
  176. // needed to calculate a score
  177. function setMscps_29(nmscps) {
  178. if (nmscps != mscps_29) {
  179. mscps_29 = nmscps;
  180. fmlts_29 = [];
  181. fpsls_29 = [];
  182. for (let i = 0; i <= mscps_29; i++) {
  183. if (i >= mscps_29)
  184. fmlts_29.push(fmlts_29[i - 1]);
  185. else
  186. fmlts_29.push(Math.pow(1 - i / mscps_29, 2.25));
  187. if (i == 0)
  188. fpsls_29.push(0);
  189. else
  190. fpsls_29.push(fpsls_29[i - 1] + 1 / fmlts_29[i - 1])
  191. }
  192. let t_fmlt = fmlts_29[fmlts_29.length - 1];
  193. let t_fpsl = fpsls_29[fpsls_29.length - 1];
  194. for (let i = 0; i < 2048; i++) {
  195. fmlts_29.push(t_fmlt);
  196. fpsls_29.push(t_fpsl)
  197. }
  198. }
  199. }
  200.  
  201. function newSnake_29(id, xx, yy, cv, ang, pts) {
  202. let o = {};
  203. o.id = id;
  204. o.xx = xx;
  205. o.yy = yy;
  206. o.chl = 0;
  207. o.tsp = 0;
  208. o.sc = 1;
  209. o.ssp = nsp1_29 + nsp2_29 * o.sc;
  210. o.fsp = o.ssp + .1;
  211. o.msp = nsp3_29;
  212. o.msl = 42;
  213. o.fam = 0;
  214. o.rsc = 0;
  215. o.ang = ang;
  216. o.eang = ang;
  217. o.wang = ang;
  218. o.sp = 2;
  219. if (pts) {
  220. o.pts = pts;
  221. o.sct = pts.length;
  222. } else {
  223. o.pts = [];
  224. o.sct = 0
  225. }
  226. o.tl = o.sct + o.fam;
  227. o.cfl = o.tl;
  228. o.scang = 1;
  229. snakes_29.push(o);
  230. return o;
  231. }
  232.  
  233. function newPrey_29(id, xx, yy, rad, dir, wang, ang, speed) {
  234. let pr = {};
  235. pr.id = id;
  236. pr.xx = xx;
  237. pr.yy = yy;
  238. pr.sz = rad;
  239. pr.dir = dir;
  240. pr.wang = wang;
  241. pr.ang = ang;
  242. pr.sp = speed;
  243. preys_29.push(pr);
  244. return pr;
  245. }
  246.  
  247. function newFood_29(id, xx, yy, rad) {
  248. let fo = {};
  249. fo.id = id;
  250. fo.xx = xx;
  251. fo.yy = yy;
  252. fo.sz = rad;
  253. foods_29[foods_c_29++] = fo;
  254. return fo;
  255. }
  256.  
  257. // function is executed before each frame is drawn
  258. function oef_29() {
  259. let ctm = Date.now();
  260. vfr_29 = (ctm - ltm_29) / 8;
  261. if (vfr_29 > 5)
  262. vfr_29 = 5;
  263. if (vfr_29 < 1.56)
  264. vfr_29 = 1.56;
  265. ltm_29 = ctm;
  266. lfr_29 = fr_29;
  267. fr_29 += vfr_29;
  268. vfrb_29 = Math.floor(fr_29) - Math.floor(lfr_29);
  269.  
  270. let mang, vang;
  271. for (let i = snakes_29.length - 1; i >= 0; i--) {
  272. let o = snakes_29[i];
  273. mang = mamu_29 * vfr_29 * o.scang * o.spang;
  274. let csp = o.sp * vfr_29 / 4;
  275. if (csp > o.msl)
  276. csp = o.msl;
  277. if (o.tsp != o.sp)
  278. if (o.tsp < o.sp) {
  279. o.tsp += .3 * vfr_29;
  280. if (o.tsp > o.sp)
  281. o.tsp = o.sp;
  282. } else {
  283. o.tsp -= .3 * vfr_29;
  284. if (o.tsp < o.sp)
  285. o.tsp = o.sp;
  286. }
  287. o.cfl = o.tl;
  288. if (o.dir == 1) {
  289. o.ang -= mang;
  290. if (o.ang < 0 || o.ang >= pi2_29)
  291. o.ang %= pi2_29;
  292. if (o.ang < 0)
  293. o.ang += pi2_29;
  294. vang = (o.wang - o.ang) % pi2_29;
  295. if (vang < 0)
  296. vang += pi2_29;
  297. if (vang > Math.PI)
  298. vang -= pi2_29;
  299. if (vang > 0) {
  300. o.ang = o.wang;
  301. o.dir = 0
  302. }
  303. } else if (o.dir == 2) {
  304. o.ang += mang;
  305. if (o.ang < 0 || o.ang >= pi2_29)
  306. o.ang %= pi2_29;
  307. if (o.ang < 0)
  308. o.ang += pi2_29;
  309. vang = (o.wang - o.ang) % pi2_29;
  310. if (vang < 0)
  311. vang += pi2_29;
  312. if (vang > Math.PI)
  313. vang -= pi2_29;
  314. if (vang < 0) {
  315. o.ang = o.wang;
  316. o.dir = 0
  317. }
  318. } else
  319. o.ang = o.wang;
  320. let po = o.pts[o.pts.length - 1];
  321. o.xx += Math.cos(o.ang) * csp;
  322. o.yy += Math.sin(o.ang) * csp;
  323. o.chl += csp / o.msl
  324. if (vfrb_29 > 0) {
  325. for (let j = o.pts.length - 1; j >= 0; j--) {
  326. let po = o.pts[j];
  327. if (po.dying) {
  328. po.da += .0015 * vfrb_29;
  329. if (po.da > 1) {
  330. o.pts.splice(j, 1);
  331. }
  332. }
  333. }
  334. }
  335. }
  336. for (let i = preys_29.length - 1; i >= 0; i--) {
  337. let pr = preys_29[i];
  338. mang = mamu2_29 * vfr_29;
  339. let csp = pr.sp * vfr_29 / 4;
  340. if (pr.dir == 1) {
  341. pr.ang -= mang;
  342. if (pr.ang < 0 || pr.ang >= pi2_29)
  343. pr.ang %= pi2_29;
  344. if (pr.ang < 0)
  345. pr.ang += pi2_29;
  346. vang = (pr.wang - pr.ang) % pi2_29;
  347. if (vang < 0)
  348. vang += pi2_29;
  349. if (vang > Math.PI)
  350. vang -= pi2_29;
  351. if (vang > 0) {
  352. pr.ang = pr.wang;
  353. pr.dir = 0
  354. }
  355. } else if (pr.dir == 2) {
  356. pr.ang += mang;
  357. if (pr.ang < 0 || pr.ang >= pi2_29)
  358. pr.ang %= pi2_29;
  359. if (pr.ang < 0)
  360. pr.ang += pi2_29;
  361. vang = (pr.wang - pr.ang) % pi2_29;
  362. if (vang < 0)
  363. vang += pi2_29;
  364. if (vang > Math.PI)
  365. vang -= pi2_29;
  366. if (vang < 0) {
  367. pr.ang = pr.wang;
  368. pr.dir = 0
  369. }
  370. } else
  371. pr.ang = pr.wang;
  372. pr.xx += Math.cos(pr.ang) * csp;
  373. pr.yy += Math.sin(pr.ang) * csp;
  374. }
  375. vfr_29 = 0;
  376. vfrb_29 = 0;
  377.  
  378. if (!wantCloseCurrentGame_29 && !wfpr_29) {
  379. if (ctm - last_ping_mtm_29 > 250) {
  380. last_ping_mtm_29 = ctm;
  381. wfpr_29 = true;
  382. const ba = new Uint8Array([251]);
  383. ws_29.send(ba);
  384. }
  385. }
  386. if (!wantCloseCurrentGame_29 && acceleration_29 != lstSnddAclState_29 && ctm - last_accel_mtm_29 > 150) {
  387. lstSnddAclState_29 = acceleration_29;
  388. last_accel_mtm_29 = ctm;
  389. let ba = new Uint8Array(1);
  390. if (acceleration_29)
  391. ba[0] = 253;
  392. else
  393. ba[0] = 254;
  394. ws_29.send(ba);
  395. }
  396. if (!wantCloseCurrentGame_29 && ctm - last_e_mtm_29 > 100 && whereMouseX_29 != -1 && whereMouseY_29 != -1) {
  397. let centerX = playingArenaWidth / 2;
  398. let centerY = playingArenaHeight / 2;
  399. let differeX = whereMouseX_29 - centerX;
  400. let differeY = whereMouseY_29 - centerY;
  401. let mouAng = Math.atan2(differeY, differeX);
  402. if (mouAng < 0)
  403. mouAng += Math.PI * 2;
  404. const angleToSend = createAngleToSend(mouAng);
  405. if (angleToSend != prevComndForEang_29) {
  406. prevComndForEang_29 = angleToSend;
  407. last_e_mtm_29 = ctm;
  408. let ba = new Uint8Array([angleToSend]);
  409. ws_29.send(ba);
  410. }
  411.  
  412. function createAngleToSend(angle) {
  413. let angleToSend = Math.round(angle / pi2_29 * 256);
  414. if (angleToSend <= 50)
  415. return angleToSend;
  416. for (let tmp = 51, ofs = 0; tmp <= 255; tmp += 51, ofs++) {
  417. if (angleToSend >= tmp - 50 && angleToSend <= tmp - 1)
  418. angleToSend -= ofs;
  419. else if (angleToSend == tmp) {
  420. if (angle < Math.PI * 2 / 256 * tmp)
  421. angleToSend = tmp - ofs - 1;
  422. else
  423. angleToSend = tmp - ofs;
  424. }
  425. }
  426. if (angleToSend == 251 || angleToSend == 256)
  427. angleToSend = 0;
  428. return angleToSend;
  429. }
  430. }
  431.  
  432. drawFrame();
  433. oefTimerId_29 = setTimeout(oef_29, Math.max(lastStartOtrisTime_29 + (1000 / maxFps_29) - Date.now(), 0));
  434. if (wantCloseCurrentGame_29 && ws_29.readyState === WebSocket.OPEN)
  435. ws_29.close();
  436. }
  437.  
  438. function connect_29() {
  439. ws_29 = new WebSocket("ws://" + serverIpAndPortField.value + "/slither");
  440. ws_29.binaryType = "arraybuffer";
  441. ws_29.onopen = function() {
  442. const ba = new Uint8Array([99, 4]);
  443. ws_29.send(ba);
  444. };
  445. ws_29.onmessage = function(e) {
  446. let a = new Uint8Array(e.data);
  447. if (a.length >= 2) {
  448. let cmd = String.fromCharCode(a[2]);
  449. let m = 3;
  450. let alen = a.length;
  451. let plen = a.length - 2;
  452. let dlen = a.length - 3;
  453.  
  454. // initial setup
  455. if (cmd == "a") {
  456. grd_29 = a[m] << 16 | a[m + 1] << 8 | a[m + 2];
  457. m += 3;
  458. real_flux_grd_29 = grd_29;
  459. rfgrdForMinimap_29 = real_flux_grd_29;
  460. let nmscps = a[m] << 8 | a[m + 1];
  461. m += 2;
  462. sector_size_29 = a[m] << 8 | a[m + 1];
  463. m += 2;
  464. m += 2;
  465. spangdv_29 = a[m] / 10;
  466. m++;
  467. nsp1_29 = (a[m] << 8 | a[m + 1]) / 100;
  468. m += 2;
  469. nsp2_29 = (a[m] << 8 | a[m + 1]) / 100;
  470. m += 2;
  471. nsp3_29 = (a[m] << 8 | a[m + 1]) / 100;
  472. m += 2;
  473. mamu_29 = (a[m] << 8 | a[m + 1]) / 1E3;
  474. m += 2;
  475. mamu2_29 = (a[m] << 8 | a[m + 1]) / 1E3;
  476. m += 2;
  477. cst_29 = (a[m] << 8 | a[m + 1]) / 1E3;
  478. m += 2;
  479. if (m < alen) {
  480. protocol_version_29 = a[m];
  481. m++;
  482. if (protocol_version_29 != 13) {
  483. ws_29.close();
  484. }
  485. }
  486. setMscps_29(nmscps);
  487. }
  488. // snake rotation
  489. else if (cmd == "e" || cmd == "E" || cmd == "3" || cmd == "4" || cmd == "5") {
  490. let id = a[m] << 8 | a[m + 1];
  491. m += 2;
  492. let dir = -1;
  493. let ang = -1;
  494. let wang = -1;
  495. let speed = -1;
  496. if (protocol_version_29 >= 6)
  497. if (plen == 6) {
  498. if (cmd == "e")
  499. dir = 1;
  500. else
  501. dir = 2;
  502. ang = a[m] * 2 * Math.PI / 256;
  503. m++;
  504. wang = a[m] * 2 * Math.PI / 256;
  505. m++;
  506. speed = a[m] / 18;
  507. m++
  508. } else if (plen == 5)
  509. if (cmd == "e") {
  510. ang = a[m] * 2 * Math.PI / 256;
  511. m++;
  512. speed = a[m] / 18;
  513. m++
  514. } else if (cmd == "E") {
  515. dir = 1;
  516. wang = a[m] * 2 * Math.PI / 256;
  517. m++;
  518. speed = a[m] / 18;
  519. m++
  520. } else if (cmd == "4") {
  521. dir = 2;
  522. wang = a[m] * 2 * Math.PI / 256;
  523. m++;
  524. speed = a[m] / 18;
  525. m++
  526. } else if (cmd == "3") {
  527. dir = 1;
  528. ang = a[m] * 2 * Math.PI / 256;
  529. m++;
  530. wang = a[m] * 2 * Math.PI / 256;
  531. m++
  532. } else {
  533. if (cmd == "5") {
  534. dir = 2;
  535. ang = a[m] * 2 * Math.PI / 256;
  536. m++;
  537. wang = a[m] * 2 * Math.PI / 256;
  538. m++
  539. }
  540. }
  541. else {
  542. if (plen == 4)
  543. if (cmd == "e") {
  544. ang = a[m] * 2 * Math.PI / 256;
  545. m++
  546. } else if (cmd == "E") {
  547. dir = 1;
  548. wang = a[m] * 2 * Math.PI / 256;
  549. m++
  550. } else if (cmd == "4") {
  551. dir = 2;
  552. wang = a[m] * 2 * Math.PI / 256;
  553. m++
  554. } else if (cmd == "3") {
  555. speed = a[m] / 18;
  556. m++
  557. }
  558. }
  559. else if (protocol_version_29 >= 3) {
  560. if (cmd != "3")
  561. if (plen == 8 || plen == 7 || plen == 6 && cmd != "3" || plen == 5 && cmd != "3")
  562. if (cmd == "e")
  563. dir = 1;
  564. else
  565. dir = 2;
  566. if (plen == 8 || plen == 7 || plen == 5 && cmd == "3" || plen == 6 && cmd == "3") {
  567. ang = (a[m] << 8 | a[m + 1]) * 2 * Math.PI / 65535;
  568. m += 2
  569. }
  570. if (plen == 8 || plen == 7 || plen == 5 && cmd != "3" || plen == 6 && cmd != "3") {
  571. wang = (a[m] << 8 | a[m + 1]) * 2 * Math.PI / 65535;
  572. m += 2
  573. }
  574. if (plen == 8 || plen == 6 || plen == 4) {
  575. speed = a[m] / 18;
  576. m++
  577. }
  578. } else {
  579. if (dlen == 11 || dlen == 8 || dlen == 9 || dlen == 6) {
  580. dir = a[m] - 48;
  581. m++
  582. }
  583. if (dlen == 11 || dlen == 7 || dlen == 9 || dlen == 5) {
  584. ang = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) * 2 * Math.PI / 16777215;
  585. m += 3
  586. }
  587. if (dlen == 11 || dlen == 8 || dlen == 9 || dlen == 6) {
  588. wang = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) * 2 * Math.PI / 16777215;
  589. m += 3
  590. }
  591. if (dlen == 11 || dlen == 7 || dlen == 8 || dlen == 4) {
  592. speed = (a[m] << 8 | a[m + 1]) / 1E3;
  593. m += 2
  594. }
  595. }
  596. let o;
  597. for (let i = snakes_29.length - 1; i >= 0; i--) {
  598. if (snakes_29[i].id == id) {
  599. o = snakes_29[i];
  600. break;
  601. }
  602. }
  603. if (o) {
  604. if (dir != -1)
  605. o.dir = dir;
  606. if (ang != -1) {
  607. o.ang = ang;
  608. }
  609. if (wang != -1) {
  610. o.wang = wang;
  611. o.eang = wang;
  612. }
  613. if (speed != -1) {
  614. o.sp = speed;
  615. o.spang = o.sp / spangdv_29;
  616. if (o.spang > 1)
  617. o.spang = 1;
  618. }
  619. }
  620. }
  621. // pre-init response
  622. else if (cmd == "6") {
  623. let server_version = new Uint8Array(alen - m);
  624. for (let i = 0; m < alen; i++) {
  625. server_version[i] = a[m];
  626. m++;
  627. }
  628. let idba = new Uint8Array(24);
  629. decodeSecret_29(server_version, idba);
  630. ws_29.send(idba);
  631.  
  632. let ca = [];
  633. if (useCustomSkin_29 && myCustomSkinData_29.length > 8)
  634. ca = myCustomSkinData_29;
  635. let lgba = new Uint8Array(6 + myValidNick_29.length + ca.length);
  636. lgba[0] = 115;
  637. lgba[1] = 12;
  638. lgba[2] = myValidSkin_29;
  639. lgba[3] = myValidNick_29.length;
  640. let m2 = 4;
  641. for (let i = 0; i < myValidNick_29.length; i++) {
  642. lgba[m2] = myValidNick_29.charCodeAt(i);
  643. m2++;
  644. }
  645. lgba[m2] = 0;
  646. m2++;
  647. lgba[m2] = myValidCosmetic_29;
  648. m2++;
  649. for (let i = 0; i < ca.length; i++) {
  650. lgba[m2] = ca[i];
  651. m2++
  652. }
  653. ws_29.send(lgba);
  654.  
  655. // send first ping
  656. last_ping_mtm_29 = Date.now();
  657. wfpr_29 = true;
  658. const ba = new Uint8Array([251]);
  659. ws_29.send(ba);
  660. }
  661. // update snake last body part fullness (fam)
  662. else if (cmd == "h") {
  663. let id = a[m] << 8 | a[m + 1];
  664. m += 2;
  665. let fam = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) / 16777215;
  666. m += 3;
  667. let o;
  668. for (let i = snakes_29.length - 1; i >= 0; i--) {
  669. if (snakes_29[i].id == id) {
  670. o = snakes_29[i];
  671. break;
  672. }
  673. }
  674. if (o) {
  675. o.fam = fam;
  676. o.tl = o.sct + o.fam;
  677. }
  678. }
  679. // remove snake part
  680. else if (cmd == "r") {
  681. let id = a[m] << 8 | a[m + 1];
  682. m += 2;
  683. let o;
  684. for (let i = snakes_29.length - 1; i >= 0; i--) {
  685. if (snakes_29[i].id == id) {
  686. o = snakes_29[i];
  687. break;
  688. }
  689. }
  690. if (o) {
  691. if (dlen >= 4) {
  692. o.fam = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) / 16777215;
  693. m += 3
  694. }
  695. for (let j = 0; j < o.pts.length; j++)
  696. if (!o.pts[j].dying) {
  697. o.pts[j].dying = true;
  698. o.sct--;
  699. o.sc = Math.min(6, 1 + (o.sct - 2) / 106);
  700. o.scang = .13 + .87 * Math.pow((7 - o.sc) / 6, 2);
  701. o.ssp = nsp1_29 + nsp2_29 * o.sc;
  702. o.fsp = o.ssp + .1;
  703. break;
  704. }
  705. o.tl = o.sct + o.fam;
  706. }
  707. }
  708. // update number of snake parts that you lost while spinning in a closed circle (rsc)
  709. else if (cmd == "R") {
  710. for (let i = snakes_29.length - 1; i >= 0; i--) {
  711. if (snakes_29[i].id == myId_29) {
  712. snakes_29[i].rsc = a[m];
  713. break;
  714. }
  715. }
  716. m++;
  717. }
  718. // move or increase snake
  719. else if (cmd == "g" || cmd == "n" || cmd == "G" || cmd == "N") {
  720. let adding_only = cmd == "n" || cmd == "N";
  721. let id = a[m] << 8 | a[m + 1];
  722. m += 2;
  723. let o;
  724. for (let i = snakes_29.length - 1; i >= 0; i--) {
  725. if (snakes_29[i].id == id) {
  726. o = snakes_29[i];
  727. break;
  728. }
  729. }
  730. if (o) {
  731. if (adding_only)
  732. o.sct++;
  733. else
  734. for (let j = 0; j < o.pts.length; j++)
  735. if (!o.pts[j].dying) {
  736. o.pts[j].dying = true;
  737. break
  738. }
  739. let po = o.pts[o.pts.length - 1];
  740. let lpo = po;
  741. let mpo;
  742. let mv;
  743. let lmpo;
  744. if (cmd == "g" || cmd == "n") {
  745. xx_29 = a[m] << 8 | a[m + 1];
  746. m += 2;
  747. yy_29 = a[m] << 8 | a[m + 1];
  748. m += 2
  749. } else {
  750. xx_29 = lpo.xx + a[m] - 128;
  751. m++;
  752. yy_29 = lpo.yy + a[m] - 128;
  753. m++;
  754. }
  755. if (adding_only) {
  756. o.fam = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) / 16777215;
  757. m += 3
  758. }
  759. po = {};
  760. po.xx = xx_29;
  761. po.yy = yy_29;
  762. po.da = 0;
  763. o.pts.push(po);
  764. let k = o.pts.length - 3;
  765. let n;
  766. if (k >= 1) {
  767. lmpo = o.pts[k];
  768. n = 0;
  769. mv = 0;
  770. for (let j = k - 1; j >= 0; j--) {
  771. mpo = o.pts[j];
  772. n++;
  773. if (n <= 4)
  774. mv = cst_29 * n / 4;
  775. mpo.xx += (lmpo.xx - mpo.xx) * mv;
  776. mpo.yy += (lmpo.yy - mpo.yy) * mv;
  777. lmpo = mpo;
  778. }
  779. }
  780. o.sc = Math.min(6, 1 + (o.sct - 2) / 106);
  781. o.scang = .13 + .87 * Math.pow((7 - o.sc) / 6, 2);
  782. o.ssp = nsp1_29 + nsp2_29 * o.sc;
  783. o.fsp = o.ssp + .1;
  784. if (adding_only)
  785. o.tl = o.sct + o.fam;
  786. o.chl = 0;
  787. o.xx = xx_29;
  788. o.yy = yy_29;
  789. }
  790. }
  791. // leaderboard
  792. else if (cmd == "l") {
  793. playersInfo_29 = "";
  794. let nc = 0;
  795. let pos = 0;
  796. let v;
  797. let score;
  798. let my_pos = a[m];
  799. m++;
  800. let rank = a[m] << 8 | a[m + 1];
  801. m += 2;
  802. let snake_count = a[m] << 8 | a[m + 1];
  803. m += 2;
  804. while (m < alen) {
  805. let sct = a[m] << 8 | a[m + 1];
  806. m += 2;
  807. let fam = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) / 16777215;
  808. m += 3;
  809. m++;
  810. let nl = a[m];
  811. m++;
  812. pos++;
  813. let nk = "";
  814. for (let j = 0; j < nl; j++) {
  815. v = a[m];
  816. nk += String.fromCharCode(v);
  817. m++;
  818. }
  819. if (pos == my_pos) {
  820. nk = myValidNick_29;
  821. }
  822. nc++;
  823. score = Math.floor((fpsls_29[sct] + fam / fmlts_29[sct] - 1) * 15 - 5) / 1;
  824. playersInfo_29 += nc + " " + score + " " + nk + "\n";
  825. }
  826. playersInfo_29 += "\n " + rank + " / " + snake_count;
  827. }
  828. // add sector (for foods)
  829. else if (cmd == "W") {
  830. xx_29 = a[m];
  831. m++;
  832. yy_29 = a[m];
  833. m++;
  834. let o = {};
  835. o.xx = xx_29;
  836. o.yy = yy_29;
  837. sectors_29.push(o)
  838. }
  839. // remove sector (for foods)
  840. else if (cmd == "w") {
  841. xx_29 = a[m];
  842. m++;
  843. yy_29 = a[m];
  844. m++;
  845. cm1_29 = foods_c_29 - 1;
  846. for (let i = cm1_29; i >= 0; i--) {
  847. let fo = foods_29[i];
  848. if (fo.sx == xx_29)
  849. if (fo.sy == yy_29)
  850. if (i == cm1_29) {
  851. foods_29[i] = null;
  852. foods_c_29--;
  853. cm1_29--;
  854. } else {
  855. foods_29[i] = foods_29[cm1_29];
  856. foods_29[cm1_29] = null;
  857. foods_c_29--;
  858. cm1_29--;
  859. }
  860. }
  861. for (let i = sectors_29.length - 1; i >= 0; i--) {
  862. let o = sectors_29[i];
  863. if (o.xx == xx_29)
  864. if (o.yy == yy_29)
  865. sectors_29.splice(i, 1);
  866. }
  867. }
  868. // pong
  869. else if (cmd == "p") {
  870. wfpr_29 = false;
  871. lastPings_29[lastPingsIndex_29] = Date.now() - last_ping_mtm_29;
  872. lastPingsIndex_29++;
  873. if (lastPingsIndex_29 == 60)
  874. lastPingsIndex_29 = 0;
  875. avgPing_29 = 0;
  876. for (let i = 0; i < lastPings_29.length; i++)
  877. avgPing_29 += lastPings_29[i];
  878. avgPing_29 /= lastPings_29.length;
  879. }
  880. // update minimap
  881. else if (cmd == "M") {
  882. rfgrdForMinimap_29 = real_flux_grd_29;
  883. minimapObjs_29 = [];
  884. let moInd = 0;
  885. const u_m = [64, 32, 16, 8, 4, 2, 1];
  886. let sz = a[m] << 8 | a[m + 1];
  887. m += 2;
  888. if (sz > 512)
  889. sz = 512;
  890. minimapObjs_29[moInd] = {};
  891. minimapObjs_29[moInd].sz = sz;
  892. moInd++;
  893. let i;
  894. let k = 0;
  895. let xx = sz - 1;
  896. let yy = sz - 1;
  897. while (m < alen) {
  898. if (yy < 0)
  899. break;
  900. k = a[m++];
  901. if (k >= 128) {
  902. if (k == 255)
  903. k = 126 * a[m++];
  904. else
  905. k -= 128;
  906. for (i = 0; i < k; i++) {
  907. xx--;
  908. if (xx < 0) {
  909. xx = sz - 1;
  910. yy--;
  911. if (yy < 0)
  912. break;
  913. }
  914. }
  915. } else
  916. for (i = 0; i < 7; i++) {
  917. if ((k & u_m[i]) > 0) {
  918. minimapObjs_29[moInd] = {};
  919. minimapObjs_29[moInd].xx = xx;
  920. minimapObjs_29[moInd].yy = yy;
  921. moInd++;
  922. }
  923. xx--;
  924. if (xx < 0) {
  925. xx = sz - 1;
  926. yy--;
  927. if (yy < 0)
  928. break;
  929. }
  930. }
  931. }
  932. }
  933. // add/remove snake
  934. else if (cmd == "s") {
  935. let id = a[m] << 8 | a[m + 1];
  936. m += 2;
  937. if (dlen > 6) {
  938. let ang = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) * 2 * Math.PI / 16777215;
  939. m += 3;
  940. let dir = a[m] - 48;
  941. m++;
  942. let wang = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) * 2 * Math.PI / 16777215;
  943. m += 3;
  944. let speed = (a[m] << 8 | a[m + 1]) / 1E3;
  945. m += 2;
  946. let fam = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) / 16777215;
  947. m += 3;
  948. let cv = a[m];
  949. m++;
  950. let pts = [];
  951. let snx = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) / 5;
  952. m += 3;
  953. let sny = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) / 5;
  954. m += 3;
  955. let nl = a[m];
  956. m++;
  957. let nk = "";
  958. for (let j = 0; j < nl; j++) {
  959. nk += String.fromCharCode(a[m]);
  960. m++
  961. }
  962. let skl = a[m];
  963. m++;
  964. m += skl;
  965. m++;
  966. xx_29 = 0;
  967. yy_29 = 0;
  968. let fp = false;
  969. while (m < alen) {
  970. if (!fp) {
  971. xx_29 = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) / 5;
  972. m += 3;
  973. yy_29 = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) / 5;
  974. m += 3;
  975. fp = true
  976. } else {
  977. xx_29 += (a[m] - 127) / 2;
  978. m++;
  979. yy_29 += (a[m] - 127) / 2;
  980. m++
  981. }
  982. let po = {};
  983. po.dying = false;
  984. po.xx = xx_29;
  985. po.yy = yy_29;
  986. po.da = 0;
  987. pts.push(po)
  988. }
  989. let o = newSnake_29(id, snx, sny, cv, ang, pts);
  990. o.nk = nk;
  991. o.eang = o.wang = wang;
  992. o.sp = speed;
  993. o.spang = o.sp / spangdv_29;
  994. if (o.spang > 1)
  995. o.spang = 1;
  996. o.fam = fam;
  997. o.sc = Math.min(6, 1 + (o.sct - 2) / 106);
  998. o.scang = .13 + .87 * Math.pow((7 - o.sc) / 6, 2);
  999. o.ssp = nsp1_29 + nsp2_29 * o.sc;
  1000. o.fsp = o.ssp + .1;
  1001. o.tl = o.sct + o.fam;
  1002. if (myIdWas_29 == false) {
  1003. myId_29 = id;
  1004. myIdWas_29 = true;
  1005. }
  1006. } else {
  1007. m++;
  1008. for (let i = snakes_29.length - 1; i >= 0; i--) {
  1009. if (snakes_29[i].id == id) {
  1010. snakes_29.splice(i, 1);
  1011. break;
  1012. }
  1013. }
  1014. }
  1015. if (!oefTimerStarted_29) {
  1016. oefTimerStarted_29 = true;
  1017. oef_29();
  1018. }
  1019. buttonFunctionality_29 = true;
  1020. }
  1021. // add food
  1022. else if (cmd == "F") {
  1023. let gsi = false;
  1024. let sx, sy;
  1025. while (m < alen) {
  1026. m++;
  1027. xx_29 = a[m] << 8 | a[m + 1];
  1028. m += 2;
  1029. yy_29 = a[m] << 8 | a[m + 1];
  1030. m += 2;
  1031. let rad = a[m] / 5;
  1032. m++;
  1033. let id = yy_29 * grd_29 * 3 + xx_29;
  1034. if (rad > 0) {
  1035. let fo = newFood_29(id, xx_29, yy_29, rad);
  1036. if (!gsi) {
  1037. gsi = true;
  1038. sx = Math.floor(xx_29 / sector_size_29);
  1039. sy = Math.floor(yy_29 / sector_size_29);
  1040. }
  1041. fo.sx = sx;
  1042. fo.sy = sy;
  1043. }
  1044. else {
  1045. if (!gsi) {
  1046. gsi = true;
  1047. sx = Math.floor(xx_29 / sector_size_29);
  1048. sy = Math.floor(yy_29 / sector_size_29);
  1049. }
  1050. }
  1051. }
  1052. }
  1053. // add food
  1054. else if (cmd == "b" || cmd == "f") {
  1055. m++;
  1056. if (dlen > 4) {
  1057. xx_29 = a[m] << 8 | a[m + 1];
  1058. m += 2;
  1059. yy_29 = a[m] << 8 | a[m + 1];
  1060. m += 2;
  1061. let id = yy_29 * grd_29 * 3 + xx_29;
  1062. let rad = a[m] / 5;
  1063. m++;
  1064. if (rad > 0) {
  1065. let fo = newFood_29(id, xx_29, yy_29, rad);
  1066. fo.sx = Math.floor(xx_29 / sector_size_29);
  1067. fo.sy = Math.floor(yy_29 / sector_size_29);
  1068. }
  1069. }
  1070. }
  1071. // food eaten
  1072. else if (cmd == "c") {
  1073. let xx = a[m] << 8 | a[m + 1];
  1074. m += 2;
  1075. let yy = a[m] << 8 | a[m + 1];
  1076. m += 2;
  1077. let id = yy * grd_29 * 3 + xx
  1078. cm1_29 = foods_c_29 - 1;
  1079. for (let i = cm1_29; i >= 0; i--) {
  1080. let fo = foods_29[i];
  1081. if (fo.id == id) {
  1082. if (m + 2 <= alen) {
  1083. m += 2;
  1084. }
  1085. if (i == cm1_29) {
  1086. foods_29[i] = null;
  1087. foods_c_29--;
  1088. cm1_29--;
  1089. } else {
  1090. foods_29[i] = foods_29[cm1_29];
  1091. foods_29[cm1_29] = null;
  1092. foods_c_29--;
  1093. cm1_29--;
  1094. }
  1095. break;
  1096. }
  1097. }
  1098. }
  1099. // update prey
  1100. else if (cmd == "j") {
  1101. let id = a[m] << 8 | a[m + 1];
  1102. m += 2;
  1103. xx_29 = 1 + (a[m] << 8 | a[m + 1]) * 3;
  1104. m += 2;
  1105. yy_29 = 1 + (a[m] << 8 | a[m + 1]) * 3;
  1106. m += 2;
  1107. let pr = null;
  1108. for (let i = preys_29.length - 1; i >= 0; i--)
  1109. if (preys_29[i].id == id) {
  1110. pr = preys_29[i];
  1111. break;
  1112. }
  1113. if (pr) {
  1114. if (dlen == 15) {
  1115. pr.dir = a[m] - 48;
  1116. m++;
  1117. pr.ang = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) * 2 * Math.PI / 16777215;
  1118. m += 3;
  1119. pr.wang = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) * 2 * Math.PI / 16777215;
  1120. m += 3;
  1121. pr.sp = (a[m] << 8 | a[m + 1]) / 1E3;
  1122. m += 2
  1123. } else if (dlen == 11) {
  1124. pr.ang = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) * 2 * Math.PI / 16777215;
  1125. m += 3;
  1126. pr.sp = (a[m] << 8 | a[m + 1]) / 1E3;
  1127. m += 2
  1128. } else if (dlen == 12) {
  1129. pr.dir = a[m] - 48;
  1130. m++;
  1131. pr.wang = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) * 2 * Math.PI / 16777215;
  1132. m += 3;
  1133. pr.sp = (a[m] << 8 | a[m + 1]) / 1E3;
  1134. m += 2
  1135. } else if (dlen == 13) {
  1136. pr.dir = a[m] - 48;
  1137. m++;
  1138. pr.ang = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) * 2 * Math.PI / 16777215;
  1139. m += 3;
  1140. pr.wang = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) * 2 * Math.PI / 16777215;
  1141. m += 3
  1142. } else if (dlen == 9) {
  1143. pr.ang = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) * 2 * Math.PI / 16777215;
  1144. m += 3
  1145. } else if (dlen == 10) {
  1146. pr.dir = a[m] - 48;
  1147. m++;
  1148. pr.wang = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) * 2 * Math.PI / 16777215;
  1149. m += 3
  1150. } else if (dlen == 8) {
  1151. pr.sp = (a[m] << 8 | a[m + 1]) / 1E3;
  1152. m += 2
  1153. }
  1154. pr.xx = xx_29;
  1155. pr.yy = yy_29;
  1156. }
  1157. }
  1158. // add/remove prey
  1159. else if (cmd == "y") {
  1160. let id = a[m] << 8 | a[m + 1];
  1161. m += 2;
  1162. if (dlen == 2)
  1163. for (let i = preys_29.length - 1; i >= 0; i--) {
  1164. let pr = preys_29[i];
  1165. if (pr.id == id) {
  1166. preys_29.splice(i, 1);
  1167. break;
  1168. }
  1169. }
  1170. else if (dlen == 4) {
  1171. m += 2;
  1172. for (let i = preys_29.length - 1; i >= 0; i--) {
  1173. let pr = preys_29[i];
  1174. if (pr.id == id) {
  1175. preys_29.splice(i, 1);
  1176. break;
  1177. }
  1178. }
  1179. } else {
  1180. m++;
  1181. xx_29 = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) / 5;
  1182. m += 3;
  1183. yy_29 = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) / 5;
  1184. m += 3;
  1185. let rad = a[m] / 5;
  1186. m++;
  1187. let dir = a[m] - 48;
  1188. m++;
  1189. let wang = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) * 2 * Math.PI / 16777215;
  1190. m += 3;
  1191. let ang = (a[m] << 16 | a[m + 1] << 8 | a[m + 2]) * 2 * Math.PI / 16777215;
  1192. m += 3;
  1193. let speed = (a[m] << 8 | a[m + 1]) / 1E3;
  1194. m += 2;
  1195. newPrey_29(id, xx_29, yy_29, rad, dir, wang, ang, speed)
  1196. }
  1197. }
  1198. // update map border
  1199. else if (cmd == "z") {
  1200. real_flux_grd_29 = a[m] << 16 | a[m + 1] << 8 | a[m + 2];
  1201. }
  1202. }
  1203. };
  1204. ws_29.onerror = function(error) {
  1205. console.error('WebSocket error: ', error);
  1206. };
  1207. ws_29.onclose = function() {
  1208. if (oefTimerStarted_29) {
  1209. clearTimeout(oefTimerId_29);
  1210. }
  1211. oefTimerStarted_29 = false;
  1212. wantCloseCurrentGame_29 = false;
  1213. gameExists_29 = false;
  1214. buttonFunctionality_29 = true;
  1215. if (wantNewGame_29) {
  1216. buttonFunctionality_29 = false;
  1217. wantNewGame_29 = false;
  1218. prepareNewGame_29();
  1219. }
  1220. };
  1221. };
  1222.  
  1223.  
  1224. let playingArenaWidth = Math.ceil(window.innerWidth);
  1225. let playingArenaHeight = Math.ceil(window.innerHeight);
  1226. let plArCanv = document.createElement('canvas');
  1227. plArCanv.style.position = 'fixed';
  1228. plArCanv.style.left = '0px';
  1229. plArCanv.style.top = '0px';
  1230. plArCanv.width = playingArenaWidth;
  1231. plArCanv.height = playingArenaHeight;
  1232. plArCanv.style.zIndex = 1;
  1233. document.body.appendChild(plArCanv);
  1234. let ctx = plArCanv.getContext('2d');
  1235. let zoom = 0.3;
  1236. let centerSiX = 20000;
  1237. let centerSiY = 20000;
  1238. let strokeMoveWas;
  1239.  
  1240. function drawFrame() {
  1241. if (playingArenaWidth !== Math.ceil(window.innerWidth)) {
  1242. playingArenaWidth = Math.ceil(window.innerWidth);
  1243. plArCanv.width = playingArenaWidth;
  1244. }
  1245. if (playingArenaHeight !== Math.ceil(window.innerHeight)) {
  1246. playingArenaHeight = Math.ceil(window.innerHeight);
  1247. plArCanv.height = playingArenaHeight;
  1248. }
  1249. let mySnake;
  1250. let finded = false;
  1251. for (let i = 0; i < snakes_29.length; i++) {
  1252. if (snakes_29[i].id == myId_29 && snakes_29[i].pts.length >= 1) {
  1253. mySnake = snakes_29[i];
  1254. finded = true;
  1255. break;
  1256. }
  1257. }
  1258. if (!finded && gameExists_29) {
  1259. wantCloseCurrentGame_29 = true;
  1260. return;
  1261. }
  1262. if (mySnake) {
  1263. centerSiX = mySnake.xx;
  1264. centerSiY = mySnake.yy;
  1265. }
  1266. const leftSiX = centerSiX - ((playingArenaWidth / 2) / zoom);
  1267. const topSiY = centerSiY - ((playingArenaHeight / 2) / zoom);
  1268. const rightSiX = centerSiX + ((playingArenaWidth / 2) / zoom);
  1269. const bottomSiY = centerSiY + ((playingArenaHeight / 2) / zoom);
  1270.  
  1271. const currentTime = Date.now();
  1272. if (currentTime - currentFpsLastShowTime_29 > 200) {
  1273. currentFps_29 = Math.round(1000 / (currentTime - lastStartOtrisTime_29));
  1274. currentFpsLastShowTime_29 = currentTime;
  1275. }
  1276. lastStartOtrisTime_29 = currentTime;
  1277. // drawing background
  1278. const lightSquareColor = 'rgb(255,255,255)';
  1279. let darkSquareColor;
  1280. if (wfpr_29 && Date.now() - last_ping_mtm_29 > 500)
  1281. darkSquareColor = 'rgb(255,235,235)';
  1282. else
  1283. darkSquareColor = 'rgb(235,235,235)';
  1284. const smallSquareSizeSi = 220;
  1285. const smallSquareSizePi = smallSquareSizeSi * zoom;
  1286. const startCoordSiX = smallSquareSizeSi * Math.floor(leftSiX / smallSquareSizeSi);
  1287. const startCoordSiY = smallSquareSizeSi * Math.floor(topSiY / smallSquareSizeSi);
  1288. ctx.fillStyle = lightSquareColor;
  1289. ctx.fillRect(0, 0, playingArenaWidth, playingArenaHeight);
  1290. ctx.fillStyle = darkSquareColor;
  1291. for (let i = startCoordSiX; i < rightSiX; i += smallSquareSizeSi) {
  1292. for (let j = startCoordSiY; j < bottomSiY; j += smallSquareSizeSi) {
  1293. if ((i % (smallSquareSizeSi * 2) !== 0 && j % (smallSquareSizeSi * 2) === 0) || (i % (smallSquareSizeSi * 2) === 0 && j % (smallSquareSizeSi * 2) !== 0)) {
  1294. ctx.fillRect(playingArenaWidth / 2 - ((centerSiX - i) * zoom), playingArenaHeight / 2 - ((centerSiY - j) * zoom), smallSquareSizePi, smallSquareSizePi);
  1295. }
  1296. }
  1297. }
  1298.  
  1299. // drawing foods
  1300. ctx.fillStyle = 'blue';
  1301. let scoreForFood;
  1302. let foodSide;
  1303. for (let i = 0; i < foods_c_29; i++) {
  1304. scoreForFood = (Math.PI * Math.pow(foods_29[i].sz, 2)) * 0.015183;
  1305. foodSide = Math.sqrt(scoreForFood) * 2.4 * zoom;
  1306. ctx.fillRect(siToPiX(foods_29[i].xx) - foodSide / 2, siToPiY(foods_29[i].yy) - foodSide / 2, foodSide, foodSide);
  1307. }
  1308.  
  1309. // drawing preys
  1310. ctx.fillStyle = 'rgba(165,42,42,0.7)';
  1311. let preyRad;
  1312. for (let i = 0; i < preys_29.length; i++) {
  1313. preyRad = preys_29[i].sz * 2;
  1314. ctx.beginPath();
  1315. ctx.arc(siToPiX(preys_29[i].xx), siToPiY(preys_29[i].yy), preyRad * zoom, 0, 2*Math.PI);
  1316. ctx.fill();
  1317. }
  1318. ctx.strokeStyle = 'rgb(36,255,255)';
  1319. ctx.lineWidth = 1;
  1320. let preyAngLineLen;
  1321. for (let i = 0; i < preys_29.length; i++) {
  1322. preyAngLineLen = preys_29[i].sp * 9.2;
  1323. strokeMoveWas = false;
  1324. ctx.beginPath();
  1325. addPointToPolyline(preys_29[i].xx + preyAngLineLen * Math.cos(preys_29[i].ang), preys_29[i].yy + preyAngLineLen * Math.sin(preys_29[i].ang));
  1326. addPointToPolyline(preys_29[i].xx, preys_29[i].yy);
  1327. ctx.stroke();
  1328. }
  1329. ctx.strokeStyle = 'red';
  1330. ctx.lineWidth = 1;
  1331. const preyWangLineLen = 25;
  1332. for (let i = 0; i < preys_29.length; i++) {
  1333. strokeMoveWas = false;
  1334. ctx.beginPath();
  1335. addPointToPolyline(preys_29[i].xx + preyWangLineLen * Math.cos(preys_29[i].wang), preys_29[i].yy + preyWangLineLen * Math.sin(preys_29[i].wang));
  1336. addPointToPolyline(preys_29[i].xx, preys_29[i].yy);
  1337. ctx.stroke();
  1338. }
  1339.  
  1340. // drawing snakes
  1341. ctx.lineCap = 'round';
  1342. ctx.lineJoin = 'round';
  1343. for (let i = 0; i < snakes_29.length; i++) {
  1344. if (snakes_29[i].pts.length >= 2) {
  1345. const lineNearHeadLen = distBetwCoords(snakes_29[i].xx, snakes_29[i].yy, snakes_29[i].pts[snakes_29[i].pts.length-1].xx, snakes_29[i].pts[snakes_29[i].pts.length-1].yy);
  1346. let oneFreshPartLen;
  1347. if (snakes_29[i].sct <= 1) oneFreshPartLen = 42.000;
  1348. if (snakes_29[i].sct == 2) oneFreshPartLen = 37.485;
  1349. if (snakes_29[i].sct == 3) oneFreshPartLen = 32.970;
  1350. if (snakes_29[i].sct == 4) oneFreshPartLen = 28.455;
  1351. if (snakes_29[i].sct >= 5) oneFreshPartLen = 23.940;
  1352. const lineNearHeadInFam = lineNearHeadLen / oneFreshPartLen;
  1353. const snakeLenghtInParts = Math.max(snakes_29[i].sct + snakes_29[i].fam - Math.max(lineNearHeadInFam, 0), 1);
  1354. let predSnakeLen = distBetwCoords(snakes_29[i].xx, snakes_29[i].yy, snakes_29[i].pts[snakes_29[i].pts.length - 1].xx, snakes_29[i].pts[snakes_29[i].pts.length - 1].yy);
  1355. let j;
  1356. for (j = snakes_29[i].pts.length - 2; j >= Math.max(snakes_29[i].pts.length - Math.floor(snakeLenghtInParts) - 2, 0); j--) {
  1357. predSnakeLen += distBetwCoords(snakes_29[i].pts[j].xx, snakes_29[i].pts[j].yy, snakes_29[i].pts[j+1].xx, snakes_29[i].pts[j+1].yy);
  1358. }
  1359. if (snakeLenghtInParts % 1 > 0 && j >= 0) {
  1360. let intermedX = snakes_29[i].pts[j+1].xx + (snakes_29[i].pts[j].xx - snakes_29[i].pts[j+1].xx) * (snakeLenghtInParts % 1) / 1;
  1361. let intermedY = snakes_29[i].pts[j+1].yy + (snakes_29[i].pts[j].yy - snakes_29[i].pts[j+1].yy) * (snakeLenghtInParts % 1) / 1;
  1362. predSnakeLen += distBetwCoords(intermedX, intermedY, snakes_29[i].pts[j+1].xx, snakes_29[i].pts[j+1].yy);
  1363. }
  1364. let newSnakeLen;
  1365. if (predSnakeLen <= 240) {
  1366. let bottomEdge = 80;
  1367. let topEdge = 240;
  1368. let newBottomEdge = predSnakeLen * 0.50;
  1369. let newTopEdge = predSnakeLen;
  1370. newSnakeLen = newBottomEdge + ((newTopEdge - newBottomEdge) * (predSnakeLen - bottomEdge) / (topEdge - bottomEdge));
  1371. }
  1372. else {
  1373. newSnakeLen = predSnakeLen;
  1374. }
  1375.  
  1376. if (snakes_29[i].id === myId_29)
  1377. ctx.strokeStyle = createRgbaStr(255, 0, 255, 0.8, 128, 0, 128, 0.8, snakes_29[i].sp);
  1378. else
  1379. ctx.strokeStyle = createRgbaStr(0, 128, 0, 0.9, 128, 0, 0, 0.9, snakes_29[i].sp);
  1380. ctx.lineWidth = snakes_29[i].sc * 29 * zoom;
  1381. strokeMoveWas = false;
  1382. ctx.beginPath();
  1383. addPointToPolyline(snakes_29[i].xx, snakes_29[i].yy);
  1384. if (newSnakeLen < lineNearHeadLen) {
  1385. const distKf = newSnakeLen / distBetwCoords(snakes_29[i].xx, snakes_29[i].yy, snakes_29[i].pts[snakes_29[i].pts.length - 1].xx, snakes_29[i].pts[snakes_29[i].pts.length - 1].yy);
  1386. addPointToPolyline(getIntermed(snakes_29[i].xx, snakes_29[i].pts[snakes_29[i].pts.length - 1].xx, distKf), getIntermed(snakes_29[i].yy, snakes_29[i].pts[snakes_29[i].pts.length - 1].yy, distKf));
  1387. }
  1388. else {
  1389. newSnakeLen -= lineNearHeadLen;
  1390. addPointToPolyline(snakes_29[i].pts[snakes_29[i].pts.length - 1].xx, snakes_29[i].pts[snakes_29[i].pts.length - 1].yy);
  1391. }
  1392. for (let j = snakes_29[i].pts.length - 2; j >= 0; j--) {
  1393. const temp = distBetwCoords(snakes_29[i].pts[j].xx, snakes_29[i].pts[j].yy, snakes_29[i].pts[j+1].xx, snakes_29[i].pts[j+1].yy);
  1394. if (newSnakeLen < temp) {
  1395. const distKf = newSnakeLen / distBetwCoords(snakes_29[i].pts[j+1].xx, snakes_29[i].pts[j+1].yy, snakes_29[i].pts[j].xx, snakes_29[i].pts[j].yy);
  1396. addPointToPolyline(getIntermed(snakes_29[i].pts[j+1].xx, snakes_29[i].pts[j].xx, distKf), getIntermed(snakes_29[i].pts[j+1].yy, snakes_29[i].pts[j].yy, distKf));
  1397. break;
  1398. }
  1399. addPointToPolyline(snakes_29[i].pts[j].xx, snakes_29[i].pts[j].yy);
  1400. newSnakeLen -= temp;
  1401. }
  1402. function getIntermed (X1orY1, X2orY2, distKoef) {
  1403. return X1orY1 + (X2orY2 - X1orY1) * distKoef;
  1404. }
  1405. ctx.stroke();
  1406. }
  1407. }
  1408. ctx.lineCap = 'butt';
  1409. ctx.lineJoin = 'miter';
  1410. ctx.strokeStyle = 'rgb(36,255,255)';
  1411. ctx.lineWidth = 1;
  1412. const snakeAngLineLen = 100;
  1413. for (let i = 0; i < snakes_29.length; i++) {
  1414. if (snakes_29[i].pts.length >= 2) {
  1415. strokeMoveWas = false;
  1416. ctx.beginPath();
  1417. addPointToPolyline(snakes_29[i].xx + snakeAngLineLen * Math.cos(snakes_29[i].ang), snakes_29[i].yy + snakeAngLineLen * Math.sin(snakes_29[i].ang));
  1418. addPointToPolyline(snakes_29[i].xx, snakes_29[i].yy);
  1419. ctx.stroke();
  1420. }
  1421. }
  1422. ctx.strokeStyle = 'red';
  1423. ctx.lineWidth = 1;
  1424. const snakeWangLineLen = 50;
  1425. for (let i = 0; i < snakes_29.length; i++) {
  1426. if (snakes_29[i].pts.length >= 2) {
  1427. if (snakes_29[i].id === myId_29)
  1428. ctx.strokeStyle = 'rgb(36,255,255)';
  1429. strokeMoveWas = false;
  1430. ctx.beginPath();
  1431. addPointToPolyline(snakes_29[i].xx + snakeWangLineLen * Math.cos(snakes_29[i].eang), snakes_29[i].yy + snakeWangLineLen * Math.sin(snakes_29[i].eang));
  1432. addPointToPolyline(snakes_29[i].xx, snakes_29[i].yy);
  1433. ctx.stroke();
  1434. if (snakes_29[i].id === myId_29)
  1435. ctx.strokeStyle = 'red';
  1436. }
  1437. }
  1438. ctx.fillStyle = 'rgba(0,0,0,0.5)';
  1439. ctx.textAlign = "center";
  1440. for (let i = 0; i < snakes_29.length; i++) {
  1441. if (snakes_29[i].pts.length >= 2) {
  1442. ctx.font = 37 * zoom + "px sans-serif";
  1443. ctx.fillText(snakes_29[i].nk, siToPiX(snakes_29[i].xx), siToPiY(snakes_29[i].yy) + 67 * zoom);
  1444. }
  1445. }
  1446.  
  1447. // drawing map border
  1448. if ((real_flux_grd_29 - distBetwCoords(0, 0, centerSiX - grd_29, centerSiY - grd_29)) * zoom < distBetwCoords(playingArenaWidth / 2, playingArenaHeight / 2, 0, 0)) {
  1449. ctx.strokeStyle = 'orange';
  1450. const edgeLineWidth = 30 * zoom;
  1451. ctx.lineWidth = edgeLineWidth;
  1452. ctx.beginPath();
  1453. ctx.arc(siToPiX(grd_29), siToPiY(grd_29), real_flux_grd_29 * zoom + edgeLineWidth / 2, 0, 2*Math.PI);
  1454. ctx.stroke();
  1455. }
  1456.  
  1457. // drawing minimap
  1458. const mmapScale = 2;
  1459. let mmapBeginX;
  1460. let mmapBeginY;
  1461. if (minimapObjs_29.length >= 1) {
  1462. mmapBeginX = playingArenaWidth - minimapObjs_29[0].sz * mmapScale + 0;
  1463. mmapBeginY = playingArenaHeight - minimapObjs_29[0].sz * mmapScale + 0;
  1464.  
  1465. const mmapEdgeLineWidth = 2.5;
  1466. ctx.lineWidth = mmapEdgeLineWidth;
  1467. ctx.beginPath();
  1468. ctx.arc(mmapBeginX + ((minimapObjs_29[0].sz - 0.5) * mmapScale) / 2, mmapBeginY + ((minimapObjs_29[0].sz - 0.5) * mmapScale) / 2, ((minimapObjs_29[0].sz - 1) / 2 * mmapScale) * real_flux_grd_29 / rfgrdForMinimap_29 + mmapEdgeLineWidth / 2, 0, 2*Math.PI);
  1469. ctx.fillStyle = 'rgba(255,255,255,0.2)';
  1470. ctx.fill();
  1471. ctx.strokeStyle = 'rgba(255,165,0,1)';
  1472. ctx.stroke();
  1473. }
  1474. ctx.fillStyle = 'rgba(0,0,0,0.8)';
  1475. for (let i = 1; i < minimapObjs_29.length; i++) {
  1476. ctx.fillRect(mmapBeginX + minimapObjs_29[i].xx * mmapScale, mmapBeginY + minimapObjs_29[i].yy * mmapScale, mmapScale, mmapScale);
  1477. }
  1478. if (minimapObjs_29.length >= 1 && mySnake) {
  1479. ctx.fillStyle = 'rgba(255,0,70,0.8)';
  1480. const radius = 3;
  1481. ctx.beginPath();
  1482. ctx.arc(mmapBeginX + ((minimapObjs_29[0].sz - 0.5) * mmapScale) / 2 + (mySnake.xx - grd_29) * ((minimapObjs_29[0].sz - 1) * mmapScale) / (rfgrdForMinimap_29 * 2), mmapBeginY + ((minimapObjs_29[0].sz - 0.5) * mmapScale) / 2 + (mySnake.yy - grd_29) * ((minimapObjs_29[0].sz - 1) * mmapScale) / (rfgrdForMinimap_29 * 2), radius, 0, 2*Math.PI);
  1483. ctx.fill();
  1484. }
  1485.  
  1486. // drawing fps and zoom info
  1487. ctx.fillStyle = 'rgb(0,0,0)';
  1488. ctx.font = "11px sans-serif";
  1489. ctx.fillText("fps: " + currentFps_29 + " zoom: " + zoom.toFixed(2) + " ping: " + avgPing_29.toFixed(2), 280, 15);
  1490.  
  1491. // drawing leaderboard, rank, score
  1492. let myLenghtInfo = "";
  1493. if (mySnake) {
  1494. const sct = mySnake.sct + mySnake.rsc;
  1495. const score = Math.floor((fpsls_29[sct] + mySnake.fam / fmlts_29[sct] - 1) * 15 - 5) / 1;
  1496. myLenghtInfo = " " + score + " " + mySnake.rsc;
  1497. }
  1498. const infoText = playersInfo_29 == "" ? myLenghtInfo : playersInfo_29 + "\n" + myLenghtInfo;
  1499. ctx.textAlign = "left";
  1500. ctx.fillStyle = 'rgb(30,60,255)';
  1501. infoText.split('\n').forEach((line, index) => ctx.fillText(line, 10, 15 + index * 14));
  1502.  
  1503. function addPointToPolyline(slx, sly) {
  1504. const piX = (slx - leftSiX) * zoom;
  1505. const piY = (sly - topSiY) * zoom;
  1506. if (strokeMoveWas) {
  1507. ctx.lineTo(piX, piY);
  1508. }
  1509. else {
  1510. ctx.moveTo(piX, piY);
  1511. strokeMoveWas = true;
  1512. }
  1513. }
  1514. function siToPiX(siX) {
  1515. return (siX - leftSiX) * zoom;
  1516. }
  1517. function siToPiY(siY) {
  1518. return (siY - topSiY) * zoom;
  1519. }
  1520. function distBetwCoords(x1, y1, x2, y2) {
  1521. return Math.sqrt(Math.pow(Math.abs(x1-x2), 2) + Math.pow(Math.abs(y2-y1), 2));
  1522. }
  1523. function createRgbaStr(r1, g1, b1, a1, r2, g2, b2, a2, speed) {
  1524. function clcParam(paramDownPoint, paramUpPoint) {
  1525. const speedDownPoint = 5.5;
  1526. const speedUpPoint = 14;
  1527. const speDif = speedUpPoint - speedDownPoint;
  1528. const prmDif = paramUpPoint - paramDownPoint;
  1529. return paramDownPoint + (prmDif * (speed - speedDownPoint) / speDif);
  1530. }
  1531. return 'rgba(' + clcParam(r1, r2) + ',' + clcParam(g1, g2) + ',' + clcParam(b1, b2) + ',' + clcParam(a1, a2) + ')';
  1532. }
  1533. }
  1534.  
  1535. {
  1536. myValidNick_29 = "";
  1537. let v;
  1538. for (let i = 0; i < myNick_29.length; i++) {
  1539. v = myNick_29.charCodeAt(i);
  1540. if (v < 32 || v > 127)
  1541. myValidNick_29 += " ";
  1542. else
  1543. myValidNick_29 += String.fromCharCode(v)
  1544. }
  1545. if (myValidNick_29.length > 24)
  1546. myValidNick_29 = myValidNick_29.substr(0, 24);
  1547.  
  1548. myValidSkin_29 = Math.min(Math.max(mySkin_29, 0), 65);
  1549.  
  1550. myCustomSkinData_29 = [255, 255, 255, 0, 0, 0];
  1551. myCustomSkinData_29.push(Math.floor(Math.random() * 256));
  1552. myCustomSkinData_29.push(Math.floor(Math.random() * 256));
  1553. let myValidCustomSkin_29 = [];
  1554. for (let i = 0; i < myCustomSkin_29.length; i++) {
  1555. if ((myCustomSkin_29[i] < 0 || myCustomSkin_29[i] > 35) && myCustomSkin_29[i] != 37 && myCustomSkin_29[i] != 39 && myCustomSkin_29[i] != 41)
  1556. continue;
  1557. myValidCustomSkin_29.push(myCustomSkin_29[i]);
  1558. }
  1559. let mvcsLen = Math.min(myValidCustomSkin_29.length, 227);
  1560. let currentNumber;
  1561. let repeNumbCounter;
  1562. for (let i = 0; i < mvcsLen; i++) {
  1563. currentNumber = myValidCustomSkin_29[i];
  1564. repeNumbCounter = 1;
  1565. while (currentNumber == myValidCustomSkin_29[i + 1] && i < mvcsLen - 1) {
  1566. repeNumbCounter++;
  1567. i++;
  1568. }
  1569. myCustomSkinData_29.push(repeNumbCounter);
  1570. myCustomSkinData_29.push(currentNumber);
  1571. }
  1572.  
  1573. myValidCosmetic_29 = myCosmetic_29;
  1574. if (myValidCosmetic_29 != 255 && (myValidCosmetic_29 < 0 || myValidCosmetic_29 > 31))
  1575. myValidCosmetic_29 = 255;
  1576. }
  1577.  
  1578. const serverIpAndPortField = document.createElement('input');
  1579. serverIpAndPortField.type = 'text';
  1580. serverIpAndPortField.placeholder = '57.129.37.42:444';
  1581. serverIpAndPortField.value = serverIpAndPortForInputField_29;
  1582. serverIpAndPortField.style.position = 'fixed';
  1583. serverIpAndPortField.style.right = '10px';
  1584. serverIpAndPortField.style.top = '7px';
  1585. serverIpAndPortField.style.width = '130px';
  1586. serverIpAndPortField.style.height = '20px';
  1587. serverIpAndPortField.style.background = 'rgba(255,255,255,0.2)';
  1588. serverIpAndPortField.style.border = '2px solid rgb(140,140,140)';
  1589. serverIpAndPortField.style.borderRadius = '5px';
  1590. serverIpAndPortField.style.color = 'rgb(50,50,50)';
  1591. serverIpAndPortField.style.zIndex = 2;
  1592. document.body.appendChild(serverIpAndPortField);
  1593.  
  1594. const stopGameBtn = document.createElement('button');
  1595. stopGameBtn.textContent = 'Stop the game';
  1596. stopGameBtn.style.position = 'fixed';
  1597. stopGameBtn.style.right = '10px';
  1598. stopGameBtn.style.top = '35px';
  1599. stopGameBtn.style.width = '130px';
  1600. stopGameBtn.style.height = '20px';
  1601. stopGameBtn.style.background = 'rgba(255,255,255,0.2)';
  1602. stopGameBtn.style.border = '2px solid rgb(140,140,140)';
  1603. stopGameBtn.style.borderRadius = '10px';
  1604. stopGameBtn.style.color = 'rgb(140,140,140)';
  1605. stopGameBtn.style.zIndex = 2;
  1606. document.body.appendChild(stopGameBtn);
  1607.  
  1608. const newGameBtn = document.createElement('button');
  1609. newGameBtn.textContent = 'New game';
  1610. newGameBtn.style.position = 'fixed';
  1611. newGameBtn.style.right = '10px';
  1612. newGameBtn.style.top = '63px';
  1613. newGameBtn.style.width = '130px';
  1614. newGameBtn.style.height = '20px';
  1615. newGameBtn.style.background = 'rgba(255,255,255,0.2)';
  1616. newGameBtn.style.border = '2px solid rgb(140,140,140)';
  1617. newGameBtn.style.borderRadius = '10px';
  1618. newGameBtn.style.color = 'rgb(140,140,140)';
  1619. newGameBtn.style.zIndex = 2;
  1620. document.body.appendChild(newGameBtn);
  1621.  
  1622. window.onwheel = function(e) {
  1623. const minZoom = 0.01;
  1624. const maxZoom = 5.0;
  1625. let consideredZoom;
  1626. if (e.deltaY > 0) {
  1627. consideredZoom = zoom - (zoom / 10.0);
  1628. if (consideredZoom >= minZoom)
  1629. zoom = consideredZoom;
  1630. }
  1631. else {
  1632. consideredZoom = zoom + (zoom / 9.0);
  1633. if (consideredZoom <= maxZoom)
  1634. zoom = consideredZoom;
  1635. }
  1636. };
  1637.  
  1638. window.onmousedown = function(e) {
  1639. acceleration_29 = true;
  1640. };
  1641.  
  1642. window.onmouseup = function(e) {
  1643. acceleration_29 = false;
  1644. };
  1645.  
  1646. window.onmousemove = function(e) {
  1647. whereMouseX_29 = e.clientX;
  1648. whereMouseY_29 = e.clientY;
  1649. };
  1650.  
  1651. stopGameBtn.onclick = function() {
  1652. if (buttonFunctionality_29) {
  1653. if (gameExists_29) {
  1654. wantCloseCurrentGame_29 = true;
  1655. }
  1656. }
  1657. };
  1658.  
  1659. newGameBtn.onclick = function() {
  1660. if (buttonFunctionality_29) {
  1661. buttonFunctionality_29 = false;
  1662. if (gameExists_29) {
  1663. wantCloseCurrentGame_29 = true;
  1664. wantNewGame_29 = true;
  1665. }
  1666. else {
  1667. prepareNewGame_29();
  1668. }
  1669. }
  1670. };
  1671.  
  1672. })();