Advertisement
Gudu0

UMT Main JS

May 3rd, 2025 (edited)
62
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 21.91 KB | Source Code | 0 0
  1. // grid_editor.js
  2. import machineData from './JS/machine_data.js';
  3. import { setupSaveLoadHandlers } from './JS/save_load.js';
  4. import { setupVariables, handleImageSize, calculateTotalCost } from './JS/utility.js';
  5. import oreData from './JS/ore_data.js'; // Adjust the path if needed
  6. import { runInputerTick } from './JS/simulation.js';
  7.  
  8. document.addEventListener('DOMContentLoaded', () => {
  9. populateOreSelectionMenu()
  10. setupSaveLoadHandlers();
  11. const variables = setupVariables();
  12.  
  13. document.getElementById('toggle-preview').checked = variables.showPreviewtoggle;
  14. document.getElementById('toggle-overlap').checked = variables.allowPlacementOver;
  15.  
  16. document.addEventListener('mousedown', () => variables.isMouseDown = true);
  17. document.addEventListener('mouseup', () => variables.isMouseDown = false);
  18.  
  19. function rotateMatrix(matrix, rotationCount) {
  20. let result = matrix;
  21. for (let i = 0; i < (rotationCount % 4 + 4) % 4; i++) {
  22. result = result[0].map((_, idx) => result.map(row => row[idx]).reverse());
  23. }
  24. return result;
  25. }
  26.  
  27. function rotateCoords(x, y, rotation, width, height) {
  28. switch (rotation % 4) {
  29. case 0: return [y, x];
  30. case 1: return [x, height - 1 - y];
  31. case 2: return [height - 1 - y, width - 1 - x];
  32. case 3: return [width - 1 - x, y];
  33. }
  34. }
  35.  
  36.  
  37. document.querySelectorAll('#image-selector img').forEach(img => {
  38. img.addEventListener('click', () => {
  39. variables.selectedImage = img.dataset.img;
  40. document.querySelectorAll('#image-selector img').forEach(i => i.classList.remove('selected'));
  41. img.classList.add('selected');
  42. });
  43. const selectorImages = document.querySelectorAll('#image-selector img');
  44.  
  45. selectorImages.forEach(img => {
  46. if (img.complete) {
  47. handleImageSize(img);
  48. } else {
  49. img.onload = () => handleImageSize(img);
  50. }
  51. });
  52. });
  53.  
  54. function clickableGrid(rows, cols, callback) {
  55. let i = 0;
  56. const grid = document.createElement('table');
  57. grid.className = 'grid';
  58.  
  59. for (let r = 0; r < rows; r++) {
  60. const tr = grid.appendChild(document.createElement('tr'));
  61. for (let c = 0; c < cols; c++) {
  62. const cell = tr.appendChild(document.createElement('td'));
  63. const tile = document.createElement('div');
  64. tile.classList.add('tile');
  65. tile.style.backgroundImage = "url('Images/Black_Square32.jpg')";
  66. tile.dataset.rotationCount = '0';
  67. tile.dataset.machineId = '';
  68. cell.appendChild(tile);
  69.  
  70. if (r >= 30 && c === 23) {
  71. tile.classList.add('Input');
  72. tile.style.backgroundImage = "url('Images/Input.png')";
  73. tile.dataset.rotationCount = '0';
  74. tile.dataset.machineId = 'input';
  75. tile.style.backgroundPosition = "top"
  76. };
  77. if (r === 31 && c === 23) {
  78. tile.classList.add('Input');
  79. tile.style.backgroundImage = "url('Images/Input.png')";
  80. tile.dataset.rotationCount = '0';
  81. tile.dataset.machineId = 'input';
  82. tile.style.backgroundPosition = "center"
  83. };
  84. if (r === 32 && c === 23) {
  85. tile.classList.add('Input');
  86. tile.style.backgroundImage = "url('Images/Input.png')";
  87. tile.dataset.rotationCount = '0';
  88. tile.dataset.machineId = 'input';
  89. tile.style.backgroundPosition = "bottom"
  90. };
  91. if (r >= 30 && c != 23) {
  92. tile.classList.remove('tile');
  93. tile.classList.add('invisible-tile')
  94. tile.id = 'crazy';
  95. tile.style.cursor = 'default';
  96. tile.style.backgroundImage = '';
  97. delete tile.dataset.machineId;
  98. delete tile.dataset.rotationCount;
  99.  
  100. }
  101. if (r <= 29 ) {
  102. const preview = document.createElement('div');
  103. preview.classList.add('preview');
  104. tile.appendChild(preview);
  105. }
  106.  
  107.  
  108. cell.addEventListener('mouseenter', () => {
  109. variables.currentHoverCell = { row: r, col: c };
  110. showPreview(r, c);
  111. if (variables.isMouseDown && dragPlacementEnabled) {
  112. placeMachine(r, c);
  113. callback(cell, r, c, i);
  114. }
  115. });
  116.  
  117. cell.addEventListener('mouseleave', () => {
  118. variables.currentHoverCell = null;
  119. clearPreview();
  120. });
  121.  
  122. cell.addEventListener('click', () => {
  123. placeMachine(r, c);
  124. callback(cell, r, c, i);
  125. });
  126.  
  127. cell.addEventListener('contextmenu', (e) => {
  128. e.preventDefault();
  129.  
  130. const tile = cell.querySelector('.tile');
  131. const machineId = tile.dataset.machineId;
  132.  
  133. // If there's no machine to delete, do nothing
  134. if (!machineId) return;
  135.  
  136. const allRows = Array.from(document.querySelectorAll('.grid tr'));
  137.  
  138. // Loop through all rows and cells to remove the machine
  139. allRows.forEach((row) => {
  140. Array.from(row.children).forEach((cell) => {
  141. const targetTile = cell.querySelector('.tile');
  142. if (targetTile && targetTile.dataset.machineId === machineId) {
  143. // Clear the tile data for each part of the multi-cell machine
  144. targetTile.style.backgroundImage = "url('Images/Black_Square32.jpg')";
  145. targetTile.style.backgroundPosition = "0px 0px";
  146. targetTile.style.transform = 'rotate(0deg)';
  147. targetTile.dataset.machineId = '';
  148. targetTile.dataset.rotationCount = '0';
  149. }
  150. });
  151. });
  152.  
  153. // Recalculate the total cost after removing the machine
  154. calculateTotalCost();
  155. });
  156.  
  157.  
  158. i++;
  159. }
  160. }
  161. // Disable dragging on all tiles
  162. disableTileDragging();
  163.  
  164. return grid;
  165. }
  166. document.querySelectorAll('.invisible-tile').forEach(tile => {
  167. tile.style.setProperty('cursor', 'default', 'important');
  168. });
  169. /* Moved to grid_generation.js */
  170. function generateUniqueMachineId() {
  171. let id = `machine-${variables.machineIdCounter++}`;
  172. // Check if the ID already exists
  173. while (document.querySelector(`[data-machine-id="${id}"]`)) {
  174. id = `machine-${variables.machineIdCounter++}`; // Increment and try again if the ID exists
  175. }
  176. return id;
  177. }
  178.  
  179. /* Moved to grid_generation */
  180. function placeMachine(r, c) {
  181. const machine = machineData[variables.selectedImage];
  182. if (!machine) return;
  183.  
  184. const originalShape = machine.shape;
  185. const shapeRows = originalShape.length;
  186. const shapeCols = originalShape[0].length;
  187. const allRows = Array.from(document.querySelectorAll('.grid tr'));
  188.  
  189. // Generate a unique machine ID
  190. const machineId = generateUniqueMachineId();
  191.  
  192. // First check placement validity
  193. let canPlace = true;
  194. const reservedRowCount = 3; // Adjust this if you change the number of reserved rows
  195. for (let y = 0; y < shapeRows; y++) {
  196. for (let x = 0; x < shapeCols; x++) {
  197. if (originalShape[y][x] === 1) {
  198. const [dy, dx] = rotateCoords(x, y, variables.globalRotationCount, shapeCols, shapeRows);
  199. const row = r + dy;
  200. const col = c + dx;
  201.  
  202. // Prevent placement into rows that are reserved
  203. if (row >= allRows.length - reservedRowCount || row < 0 || col < 0 || col >= allRows[row]?.children.length) {
  204. canPlace = false;
  205. break;
  206. }
  207.  
  208. const tile = allRows[row]?.children[col]?.querySelector('.tile');
  209. if (tile && tile.dataset.machineId && !variables.allowPlacementOver) {
  210. canPlace = false;
  211. break;
  212. }
  213. }
  214. }
  215. }
  216.  
  217.  
  218. // Collect all machine IDs that would be overlapped
  219. const machinesToRemove = new Set();
  220. for (let y = 0; y < shapeRows; y++) {
  221. for (let x = 0; x < shapeCols; x++) {
  222. if (originalShape[y][x] === 1) {
  223. const [dy, dx] = rotateCoords(x, y, variables.globalRotationCount, shapeCols, shapeRows);
  224. const row = r + dy;
  225. const col = c + dx;
  226. const tile = allRows[row]?.children[col]?.querySelector('.tile');
  227. const existingMachineId = tile?.dataset.machineId;
  228.  
  229. if (existingMachineId) {
  230. machinesToRemove.add(existingMachineId);
  231. }
  232. }
  233. }
  234. }
  235.  
  236. // Remove all parts of the machines that overlap
  237. if (variables.allowPlacementOver) {
  238. for (const row of allRows) {
  239. for (const cell of row.children) {
  240. const tile = cell.querySelector('.tile');
  241. if (tile && machinesToRemove.has(tile.dataset.machineId)) {
  242. tile.style.backgroundImage = "url('Images/Black_Square32.jpg')";
  243. tile.style.backgroundPosition = '';
  244. tile.style.transform = '';
  245. delete tile.dataset.machineId;
  246. delete tile.dataset.rotationCount;
  247. }
  248. }
  249. }
  250. }
  251. //recalculate when removing a tiles
  252. calculateTotalCost();
  253.  
  254. // If placement is not allowed, return early
  255. if (!canPlace) return;
  256.  
  257. // Place the new machine
  258. for (let y = 0; y < shapeRows; y++) {
  259. for (let x = 0; x < shapeCols; x++) {
  260. if (originalShape[y][x] === 1) {
  261. const cropX = x;
  262. const cropY = y;
  263.  
  264. const [dy, dx] = rotateCoords(cropX, cropY, variables.globalRotationCount, shapeCols, shapeRows);
  265. const row = r + dy;
  266. const col = c + dx;
  267. const targetTile = allRows[row]?.children[col]?.querySelector('.tile');
  268. if (!targetTile) continue;
  269.  
  270. targetTile.dataset.machineId = machineId;
  271. targetTile.dataset.rotationCount = variables.globalRotationCount;
  272. targetTile.style.transform = `rotate(${variables.globalRotationCount * 90}deg)`;
  273. targetTile.style.backgroundImage = `url('Images/${variables.selectedImage}')`;
  274. targetTile.style.backgroundPosition = `-${cropX * 32}px -${cropY * 32}px`;
  275. }
  276. }
  277. }
  278. //recalculate cost after placing
  279. calculateTotalCost();
  280. }
  281.  
  282. /* Moved to grid_generation.js */
  283. function showPreview(startRow, startCol) {
  284. if (!variables.showPreviewtoggle) return; // If the preview is disabled, do nothing.
  285.  
  286. const machine = machineData[variables.selectedImage];
  287. if (!machine) return;
  288.  
  289. const shape = rotateMatrix(machine.shape, variables.globalRotationCount);
  290. const shapeRows = shape.length;
  291. const shapeCols = shape[0].length;
  292. const allRows = Array.from(document.querySelectorAll('.grid tr'));
  293.  
  294. let valid = true;
  295. const previewCells = [];
  296.  
  297. for (let y = 0; y < shapeRows; y++) {
  298. for (let x = 0; x < shapeCols; x++) {
  299. if (shape[y][x] === 1) {
  300. const row = startRow + y;
  301. const col = startCol + x;
  302.  
  303. if (row >= allRows.length - 3 || col >= allRows[row].children.length) {
  304. valid = false;
  305. continue;
  306. }
  307.  
  308. const tile = allRows[row].children[col].querySelector('.tile');
  309. const preview = tile.querySelector('.preview');
  310.  
  311. if (!variables.allowPlacementOver && tile.dataset.machineId) {
  312. valid = false;
  313. }
  314.  
  315. preview.style.opacity = '1';
  316. previewCells.push(preview);
  317. }
  318. }
  319. }
  320.  
  321. previewCells.forEach(preview => {
  322. preview.style.backgroundColor = valid
  323. ? 'rgba(0, 255, 0, 0.3)'
  324. : 'rgba(255, 0, 0, 0.4)';
  325. });
  326. }
  327.  
  328. function clearPreview() {
  329. document.querySelectorAll('.preview').forEach(p => {
  330. p.style.opacity = '0';
  331. p.classList.remove('preview-error');
  332. });
  333. }
  334.  
  335. const gridContainer = document.getElementById('grid-container');
  336. const grid = clickableGrid(33, 30, (el, r, c, i) => {
  337. variables.lastClicked = el;
  338. });
  339. gridContainer.appendChild(grid);
  340.  
  341. document.addEventListener('keydown', (e) => {
  342. if (e.key === 'r' || e.key === 'R') {
  343. variables.globalRotationCount = (variables.globalRotationCount + 1) % 4;
  344. } else if (e.key === 'l' || e.key === 'L') {
  345. variables.globalRotationCount = (variables.globalRotationCount + 3) % 4;
  346. }
  347.  
  348. if (variables.currentHoverCell) {
  349. clearPreview();
  350. showPreview(variables.currentHoverCell.row, variables.currentHoverCell.col);
  351. }
  352. });
  353.  
  354. const togglePreview = document.getElementById('toggle-preview');
  355. const togglePlacementOver = document.getElementById('toggle-overlap');
  356.  
  357. // Listen for changes to the placement preview toggle
  358. togglePreview.addEventListener('change', () => {
  359. variables.showPreviewtoggle = togglePreview.checked;
  360. localStorage.setItem('showPreview', variables.showPreviewtoggle); // Save to localStorage
  361. // Optionally, you could re-render the preview if needed
  362. if (variables.currentHoverCell) {
  363. clearPreview();
  364. showPreview && showPreview(variables.currentHoverCell.row, variables.currentHoverCell.col);
  365. }
  366. });
  367.  
  368. // Listen for changes to the allow placement over other machines toggle
  369. togglePlacementOver.addEventListener('change', () => {
  370. variables.allowPlacementOver = togglePlacementOver.checked;
  371. localStorage.setItem('allowOverlap', variables.allowPlacementOver); // Save to localStorage
  372. });
  373.  
  374. // Initialize the drag placement toggle based on localStorage or default to true
  375. let dragPlacementEnabled = localStorage.getItem('dragPlacement') !== 'false';
  376.  
  377. // Set the checkbox state on page load
  378. document.getElementById('toggle-drag').checked = dragPlacementEnabled;
  379.  
  380. // Update the variable and localStorage when the checkbox state changes
  381. document.getElementById('toggle-drag').addEventListener('change', (e) => {
  382. dragPlacementEnabled = e.target.checked;
  383. localStorage.setItem('dragPlacement', dragPlacementEnabled);
  384. });
  385.  
  386. function disableTileDragging() {
  387. document.querySelectorAll('.tile').forEach(tile => {
  388. tile.setAttribute('draggable', 'false');
  389. tile.addEventListener('dragstart', e => e.preventDefault());
  390. });
  391. }
  392.  
  393.  
  394. function populateOreSelectionMenu() {
  395. const menu = document.getElementById('ore-selection-menu');
  396. if (!menu) return;
  397.  
  398. for (const [oreName, data] of Object.entries(oreData)) {
  399. if (data.type !== 'ore') continue; // Skip gems for now
  400.  
  401. const container = document.createElement('div');
  402. container.classList.add('ore-entry');
  403.  
  404. const checkbox = document.createElement('input');
  405. checkbox.type = 'checkbox';
  406. checkbox.id = `ore-${oreName}`;
  407. checkbox.checked = false;
  408. checkbox.dataset.oreName = oreName;
  409.  
  410. // Create label that wraps the image and links to the checkbox
  411. if (data.selectorImg) {
  412. const imgLabel = document.createElement('label');
  413. imgLabel.htmlFor = checkbox.id;
  414.  
  415. const img = document.createElement('img');
  416. img.src = data.selectorImg;
  417. img.alt = oreName;
  418. img.classList.add('ore-icon');
  419.  
  420. imgLabel.appendChild(img);
  421. container.appendChild(imgLabel);
  422. }
  423.  
  424. // Label with ore name
  425. const textLabel = document.createElement('label');
  426. textLabel.htmlFor = checkbox.id;
  427. textLabel.textContent = oreName;
  428.  
  429. container.appendChild(checkbox);
  430. container.appendChild(textLabel);
  431. menu.appendChild(container);
  432. }
  433. }
  434.  
  435. let debugMode = false;
  436. let debugFrozen = false;
  437.  
  438. // Create debug box
  439. const debugBox = document.createElement('div');
  440. debugBox.id = 'debug-box';
  441. Object.assign(debugBox.style, {
  442. position: 'fixed',
  443. pointerEvents: 'auto', // allow interaction if needed
  444. background: 'rgba(0, 0, 0, 0.75)',
  445. color: 'white',
  446. padding: '6px 10px',
  447. fontSize: '12px',
  448. borderRadius: '6px',
  449. zIndex: 9999,
  450. display: 'none',
  451. maxWidth: '300px',
  452. maxHeight: '300px',
  453. overflowY: 'auto'
  454. });
  455. document.body.appendChild(debugBox);
  456.  
  457. // Toggle debug mode
  458. document.addEventListener('keydown', (e) => {
  459. if (e.key.toLowerCase() === 'e') {
  460. debugMode = !debugMode;
  461. debugBox.style.display = debugMode ? 'block' : 'none';
  462. console.log(`Debug mode: ${debugMode ? 'ON' : 'OFF'}`);
  463. }
  464.  
  465. if (e.key.toLowerCase() === 'f' && debugMode) {
  466. debugFrozen = !debugFrozen;
  467. debugBox.style.border = debugFrozen ? '2px solid yellow' : 'none';
  468. console.log(`Debug box ${debugFrozen ? 'frozen' : 'unfrozen'}`);
  469. }
  470. });
  471.  
  472. // Track mouse & update debug info
  473. document.addEventListener('mousemove', (e) => {
  474. if (!debugMode) return;
  475.  
  476. if (!debugFrozen) {
  477. debugBox.style.left = e.pageX + 15 + 'px';
  478. debugBox.style.top = e.pageY + 15 + 'px';
  479.  
  480. const tile = e.target.closest('.tile');
  481. if (!tile) {
  482. debugBox.style.display = 'none';
  483. return;
  484. }
  485.  
  486. const cell = tile.parentElement;
  487. const row = cell?.parentElement;
  488. const rowIndex = [...row?.parentElement?.children || []].indexOf(row);
  489. const colIndex = [...row?.children || []].indexOf(cell);
  490.  
  491. const machineId = tile.dataset.machineId || 'none';
  492. const rotation = tile.dataset.rotationCount || '0';
  493. const backgroundImage = tile.style.backgroundImage || 'none';
  494. const backgroundPosition = tile.style.backgroundPosition || '0px 0px';
  495. const classList = Array.from(tile.classList).join(' ') || 'none';
  496. const inlineStyles = tile.getAttribute('style') || 'none';
  497. const computedStyles = window.getComputedStyle(tile);
  498.  
  499. let fullComputed = '';
  500. for (let i = 0; i < computedStyles.length; i++) {
  501. const prop = computedStyles[i];
  502. const val = computedStyles.getPropertyValue(prop);
  503. fullComputed += `${prop}: ${val}<br>`;
  504. }
  505.  
  506. const extraData = Object.entries(tile.dataset)
  507. .map(([key, value]) => `${key}: ${value}`)
  508. .join('<br>');
  509.  
  510. debugBox.style.display = 'block';
  511. debugBox.innerHTML = `
  512. <strong>Tile Debug</strong><br>
  513. Row: ${rowIndex}, Col: ${colIndex}<br>
  514. Machine ID: ${machineId}<br>
  515. Rotation: ${rotation}<br>
  516. BG Image: ${backgroundImage}<br>
  517. BG Pos: ${backgroundPosition}<br>
  518. Classes: ${classList}<br><br>
  519.  
  520. <strong>Inline Styles:</strong><br>
  521. ${inlineStyles}<br><br>
  522.  
  523. <strong>All Computed Styles:</strong><br>
  524. <div style="max-height: 200px; overflow-y: auto; font-size: 12px;">${fullComputed}</div>
  525.  
  526. <strong>Dataset:</strong><br>
  527. ${extraData}
  528. `;
  529. }
  530. });
  531.  
  532. const toggleCheckbox = document.getElementById('toggle-ore-panel');
  533. const orePanel = document.getElementById('ore-selection-menu');
  534.  
  535. if (toggleCheckbox && orePanel) {
  536. toggleCheckbox.addEventListener('change', () => {
  537. orePanel.classList.toggle('hidden', !toggleCheckbox.checked);
  538. });
  539.  
  540. // Initialize state
  541. orePanel.classList.toggle('hidden', !toggleCheckbox.checked);
  542. }
  543.  
  544.  
  545. });
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement