From 761a3172bf4c15aed3836e4d1cd6f815b651b0e0 Mon Sep 17 00:00:00 2001 From: LLLL Colonq Date: Sat, 29 Aug 2026 04:06:51 -0400 Subject: Fix --- 2026/games_submissions/the0x539/.gitignore | 1 - .../the0x539/MinecraftStandard.otf | Bin 159732 -> 0 bytes 2026/games_submissions/the0x539/crafting.js | 98 ---- 2026/games_submissions/the0x539/data.js | 101 ---- 2026/games_submissions/the0x539/difficulty.js | 100 ---- 2026/games_submissions/the0x539/index.html | 26 - 2026/games_submissions/the0x539/interaction.js | 581 --------------------- 2026/games_submissions/the0x539/items/boots.png | Bin 142 -> 0 bytes 2026/games_submissions/the0x539/items/bow.png | Bin 160 -> 0 bytes 2026/games_submissions/the0x539/items/chest.png | Bin 775 -> 0 bytes .../the0x539/items/chestplate.png | Bin 389 -> 0 bytes 2026/games_submissions/the0x539/items/clock.gif | Bin 2153 -> 0 bytes 2026/games_submissions/the0x539/items/cobble.png | Bin 518 -> 0 bytes 2026/games_submissions/the0x539/items/dust.png | Bin 179 -> 0 bytes 2026/games_submissions/the0x539/items/gold.png | Bin 399 -> 0 bytes 2026/games_submissions/the0x539/items/helmet.png | Bin 134 -> 0 bytes 2026/games_submissions/the0x539/items/hopper.png | Bin 404 -> 0 bytes 2026/games_submissions/the0x539/items/ingot.png | Bin 156 -> 0 bytes 2026/games_submissions/the0x539/items/leggings.png | Bin 146 -> 0 bytes 2026/games_submissions/the0x539/items/log.png | Bin 3913 -> 0 bytes 2026/games_submissions/the0x539/items/pickaxe.png | Bin 174 -> 0 bytes 2026/games_submissions/the0x539/items/piston.png | Bin 635 -> 0 bytes 2026/games_submissions/the0x539/items/plank.png | Bin 4974 -> 0 bytes 2026/games_submissions/the0x539/items/rod.png | Bin 183 -> 0 bytes 2026/games_submissions/the0x539/items/stick.png | Bin 388 -> 0 bytes 2026/games_submissions/the0x539/items/string.png | Bin 162 -> 0 bytes .../the0x539/items/tooltip-backdrop.png | Bin 768 -> 0 bytes 2026/games_submissions/the0x539/main.js | 197 ------- 2026/games_submissions/the0x539/screen.css | 168 ------ 2026/games_submissions/the0x539/sfx/big-ding.ogg | Bin 15799 -> 0 bytes 2026/games_submissions/the0x539/sfx/oof.ogg | Bin 12546 -> 0 bytes 2026/games_submissions/the0x539/sfx/small-ding.ogg | Bin 7139 -> 0 bytes .../the0x539/tooltip-backdrop.png | Bin 710 -> 0 bytes 2026/games_submissions/the0x539/ui.png | Bin 764 -> 0 bytes 34 files changed, 1272 deletions(-) delete mode 100644 2026/games_submissions/the0x539/.gitignore delete mode 100755 2026/games_submissions/the0x539/MinecraftStandard.otf delete mode 100644 2026/games_submissions/the0x539/crafting.js delete mode 100644 2026/games_submissions/the0x539/data.js delete mode 100644 2026/games_submissions/the0x539/difficulty.js delete mode 100644 2026/games_submissions/the0x539/index.html delete mode 100644 2026/games_submissions/the0x539/interaction.js delete mode 100755 2026/games_submissions/the0x539/items/boots.png delete mode 100755 2026/games_submissions/the0x539/items/bow.png delete mode 100755 2026/games_submissions/the0x539/items/chest.png delete mode 100644 2026/games_submissions/the0x539/items/chestplate.png delete mode 100755 2026/games_submissions/the0x539/items/clock.gif delete mode 100755 2026/games_submissions/the0x539/items/cobble.png delete mode 100755 2026/games_submissions/the0x539/items/dust.png delete mode 100644 2026/games_submissions/the0x539/items/gold.png delete mode 100755 2026/games_submissions/the0x539/items/helmet.png delete mode 100644 2026/games_submissions/the0x539/items/hopper.png delete mode 100755 2026/games_submissions/the0x539/items/ingot.png delete mode 100755 2026/games_submissions/the0x539/items/leggings.png delete mode 100755 2026/games_submissions/the0x539/items/log.png delete mode 100755 2026/games_submissions/the0x539/items/pickaxe.png delete mode 100755 2026/games_submissions/the0x539/items/piston.png delete mode 100644 2026/games_submissions/the0x539/items/plank.png delete mode 100755 2026/games_submissions/the0x539/items/rod.png delete mode 100755 2026/games_submissions/the0x539/items/stick.png delete mode 100755 2026/games_submissions/the0x539/items/string.png delete mode 100755 2026/games_submissions/the0x539/items/tooltip-backdrop.png delete mode 100644 2026/games_submissions/the0x539/main.js delete mode 100644 2026/games_submissions/the0x539/screen.css delete mode 100755 2026/games_submissions/the0x539/sfx/big-ding.ogg delete mode 100755 2026/games_submissions/the0x539/sfx/oof.ogg delete mode 100755 2026/games_submissions/the0x539/sfx/small-ding.ogg delete mode 100755 2026/games_submissions/the0x539/tooltip-backdrop.png delete mode 100644 2026/games_submissions/the0x539/ui.png (limited to '2026/games_submissions/the0x539') diff --git a/2026/games_submissions/the0x539/.gitignore b/2026/games_submissions/the0x539/.gitignore deleted file mode 100644 index 845270b..0000000 --- a/2026/games_submissions/the0x539/.gitignore +++ /dev/null @@ -1 +0,0 @@ -harness diff --git a/2026/games_submissions/the0x539/MinecraftStandard.otf b/2026/games_submissions/the0x539/MinecraftStandard.otf deleted file mode 100755 index 8fa0b3e..0000000 Binary files a/2026/games_submissions/the0x539/MinecraftStandard.otf and /dev/null differ diff --git a/2026/games_submissions/the0x539/crafting.js b/2026/games_submissions/the0x539/crafting.js deleted file mode 100644 index 7a61cfc..0000000 --- a/2026/games_submissions/the0x539/crafting.js +++ /dev/null @@ -1,98 +0,0 @@ -import { recipes, amounts } from './data.js'; - -export function getRecipeOutput() { - const input = readGrid(); - if (input.length === 0) return null; - - const mirroredInput = input.map(row => row.toReversed()); - - for (const [item, recipe] of Object.entries(recipes)) { - const isMatch = compare(input, recipe) || compare(mirroredInput, recipe); - if (!isMatch) continue; - - const amount = amounts[item] ?? 1; - return [item, amount]; - } - - return null; -} - -function last(arr) { - return arr[arr.length - 1]; -} - -function isSymmetric(grid) { - return grid.every(row => row[0] === last(row)); -} - -function readGrid() { - const cells = document.querySelectorAll('crafting-grid > inventory-cell'); - - const rows = []; - for (let y = 0; y < 3; y++) { - const row = []; - for (let x = 0; x < 3; x++) { - let item = null; - const stack = cells[3 * y + x].firstElementChild; - if (!!stack) { - item = stack.getAttribute('data-item'); - } - row.push(item); - } - rows.push(row); - } - - trimGrid(rows); - - return rows; -} - -function trimGrid(grid) { - if (grid.flat().every(v => v === null)) { - while (grid.length > 0) { - grid.pop(); - } - return; - } - - // it is now established that the grid is non-empty, - // so there will always be at least one row+col - - // trim blank rows from bottom - while (last(grid).every(v => v === null)) { - grid.pop(); - } - - // trim blank rows from top - while (grid[0].every(v => v === null)) { - grid.shift(); - } - - // trim blank columns from right - while (grid.every(row => last(row) === null)) { - for (const row of grid) { - row.pop(); - } - } - - // trim blank columns from left - while (grid.every(row => row[0] === null)) { - for (const row of grid) { - row.shift(); - } - } -} - -function compare(a, b) { - if (a.length !== b.length) return false; - - for (let y = 0; y < a.length; y++) { - if (a[y].length !== b[y].length) return false; - - for (let x = 0; x < a[y].length; x++) { - if (a[y][x] !== b[y][x]) return false; - } - } - - return true; -} diff --git a/2026/games_submissions/the0x539/data.js b/2026/games_submissions/the0x539/data.js deleted file mode 100644 index 977c557..0000000 --- a/2026/games_submissions/the0x539/data.js +++ /dev/null @@ -1,101 +0,0 @@ -const ingredients = { - i: 'ingot', - l: 'log', - p: 'plank', - s: 'stick', - d: 'dust', - c: 'cobble', - C: 'chest', - S: 'string', - g: 'gold', -} - -function recipe(...shape) { - return shape.map(line => Array.from(line).map(ch => { - if (ch === ' ') { - return null; - } else { - const item = ingredients[ch]; - console.assert(!!item); - return item; - } - })); -} - -export const recipes = { - helmet: recipe( - 'iii', - 'i i', - ), - chestplate: recipe( - 'i i', - 'iii', - 'iii', - ), - leggings: recipe( - 'iii', - 'i i', - 'i i', - ), - boots: recipe( - 'i i', - 'i i', - ), - plank: recipe( - 'l', - ), - stick: recipe( - 'p', - 'p', - ), - pickaxe: recipe( - 'ppp', - ' s ', - ' s ', - ), - piston: recipe( - 'ppp', - 'cic', - 'cdc', - ), - chest: recipe( - 'ppp', - 'p p', - 'ppp', - ), - hopper: recipe( - 'i i', - 'iCi', - ' i ', - ), - rod: recipe( - ' s', - ' sS', - 's S', - ), - bow: recipe( - ' sS', - 's S', - ' sS', - ), - clock: recipe( - ' g ', - 'gdg', - ' g ', - ), -}; - -export const amounts = { - plank: 4, - stick: 4, -} - -export const stackSizes = { - helmet: 1, - chestplate: 1, - leggings: 1, - boots: 1, - pickaxe: 1, - rod: 1, - bow: 1, -} diff --git a/2026/games_submissions/the0x539/difficulty.js b/2026/games_submissions/the0x539/difficulty.js deleted file mode 100644 index 87a86b9..0000000 --- a/2026/games_submissions/the0x539/difficulty.js +++ /dev/null @@ -1,100 +0,0 @@ -export const scenarios = [ - { - level: 0, - items: { - log: 2, - }, - goal: ['chest'], - time: _ => 10, - }, - { - level: 5, - items: { - plank: 7, - cobble: 6, - dust: 8, - ingot: 4, - }, - goal: ['piston'], - time: d => 15 - d, - }, - { - level: 10, - items: { - log: 2, - cobble: 4, - dust: 2, - ingot: 1, - }, - goal: ['piston'], - time: d => 15 - d, - }, - { - level: 13, - items: { - log: 8, - }, - goal: ['pickaxe'], - time: d => 15 - d, - }, - { - level: 18, - items: { - ingot: 8, - plank: 8, - }, - goal: ['hopper'], - time: d => 20 - d, - }, - { - level: 21, - items: { - ingot: 12, - log: 3, - }, - goal: ['hopper'], - time: d => 20 - d, - }, - { - level: 25, - items: { - ingot: 24, - }, - goal: ['helmet', 'chestplate', 'leggings', 'boots'], - time: d => 18 - d, - }, - { - level: 30, - items: { - ingot: 28, - log: 1, - string: 3, - }, - goal: ['helmet', 'chestplate', 'leggings', 'boots', 'bow'], - time: d => 30 - d, - }, - { - level: 35, - items: { - ingot: 24, - log: 1, - string: 3, - gold: 64, - dust: 17, - }, - goal: ['helmet', 'chestplate', 'leggings', 'boots', 'bow'], - time: _ => 15, - }, - { - level: 40, - items: { - ingot: 24, - log: 1, - string: 3, - gold: 63, - dust: 15, - }, - goal: ['helmet', 'chestplate', 'leggings', 'boots', 'bow'], - time: _ => 15, - }, -]; diff --git a/2026/games_submissions/the0x539/index.html b/2026/games_submissions/the0x539/index.html deleted file mode 100644 index 5a073ed..0000000 --- a/2026/games_submissions/the0x539/index.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/2026/games_submissions/the0x539/interaction.js b/2026/games_submissions/the0x539/interaction.js deleted file mode 100644 index d45d5c9..0000000 --- a/2026/games_submissions/the0x539/interaction.js +++ /dev/null @@ -1,581 +0,0 @@ -import { stackSizes } from './data.js'; -import { getRecipeOutput } from './crafting.js'; - -class CraftEvent extends Event { - item; - constructor(item) { - super('craft'); - this.item = item; - } -} - -const grabbedStack = document.querySelector('grabbed-stack'); -const craftingGrid = document.querySelector('crafting-grid'); -const inventoryGrid = document.querySelector('inventory-grid'); -const outputCell = document.querySelector('crafting-output'); - -let state = 'idle'; - -const splitTargets = new Set(); - -export function resetInventory() { - for (const stack of document.querySelectorAll('item-stack')) { - stack.remove(); - } - splitTargets.clear(); - state = 'idle'; -} - -export function createItem(item, count) { - const elem = document.createElement('item-stack'); - elem.setAttribute('data-item', item); - elem.setAttribute('data-count', count); - const countElem = document.createElement('data'); - countElem.textContent = count.toString(); - elem.appendChild(countElem); - return elem; -} - -export function mouseDown(event) { - if (state !== 'idle') return; - if (event.button !== 0 && event.button !== 2) return; - - const cell = event.currentTarget; - - // Shift click: Transfer a full stack to the other place. - if (event.shiftKey) { - const sourceStack = cell.firstElementChild; - if (sourceStack) { - const targetGrid = cell.parentElement === inventoryGrid ? craftingGrid : inventoryGrid; - shiftClickTransfer(sourceStack, targetGrid); - } - state = 'shift-drag'; - return; - } - - const heldStack = grabbedStack.firstElementChild; - - // Click with empty cursor: pick up items - if (!heldStack) { - const sourceStack = cell.firstElementChild; - if (!sourceStack) { - return; - } - - if (event.button === 2) { - // Right click: take half the stack, rounded up - const sourceCount = getCount(sourceStack); - if (sourceCount === 1) { - grabbedStack.appendChild(sourceStack); - updateRecipeOutput(); - return; - } - - const takenCount = Math.ceil(sourceCount / 2); - const newCount = sourceCount - takenCount; - const item = sourceStack.getAttribute('data-item'); - setCount(sourceStack, newCount); - grabbedStack.appendChild(createItem(item, takenCount)); - } else { - // Left click: take the whole stack. Drag to pick up other stacks - grabbedStack.appendChild(sourceStack); - state = 'pickup-drag'; - updateRecipeOutput(); - } - } else { - // Click with items held: deposit items - - if (event.button === 2) { - // Right click: deposit one item. Drag to deposit one item in each cell - state = 'split-one'; - depositOne(cell); - } else { - // Left click: split stack evenly across all empty/compatible cells. - // If no compatible cells are dragged over, swap stack with the cell the mouse was released on. - // (In the common case, this is just what a "click" looks like on a cell with incompatible contents.) - heldStack.setAttribute('data-original-count', heldStack.getAttribute('data-count')); - state = 'split-evenly'; - addSplitTarget(cell); - } - } -} - -export function mouseEnter(event) { - const cell = event.currentTarget; - - switch (state) { - case 'shift-drag': { - const sourceStack = cell.firstElementChild; - if (!sourceStack) break; - const targetGrid = cell.parentElement === inventoryGrid ? craftingGrid : inventoryGrid; - shiftClickTransfer(sourceStack, targetGrid); - updateRecipeOutput(); - break; - } - - case 'pickup-drag': { - const sourceStack = cell.firstElementChild; - if (!sourceStack) break; - const heldStack = grabbedStack.firstElementChild; - const item = sourceStack.getAttribute('data-item'); - if (item !== heldStack.getAttribute('data-item')) return; - - const stackSize = stackSizes[item] ?? 64; - - const newCount = getCount(heldStack) + getCount(sourceStack); - if (newCount > stackSize) return; - - setCount(heldStack, newCount); - sourceStack.remove(); - updateRecipeOutput(); - break; - } - - case 'split-one': - depositOne(cell); - break; - - case 'split-evenly': - addSplitTarget(cell); - break; - - default: - break; - } -} - -export function mouseUp(event) { - switch (state) { - case 'split-evenly': - case 'split-exhausted': { - if (event.button !== 0) return; - - if (splitTargets.size <= 1) { - const targetCell = event.target.closest('inventory-cell'); - if (targetCell) { - depositAll(targetCell); - } - } else { - commitSplit(); - } - break; - } - - case 'pickup-drag': - if (event.button !== 0) return; - state = 'idle'; - break; - - case 'split-one': - if (event.button !== 2) return; - state = 'idle'; - break; - - case 'shift-drag': - // this could be either button. whatever. - state = 'idle'; - break; - - default: - break; - } -} - -export function craftClick(event) { - if (event.shiftKey) { - craftAll(); - } else { - craftOne(); - } -} - -function craftOne() { - const previewStack = outputCell.firstElementChild; - if (!previewStack) return; - - const item = previewStack.getAttribute('data-item'); - const craftCount = getCount(previewStack); - const stackSize = stackSizes[item] ?? 64; - - const heldStack = grabbedStack.firstElementChild; - if (heldStack !== null) { - if (heldStack.getAttribute('data-item') !== item) { - return; - } - - const heldCount = getCount(heldStack); - if (heldCount + craftCount > stackSize) { - return; - } - - setCount(heldStack, heldCount + craftCount); - } else { - grabbedStack.appendChild(createItem(item, craftCount)); - } - consumeIngredients(); - document.dispatchEvent(new CraftEvent(item)); -} - -function craftAll() { - const previewStack = outputCell.firstElementChild; - if (!previewStack) return; - - const item = previewStack.getAttribute('data-item'); - const craftCount = getCount(previewStack); - const stackSize = stackSizes[item] ?? 64; - - let success = false; - - do { - let unallocated = craftCount; - - const nonEmptyTargets = []; - let emptyTarget = null; - - for (const cell of inventoryGrid.children) { - const stack = cell.firstElementChild; - if (stack === null) { - // This slot is empty. - // All crafting outputs that don't fit into existing stacks - // will be deposited into the first empty slot. - emptyTarget ??= cell; - continue; - } - - if (stack.getAttribute('data-item') !== item) { - // This slot already contains a different item, - // so we can't add crafting outputs to it. - continue; - } - - const spareCapacity = stackSize - getCount(stack); - if (spareCapacity <= 0) { - // This slot contains the correct item, but is already full. - continue; - } - - const amountToAdd = Math.min(unallocated, spareCapacity); - unallocated -= amountToAdd; - nonEmptyTargets.push([stack, amountToAdd]); - - if (unallocated === 0) { - // All crafting outputs can fit into existing stacks of the item. - break; - } - } - - if (unallocated > 0 && emptyTarget === null) { - // The inventory is full: no slots are empty and existing stacks don't have enough room. - // Abort this attempt and conclude the loop. - break; - } - - // Add crafting output to existing stacks, to whatever extent possible. - for (const [stack, amountToAdd] of nonEmptyTargets) { - setCount(stack, getCount(stack) + amountToAdd); - } - - // Put any remaining items into the first empty slot. - if (unallocated > 0) { - emptyTarget.appendChild(createItem(item, unallocated)); - } - - success = true; - - // Consume one set of ingredients. - // Cease crafting if this causes the recipe output to change. - } while (!consumeIngredients()); - - if (success) { - document.dispatchEvent(new CraftEvent(item)); - } -} - -function consumeIngredients() { - let anyExhausted = false; - - for (const cell of craftingGrid.children) { - const stack = cell.firstElementChild; - if (!stack) continue; - - const count = getCount(stack); - if (count === 1) { - stack.remove(); - anyExhausted = true; - } else { - setCount(stack, count - 1); - } - } - - return anyExhausted && updateRecipeOutput(); -} - -// Returns whether the output actually changed -function updateRecipeOutput() { - const outputStack = outputCell.firstElementChild; - - const output = getRecipeOutput(); - if (output === null) { - if (outputStack === null) { - return false; - } else { - outputStack.remove(); - return true; - } - } - - const [item, count] = output; - if (outputStack === null) { - outputCell.appendChild(createItem(item, count)); - return true; - } - - if (outputStack.getAttribute('data-item') === item && getCount(outputStack) === count) { - return false; - } - - outputStack.setAttribute('data-item', item); - setCount(outputStack, count); - return true; -} - -export function consumeClock() { - if (state === 'split-exhausted') { - commitSplit(); - } - - if (state === 'split-evenly' && splitTargets.size > 1) { - // oh dear. this is a complicated situation - // first, let's try to search for uninvolved clocks - const uninvolved = document.querySelector('inventory-cell > item-stack[data-item="clock"]:not([data-original-count]):not(crafting-output item-stack)'); - if (!!uninvolved) { - const count = getCount(uninvolved); - if (count === 1) { - uninvolved.remove(); - } else { - setCount(uninvolved, count - 1); - } - // phew - return; - } - - // okay so we will actually need to remove a clock from the items being split, ugh - // not a lot of code, but low confidence that it works properly - const heldStack = grabbedStack.firstElementChild; - const count = +heldStack.getAttribute('data-original-count'); - heldStack.setAttribute('data-original-count', count - 1); - updateSplitPreview(); - return; - } - - const stack = document.querySelector('item-stack[data-item="clock"][data-count]:not(crafting-output item-stack)') - const count = getCount(stack); - if (count === 1) { - if (stack.parentElement === grabbedStack) { - // conclude drag operations if they're done using a stack of clocks that gets deleted - state = 'idle'; - } - stack.remove(); - } else { - setCount(stack, count - 1); - } -} - -function getCount(itemStack) { - return +itemStack.getAttribute('data-count'); -} - -function setCount(itemStack, value) { - itemStack.setAttribute('data-count', value); - itemStack.firstElementChild.textContent = value.toString(); -} - -function depositOne(targetCell) { - const heldStack = grabbedStack.firstElementChild; - const item = heldStack.getAttribute('data-item'); - const heldCount = getCount(heldStack); - - const stackSize = stackSizes[item] ?? 64; - - const targetStack = targetCell.firstElementChild; - if (targetStack) { - if (targetStack.getAttribute('data-item') !== item) { - return; - } - - const targetCount = getCount(targetStack); - if (targetCount >= stackSize) return; - - setCount(targetStack, targetCount + 1); - } else { - targetCell.appendChild(createItem(item, 1)); - } - - if (heldCount === 1) { - heldStack.remove(); - state = 'idle'; - } else { - setCount(heldStack, heldCount - 1); - } - - updateRecipeOutput(); -} - -function shiftClickTransfer(sourceStack, targetGrid) { - const item = sourceStack.getAttribute('data-item'); - const stackSize = stackSizes[item] ?? 64; - let count = getCount(sourceStack); - - // First, search for existing stacks to add to - for (const cell of targetGrid.children) { - const targetStack = cell.firstElementChild; - if (!targetStack) continue; - if (targetStack.getAttribute('data-item') !== item) continue; - const curCount = getCount(targetStack); - const available = stackSize - curCount; - if (available === 0) continue; - - const transferSize = Math.min(count, available); - const newCount = curCount + transferSize; - setCount(targetStack, newCount); - - count -= transferSize; - if (count === 0) { - sourceStack.remove(); - updateRecipeOutput(); - return; - } else { - setCount(sourceStack, count); - } - } - - // Now, look for any empty slots to move whatever's left to - for (const cell of targetGrid.children) { - if (!cell.firstElementChild) { - cell.appendChild(sourceStack); - break; - } - } - - updateRecipeOutput(); -} - -function addSplitTarget(targetCell) { - const heldStack = grabbedStack.firstElementChild; - const item = heldStack.getAttribute('data-item'); - - const targetStack = targetCell.firstElementChild; - if (targetStack) { - if (targetStack.getAttribute('data-item') !== item) { - return; - } - } - - splitTargets.add(targetCell); - - if (splitTargets.size > 1) { - updateSplitPreview(); - } -} - -function updateSplitPreview() { - const heldStack = grabbedStack.firstElementChild; - const item = heldStack.getAttribute('data-item'); - const heldCount = +heldStack.getAttribute('data-original-count'); - - const stackSize = stackSizes[item] ?? 64; - - const splitCount = Math.max(1, Math.floor(heldCount / splitTargets.size)); - let remainder = heldCount; - - for (const targetCell of splitTargets) { - let targetStack = targetCell.firstElementChild; - if (!targetStack) { - targetStack = createItem(item, 0); - targetCell.appendChild(targetStack); - } - if (!targetStack.hasAttribute('data-original-count')) { - targetStack.setAttribute('data-original-count', targetStack.getAttribute('data-count')); - } - const targetCount = +targetStack.getAttribute('data-original-count'); - const available = stackSize - targetCount; - const transferSize = Math.min(splitCount, available); - setCount(targetStack, targetCount + transferSize); - remainder -= transferSize; - // TODO: give stacks yellow text if they're too full to accomodate their full share of the split - - if (remainder === 0) break; - } - - setCount(heldStack, remainder); - - if (splitCount === 1 && remainder === 0) { - state = 'split-exhausted'; - } -} - -function commitSplit() { - const heldStack = grabbedStack.firstElementChild; - const heldCount = getCount(heldStack); - - if (heldCount === 0) { - heldStack.remove(); - } else { - heldStack.removeAttribute('data-original-count'); - } - - for (const target of splitTargets) { - target.firstElementChild?.removeAttribute('data-original-count'); - } - - splitTargets.clear(); - - state = 'idle'; - - updateRecipeOutput(); -} - -function depositAll(targetCell) { - const heldStack = grabbedStack.firstElementChild; - const item = heldStack.getAttribute('data-item'); - const heldCount = getCount(heldStack); - - const stackSize = stackSizes[item] ?? 64; - - const targetStack = targetCell.firstElementChild; - if (!!targetStack && targetStack.getAttribute('data-item') !== item) { - // swap held and target stacks because they don't match - targetCell.appendChild(heldStack); - grabbedStack.appendChild(targetStack); - } else { - if (!targetStack) { - // deposit the full stack to the slot - targetCell.appendChild(heldStack); - } else { - // deposit as much as possible - const targetCount = getCount(targetStack); - const available = stackSize - targetCount; - const transferSize = Math.min(heldCount, available); - const newCount = targetCount + transferSize; - setCount(targetStack, newCount); - - if (transferSize < heldCount) { - setCount(heldStack, heldCount - transferSize); - } else { - heldStack.remove(); - } - } - } - - heldStack.removeAttribute('data-original-count'); - - for (const target of splitTargets) { - target.firstElementChild?.removeAttribute('data-original-count'); - } - - splitTargets.clear(); - - state = 'idle'; - - updateRecipeOutput(); -} diff --git a/2026/games_submissions/the0x539/items/boots.png b/2026/games_submissions/the0x539/items/boots.png deleted file mode 100755 index ca6c33b..0000000 Binary files a/2026/games_submissions/the0x539/items/boots.png and /dev/null differ diff --git a/2026/games_submissions/the0x539/items/bow.png b/2026/games_submissions/the0x539/items/bow.png deleted file mode 100755 index 6922e69..0000000 Binary files a/2026/games_submissions/the0x539/items/bow.png and /dev/null differ diff --git a/2026/games_submissions/the0x539/items/chest.png b/2026/games_submissions/the0x539/items/chest.png deleted file mode 100755 index eb7f766..0000000 Binary files a/2026/games_submissions/the0x539/items/chest.png and /dev/null differ diff --git a/2026/games_submissions/the0x539/items/chestplate.png b/2026/games_submissions/the0x539/items/chestplate.png deleted file mode 100644 index 0cc9a63..0000000 Binary files a/2026/games_submissions/the0x539/items/chestplate.png and /dev/null differ diff --git a/2026/games_submissions/the0x539/items/clock.gif b/2026/games_submissions/the0x539/items/clock.gif deleted file mode 100755 index d4a7698..0000000 Binary files a/2026/games_submissions/the0x539/items/clock.gif and /dev/null differ diff --git a/2026/games_submissions/the0x539/items/cobble.png b/2026/games_submissions/the0x539/items/cobble.png deleted file mode 100755 index 55dbc4f..0000000 Binary files a/2026/games_submissions/the0x539/items/cobble.png and /dev/null differ diff --git a/2026/games_submissions/the0x539/items/dust.png b/2026/games_submissions/the0x539/items/dust.png deleted file mode 100755 index 9d17c14..0000000 Binary files a/2026/games_submissions/the0x539/items/dust.png and /dev/null differ diff --git a/2026/games_submissions/the0x539/items/gold.png b/2026/games_submissions/the0x539/items/gold.png deleted file mode 100644 index 99b1a46..0000000 Binary files a/2026/games_submissions/the0x539/items/gold.png and /dev/null differ diff --git a/2026/games_submissions/the0x539/items/helmet.png b/2026/games_submissions/the0x539/items/helmet.png deleted file mode 100755 index 850dac6..0000000 Binary files a/2026/games_submissions/the0x539/items/helmet.png and /dev/null differ diff --git a/2026/games_submissions/the0x539/items/hopper.png b/2026/games_submissions/the0x539/items/hopper.png deleted file mode 100644 index 9655818..0000000 Binary files a/2026/games_submissions/the0x539/items/hopper.png and /dev/null differ diff --git a/2026/games_submissions/the0x539/items/ingot.png b/2026/games_submissions/the0x539/items/ingot.png deleted file mode 100755 index 17e8aa8..0000000 Binary files a/2026/games_submissions/the0x539/items/ingot.png and /dev/null differ diff --git a/2026/games_submissions/the0x539/items/leggings.png b/2026/games_submissions/the0x539/items/leggings.png deleted file mode 100755 index a28a10f..0000000 Binary files a/2026/games_submissions/the0x539/items/leggings.png and /dev/null differ diff --git a/2026/games_submissions/the0x539/items/log.png b/2026/games_submissions/the0x539/items/log.png deleted file mode 100755 index 56d24f0..0000000 Binary files a/2026/games_submissions/the0x539/items/log.png and /dev/null differ diff --git a/2026/games_submissions/the0x539/items/pickaxe.png b/2026/games_submissions/the0x539/items/pickaxe.png deleted file mode 100755 index 9dea9e2..0000000 Binary files a/2026/games_submissions/the0x539/items/pickaxe.png and /dev/null differ diff --git a/2026/games_submissions/the0x539/items/piston.png b/2026/games_submissions/the0x539/items/piston.png deleted file mode 100755 index f08618a..0000000 Binary files a/2026/games_submissions/the0x539/items/piston.png and /dev/null differ diff --git a/2026/games_submissions/the0x539/items/plank.png b/2026/games_submissions/the0x539/items/plank.png deleted file mode 100644 index 863206a..0000000 Binary files a/2026/games_submissions/the0x539/items/plank.png and /dev/null differ diff --git a/2026/games_submissions/the0x539/items/rod.png b/2026/games_submissions/the0x539/items/rod.png deleted file mode 100755 index 6610384..0000000 Binary files a/2026/games_submissions/the0x539/items/rod.png and /dev/null differ diff --git a/2026/games_submissions/the0x539/items/stick.png b/2026/games_submissions/the0x539/items/stick.png deleted file mode 100755 index d32381d..0000000 Binary files a/2026/games_submissions/the0x539/items/stick.png and /dev/null differ diff --git a/2026/games_submissions/the0x539/items/string.png b/2026/games_submissions/the0x539/items/string.png deleted file mode 100755 index ad78eb4..0000000 Binary files a/2026/games_submissions/the0x539/items/string.png and /dev/null differ diff --git a/2026/games_submissions/the0x539/items/tooltip-backdrop.png b/2026/games_submissions/the0x539/items/tooltip-backdrop.png deleted file mode 100755 index 05c02cd..0000000 Binary files a/2026/games_submissions/the0x539/items/tooltip-backdrop.png and /dev/null differ diff --git a/2026/games_submissions/the0x539/main.js b/2026/games_submissions/the0x539/main.js deleted file mode 100644 index 14a2b45..0000000 --- a/2026/games_submissions/the0x539/main.js +++ /dev/null @@ -1,197 +0,0 @@ -import { recipes, amounts } from './data.js'; -import { - createItem, - mouseDown, - mouseEnter, - mouseUp, - craftClick, - consumeClock, - resetInventory, -} from './interaction.js'; -import { scenarios } from './difficulty.js'; - -const followCursor = document.querySelector('follow-cursor'); -const tooltip = document.querySelector('item-tooltip'); -const craftingGrid = document.querySelector('crafting-grid'); -const inventoryGrid = document.querySelector('inventory-grid'); -const craftingOutput = document.querySelector('crafting-output'); -const todoList = document.getElementById('todo-list'); - -const desiredCrafts = new Set(); - -const playSound = { - playImpl(id, volume = 1.0, pitch = 1.0) { - const audio = document.getElementById(id); - - audio.currentTime = 0; - - const p = new Promise(resolve => { - const f = (event) => { - audio.removeEventListener('ended', f); - resolve(event); - }; - audio.addEventListener('ended', f); - }); - - audio.volume = volume; - audio.playbackRate = pitch; - audio.preservesPitch = false; - - audio.play(); - return p; - }, - - smallDing() { - return this.playImpl('small-ding', 0.1, 0.55 + 0.7 * Math.random()); - }, - - bigDing() { - return this.playImpl('big-ding', 0.75); - }, - - oof() { - return this.playImpl('oof', 0.75); - }, -}; - -function onCraft(event) { - const item = event.item; - if (desiredCrafts.has(item)) { - desiredCrafts.delete(item); - - document.querySelector(`#todo-list > li:has([data-item="${item}"])`)?.remove(); - - if (desiredCrafts.size > 0) { - playSound.smallDing(); - } else { - endGame(true); - } - } -} - -function handleMessage(msg) { - if (msg.op === 'start') { - startGame(msg.difficulty); - } -} - -function giveItem(item, count) { - const emptySlots = document.querySelectorAll('inventory-grid > inventory-cell:empty'); - const index = Math.floor(Math.random() * emptySlots.length); - emptySlots[index].appendChild(createItem(item, count)); -} - -let timerInterval = null; - -function timer() { - if (!document.querySelector('item-stack[data-item="clock"]:not(crafting-output item-stack)')) { - // time's up! - endGame(false); - } else { - consumeClock(); - } -} - -function startGame(difficulty) { - document.body.classList.remove('failed'); - - resetInventory(); - - const scenario = scenarios.toReversed().find(s => difficulty >= s.level); - - desiredCrafts.clear(); - for (const item of scenario.goal) { - desiredCrafts.add(item); - } - - todoList.replaceChildren(); - for (const item of desiredCrafts) { - const listItem = document.createElement('li'); - - const stack = document.createElement('item-stack'); - stack.setAttribute('data-item', item); - listItem.append(stack); - - todoList.append(listItem); - } - - for (const [item, amount] of Object.entries(scenario.items)) { - giveItem(item, amount); - } - giveItem('clock', scenario.time(difficulty - scenario.level)); - - document.addEventListener('mousemove', onMouseMove); - timerInterval = setInterval(timer, 1000); - window.parent.postMessage({ op: 'started', verb: 'craft!' }); -} - -async function endGame(win) { - clearInterval(timerInterval); - timerInterval = null; - if (win) { - await playSound.bigDing(); - } else { - document.body.classList.add('failed'); - await playSound.oof(); - } - await new Promise(resolve => setTimeout(resolve, 500)); - document.removeEventListener('mousemove', onMouseMove); - window.parent.postMessage({ op: 'done', win }); -} - -function createCell() { - const elem = document.createElement('inventory-cell'); - elem.addEventListener('mousedown', mouseDown); - elem.addEventListener('mouseenter', mouseEnter); - return elem; -} - -function onMouseMove(event) { - followCursor.setAttribute('style', `left: ${event.clientX}px; top: ${event.clientY}px`); - - const hoverItem = document.querySelector('item-stack:hover'); - if (hoverItem !== null) { - const name = hoverItem.getAttribute('data-item'); - tooltip.textContent = name; - } else { - tooltip.textContent = ''; - } -} - -document.addEventListener('contextmenu', e => e.preventDefault()); - -const allItems = new Set(); -for (const [output, shape] of Object.entries(recipes)) { - allItems.add(output); - for (const item of shape.flat()) { - if (item) { - allItems.add(item); - } - } -} - -const stylesheet = document.styleSheets[0]; - -for (const item of allItems) { - stylesheet.insertRule(` - item-stack[data-item="${item}"]::before { - background-image: url("./items/${item}.png"); - } - `); -} - -for (let i = 0; i < 3 * 3; i++) { - craftingGrid.appendChild(createCell()); -} - -for (let i = 0; i < 12 * 3; i++) { - inventoryGrid.appendChild(createCell()); -} - -document.addEventListener('mouseup', mouseUp); -document.addEventListener('craft', onCraft); - -craftingOutput.addEventListener('click', craftClick); - -window.addEventListener('message', m => handleMessage(m.data)); -window.parent.postMessage({ op: 'ready' }); diff --git a/2026/games_submissions/the0x539/screen.css b/2026/games_submissions/the0x539/screen.css deleted file mode 100644 index d9a6f72..0000000 --- a/2026/games_submissions/the0x539/screen.css +++ /dev/null @@ -1,168 +0,0 @@ -@font-face { - font-family: "Minecraft"; - src: url("./MinecraftStandard.otf") format("opentype"); -} - -* { - box-sizing: border-box; - user-select: none; - font-family: Minecraft; - font-smooth: never; - font-size: 6px; - text-rendering: geometricPrecision; - line-height: 1em; -} - -body { - margin: 0; -} - -crafting-grid, -inventory-grid { - position: absolute; - display: grid; - align-items: center; - justify-items: center; -} - -follow-cursor { - position: absolute; - pointer-events: none; -} - -grabbed-stack { - display: block; - translate: -50% -50%; - z-index: 10; - pointer-events: none; -} - -:root:has(grabbed-stack > item-stack) { - cursor: grabbing; -} - -inventory-cell, -crafting-output { - width: 16px; - height: 16px; - - &:hover, - &:has(> item-stack[data-original-count]) { - background-color: rgba(255, 255, 255, 0.5); - } - - &:has(> item-stack) { - cursor: grab; - } -} - -crafting-grid { - left: 62px; - top: 22px; - grid-template: repeat(3, 18px) / repeat(3, 18px); -} - -crafting-output { - position: absolute; - left: 157px; - top: 41px; -} - -inventory-grid { - left: 12px; - top: 94px; - grid-template: repeat(3, 18px) / repeat(12, 18px); -} - -item-stack { - display: block; - position: relative; - - & > data { - position: absolute; - color: #fcfcfc; - text-shadow: #3e3e3e 1px 1px; - bottom: 0; - right: 0; - translate: 1px -1px; - } - - &[data-count="0"] { - display: none; - } - - &[data-count="1"] > data { - display: none; - } - - &[data-item="clock"]::before { - background-image: url("./items/clock.gif"); - } - - &::before { - display: block; - width: 16px; - height: 16px; - content: ""; - background-size: 16px 16px; - } -} - -img { - pointer-events: none; -} - -item-tooltip { - display: block; - color: white; - border-style: solid; - border-width: 4px; - border-image-source: url("./tooltip-backdrop.png"); - border-image-slice: 4 fill; - text-shadow: gray 1px 1px; - height: 16px; - line-height: 1em; - color: #fcfcfc; - text-shadow: #3e3e3e 1px 1px; - translate: 8px -100%; - - &:empty, - &:has(+ * > item-stack) { - display: none; - } -} - -body.failed { - filter: brightness(0.8) sepia(75%) hue-rotate(-45deg); - cursor: not-allowed; - & > * { - pointer-events: none; - } -} - -label[for="todo-list"] { - position: absolute; - top: 12px; - left: 12px; - color: #3f3f3f; - - &:has(+ #todo-list:empty) { - display: none; - } -} - -#todo-list { - position: absolute; - left: 12px; - top: 24px; - margin: 0; - padding: 0; - display: flex; - width: 32px; - flex-wrap: wrap; - justify-content: center; - - & > li { - list-style: none; - } -} diff --git a/2026/games_submissions/the0x539/sfx/big-ding.ogg b/2026/games_submissions/the0x539/sfx/big-ding.ogg deleted file mode 100755 index a3f4c0b..0000000 Binary files a/2026/games_submissions/the0x539/sfx/big-ding.ogg and /dev/null differ diff --git a/2026/games_submissions/the0x539/sfx/oof.ogg b/2026/games_submissions/the0x539/sfx/oof.ogg deleted file mode 100755 index 10448dc..0000000 Binary files a/2026/games_submissions/the0x539/sfx/oof.ogg and /dev/null differ diff --git a/2026/games_submissions/the0x539/sfx/small-ding.ogg b/2026/games_submissions/the0x539/sfx/small-ding.ogg deleted file mode 100755 index a38b2cc..0000000 Binary files a/2026/games_submissions/the0x539/sfx/small-ding.ogg and /dev/null differ diff --git a/2026/games_submissions/the0x539/tooltip-backdrop.png b/2026/games_submissions/the0x539/tooltip-backdrop.png deleted file mode 100755 index 893b468..0000000 Binary files a/2026/games_submissions/the0x539/tooltip-backdrop.png and /dev/null differ diff --git a/2026/games_submissions/the0x539/ui.png b/2026/games_submissions/the0x539/ui.png deleted file mode 100644 index ab1873c..0000000 Binary files a/2026/games_submissions/the0x539/ui.png and /dev/null differ -- cgit v1.3.1