New Jacks Agario Mod

Enhances Agar.io with custom controls, advanced features, and skin-maker drag-and-drop

  1. // ==UserScript==
  2. // @name New Jacks Agario Mod
  3. // @namespace All in one mod, doesnt add cheats.
  4. // @version 1.1
  5. // @description Enhances Agar.io with custom controls, advanced features, and skin-maker drag-and-drop
  6. // @author 𝓝𝑒ⓦ 𝓙ⓐ¢𝓀🕹️
  7. // @match https://agar.io/*
  8. // @grant none
  9. // @license MIT
  10. // @run-at document-start
  11. // ==/UserScript==
  12.  
  13. (function() {
  14. 'use strict';
  15.  
  16. // Remove background image
  17. const originalDrawImage = CanvasRenderingContext2D.prototype.drawImage;
  18. CanvasRenderingContext2D.prototype.drawImage = function (img) {
  19. if (img && img.src === "https://agar.io/img/background.png") {
  20. return;
  21. }
  22. originalDrawImage.apply(this, arguments);
  23. };
  24.  
  25. window.addEventListener('DOMContentLoaded', function() {
  26. document.documentElement.removeAttribute('style');
  27. const adDiv = document.querySelector('#agar-io_970x90');
  28. if (adDiv) {
  29. adDiv.remove();
  30. }
  31. initAgarioMod();
  32. observeTargetContainer();
  33. initRussiaToUkraine();
  34. });
  35.  
  36. //------------------------------------------------------------------
  37. // 1) Main Agar.io Mod
  38. //------------------------------------------------------------------
  39. function initAgarioMod() {
  40. const CONFIG = {
  41. enableMod: true,
  42. leftMouseAction: 'macroFeed', // "none" | "singleFeed" | "macroFeed" | "split"
  43. rightMouseAction: 'split',
  44. singleFeedKey: 'w',
  45. macroFeedKey: 'm',
  46. doubleSplitKey: 'd',
  47. tripleSplitKey: 't',
  48. quadSplitKey: 'q',
  49. straightLineKey: 'e',
  50. zoomOutKey: '-',
  51. zoomInKey: '=',
  52. acidModeKey: 'a',
  53. skinSwitcherKey: 's',
  54. toggleUIKey: 'h',
  55. pauseMovementKey: 'p',
  56. enableGamepad: false,
  57. enableAcidMode: false,
  58. enableMinimap: true,
  59. enableCustomSkin: true,
  60. customSkinUrl: '',
  61. feedRate: 50,
  62. splitDelay: 50,
  63. gamepadSplit: 0,
  64. gamepadFeed: 1,
  65. gamepadDoubleSplit: 2,
  66. gamepadTripleSplit: 3,
  67. gamepadAcidMode: 9,
  68. gamepadStraightLine: 10,
  69. };
  70.  
  71. let isMacroFeeding = false;
  72. let macroFeedInterval = null;
  73. let gameCanvas = null;
  74. let startingMousePosition = { x: 0, y: 0 };
  75. let currentMousePosition = { x: 0, y: 0 };
  76. let isStraightLineMode = false;
  77. let originalSkin = '';
  78. let modUIVisible = false;
  79. let isPaused = false;
  80. let connectedGamepads = [];
  81. let lastGamepadState = {};
  82. let isRemappingGamepad = false;
  83. let remappingButton = null;
  84. let showControlsButton = null;
  85. let mainOverlay = null;
  86.  
  87. function initMod() {
  88. console.log('Initializing New Jacks Agario Mod...');
  89. createShowControlsButton();
  90. createMainOverlay();
  91. setTimeout(findGameCanvas, 2000);
  92. document.addEventListener('keydown', handleKeyDown);
  93. document.addEventListener('keyup', handleKeyUp);
  94. captureOriginalSkin();
  95. increaseNickLimit();
  96. console.log('Mod initialized successfully!');
  97. }
  98.  
  99. function createShowControlsButton() {
  100. showControlsButton = document.createElement('button');
  101. showControlsButton.id = 'show-controls-button';
  102. showControlsButton.textContent = 'Show Controls';
  103. showControlsButton.style.cssText = `
  104. position: fixed;
  105. top: 10px;
  106. left: 10px;
  107. z-index: 99999;
  108. padding: 5px 10px;
  109. background-color: #54c800;
  110. color: #fff;
  111. border: none;
  112. border-radius: 5px;
  113. cursor: pointer;
  114. font-family: Arial, sans-serif;
  115. transition: background-color 0.2s ease;
  116. `;
  117. showControlsButton.addEventListener('mouseover', () => {
  118. showControlsButton.style.backgroundColor = '#347f01';
  119. });
  120. showControlsButton.addEventListener('mouseout', () => {
  121. showControlsButton.style.backgroundColor = '#54c800';
  122. });
  123. showControlsButton.addEventListener('mousedown', () => {
  124. showControlsButton.style.backgroundColor = '#347f01';
  125. });
  126. showControlsButton.addEventListener('mouseup', () => {
  127. showControlsButton.style.backgroundColor = '#54c800';
  128. });
  129. showControlsButton.onclick = toggleMainOverlay;
  130. document.body.appendChild(showControlsButton);
  131. }
  132.  
  133. function findGameCanvas() {
  134. const canvases = document.getElementsByTagName('canvas');
  135. if (canvases.length > 0) {
  136. for (let i = 0; i < canvases.length; i++) {
  137. if (canvases[i].width > 500 && canvases[i].height > 500) {
  138. gameCanvas = canvases[i];
  139. break;
  140. }
  141. }
  142. if (gameCanvas) {
  143. console.log('Game canvas found!');
  144. gameCanvas.addEventListener('mousedown', handleMouseDown);
  145. gameCanvas.addEventListener('mouseup', handleMouseUp);
  146. gameCanvas.addEventListener('contextmenu', (e) => e.preventDefault() );
  147. gameCanvas.addEventListener('mousemove', (e) => {
  148. currentMousePosition.x = e.clientX;
  149. currentMousePosition.y = e.clientY;
  150. if (isStraightLineMode) {
  151. applyLineConstraint();
  152. }
  153. });
  154. showNotification('Advanced Controls Active! Press H for help or to toggle UI.');
  155. } else {
  156. console.log('Game canvas not found, retrying...');
  157. setTimeout(findGameCanvas, 2000);
  158. }
  159. } else {
  160. console.log('No canvases found, retrying...');
  161. setTimeout(findGameCanvas, 2000);
  162. }
  163. }
  164.  
  165. function handleMouseDown(e) {
  166. if (!CONFIG.enableMod) return;
  167. if (isPaused) return;
  168. if (e.button === 0) {
  169. doMouseAction(CONFIG.leftMouseAction, 'down');
  170. } else if (e.button === 2) {
  171. doMouseAction(CONFIG.rightMouseAction, 'down');
  172. }
  173. }
  174. function handleMouseUp(e) {
  175. if (!CONFIG.enableMod) return;
  176. if (isPaused) return;
  177. if (e.button === 0) {
  178. doMouseAction(CONFIG.leftMouseAction, 'up');
  179. } else if (e.button === 2) {
  180. doMouseAction(CONFIG.rightMouseAction, 'up');
  181. }
  182. }
  183.  
  184. function doMouseAction(action, phase) {
  185. if (action === 'none') {
  186. return;
  187. }
  188. else if (action === 'singleFeed') {
  189. if (phase === 'down') {
  190. window.core.eject();
  191. }
  192. }
  193. else if (action === 'macroFeed') {
  194. if (phase === 'down') {
  195. startMacroFeed();
  196. } else if (phase === 'up') {
  197. stopMacroFeed();
  198. }
  199. }
  200. else if (action === 'split') {
  201. if (phase === 'down') {
  202. window.core.split();
  203. }
  204. }
  205. }
  206.  
  207. function handleKeyDown(e) {
  208. if (e.key.toLowerCase() === CONFIG.toggleUIKey) {
  209. toggleMainOverlay();
  210. return;
  211. }
  212. if (!CONFIG.enableMod) return;
  213. if (isPaused) { }
  214. switch (e.key.toLowerCase()) {
  215. case CONFIG.singleFeedKey:
  216. window.core.eject();
  217. break;
  218. case CONFIG.macroFeedKey:
  219. startMacroFeed();
  220. break;
  221. case CONFIG.doubleSplitKey:
  222. performMultiSplit(2);
  223. break;
  224. case CONFIG.tripleSplitKey:
  225. performMultiSplit(3);
  226. break;
  227. case CONFIG.quadSplitKey:
  228. performMultiSplit(4);
  229. break;
  230. case CONFIG.straightLineKey:
  231. toggleStraightLineMode();
  232. break;
  233. case CONFIG.zoomOutKey:
  234. window.core.playerZoom(0.8);
  235. break;
  236. case CONFIG.zoomInKey:
  237. window.core.playerZoom(1.2);
  238. break;
  239. case CONFIG.acidModeKey:
  240. toggleAcidMode();
  241. break;
  242. case CONFIG.skinSwitcherKey:
  243. openSkinSwitcherUI();
  244. break;
  245. case CONFIG.pauseMovementKey:
  246. isPaused = !isPaused;
  247. showNotification(isPaused ? 'Movement is paused.' : 'Movement unpaused.');
  248. break;
  249. }
  250. }
  251. function handleKeyUp(e) {
  252. if (!CONFIG.enableMod) return;
  253. if (e.key.toLowerCase() === CONFIG.macroFeedKey) {
  254. stopMacroFeed();
  255. }
  256. }
  257.  
  258. function startMacroFeed() {
  259. if (isMacroFeeding) return;
  260. isMacroFeeding = true;
  261. showNotification('Macro feeding started');
  262. window.core.eject();
  263. macroFeedInterval = setInterval(() => {
  264. window.core.eject();
  265. }, CONFIG.feedRate);
  266. }
  267. function stopMacroFeed() {
  268. if (!isMacroFeeding) return;
  269. clearInterval(macroFeedInterval);
  270. isMacroFeeding = false;
  271. showNotification('Macro feeding stopped');
  272. }
  273.  
  274. function performMultiSplit(count) {
  275. if (!window.core.playerHasCells || !window.core.playerHasCells()) {
  276. showNotification('Cannot split when dead');
  277. return;
  278. }
  279. showNotification(`${count}x Split`);
  280. for (let i = 0; i < count; i++) {
  281. setTimeout(() => {
  282. window.core.split();
  283. }, CONFIG.splitDelay * i);
  284. }
  285. }
  286.  
  287. function toggleStraightLineMode() {
  288. isStraightLineMode = !isStraightLineMode;
  289. if (isStraightLineMode) {
  290. startingMousePosition.x = currentMousePosition.x;
  291. startingMousePosition.y = currentMousePosition.y;
  292. showNotification('Straight line mode ON');
  293. } else {
  294. showNotification('Straight line mode OFF');
  295. }
  296. }
  297. function applyLineConstraint() {
  298. if (!isStraightLineMode) return;
  299. const dx = currentMousePosition.x - startingMousePosition.x;
  300. const dy = currentMousePosition.y - startingMousePosition.y;
  301. const angle = Math.atan2(dy, dx);
  302. const snappedAngle = Math.round(angle / (Math.PI / 4)) * (Math.PI / 4);
  303. const distance = Math.sqrt(dx*dx + dy*dy);
  304. const newX = startingMousePosition.x + Math.cos(snappedAngle)*distance;
  305. const newY = startingMousePosition.y + Math.sin(snappedAngle)*distance;
  306. window.core.setTarget(newX, newY);
  307. }
  308.  
  309. function increaseNickLimit() {
  310. const updateNickInput = () => {
  311. const nickInputs = document.querySelectorAll('input[id="nick"], input[placeholder="Nick"], input[maxlength="15"]');
  312. if (nickInputs.length > 0) {
  313. nickInputs.forEach(input => {
  314. input.setAttribute('maxlength', '50');
  315. });
  316. showNotification('Nickname limit increased to 50 characters');
  317. } else {
  318. setTimeout(updateNickInput, 2000);
  319. }
  320. };
  321. updateNickInput();
  322. try {
  323. const observer = new MutationObserver(mutations => {
  324. for (const mutation of mutations) {
  325. if (mutation.type === 'childList' && mutation.addedNodes.length) {
  326. for (const node of mutation.addedNodes) {
  327. if (node.nodeType === Node.ELEMENT_NODE) {
  328. const inputs = node.querySelectorAll ?
  329. node.querySelectorAll('input[id="nick"], input[placeholder="Nick"], input[maxlength="15"]') : [];
  330. if (
  331. node.tagName === 'INPUT' &&
  332. (node.id === 'nick' || node.placeholder === 'Nick' || node.getAttribute('maxlength') === '15')
  333. ) {
  334. node.setAttribute('maxlength', '50');
  335. }
  336. if (inputs.length > 0) {
  337. inputs.forEach(input => {
  338. input.setAttribute('maxlength', '50');
  339. });
  340. }
  341. }
  342. }
  343. }
  344. }
  345. });
  346. observer.observe(document.body, { childList: true, subtree: true });
  347. } catch (e) {
  348. console.error('Error setting up MutationObserver:', e);
  349. }
  350. }
  351.  
  352. function showNotification(message) {
  353. let notification = document.getElementById('agario-mod-notification');
  354. if (!notification) {
  355. notification = document.createElement('div');
  356. notification.id = 'agario-mod-notification';
  357. notification.style.cssText = `
  358. position: absolute;
  359. top: 80px;
  360. left: 50%;
  361. transform: translateX(-50%);
  362. background-color: rgba(0, 0, 0, 0.7);
  363. color: white;
  364. padding: 10px 20px;
  365. border-radius: 5px;
  366. font-family: Arial, sans-serif;
  367. font-size: 16px;
  368. z-index: 1000;
  369. transition: opacity 0.5s;
  370. pointer-events: none;
  371. `;
  372. document.body.appendChild(notification);
  373. }
  374. notification.textContent = message;
  375. notification.style.opacity = '1';
  376. clearTimeout(notification.fadeTimeout);
  377. notification.fadeTimeout = setTimeout(() => {
  378. notification.style.opacity = '0';
  379. }, 2000);
  380. }
  381.  
  382. function captureOriginalSkin() {
  383. if (window.core) {
  384. try {
  385. const observer = new MutationObserver((mutations, obs) => {
  386. const skinContainer = document.querySelector('#skin-preview');
  387. if (skinContainer) {
  388. const skinImg = skinContainer.querySelector('img');
  389. if (skinImg && skinImg.src) {
  390. originalSkin = skinImg.src;
  391. obs.disconnect();
  392. }
  393. }
  394. });
  395. observer.observe(document.body, { childList: true, subtree: true });
  396. try {
  397. const localData = localStorage.getItem('ogarioSettings');
  398. if (localData) {
  399. const settings = JSON.parse(localData);
  400. if (settings && settings.skin) {
  401. originalSkin = settings.skin;
  402. }
  403. }
  404. } catch (e) {
  405. console.warn('Failed to get skin from localStorage', e);
  406. }
  407. } catch (e) {
  408. console.warn('Failed to capture original skin', e);
  409. }
  410. }
  411. }
  412.  
  413. function applyCustomSkin(url) {
  414. if (!window.core) return;
  415. try {
  416. if (!originalSkin) {
  417. captureOriginalSkin();
  418. }
  419. window.core.registerSkin(null, "customskin", url, 0, 0);
  420. window.core.loadSkin("customskin");
  421. CONFIG.customSkinUrl = url;
  422. CONFIG.enableCustomSkin = true;
  423. showNotification('Custom skin applied');
  424. } catch (e) {
  425. showNotification('Failed to apply skin: ' + e.message);
  426. console.error('Failed to apply skin:', e);
  427. }
  428. }
  429.  
  430. function toggleCustomSkin() {
  431. CONFIG.enableCustomSkin = !CONFIG.enableCustomSkin;
  432. if (CONFIG.enableCustomSkin && CONFIG.customSkinUrl) {
  433. applyCustomSkin(CONFIG.customSkinUrl);
  434. } else {
  435. if (window.core) {
  436. if (originalSkin && originalSkin.startsWith('http')) {
  437. window.core.registerSkin(null, "originalskin", originalSkin, 0, 0);
  438. window.core.loadSkin("originalskin");
  439. showNotification('Restored original skin');
  440. } else if (originalSkin) {
  441. window.core.loadSkin(originalSkin);
  442. showNotification('Restored original skin');
  443. } else {
  444. window.core.loadSkin("");
  445. showNotification('Custom skin disabled');
  446. }
  447. }
  448. }
  449. }
  450.  
  451. function loadSkinsFromStorage() {
  452. let data = localStorage.getItem('myCustomSkins');
  453. if (!data) return [];
  454. try {
  455. return JSON.parse(data);
  456. } catch(e) {
  457. console.error('Failed to parse myCustomSkins:', e);
  458. return [];
  459. }
  460. }
  461. function saveSkinsToStorage(arr) {
  462. localStorage.setItem('myCustomSkins', JSON.stringify(arr));
  463. }
  464.  
  465. function openSkinSwitcherUI() {
  466. let existing = document.getElementById('skin-switcher-overlay');
  467. if (existing) {
  468. existing.style.display = 'flex';
  469. return;
  470. }
  471. const overlay = document.createElement('div');
  472. overlay.id = 'skin-switcher-overlay';
  473. overlay.style.cssText = `
  474. position: fixed;
  475. top: 10%;
  476. left: 10%;
  477. width: 640px;
  478. max-width: 90%;
  479. background-color: rgba(255, 255, 255, 0.9);
  480. border-radius: 8px;
  481. padding: 20px;
  482. z-index: 1000000;
  483. display: flex;
  484. flex-direction: column;
  485. box-shadow: 0 0 15px rgba(0,0,0,0.3);
  486. font-family: Arial, sans-serif;
  487. `;
  488. document.body.appendChild(overlay);
  489. const titleRow = document.createElement('div');
  490. titleRow.style.cssText = 'width: 100%; display: flex; justify-content: space-between; margin-bottom: 10px;';
  491. const titleH2 = document.createElement('h2');
  492. titleH2.textContent = 'Skin Switcher';
  493. titleH2.style.margin = '0';
  494. titleRow.appendChild(titleH2);
  495. const closeBtn = document.createElement('button');
  496. closeBtn.textContent = 'X';
  497. closeBtn.style.cssText = `
  498. background-color: #00d3ff;
  499. border: 1px solid #ff0000;
  500. color: #ff0000;
  501. font-size: 20px;
  502. font-weight: bold;
  503. cursor: pointer;
  504. padding: 0 8px;
  505. border-radius: 4px;
  506. transition: background-color 0.2s ease;
  507. `;
  508. closeBtn.onclick = () => {
  509. overlay.style.display = 'none';
  510. };
  511. titleRow.appendChild(closeBtn);
  512. overlay.appendChild(titleRow);
  513. const previewContainer = document.createElement('div');
  514. previewContainer.style.cssText = `
  515. position: relative;
  516. width: 200px;
  517. height: 200px;
  518. border-radius: 50%;
  519. overflow: hidden;
  520. margin: 10px auto 0 auto;
  521. display: flex;
  522. align-items: center;
  523. justify-content: center;
  524. background: #f0f0f0;
  525. `;
  526. overlay.appendChild(previewContainer);
  527. const previewImg = document.createElement('img');
  528. previewImg.style.cssText = `
  529. width: 100%;
  530. height: 100%;
  531. object-fit: cover;
  532. `;
  533. previewContainer.appendChild(previewImg);
  534. const arrowsContainer = document.createElement('div');
  535. arrowsContainer.style.cssText = `
  536. display: flex;
  537. justify-content: space-between;
  538. align-items: center;
  539. width: 200px;
  540. margin: 10px auto 0 auto;
  541. `;
  542. overlay.appendChild(arrowsContainer);
  543. const leftArrow = document.createElement('button');
  544. leftArrow.textContent = '◀';
  545. leftArrow.style.cssText = arrowButtonStyle();
  546. leftArrow.addEventListener('mouseover', () => {
  547. leftArrow.style.backgroundColor = '#347f01';
  548. });
  549. leftArrow.addEventListener('mouseout', () => {
  550. leftArrow.style.backgroundColor = '#54c800';
  551. });
  552. leftArrow.addEventListener('mousedown', () => {
  553. leftArrow.style.backgroundColor = '#347f01';
  554. });
  555. leftArrow.addEventListener('mouseup', () => {
  556. leftArrow.style.backgroundColor = '#54c800';
  557. });
  558. arrowsContainer.appendChild(leftArrow);
  559. const rightArrow = document.createElement('button');
  560. rightArrow.textContent = '▶';
  561. rightArrow.style.cssText = arrowButtonStyle();
  562. rightArrow.addEventListener('mouseover', () => {
  563. rightArrow.style.backgroundColor = '#347f01';
  564. });
  565. rightArrow.addEventListener('mouseout', () => {
  566. rightArrow.style.backgroundColor = '#54c800';
  567. });
  568. rightArrow.addEventListener('mousedown', () => {
  569. rightArrow.style.backgroundColor = '#347f01';
  570. });
  571. rightArrow.addEventListener('mouseup', () => {
  572. rightArrow.style.backgroundColor = '#54c800';
  573. });
  574. arrowsContainer.appendChild(rightArrow);
  575. const skinUrlLabel = document.createElement('div');
  576. skinUrlLabel.style.cssText = 'margin-top: 10px; text-align: center; font-style: italic; color: #333;';
  577. overlay.appendChild(skinUrlLabel);
  578. const urlInput = document.createElement('input');
  579. urlInput.type = 'text';
  580. urlInput.placeholder = 'https://i.imgur.com/skin.png';
  581. urlInput.style.cssText = `
  582. margin: 10px auto 0 auto;
  583. width: 80%;
  584. padding: 5px;
  585. border: 1px solid #ccc;
  586. border-radius: 3px;
  587. display: block;
  588. `;
  589. overlay.appendChild(urlInput);
  590. const buttonsContainer = document.createElement('div');
  591. buttonsContainer.style.cssText = 'display: flex; justify-content: space-around; margin-top: 10px;';
  592. overlay.appendChild(buttonsContainer);
  593. const addSkinBtn = document.createElement('button');
  594. addSkinBtn.textContent = 'Add Skin';
  595. addSkinBtn.style.cssText = buttonStyle();
  596. addSkinBtn.onclick = addSkin;
  597. buttonsContainer.appendChild(addSkinBtn);
  598. const useSkinBtn = document.createElement('button');
  599. useSkinBtn.textContent = 'Use This Skin';
  600. useSkinBtn.style.cssText = buttonStyle();
  601. useSkinBtn.onclick = useSkin;
  602. buttonsContainer.appendChild(useSkinBtn);
  603. const deleteSkinBtn = document.createElement('button');
  604. deleteSkinBtn.textContent = 'Delete Skin';
  605. deleteSkinBtn.style.cssText = `
  606. padding: 6px 12px;
  607. border: none;
  608. border-radius: 4px;
  609. background-color: #ff0000;
  610. color: #fff;
  611. cursor: pointer;
  612. transition: background-color 0.2s ease;
  613. `;
  614. deleteSkinBtn.addEventListener('mouseover', () => {
  615. deleteSkinBtn.style.backgroundColor = '#cc0000';
  616. });
  617. deleteSkinBtn.addEventListener('mouseout', () => {
  618. deleteSkinBtn.style.backgroundColor = '#ff0000';
  619. });
  620. deleteSkinBtn.addEventListener('mousedown', () => {
  621. deleteSkinBtn.style.backgroundColor = '#cc0000';
  622. });
  623. deleteSkinBtn.addEventListener('mouseup', () => {
  624. deleteSkinBtn.style.backgroundColor = '#ff0000';
  625. });
  626. deleteSkinBtn.onclick = deleteSkin;
  627. buttonsContainer.appendChild(deleteSkinBtn);
  628. let skins = loadSkinsFromStorage();
  629. let currentIndex = 0;
  630. function renderSkins() {
  631. if (skins.length === 0) {
  632. currentIndex = 0;
  633. previewImg.src = '';
  634. skinUrlLabel.textContent = 'No skins yet';
  635. } else {
  636. if (currentIndex >= skins.length) currentIndex = skins.length - 1;
  637. if (currentIndex < 0) currentIndex = 0;
  638. previewImg.src = skins[currentIndex];
  639. skinUrlLabel.textContent = skins[currentIndex];
  640. }
  641. }
  642. leftArrow.onclick = () => {
  643. if (skins.length > 0) {
  644. currentIndex = (currentIndex - 1 + skins.length) % skins.length;
  645. renderSkins();
  646. }
  647. };
  648. rightArrow.onclick = () => {
  649. if (skins.length > 0) {
  650. currentIndex = (currentIndex + 1) % skins.length;
  651. renderSkins();
  652. }
  653. };
  654. function addSkin() {
  655. const url = urlInput.value.trim();
  656. if (!url) return;
  657. skins.push(url);
  658. saveSkinsToStorage(skins);
  659. urlInput.value = '';
  660. currentIndex = skins.length - 1;
  661. renderSkins();
  662. }
  663. function useSkin() {
  664. if (!skins[currentIndex]) {
  665. alert('No skin selected!');
  666. return;
  667. }
  668. applyCustomSkin(skins[currentIndex]);
  669. overlay.style.display = 'none';
  670. }
  671. function deleteSkin() {
  672. if (skins.length === 0) {
  673. alert('No skins to delete!');
  674. return;
  675. }
  676. if (confirm('Are you sure you want to delete this skin?')) {
  677. skins.splice(currentIndex, 1);
  678. saveSkinsToStorage(skins);
  679. if (currentIndex >= skins.length) {
  680. currentIndex = skins.length - 1;
  681. }
  682. renderSkins();
  683. }
  684. }
  685. function arrowButtonStyle() {
  686. return `
  687. font-size: 24px;
  688. width: 40px;
  689. height: 40px;
  690. border-radius: 8px;
  691. cursor: pointer;
  692. border: none;
  693. background: #54c800;
  694. color: #fff;
  695. transition: background-color 0.2s ease;
  696. `;
  697. }
  698. function buttonStyle() {
  699. return `
  700. padding: 6px 12px;
  701. border: none;
  702. border-radius: 4px;
  703. background-color: #54c800;
  704. color: #fff;
  705. cursor: pointer;
  706. transition: background-color 0.2s ease;
  707. `;
  708. }
  709. renderSkins();
  710. }
  711.  
  712. function createMainOverlay() {
  713. mainOverlay = document.createElement('div');
  714. mainOverlay.id = 'main-overlay';
  715. mainOverlay.style.cssText = `
  716. position: fixed;
  717. top: 50%;
  718. left: 50%;
  719. transform: translate(-50%, -50%);
  720. width: 700px;
  721. max-width: 90%;
  722. background: #fff;
  723. border-radius: 8px;
  724. padding: 20px;
  725. z-index: 999999;
  726. display: block;
  727. box-shadow: 0 0 20px rgba(0,0,0,0.5);
  728. font-family: Arial, sans-serif;
  729. `;
  730. document.body.appendChild(mainOverlay);
  731. const titleBar = document.createElement('div');
  732. titleBar.style.cssText = 'display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;';
  733. const h2 = document.createElement('h2');
  734. h2.textContent = 'Advanced Controls';
  735. h2.style.margin = '0';
  736. titleBar.appendChild(h2);
  737. const closeBtn = document.createElement('button');
  738. closeBtn.textContent = 'X';
  739. closeBtn.style.cssText = `
  740. background-color: #00d3ff;
  741. border: 1px solid #ff0000;
  742. color: #ff0000;
  743. font-size: 18px;
  744. font-weight: bold;
  745. cursor: pointer;
  746. padding: 0 8px;
  747. border-radius: 4px;
  748. transition: background-color 0.2s ease;
  749. `;
  750. closeBtn.onclick = toggleMainOverlay;
  751. titleBar.appendChild(closeBtn);
  752. mainOverlay.appendChild(titleBar);
  753. const mouseActionsContainer = document.createElement('div');
  754. mouseActionsContainer.style.cssText = 'display: flex; flex-direction: column; gap: 5px; margin-bottom: 10px;';
  755. mouseActionsContainer.appendChild(createMouseActionRow('Left Mouse Action', 'leftMouseAction'));
  756. mouseActionsContainer.appendChild(createMouseActionRow('Right Mouse Action','rightMouseAction'));
  757. mainOverlay.appendChild(mouseActionsContainer);
  758. mainOverlay.appendChild(document.createElement('hr'));
  759. const columnsDiv = document.createElement('div');
  760. columnsDiv.style.cssText = 'display: flex; gap: 20px; margin-top: 10px;';
  761. const pcCol = document.createElement('div');
  762. pcCol.style.cssText = 'flex:1; background: rgba(255,255,255,0.6); padding: 10px; border-radius: 5px;';
  763. pcCol.innerHTML = '<h3>PC Hotkeys</h3>';
  764. const pcHotkeysDiv = document.createElement('div');
  765. pcCol.appendChild(pcHotkeysDiv);
  766. columnsDiv.appendChild(pcCol);
  767. const gpCol = document.createElement('div');
  768. gpCol.style.cssText = 'flex:1; background: rgba(255,255,255,0.6); padding: 10px; border-radius: 5px;';
  769. gpCol.innerHTML = '<h3>Gamepad</h3>';
  770. const gpDiv = document.createElement('div');
  771. gpCol.appendChild(gpDiv);
  772. columnsDiv.appendChild(gpCol);
  773. mainOverlay.appendChild(columnsDiv);
  774. const bottomDiv = document.createElement('div');
  775. bottomDiv.style.cssText = 'margin-top: 20px; display: flex; flex-wrap: wrap; gap: 10px;';
  776. const toggleModBtn = document.createElement('button');
  777. toggleModBtn.textContent = CONFIG.enableMod ? 'Disable Mod' : 'Enable Mod';
  778. toggleModBtn.style.cssText = buttonStyle();
  779. toggleModBtn.onclick = () => {
  780. CONFIG.enableMod = !CONFIG.enableMod;
  781. toggleModBtn.textContent = CONFIG.enableMod ? 'Disable Mod' : 'Enable Mod';
  782. if (!CONFIG.enableMod) {
  783. stopMacroFeed();
  784. isStraightLineMode = false;
  785. }
  786. };
  787. bottomDiv.appendChild(toggleModBtn);
  788. const acidBtn = document.createElement('button');
  789. acidBtn.textContent = CONFIG.enableAcidMode ? 'Acid Mode: ON' : 'Acid Mode: OFF';
  790. acidBtn.style.cssText = buttonStyle();
  791. acidBtn.onclick = () => {
  792. toggleAcidMode();
  793. acidBtn.textContent = CONFIG.enableAcidMode ? 'Acid Mode: ON' : 'Acid Mode: OFF';
  794. };
  795. bottomDiv.appendChild(acidBtn);
  796. const skinBtn = document.createElement('button');
  797. skinBtn.textContent = 'Change Skin';
  798. skinBtn.style.cssText = buttonStyle();
  799. skinBtn.onclick = openSkinSwitcherUI;
  800. bottomDiv.appendChild(skinBtn);
  801. const pauseBtn = document.createElement('button');
  802. pauseBtn.textContent = 'Pause Movement';
  803. pauseBtn.style.cssText = buttonStyle();
  804. pauseBtn.onclick = () => {
  805. isPaused = !isPaused;
  806. pauseBtn.textContent = isPaused ? 'Unpause Movement' : 'Pause Movement';
  807. showNotification(isPaused ? 'Movement is paused.' : 'Movement unpaused.');
  808. };
  809. bottomDiv.appendChild(pauseBtn);
  810. mainOverlay.appendChild(bottomDiv);
  811. buildPCHotkeysUI(pcHotkeysDiv);
  812. buildGamepadUI(gpDiv);
  813. mainOverlay.style.display = 'none';
  814.  
  815. function createMouseActionRow(label, configKey) {
  816. const row = document.createElement('div');
  817. row.style.cssText = 'display: flex; align-items: center; margin-bottom: 5px;';
  818. const lbl = document.createElement('span');
  819. lbl.textContent = label + ': ';
  820. lbl.style.width = '150px';
  821. row.appendChild(lbl);
  822. const select = document.createElement('select');
  823. select.style.cssText = `
  824. border: 1px solid #777;
  825. border-radius: 4px;
  826. padding: 2px 4px;
  827. `;
  828. const actions = [
  829. { value: 'none', text: 'None' },
  830. { value: 'singleFeed', text: 'Single Feed' },
  831. { value: 'macroFeed', text: 'Macro Feed' },
  832. { value: 'split', text: 'Split' }
  833. ];
  834. actions.forEach(a => {
  835. const opt = document.createElement('option');
  836. opt.value = a.value;
  837. opt.textContent = a.text;
  838. select.appendChild(opt);
  839. });
  840. select.value = CONFIG[configKey];
  841. select.onchange = () => {
  842. CONFIG[configKey] = select.value;
  843. showNotification(`${label} changed to: ${select.value}`);
  844. };
  845. row.appendChild(select);
  846. return row;
  847. }
  848. }
  849.  
  850. function toggleMainOverlay() {
  851. modUIVisible = !modUIVisible;
  852. mainOverlay.style.display = modUIVisible ? 'block' : 'none';
  853. showControlsButton.textContent = modUIVisible ? 'Hide Controls' : 'Show Controls';
  854. }
  855.  
  856. function buttonStyle() {
  857. return `
  858. padding: 6px 12px;
  859. font-size: 14px;
  860. border: none;
  861. border-radius: 5px;
  862. cursor: pointer;
  863. background-color: #54c800;
  864. color: #fff;
  865. transition: background-color 0.2s ease;
  866. `;
  867. }
  868.  
  869. function buildPCHotkeysUI(container) {
  870. container.appendChild(createHotkeyRow('Single Feed', 'singleFeedKey'));
  871. container.appendChild(createHotkeyRow('Macro Feed', 'macroFeedKey'));
  872. container.appendChild(createHotkeyRow('Double Split', 'doubleSplitKey'));
  873. container.appendChild(createHotkeyRow('Triple Split', 'tripleSplitKey'));
  874. container.appendChild(createHotkeyRow('Quad Split', 'quadSplitKey'));
  875. container.appendChild(createHotkeyRow('Straight Line', 'straightLineKey'));
  876. container.appendChild(createHotkeyRow('Acid Mode', 'acidModeKey'));
  877. container.appendChild(createHotkeyRow('Skin Switcher', 'skinSwitcherKey'));
  878. container.appendChild(createHotkeyRow('Toggle UI', 'toggleUIKey'));
  879. container.appendChild(createHotkeyRow('Zoom Out', 'zoomOutKey'));
  880. container.appendChild(createHotkeyRow('Zoom In', 'zoomInKey'));
  881. container.appendChild(createHotkeyRow('Pause Movement', 'pauseMovementKey'));
  882. }
  883.  
  884. function createHotkeyRow(label, configKey) {
  885. const row = document.createElement('div');
  886. row.style.cssText = 'display: flex; align-items: center; margin-bottom: 5px;';
  887. const lbl = document.createElement('span');
  888. lbl.textContent = label + ': ';
  889. lbl.style.width = '120px';
  890. row.appendChild(lbl);
  891. const input = document.createElement('input');
  892. input.type = 'text';
  893. input.readOnly = true;
  894. input.value = CONFIG[configKey];
  895. input.style.cssText = `
  896. width: 50px;
  897. text-align: center;
  898. border: 1px solid #777;
  899. border-radius: 3px;
  900. background-color: #f0f0f0;
  901. cursor: pointer;
  902. `;
  903. row.appendChild(input);
  904. let waitingForKey = false;
  905. input.addEventListener('click', () => {
  906. waitingForKey = true;
  907. input.value = '???';
  908. input.focus();
  909. });
  910. input.addEventListener('keydown', (evt) => {
  911. if (!waitingForKey) return;
  912. evt.preventDefault();
  913. evt.stopPropagation();
  914. const newKey = evt.key.toLowerCase();
  915. CONFIG[configKey] = newKey;
  916. input.value = newKey;
  917. waitingForKey = false;
  918. showNotification(`${label} changed to: ${newKey.toUpperCase()}`);
  919. });
  920. return row;
  921. }
  922.  
  923. function buildGamepadUI(container) {
  924. const row = document.createElement('div');
  925. row.style.marginBottom = '10px';
  926. const label = document.createElement('label');
  927. label.textContent = 'Gamepad Enabled: ';
  928. const cb = document.createElement('input');
  929. cb.type = 'checkbox';
  930. cb.checked = CONFIG.enableGamepad;
  931. cb.style.marginLeft = '5px';
  932. cb.onchange = () => {
  933. toggleGamepadMode(cb.checked);
  934. };
  935. row.appendChild(label);
  936. row.appendChild(cb);
  937. container.appendChild(row);
  938. container.appendChild(createGamepadRow('Split Button', 'gamepadSplit', CONFIG.gamepadSplit));
  939. container.appendChild(createGamepadRow('Feed Button', 'gamepadFeed', CONFIG.gamepadFeed));
  940. container.appendChild(createGamepadRow('Double Split', 'gamepadDoubleSplit', CONFIG.gamepadDoubleSplit));
  941. container.appendChild(createGamepadRow('Triple Split', 'gamepadTripleSplit', CONFIG.gamepadTripleSplit));
  942. container.appendChild(createGamepadRow('Acid Mode', 'gamepadAcidMode', CONFIG.gamepadAcidMode));
  943. container.appendChild(createGamepadRow('Straight Line', 'gamepadStraightLine', CONFIG.gamepadStraightLine));
  944. }
  945.  
  946. function createGamepadRow(label, configKey, defaultVal) {
  947. const row = document.createElement('div');
  948. row.style.cssText = 'display: flex; align-items: center; margin-bottom: 5px;';
  949. const lbl = document.createElement('span');
  950. lbl.textContent = label + ': ';
  951. lbl.style.width = '120px';
  952. row.appendChild(lbl);
  953. const input = document.createElement('input');
  954. input.type = 'text';
  955. input.readOnly = true;
  956. input.value = `Button ${defaultVal}`;
  957. input.style.cssText = `
  958. width: 80px;
  959. text-align: center;
  960. border: 1px solid #777;
  961. border-radius: 3px;
  962. background-color: #54c800;
  963. color: #fff;
  964. cursor: pointer;
  965. transition: background-color 0.2s ease;
  966. `;
  967. input.addEventListener('mouseover', () => {
  968. input.style.backgroundColor = '#347f01';
  969. });
  970. input.addEventListener('mouseout', () => {
  971. input.style.backgroundColor = '#54c800';
  972. });
  973. input.addEventListener('mousedown', () => {
  974. input.style.backgroundColor = '#347f01';
  975. });
  976. input.addEventListener('mouseup', () => {
  977. input.style.backgroundColor = '#54c800';
  978. });
  979. input.addEventListener('click', () => {
  980. input.value = "Press Button...";
  981. input.style.backgroundColor = '#ffee99';
  982. isRemappingGamepad = true;
  983. remappingButton = configKey;
  984. setTimeout(() => {
  985. if (input.value === "Press Button...") {
  986. input.value = `Button ${CONFIG[configKey]}`;
  987. input.style.backgroundColor = '#f0f0f0';
  988. isRemappingGamepad = false;
  989. remappingButton = null;
  990. }
  991. }, 5000);
  992. });
  993. row.appendChild(input);
  994. return row;
  995. }
  996.  
  997. function setupGamepadSupport() {
  998. window.addEventListener("gamepadconnected", handleGamepadConnected);
  999. window.addEventListener("gamepaddisconnected", handleGamepadDisconnected);
  1000. if (CONFIG.enableGamepad) {
  1001. startGamepadPolling();
  1002. }
  1003. }
  1004. function handleGamepadConnected(event) {
  1005. const gamepad = event.gamepad;
  1006. connectedGamepads[gamepad.index] = gamepad;
  1007. console.log(`Gamepad connected at index ${gamepad.index}: ${gamepad.id}`);
  1008. showNotification(`Gamepad connected: ${gamepad.id.split('(')[0]}`);
  1009. if (CONFIG.enableGamepad) {
  1010. startGamepadPolling();
  1011. }
  1012. }
  1013. function handleGamepadDisconnected(event) {
  1014. const gamepad = event.gamepad;
  1015. console.log(`Gamepad disconnected from index ${gamepad.index}: ${gamepad.id}`);
  1016. showNotification('Gamepad disconnected');
  1017. delete connectedGamepads[gamepad.index];
  1018. const hasGamepads = Object.keys(connectedGamepads).length > 0;
  1019. if (!hasGamepads) {
  1020. stopGamepadPolling();
  1021. }
  1022. }
  1023. let gamepadPollingId = null;
  1024. function startGamepadPolling() {
  1025. if (gamepadPollingId === null) {
  1026. gamepadPollingId = setInterval(pollGamepads, 16);
  1027. console.log('Gamepad polling started');
  1028. }
  1029. }
  1030. function stopGamepadPolling() {
  1031. if (gamepadPollingId !== null) {
  1032. clearInterval(gamepadPollingId);
  1033. gamepadPollingId = null;
  1034. console.log('Gamepad polling stopped');
  1035. }
  1036. }
  1037. function toggleGamepadMode(enabled) {
  1038. CONFIG.enableGamepad = enabled;
  1039. if (enabled) {
  1040. startGamepadPolling();
  1041. showNotification('Gamepad mode enabled');
  1042. } else {
  1043. stopGamepadPolling();
  1044. showNotification('Gamepad mode disabled');
  1045. }
  1046. }
  1047. function pollGamepads() {
  1048. if (!CONFIG.enableGamepad) return;
  1049. const gamepads = navigator.getGamepads
  1050. ? navigator.getGamepads()
  1051. : (navigator.webkitGetGamepads ? navigator.webkitGetGamepads() : []);
  1052. for (let i = 0; i < gamepads.length; i++) {
  1053. const gamepad = gamepads[i];
  1054. if (!gamepad) continue;
  1055. if (!lastGamepadState[gamepad.index]) {
  1056. lastGamepadState[gamepad.index] = {
  1057. buttons: Array(gamepad.buttons.length).fill(false),
  1058. axes: Array(gamepad.axes.length).fill(0)
  1059. };
  1060. }
  1061. for (let j = 0; j < gamepad.buttons.length; j++) {
  1062. const isPressed = gamepad.buttons[j].pressed;
  1063. const wasPressed = lastGamepadState[gamepad.index].buttons[j];
  1064. if (isPressed && !wasPressed) {
  1065. handleGamepadButtonPressed(gamepad.index, j);
  1066. } else if (!isPressed && wasPressed) {
  1067. handleGamepadButtonReleased(gamepad.index, j);
  1068. }
  1069. lastGamepadState[gamepad.index].buttons[j] = isPressed;
  1070. }
  1071. for (let j = 0; j < gamepad.axes.length; j++) {
  1072. const axisValue = gamepad.axes[j];
  1073. const prevAxisValue = lastGamepadState[gamepad.index].axes[j];
  1074. if (Math.abs(axisValue - prevAxisValue) > 0.1) {
  1075. handleGamepadAxisMoved(gamepad.index, j, axisValue);
  1076. }
  1077. lastGamepadState[gamepad.index].axes[j] = axisValue;
  1078. }
  1079. }
  1080. if (isPaused && gameCanvas && window.core) {
  1081. const rect = gameCanvas.getBoundingClientRect();
  1082. const centerX = rect.left + rect.width / 2;
  1083. const centerY = rect.top + rect.height / 2;
  1084. window.core.setTarget(centerX, centerY);
  1085. }
  1086. }
  1087. function handleGamepadButtonPressed(gamepadIndex, buttonIndex) {
  1088. if (isRemappingGamepad) {
  1089. if (remappingButton) {
  1090. CONFIG[remappingButton] = buttonIndex;
  1091. showNotification(`Mapped ${remappingButton} to button ${buttonIndex}`);
  1092. isRemappingGamepad = false;
  1093. const gpInputs = document.querySelectorAll('input[value="Press Button..."]');
  1094. for (let i = 0; i < gpInputs.length; i++) {
  1095. const input = gpInputs[i];
  1096. if (input.style.backgroundColor === 'rgb(255, 238, 153)') {
  1097. input.value = `Button ${buttonIndex}`;
  1098. input.style.backgroundColor = '#f0f0f0';
  1099. break;
  1100. }
  1101. }
  1102. remappingButton = null;
  1103. }
  1104. return;
  1105. }
  1106. if (!window.core || isPaused) return;
  1107. if (buttonIndex === CONFIG.gamepadSplit) {
  1108. window.core.split();
  1109. }
  1110. else if (buttonIndex === CONFIG.gamepadFeed) {
  1111. window.core.eject();
  1112. }
  1113. else if (buttonIndex === CONFIG.gamepadDoubleSplit) {
  1114. performMultiSplit(2);
  1115. }
  1116. else if (buttonIndex === CONFIG.gamepadTripleSplit) {
  1117. performMultiSplit(3);
  1118. }
  1119. else if (buttonIndex === CONFIG.gamepadAcidMode) {
  1120. toggleAcidMode();
  1121. }
  1122. else if (buttonIndex === CONFIG.gamepadStraightLine) {
  1123. toggleStraightLineMode();
  1124. }
  1125. }
  1126. function handleGamepadButtonReleased() { }
  1127. function handleGamepadAxisMoved(gamepadIndex, axisIndex, value) {
  1128. if (isPaused) return;
  1129. if (axisIndex <= 1 && window.core && gameCanvas) {
  1130. const gamepad = navigator.getGamepads()[gamepadIndex];
  1131. const horizontalAxis = gamepad.axes[0];
  1132. const verticalAxis = gamepad.axes[1];
  1133. const deadzone = 0.15;
  1134. let x = Math.abs(horizontalAxis) < deadzone ? 0 : horizontalAxis;
  1135. let y = Math.abs(verticalAxis) < deadzone ? 0 : verticalAxis;
  1136. if (Math.abs(x) > 0.1 || Math.abs(y) > 0.1) {
  1137. const rect = gameCanvas.getBoundingClientRect();
  1138. const centerX = rect.left + rect.width / 2;
  1139. const centerY = rect.top + rect.height / 2;
  1140. const sensitivity = 200;
  1141. const targetX = centerX + (x * sensitivity);
  1142. const targetY = centerY + (y * sensitivity);
  1143. window.core.setTarget(targetX, targetY);
  1144. }
  1145. }
  1146. }
  1147.  
  1148. function toggleAcidMode() {
  1149. if (!window.core) return;
  1150. CONFIG.enableAcidMode = !CONFIG.enableAcidMode;
  1151. window.core.setAcid(CONFIG.enableAcidMode);
  1152. const acidButtons = document.querySelectorAll('button');
  1153. for (let i = 0; i < acidButtons.length; i++) {
  1154. if (acidButtons[i].textContent.includes('Acid Mode')) {
  1155. acidButtons[i].textContent = CONFIG.enableAcidMode ? 'Acid Mode: ON' : 'Acid Mode: OFF';
  1156. }
  1157. }
  1158. showNotification(CONFIG.enableAcidMode ? 'Acid mode: ON' : 'Acid mode: OFF');
  1159. }
  1160.  
  1161. function checkCoreAccess() {
  1162. if (typeof window.core === 'undefined') {
  1163. console.log('Waiting for core functions to load...');
  1164. setTimeout(checkCoreAccess, 1000);
  1165. return;
  1166. }
  1167. console.log('Core functions found!');
  1168. if (CONFIG.enableMinimap && window.core) {
  1169. window.core.setMinimap(true);
  1170. window.core.minimizeMinimap(false);
  1171. window.core.playersMinimap(true);
  1172. }
  1173. if (CONFIG.enableAcidMode && window.core) {
  1174. window.core.setAcid(true);
  1175. }
  1176. setupGamepadSupport();
  1177. }
  1178.  
  1179. initMod();
  1180. checkCoreAccess();
  1181. }
  1182.  
  1183. //------------------------------------------------------------------
  1184. // 4) "Skin Maker" with Drag-and-Drop
  1185. //------------------------------------------------------------------
  1186. function convertImageFileToBase64(file) {
  1187. const reader = new FileReader();
  1188. reader.onloadend = function () {
  1189. const base64 = reader.result;
  1190. drawImage(base64);
  1191. };
  1192. reader.readAsDataURL(file);
  1193. }
  1194. function convertImageToBase64(event) {
  1195. const file = event.target.files[0];
  1196. if (file) {
  1197. convertImageFileToBase64(file);
  1198. }
  1199. }
  1200. function drawImage(base64) {
  1201. const canvas = document.getElementById("skin-editor-canvas");
  1202. if (!canvas) {
  1203. console.warn("No skin-editor-canvas found to draw on!");
  1204. return;
  1205. }
  1206. const context = canvas.getContext("2d");
  1207. const image = new Image();
  1208. image.onload = function () {
  1209. canvas.width = 512;
  1210. canvas.height = 512;
  1211. context.drawImage(image, 0, 0, 512, 512);
  1212. context.save();
  1213. };
  1214. image.src = base64;
  1215. }
  1216. function createImageButton() {
  1217. const container = document.createElement("div");
  1218. container.style.position = "relative";
  1219. container.style.display = "inline-block";
  1220. const input = document.createElement("input");
  1221. input.type = "file";
  1222. input.accept = "image/*";
  1223. input.id = "customImageUpload";
  1224. input.style.width = "100%";
  1225. input.style.height = "100%";
  1226. input.style.opacity = "0";
  1227. input.style.position = "absolute";
  1228. input.style.left = "0";
  1229. input.style.top = "0";
  1230. input.style.zIndex = "1";
  1231. const button = document.createElement("button");
  1232. button.textContent = "Upload Image";
  1233. button.style.color = "#fff";
  1234. button.style.backgroundColor = "#54c800";
  1235. button.style.border = "1px solid black";
  1236. button.style.padding = "5px 10px";
  1237. button.style.cursor = "pointer";
  1238. container.appendChild(input);
  1239. container.appendChild(button);
  1240. input.addEventListener("change", convertImageToBase64);
  1241. return container;
  1242. }
  1243. function createDragAndDropZone() {
  1244. const dropZone = document.createElement('div');
  1245. dropZone.id = 'dropZone';
  1246. dropZone.style.border = "2px dashed #ccc";
  1247. dropZone.style.padding = "10px";
  1248. dropZone.style.marginTop = "10px";
  1249. dropZone.style.textAlign = "center";
  1250. dropZone.textContent = "Drag & drop your image file here";
  1251. dropZone.addEventListener("dragover", (e) => {
  1252. e.preventDefault();
  1253. dropZone.style.backgroundColor = "#ddd";
  1254. });
  1255. dropZone.addEventListener("dragleave", (e) => {
  1256. e.preventDefault();
  1257. dropZone.style.backgroundColor = "";
  1258. });
  1259. dropZone.addEventListener("drop", (e) => {
  1260. e.preventDefault();
  1261. dropZone.style.backgroundColor = "";
  1262. const file = e.dataTransfer.files[0];
  1263. if (file && file.type.startsWith("image/")) {
  1264. convertImageFileToBase64(file);
  1265. } else {
  1266. alert("Please drop an image file only!");
  1267. }
  1268. });
  1269. return dropZone;
  1270. }
  1271. function insertImageButtonAndDropZone(container, target) {
  1272. if (target) {
  1273. const newDiv = document.createElement("div");
  1274. newDiv.style.marginTop = "50px";
  1275. newDiv.appendChild(container);
  1276. const dropZone = createDragAndDropZone();
  1277. newDiv.appendChild(dropZone);
  1278. const saveArea = target.querySelector(".save");
  1279. if (saveArea) {
  1280. saveArea.appendChild(newDiv);
  1281. }
  1282. }
  1283. }
  1284. function observeTargetContainer() {
  1285. const observer = new MutationObserver((mutationsList) => {
  1286. for (let mutation of mutationsList) {
  1287. if (mutation.type === 'childList') {
  1288. const target = document.querySelector(".right-tools");
  1289. if (target && target.querySelector(".save")) {
  1290. if (
  1291. !target.querySelector("#customImageUpload") &&
  1292. !target.querySelector("#dropZone")
  1293. ) {
  1294. const button = createImageButton();
  1295. insertImageButtonAndDropZone(button, target);
  1296. }
  1297. }
  1298. }
  1299. }
  1300. });
  1301. observer.observe(document.body, {
  1302. childList: true,
  1303. subtree: true
  1304. });
  1305. }
  1306.  
  1307. //------------------------------------------------------------------
  1308. // 5) Russia -> Ukraine Replacement
  1309. //------------------------------------------------------------------
  1310. function initRussiaToUkraine() {
  1311. function replaceText() {
  1312. const options = document.querySelectorAll('option[value="RU-Russia"]');
  1313. options.forEach(option => {
  1314. const text = option.textContent;
  1315. if (text.includes("Russia")) {
  1316. option.textContent = text.replace("Russia", "Ukraine");
  1317. }
  1318. });
  1319. }
  1320. replaceText();
  1321. const observer = new MutationObserver(replaceText);
  1322. observer.observe(document.body, {
  1323. childList: true,
  1324. subtree: true
  1325. });
  1326. }
  1327. })();

QingJ © 2025

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