Truffle Pig Public

Finding all the tasty truffles for you! (Public Edition)

  1. // ==UserScript==
  2. // @name Truffle Pig Public
  3. // @namespace Truffle Pig Public
  4. // @version 0.9.1
  5. // @description Finding all the tasty truffles for you! (Public Edition)
  6. // @author Arimas
  7. // @match https://agma.io/
  8. // @icon https://www.google.com/s2/favicons?domain=agma.io
  9. // @grant none
  10. // ==/UserScript==
  11. (function() {
  12. 'use strict';
  13. var trufflePigPublic = {
  14. // Mass := cell-area * factor
  15. MASS_AREA_FACTOR: 0.0031828408,
  16. // How many times must a cell be bigger to eat another cell?
  17. CELL_EATING_FACTOR: 1.3, // TODO: Check!
  18. // Amount of mass at spawn. ATTENTION: The mass can be either this or less than this!
  19. MAX_START_SPAWN_MASS: 141,
  20. // How big must a cell be to pick up a coin? 126-134???
  21. COIN_PICKUP_MASS: 126,
  22. // If true, bot will automatically respawn when dead
  23. autoRespawn: true,
  24. // If true, mouse movements by the user will override the movement of the bot
  25. allowUserOverride: true,
  26. // Last time (in milliseconds) when the user controlled the bot ( = moved the mouse)
  27. userControlledAt: null,
  28. // If set to true, show debugging information. Do not change this after init!
  29. debug: false,
  30. // Int - current player position as it is used by the camera (midpoint of all my cells)
  31. x: null,
  32. // Int - current player position as it is used by the camera (midpoint of all my cells)
  33. y: null,
  34. // Is unknown so will be figured out while playing (prob main room borders could be detected though)
  35. mapWidth: 0,
  36. mapHeight: 0,
  37. // Maximum number of cells (pieces) a player can have (we dont really know that due to diff. servers so have to learn it on the fly)
  38. maxCells: 64,
  39. // My cells - with x, y, mass, radius, area. NOTE: The smallest cell has index 0, the biggest has the highest index!
  40. cells: [],
  41. // My cells, but only temporary. Will be copied into the cells array once its filled
  42. tempCells: [],
  43. // Visible coins
  44. coins: [],
  45. // Coinbs, but only tewmporarytemporary. Will be copied into the coins array once its filled.
  46. tempCoins: [],
  47. // Int - current total player mass (incorrect when the player is in portals!)
  48. mass: 0,
  49. // Int - temporary current total player mass, will be copied to the mass property
  50. tempMass: 0,
  51. // Is the bot currently alive?
  52. alive: false,
  53. // URL of my skin
  54. skinUrl: null,
  55. // Zoom factor
  56. zoom: null,
  57. // If true bot doesnt do anything
  58. stopped: false,
  59. // Time when the bot was initialized
  60. startedAt: null,
  61. // Last time when the bot spawned
  62. spawnedAt: null,
  63. // Last time (in milliseconds) when we tried to split
  64. splitAt: null,
  65. // Counter for the main loop iterations
  66. iteration: 0,
  67. // Is the bot respawning right now? (This is a process that needs several seconds to complete)
  68. respawning: false,
  69. // Saves the official key bindings
  70. hotkeys: null,
  71. startCoins: 0,
  72. // Original drawImage() function
  73. originalDrawImage: null,
  74. /**
  75. * Start the bot
  76. */
  77. init: function() {
  78. var self = this;
  79. window.ventron = this;
  80. this.startedAt = new Date();
  81. this.skinUrl = this.getSkinUrl();
  82. if (this.skinUrl == 'https://agma.io/skins/0_lo.png') {
  83. alert('No skin chosen - bot does not work. Pick skin and reload page.');
  84. return;
  85. }
  86. if (this.debug) {
  87. var $crosshair = $('<div id="bot-crosshair" style="position: fixed; left: 50%; top: 50%; width: 4px; height: 4px; margin-left: -2px; margin-top: -2px; background-color: red; z-index: 999"></div>');
  88. $('body').append($crosshair);
  89. }
  90. setFixedZoom(true);
  91. var agmaSettings = JSON.parse(localStorage.getItem('settings'));
  92. if (agmaSettings.fixedZoomScale > 0.4) {
  93. alert('Please zoom out a bit.');
  94. }
  95. this.startCoins = this.getCoins();
  96. this.originalDrawImage = CanvasRenderingContext2D.prototype.drawImage;
  97. CanvasRenderingContext2D.prototype.drawImage = this.drawImage;
  98. $(document).mousemove(function(event) {
  99. // Synthetic events are those we create when moving the virtual mouse pointer
  100. if (! event.synthetic && self.allowUserOverride) {
  101. self.userControlledAt = Date.now();
  102. }
  103. });
  104. // If the shop close button is clicked, get and save my skin URL - it may have been changed
  105. $('#shopModalDialog .close').click(function() {
  106. setTimeout(function() {
  107. self.skinUrl = self.getSkinUrl();
  108. }, 100);
  109. });
  110. $('#chtbox').keydown(function(event) {
  111. if (event.keyCode == 13) {
  112. if (self.checkChatBox()) {
  113. $('#chtbox').val('');
  114. }
  115. }
  116. });
  117. this.hotkeys = JSON.parse(localStorage.getItem('hotkeys'));
  118. window.addEventListener('keypress', function(event)
  119. {
  120. // Do nothing if a menu is open
  121. if (document.getElementById('overlays').style.display !== 'none' || document.getElementById('advert').style.display !== 'none') {
  122. return;
  123. }
  124. // Ignore text input fields
  125. if (document.activeElement.type === 'text' || document.activeElement.type === 'password') {
  126. return;
  127. }
  128. });
  129. if (this.debug) {
  130. this.$debugOutput = $('<div style="position: fixed; left: 250px; top: 75px; z-index: 9999; color: #3e3e3e; pointer-events: none">');
  131. $('body').append(this.$debugOutput);
  132. }
  133. var originalRequest = window.requestAnimationFrame;
  134. window.requestAnimationFrame = function (callback) {
  135. var result = originalRequest.apply(this, arguments);
  136. self.mass = self.tempMass;
  137. self.cells = self.tempCells;
  138. self.coins = self.tempCoins;
  139. self.run.apply(self);
  140. self.tempMass = 0;
  141. self.tempCells = [];
  142. self.tempCoins = [];
  143. return result;
  144. };
  145. originalRequest(this.run.bind(this));
  146. let message = '🐷 Truffle Pig Public is ready! The truffles will be yours.';
  147. self.swal(
  148. 'Truffle Pig Public Bot',
  149. message + '<br><br><b>ATTENTION</b>: Bot needs a skin to be put on.<br> Bot works best on Solo AGF.<br> Type <i>/bot help</i> for help!<br> Bot cant split while you type in the chat!');
  150. console.log('%' + message, 'background-color: black; color: pink; font-weight: bold; padding:5px;');
  151. },
  152. /**
  153. * Main method. Once started, it is running in a never ending loop.
  154. */
  155. run: function() {
  156. var agmaSettings = JSON.parse(localStorage.getItem('settings'));
  157. this.zoom = agmaSettings.fixedZoomScale;
  158. if (this.stopped) {
  159. return;
  160. }
  161. if (this.isDeathPopupVisible()) {
  162. this.alive = false;
  163. }
  164. if (this.autoRespawn && ! this.alive) {
  165. this.respawn();
  166. }
  167. if (this.alive) {
  168. if (this.mass > 0 && this.mass < 0.75 * this.MAX_START_SPAWN_MASS && ! this.respawning &&
  169. (this.coins.length == 0 || this.mass < this.COIN_PICKUP_MASS)) {
  170. this.respawn(); // No return - respawn does not always work!!
  171. }
  172. if (this.spawnedAt !== null && Date.now() - this.spawnedAt > 30000 && this.coins.length == 0) {
  173. this.respawn();
  174. }
  175. if (this.spawnedAt !== null && Date.now() - this.spawnedAt > 120000) {
  176. this.respawn();
  177. }
  178. if (! this.collectCoin()) {
  179. if (this.cells.length < 16) {
  180. self.macroSplit();
  181. }
  182. let angle = null;
  183. if (Date.now() - this.startedAt > 3 * 60 * 1000 && Date.now() - this.changedTargetAt > 1000) {
  184. if (this.x < 0.03 * this.mapWidth) {
  185. this.angle = this.getRandomInt(0 + 30,180 - 30);
  186. }
  187. if (this.x > 0.97 * this.mapWidth) {
  188. this.angle = this.getRandomInt(180 + 30,359 - 30);
  189. }
  190. if (this.y < 0.03 * this.mapHeight) {
  191. this.angle = this.getRandomInt(90 + 30,270 - 30);
  192. }
  193. if (this.y > 0.97 * this.mapHeight) {
  194. this.angle = this.getRandomInt(270 + 30, 360 + 90 - 30) % 360;
  195. }
  196. }
  197. if (this.changedTargetAt === undefined || Date.now() - this.changedTargetAt > 3000 ||angle !== null) {
  198. if (Date.now() - this.startedAt > 3 * 60 * 1000) {
  199. if (this.x < 0.1 * this.mapWidth) {
  200. this.angle = this.getRandomInt(0 + 30,180 - 30);
  201. }
  202. if (this.x > 0.9 * this.mapWidth) {
  203. this.angle = this.getRandomInt(180 + 30,359 - 30);
  204. }
  205. if (this.y < 0.1 * this.mapHeight) {
  206. this.angle = this.getRandomInt(90 + 30,270 - 30);
  207. }
  208. if (this.y > 0.9 * this.mapHeight) {
  209. this.angle = this.getRandomInt(270 + 30, 360 + 90 - 30) % 360;
  210. }
  211. }
  212. if (angle === null) {
  213. angle = this.getRandomInt(1,359);
  214. }
  215. this.steerAngle(angle);
  216. this.changedTargetAt = Date.now();
  217. }
  218. }
  219. }
  220. this.iteration++;
  221. },
  222. /**
  223. * This overwrites the original drawImage function. This allows us to get all the drawImage() calls,
  224. * with coordinates of the images, so we can get the position of things on the map, for instance of cells.
  225. */
  226. drawImage: function (image, sourceX, sourceY, sourceWidth, sourceHeight, targetX, targetY, targetWidth, targetHeight) {
  227. var self = window.ventron;
  228. var radius, mass;
  229. if (this.canvas.id === 'canvas') {
  230. // Detect myself (one of my cells)
  231. if (self.skinUrl && (image.src == self.skinUrl.replace('_lo.', '.') || image.src == self.skinUrl)) {
  232. self.alive = true;
  233. if (self.spawnedAt === null) {
  234. self.spawnedAt = Date.now();
  235. }
  236. radius = sourceWidth / 2;
  237. mass = self.getCellMass(radius);
  238. var x = parseInt(sourceX + radius);
  239. var y = parseInt(sourceY + radius);
  240. if (x > self.mapWidth) {
  241. self.mapWidth = x;
  242. }
  243. if (y > self.mapHeight) {
  244. self.mapHeight = y;
  245. }
  246. self.tempMass += mass;
  247. self.cloaked = (this.globalAlpha < 1);
  248. self.tempCells.push({ x: x, y: y, mass: mass, radius: radius });
  249. self.x = 0;
  250. self.y = 0;
  251. self.tempCells.forEach(function(cell) {
  252. self.x += cell.x;
  253. self.y += cell.y;
  254. });
  255. self.x /= self.tempCells.length;
  256. self.y /= self.tempCells.length;
  257. if (self.tempCells.length > self.maxCells) {
  258. self.maxCells = self.tempCells.length
  259. }
  260. if (self.debug) {
  261. //var $crosshair = $("#bot-crosshair");
  262. //$("#bot-crosshair").css('left', self.getScreenPosX(sourceX));
  263. //$("#bot-crosshair").css('top', self.getScreenPosY(sourceY));
  264. self.$debugOutput.text('x: ' + parseInt(self.x) + ', y: ' + parseInt(self.y) + ', mass: ' + parseInt(self.tempMass) + ', cells: ' + self.tempCells.length);
  265. }
  266. }
  267. // Detect coin
  268. if ((image.src == 'https://agma.io/skins/objects/9_lo.png?v=1' || image.src == 'https://agma.io/skins/objects/9.png?v=1')) {
  269. let matrix = this.getTransform() ;
  270. self.tempCoins.push({x: self.getGamePosX(matrix.e), y: self.getGamePosY(matrix.f)});
  271. }
  272. }
  273. return self.originalDrawImage.apply(this, arguments);
  274. },
  275. collectCoin: function() {
  276. // Eat coins
  277. if (this.coins.length > 0 && this.mass > this.COIN_PICKUP_MASS) {
  278. // Find the closest coin
  279. let coin = null, minDistance = Number.MAX_VALUE;
  280. this.coins.forEach(function(inspectedCoin) {
  281. let distance = self.getDistance(self.x, self.y, inspectedCoin.x, inspectedCoin.y);
  282. if (distance < minDistance) {
  283. minDistance = distance;
  284. coin = inspectedCoin;
  285. }
  286. });
  287. if (minDistance < 100 && this.cells.length > 1) {
  288. self.merge();
  289. } else {
  290. let myScreenX = this.getScreenPosX(this.x), myScreenY = this.getScreenPosY(this.y);
  291. let screenDistance = self.getDistance(myScreenX, myScreenY, this.getScreenPosX(coin.x), this.getScreenPosX(coin.y));
  292. self.steer(coin.x, coin.y, screenDistance + 50);
  293. }
  294. if (this.coinsMode && Date.now() - this.splitAt > 500) {
  295. if (this.cells.length === 1 && this.mass > 2 * this.COIN_PICKUP_MASS && minDistance > 50) {
  296. self.split();
  297. } else {
  298. // if (this.cells.length === 1 && this.mass > 4 * this.COIN_PICKUP_MASS && minDistance > 100) {
  299. // self.doubleSplit();
  300. //}
  301. }
  302. }
  303. return true;
  304. }
  305. return false;
  306. },
  307. merge: function(targetX, targetY)
  308. {
  309. var mouseX, mouseY;
  310. if (targetX === undefined || targetY === undefined) {
  311. mouseX = window.innerWidth / 2 + this.getRandomInt(-15, 15);
  312. mouseY = window.innerHeight / 2 + this.getRandomInt(-15, 15);
  313. } else {
  314. mouseX = this.getScreenPosX(targetX);
  315. mouseY = this.getScreenPosY(targetY);
  316. }
  317. $('canvas').trigger($.Event('mousemove', {clientX: mouseX, clientY: mouseY, synthetic: true}));
  318. },
  319. /**
  320. * Moves the bot directly in the direction of given coordinates.
  321. * Won't avoid obstacles, won't use pathfinding.
  322. * It does not matter of the coordinates are on the map or not.
  323. */
  324. steer: function(targetX, targetY, screenDistance, sourceX, sourceY) {
  325. if (typeof screenDistance === 'undefined') {
  326. screenDistance = Math.ceil(Math.max(window.innerWidth, window.innerHeight) / 2);
  327. }
  328. if (sourceX === undefined || sourceY === undefined) {
  329. sourceX = this.x;
  330. sourceY = this.y;
  331. }
  332. var angle = this.getAngle(sourceX, sourceY, targetX, targetY);
  333. this.steerAngle(angle, screenDistance);
  334. },
  335. /**
  336. * Moves the bot directly in the direction of a given angle.
  337. * Won't avoid obstacles, won't use pathfinding.
  338. * It does not matter of the coordinates are on the map or not.
  339. */
  340. steerAngle: function(angle, screenDistance) {
  341. if (typeof screenDistance === 'undefined') {
  342. screenDistance = Math.ceil(Math.max(window.innerWidth, window.innerHeight) / 2);
  343. }
  344. var mouseX = window.innerWidth / 2 + Math.sin(angle * Math.PI / 180) * screenDistance;
  345. var mouseY = window.innerHeight / 2 - Math.cos(angle * Math.PI / 180) * screenDistance;
  346. $('canvas').trigger($.Event('mousemove', {clientX: mouseX, clientY: mouseY, synthetic: true}));
  347. },
  348. /**
  349. * Moves the bot directly in the direction of given game world coordinates,
  350. * by moving the (virtual) mouse pointer to that position on the screen.
  351. * Won't avoid obstacles, won't use pathfinding.
  352. * It does not matter of the coordinates are on the map or not.
  353. */
  354. steerToGamePos: function(gameTargetX, gameTargetY) {
  355. var mouseX = this.getScreenPosX(gameTargetX);
  356. var mouseY = this.getScreenPosY(gameTargetY);
  357. $('canvas').trigger($.Event('mousemove', {clientX: mouseX, clientY: mouseY, synthetic: true}));
  358. },
  359. /**
  360. * Tries to make the bot split by sending the splitting key.
  361. * Only works if the the bot is alive, has enough mass, 2+ pieces and not too many pieces.
  362. * ATTENTION: Split does not happen immediately but with a short delay!
  363. */
  364. split: function() {
  365. $('body').trigger($.Event('keydown', { keyCode: this.hotkeys.Space.c}));
  366. $('body').trigger($.Event('keyup', { keyCode: this.hotkeys.Space.c}));
  367. this.splitAt = Date.now();
  368. },
  369. /**
  370. * Tries to make the bot double split by sending the double split key.
  371. * Only works if the the bot is alive, has enough mass, 2+ pieces and not too many pieces.
  372. */
  373. doubleSplit: function() {
  374. $('body').trigger($.Event('keydown', { keyCode: this.hotkeys.D.c}));
  375. $('body').trigger($.Event('keyup', { keyCode: this.hotkeys.D.c}));
  376. this.splitAt = Date.now();
  377. },
  378. /**
  379. * Tries to make the bot triple split by sending the triple split key.
  380. * Only works if the the bot is alive, has enough mass, 2+ pieces and not too many pieces.
  381. */
  382. tripleSplit: function() {
  383. $('body').trigger($.Event('keydown', { keyCode: this.hotkeys.T.c}));
  384. $('body').trigger($.Event('keyup', { keyCode: this.hotkeys.T.c}));
  385. this.splitAt = Date.now();
  386. },
  387. /**
  388. * Tries to make the bot macro split (16 split) by sending the macro split key.
  389. * Only works if the the bot is alive, has enough mass, 2+ pieces and not too many pieces.
  390. */
  391. macroSplit: function() {
  392. $('body').trigger($.Event('keydown', { keyCode: this.hotkeys.Z.c}));
  393. $('body').trigger($.Event('keyup', { keyCode: this.hotkeys.Z.c}));
  394. this.splitAt = Date.now();
  395. },
  396. /**
  397. * Respawns the bot/player. Uses the respawn key if the bot is alive, uses the menu otherwise.
  398. */
  399. respawn: function() {
  400. self = this;
  401. if (self.respawning) {
  402. return;
  403. }
  404. self.respawning = true;
  405. if (this.spawnedAt !== null) {
  406. this.spawnedAt = null; // Will be set in the draw method
  407. }
  408. this.splitAt = null;
  409. this.ejectedAt = null;
  410. if (self.alive) {
  411. window.onkeydown({keyCode: this.hotkeys.M.c});
  412. window.onkeyup({keyCode: this.hotkeys.M.c});
  413. self.respawning = false;
  414. } else {
  415. if (self.isDeathPopupVisible()) {
  416. // The ad cannot be closed immediately
  417. setTimeout(function() {
  418. closeAdvert();
  419. self.spawn();
  420. }, 2800);
  421. } else {
  422. self.spawn();
  423. }
  424. }
  425. },
  426. /**
  427. * Spawns the bot by using the menu. This does not work if the bot is alive,
  428. * use respawn() in that case!
  429. */
  430. spawn: function() {
  431. self = this;
  432. var performSpawn = function() {
  433. setNick(document.getElementById('nick').value);
  434. self.spawnedAt = null; // Will be set in the draw method
  435. // Respawning doesn't happen immediately, so wait a little bit
  436. setTimeout(function() {
  437. self.respawning = false;
  438. }, 500);
  439. };
  440. // Spawning is not possible immediately so we check if we have to wait
  441. if ($('#playBtn').css('opacity') < 1) {
  442. setTimeout(function() {
  443. performSpawn();
  444. }, 2400);
  445. } else {
  446. performSpawn();
  447. }
  448. },
  449. /**
  450. * Displays a message at the top of the browser window, for a couple of seconds
  451. */
  452. message: function(message) {
  453. var curser = document.querySelector('#curser');
  454. curser.textContent = message;
  455. curser.style.display = 'block';
  456. window.setTimeout(function() {
  457. curser.style.display = 'none';
  458. }, 5000);
  459. },
  460. /**
  461. * Show a sweet alert (modal/popup) with a given title and message.
  462. */
  463. swal: function (title, message, html) {
  464. if (html === undefined) {
  465. html = true;
  466. }
  467. window.swal({
  468. title: '📢 <span class="miracle-primary-color-font">' + title + '</span>',
  469. text: message,
  470. html: html
  471. });
  472. },
  473. /**
  474. * Checks if there is a bot command in the chat bot (text input field).
  475. * If that is the case, tries to execute the command.
  476. * Note: The command won't be sent as a chat message.
  477. */
  478. checkChatBox: function() {
  479. var self = this;
  480. var text = $('#chtbox').val();
  481. if (text.substr(0, 5) == '/bot ') {
  482. var command = text.substr(5);
  483. // Function context = window.ventron
  484. var execCommand = function() {
  485. switch (command) {
  486. case 'start':
  487. this.stopped = false;
  488. this.startCoins = 0;
  489. this.startedAt = new Date();
  490. this.message('Bot started!');
  491. break;
  492. case 'stop':
  493. this.stopped = true;
  494. this.message('Bot stopped!');
  495. break;
  496. case 'coins':
  497. let coins = (this.getCoins() - this.startCoins);
  498. let avg = Math.round(coins / ((Date.now() - this.startedAt) / 1000 / 60));
  499. this.swal(coins + ' coins collected! ' + avg + ' per minute, ' + (avg * 60) + ' per hour.');
  500. break;
  501. case 'info':
  502. this.stopped = false;
  503. this.swal('Map width: ' + self.mapWidth + ', map height: ' + self.mapHeight);
  504. break;
  505. case 'help':
  506. default:
  507. this.swal('These commands are available: start, stop, coins, info');
  508. }
  509. }
  510. setTimeout(execCommand.bind(self), 1);
  511. return true;
  512. }
  513. },
  514. getCoins: function()
  515. {
  516. return 1 * $('#coinsTopLeft').text().replace(/\s/g, '');
  517. },
  518. /**
  519. * Calculates the (float) mass of a cell by its radius
  520. * ATTENTION: It's important that this function returns a float!
  521. * If the bot is split and small, the mass will be 0 else!
  522. */
  523. getCellMass: function(radius) {
  524. var area = Math.PI * radius * radius;
  525. var mass = area * this.MASS_AREA_FACTOR;
  526. return mass;
  527. },
  528. /**
  529. * Calculates the radius of a cell by its mass
  530. */
  531. getCellRadius: function(mass) {
  532. var area = mass / this.MASS_AREA_FACTOR;
  533. var radius = Math.sqrt(area / Math.PI);
  534. return radius;
  535. },
  536. /**
  537. * Returns the (float) distance between two points (coordinates)
  538. */
  539. getDistance: function(x1, y1, x2, y2) {
  540. return Math.hypot(x1 - x2, y1 - y2);
  541. },
  542. /**
  543. * Returns the 360-angle between two points 8coordinates), starting by the first point.
  544. * 0° means the second point is in the north of the first point.
  545. * The returned angle will always be >= 0 and < 360.
  546. */
  547. getAngle: function(x1, y1, x2, y2) {
  548. var angle = Math.atan2(y2 - y1, x2 - x1); // range (-PI, PI]
  549. angle *= 180 / Math.PI; // rads to degs, range (-180, 180]
  550. angle += 90;
  551. if (angle < 0) angle = 360 + angle; // range [0, 360)
  552. if (angle >= 360) angle = 360 - angle; // range [0, 360)
  553. return angle;
  554. },
  555. /**
  556. * Adds angle2 to angle1 and returns the resulting angle.
  557. */
  558. addAngle: function(angle1, angle2) {
  559. var angle = angle1 + angle2;
  560. angle %= 360;
  561. if (angle < 0) angle += 360;
  562. return angle;
  563. },
  564. /**
  565. * Returns the (absolute) difference between two angles.
  566. * The minimum difference will be 0, the maximum difference will be 180.
  567. */
  568. getAngleDiff: function(angle1, angle2) {
  569. var diff = angle1 - angle2;
  570. diff = Math.abs(diff);
  571. if (diff > 180) {
  572. diff = 360 - diff;
  573. }
  574. return diff;
  575. },
  576. /**
  577. * Transforms and returns an x coordinate on the screen to an x coordinate in the game.
  578. */
  579. getGamePosX: function(screenPosX) {
  580. return this.x - (window.innerWidth / 2 - screenPosX) / this.zoom;
  581. },
  582. /**
  583. * Transforms and returns an y coordinate on the screen to an y coordinate in the game.
  584. */
  585. getGamePosY: function(screenPosY) {
  586. return this.y - (window.innerHeight / 2 - screenPosY) / this.zoom;
  587. },
  588. /**
  589. * Transforms and returns an x coordinate in the game to an x coordinate on the screen.
  590. */
  591. getScreenPosX: function(gamePosX) {
  592. return - (- this.zoom * (gamePosX - this.x) - window.innerWidth / 2)
  593. },
  594. /**
  595. * Transforms and returns an y coordinate in the game to an y coordinate on the screen.
  596. */
  597. getScreenPosY: function(gamePosY) {
  598. return - (- this.zoom * (gamePosY - this.y) - window.innerHeight / 2)
  599. },
  600. /**
  601. * Returns a random integer between min (inclusive) and max (exclusive)
  602. * Source: MDN
  603. */
  604. getRandomInt: function(min, max) {
  605. return parseInt(Math.random() * (max - min) + min);
  606. },
  607. /**
  608. * Returns true if the popup that is displayed after we die is currently visible
  609. */
  610. isDeathPopupVisible: function() {
  611. var displayingAd = (document.getElementById('advert').style.display == 'block');
  612. return displayingAd;
  613. },
  614. /**
  615. * Returns the time since the bot was initialized in seconds
  616. */
  617. getTimeSinceStart: function() {
  618. var endDate = new Date();
  619. return (endDate.getTime() - startDate.getTime()) / 1000;
  620. },
  621. /**
  622. * Returns the URI of my skin or null if not skin has been set.
  623. * Use this.skinUrl() to get it.
  624. */
  625. getSkinUrl: function() {
  626. var skinUrlRaw = $('#skinExampleMenu').css('background-image');
  627. var parts = skinUrlRaw.split('"');
  628. if (parts.length != 3) {
  629. return null;
  630. } else {
  631. return parts[1];
  632. }
  633. },
  634. }
  635. let start = function() {
  636. if (document.readyState === "complete") {
  637. // We need to have a delay, because the skin preview in the game menu is not loaded right away and also we have to wait for auto login
  638. setTimeout(function() {
  639. trufflePigPublic.init();
  640. }, 4000);
  641. } else {
  642. setTimeout(start, 1000);
  643. }
  644. };
  645. start();
  646. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址