Shift-drag draws a line for belts and other transport pieces
Belts, filters, screw conveyors, shafts and pipe pieces never fill a rectangle; a diagonal belt drag stays sloped with Shift held. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -477,6 +477,10 @@ above, including:
|
|||||||
chose to make stickiness grain against grain only: on anything built, every material slides
|
chose to make stickiness grain against grain only: on anything built, every material slides
|
||||||
freely, so slopes are useful for every material, while heaps keep their shape. Real chutes clog
|
freely, so slopes are useful for every material, while heaps keep their shape. Real chutes clog
|
||||||
with sticky material and need cleaning, but that is micromanagement the game doesn't need.
|
with sticky material and need cleaning, but that is micromanagement the game doesn't need.
|
||||||
|
- **Belts and other transport pieces never fill a rectangle (2026-10-27).** The owner said Shift
|
||||||
|
doesn't need to fill a rectangle for belts, conveyors and the like. Belts, filters, screw
|
||||||
|
conveyors, shafts, pipes, pumps and outlets (`lineOnly()`) always draw a line, Shift or not, and
|
||||||
|
a diagonal belt drag stays sloped. Walls, grates and gates still Shift-fill.
|
||||||
|
|
||||||
## Ideas not built yet
|
## Ideas not built yet
|
||||||
|
|
||||||
|
|||||||
+7
-7
@@ -205,9 +205,9 @@ Material definitions: ids, properties and metal families. ids, and drill/tank ti
|
|||||||
Material tables: typed properties, casting groups, flags, parts and tool tiers. Typed property tables
|
Material tables: typed properties, casting groups, flags, parts and tool tiers. Typed property tables
|
||||||
- variables: PH, DENS, KC, ICAP, CASTMETAL, METAL_TIER, SOLIDMETAL, F_NAT, F_CAST, F_BURN, P_NONE, P_SCREW_U, P_SCREW_D, P_SCREW_L, P_SCREW_R, P_GRATE, P_GOPEN, P_WHEEL, P_INTAKE, P_FILTER, P_PIPE, P_SCREW_UR, P_SCREW_DR, P_SCREW_DL, P_SCREW_UL, SCREW_PARTS, SCREW_DIRS, IS_SCREW, SCREW_DX, SCREW_DY, BIT_TIERS, TANK_TIERS, REACH
|
- variables: PH, DENS, KC, ICAP, CASTMETAL, METAL_TIER, SOLIDMETAL, F_NAT, F_CAST, F_BURN, P_NONE, P_SCREW_U, P_SCREW_D, P_SCREW_L, P_SCREW_R, P_GRATE, P_GOPEN, P_WHEEL, P_INTAKE, P_FILTER, P_PIPE, P_SCREW_UR, P_SCREW_DR, P_SCREW_DL, P_SCREW_UL, SCREW_PARTS, SCREW_DIRS, IS_SCREW, SCREW_DX, SCREW_DY, BIT_TIERS, TANK_TIERS, REACH
|
||||||
|
|
||||||
### src/sim/pieces.js (177 lines)
|
### src/sim/pieces.js (179 lines)
|
||||||
Everything the player can build (PIECES): blocks, machines and molds, with costs and descriptions; filter settings; wall materials and their cost.
|
Everything the player can build (PIECES): blocks, machines and molds, with costs and descriptions; filter settings; wall materials and their cost.
|
||||||
- functions: isSlopeBelt, isFilter, isBelt, beltGrade, slopeShape, beltFaceY, filterVariant, beltDirection, isSlope, isWall, slopeCell, slopeCode, isPipeCode, filterable, cleanFilterCfg, filterRec, filterPassAt, filterInfo, sameFilter, wallCost
|
- functions: isSlopeBelt, isFilter, isBelt, beltGrade, slopeShape, beltFaceY, filterVariant, beltDirection, isSlope, isWall, slopeCell, slopeCode, isPipeCode, lineOnly, filterable, cleanFilterCfg, filterRec, filterPassAt, filterInfo, sameFilter, wallCost
|
||||||
- variables: BS, BP_WALL, BP_BELT, BP_SCREW, BP_SHAFT, BP_GRATE, BP_GATE, BP_FILTER, BP_PIPE, BP_PUMP, BP_OUTLET, BP_GRIND, BP_SAW, BP_PRESS, BP_RACK, BP_SLOPE_BL, BP_SLOPE_BR, BP_SLOPE_TL, BP_SLOPE_TR, BP_BELT_UP, BP_BELT_DOWN, BP_FILTER_UP, BP_FILTER_DOWN, filterCfg, WALL_OF, WALL_LIST, BAR_OF, GRAINS_PER_BAR, POWER_FREE, CASH, PIECES, PIECE_BY_ID, PIECE_BY_CODE, BELT_POWER, SCREW_POWER, FAN_POWER, WHEEL_K, ENGINE_K, MOLDS
|
- variables: BS, BP_WALL, BP_BELT, BP_SCREW, BP_SHAFT, BP_GRATE, BP_GATE, BP_FILTER, BP_PIPE, BP_PUMP, BP_OUTLET, BP_GRIND, BP_SAW, BP_PRESS, BP_RACK, BP_SLOPE_BL, BP_SLOPE_BR, BP_SLOPE_TL, BP_SLOPE_TR, BP_BELT_UP, BP_BELT_DOWN, BP_FILTER_UP, BP_FILTER_DOWN, filterCfg, WALL_OF, WALL_LIST, BAR_OF, GRAINS_PER_BAR, POWER_FREE, CASH, PIECES, PIECE_BY_ID, PIECE_BY_CODE, BELT_POWER, SCREW_POWER, FAN_POWER, WHEEL_K, ENGINE_K, MOLDS
|
||||||
|
|
||||||
### src/sim/economy.js (152 lines)
|
### src/sim/economy.js (152 lines)
|
||||||
@@ -230,7 +230,7 @@ Exploration only: never changes grains or the random stream.
|
|||||||
- functions: fogAlloc, fogMark, fogSeen, fogInit, fogLook, fogRevealAround, fogRevealAll
|
- functions: fogAlloc, fogMark, fogSeen, fogInit, fogLook, fogRevealAround, fogRevealAll
|
||||||
- variables: FOG, FOG_SENSE, FOG_SENSE_FADE, fog, FW, FH
|
- variables: FOG, FOG_SENSE, FOG_SENSE_FADE, fog, FW, FH
|
||||||
|
|
||||||
### src/sim/cells.js (223 lines)
|
### src/sim/cells.js (225 lines)
|
||||||
Cell helpers (setCell, move, enter) and the falling-sand movement of powders, liquids and gases (simMove).
|
Cell helpers (setCell, move, enter) and the falling-sand movement of powders, liquids and gases (simMove).
|
||||||
- functions: setCell, swapCells, move, enter, enterFree, powder, passable, liquid, gas, wakeBotPowder, simMove
|
- functions: setCell, swapCells, move, enter, enterFree, powder, passable, liquid, gas, wakeBotPowder, simMove
|
||||||
- variables: SORTP, SORTP_FUEL, LSTEP, LFILM, CORNER_SEAL
|
- variables: SORTP, SORTP_FUEL, LSTEP, LFILM, CORNER_SEAL
|
||||||
@@ -274,9 +274,9 @@ Cleats are rubber ribs standing up from a sloped belt's face, one every CLEAT_SP
|
|||||||
- functions: ribMove, cleatFoot, ribCells, slopeUphill, slopeFaceAt, pushRow, scoop, pocketRoom, advanceCleat, slopeRunKey, slopeCleatsTick, rebuildCleatMask, expelFromRib, screenNudge, wakeCleatLoad
|
- functions: ribMove, cleatFoot, ribCells, slopeUphill, slopeFaceAt, pushRow, scoop, pocketRoom, advanceCleat, slopeRunKey, slopeCleatsTick, rebuildCleatMask, expelFromRib, screenNudge, wakeCleatLoad
|
||||||
- variables: CLEAT_SPACING, CLEAT_HEIGHT, CLEAT_REACH, SCREEN_NUDGE_TICKS, cleatChunks, cleatMask, cleatCells, slopePhase, ribLog
|
- variables: CLEAT_SPACING, CLEAT_HEIGHT, CLEAT_REACH, SCREEN_NUDGE_TICKS, cleatChunks, cleatMask, cleatCells, slopePhase, ribLog
|
||||||
|
|
||||||
### src/sim/blocks.js (219 lines)
|
### src/sim/blocks.js (235 lines)
|
||||||
Building blocks: placing, integrity, removing, lines and rectangles of blocks.
|
Building blocks: placing, integrity, removing, lines and rectangles of blocks.
|
||||||
- functions: blockOf, blockCellList, pieceCost, setSlopeSeal, slopeSeal, slopeSealOwner, wallCells, canPlaceBlock, placeBlock, blockIntegrity, removeWallCell, removeBlock, diagonalDrag, blockLine, blockRect, blockInReach, blockIs, placeBlocks
|
- functions: blockOf, blockCellList, pieceCost, setSlopeSeal, slopeSeal, slopeSealOwner, blockOwnsCell, clearStraySeals, wallCells, canPlaceBlock, placeBlock, blockIntegrity, removeWallCell, removeBlock, diagonalDrag, blockLine, blockRect, blockInReach, blockIs, placeBlocks
|
||||||
|
|
||||||
### src/sim/molds.js (317 lines)
|
### src/sim/molds.js (317 lines)
|
||||||
Molds: cavities for castings; ingot troughs empty themselves below. Removal returns set metal.
|
Molds: cavities for castings; ingot troughs empty themselves below. Removal returns set metal.
|
||||||
@@ -347,7 +347,7 @@ World generation helpers: noise and removal of tiny hard rock specks.
|
|||||||
World generation: staged terrain, ore, caves and placement, with synchronous and async entry points.
|
World generation: staged terrain, ore, caves and placement, with synchronous and async entry points.
|
||||||
- functions: generateWorld, generateWorldAsync
|
- functions: generateWorld, generateWorldAsync
|
||||||
|
|
||||||
### src/sim/save.js (179 lines)
|
### src/sim/save.js (180 lines)
|
||||||
Saving and loading a world (serializeWorld / deserializeWorld) and old-save migration.
|
Saving and loading a world (serializeWorld / deserializeWorld) and old-save migration.
|
||||||
- functions: serializeWorld, deserializeWorld, startLoadWake, wakeLoadArea, wakeLoadNearBot, loadWakeTick
|
- functions: serializeWorld, deserializeWorld, startLoadWake, wakeLoadArea, wakeLoadNearBot, loadWakeTick
|
||||||
- variables: SAVE_VERSION, TOFF
|
- variables: SAVE_VERSION, TOFF
|
||||||
@@ -449,7 +449,7 @@ The build menu along the bottom: categories, piece tiles and their icons.
|
|||||||
- functions: pieceIcon, catOf, selectBuildCat, cycleBuildCat, buildVariantChips, renderBuildBar, setupBuildBar
|
- functions: pieceIcon, catOf, selectBuildCat, cycleBuildCat, buildVariantChips, renderBuildBar, setupBuildBar
|
||||||
- variables: BUILD_CATS, BUILD_ORDER, PIECE_ICONS, lastBuildKey, lastBuildMenu
|
- variables: BUILD_CATS, BUILD_ORDER, PIECE_ICONS, lastBuildKey, lastBuildMenu
|
||||||
|
|
||||||
### src/ui/selection.js (120 lines)
|
### src/ui/selection.js (121 lines)
|
||||||
Tool selection: cycling, drill tuning, piece variants and costs.
|
Tool selection: cycling, drill tuning, piece variants and costs.
|
||||||
- functions: pieceSize, pieceUsesWall, setDrillWidth, tuneUnderCursor, cycleItem, cycleWall, rotate, toggleBlow, pickFilterUnderCursor, toggleFilterMat, setBrush, pieceV, pieceExtra, filterBlockAt, chipCost, pieceCostNow, pieceCode, turnSlope
|
- functions: pieceSize, pieceUsesWall, setDrillWidth, tuneUnderCursor, cycleItem, cycleWall, rotate, toggleBlow, pickFilterUnderCursor, toggleFilterMat, setBrush, pieceV, pieceExtra, filterBlockAt, chipCost, pieceCostNow, pieceCode, turnSlope
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,17 @@ What agents have done, newest first. Add an entry for every piece of work: the d
|
|||||||
note or request it was for, what changed, the files touched, the tests run, and anything left
|
note or request it was for, what changed, the files touched, the tests run, and anything left
|
||||||
open or not verified. Keep each entry short; the git history has the details.
|
open or not verified. Keep each entry short; the git history has the details.
|
||||||
|
|
||||||
|
## 2026-10-27: Shift-drag draws a line for transport pieces (Claude Code)
|
||||||
|
|
||||||
|
- Owner request: Shift shouldn't fill a rectangle for belts, conveyors and similar. New
|
||||||
|
`lineOnly(code)` in `src/sim/pieces.js` (belts, filters, screw conveyors, shafts, pipe pieces);
|
||||||
|
`primaryRelease` (`src/ui/actions.js`) and the drag preview (`src/ui/previews.js`) ignore Shift
|
||||||
|
for them, and `pieceCode` (`src/ui/selection.js`) no longer flattens a diagonal belt drag on
|
||||||
|
Shift. Build-menu "How to place" and the notebook say so; the notebook's stale "cleats up or
|
||||||
|
down" line now says uphill only.
|
||||||
|
- Tests: play.py checks a Shift-drag with a belt lays a 3-piece sloped line. Full
|
||||||
|
`run_all --browser` passes.
|
||||||
|
|
||||||
## 2026-10-27: t61 sticky materials slide freely on built surfaces (Claude Code)
|
## 2026-10-27: t61 sticky materials slide freely on built surfaces (Claude Code)
|
||||||
|
|
||||||
- The owner's video showed clay lumps creeping down a sloped wall; removing a piece was
|
- The owner's video showed clay lumps creeping down a sloped wall; removing a piece was
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ function slopeCode(dx, dy, orientation) {
|
|||||||
return dx * dy > 0 ? (orientation >= 2 ? BP_SLOPE_TR : BP_SLOPE_BL) : (orientation >= 2 ? BP_SLOPE_TL : BP_SLOPE_BR);
|
return dx * dy > 0 ? (orientation >= 2 ? BP_SLOPE_TR : BP_SLOPE_BL) : (orientation >= 2 ? BP_SLOPE_TL : BP_SLOPE_BR);
|
||||||
}
|
}
|
||||||
function isPipeCode(c) { return c === BP_PIPE || c === BP_PUMP || c === BP_OUTLET; }
|
function isPipeCode(c) { return c === BP_PIPE || c === BP_PUMP || c === BP_OUTLET; }
|
||||||
|
// pieces that carry something along a run: a Shift-drag still draws a line, never a filled rectangle
|
||||||
|
function lineOnly(c) { return isBelt(c) || isFilter(c) || c === BP_SCREW || c === BP_SHAFT || isPipeCode(c); }
|
||||||
// Filters: each filter block has a set of materials and a mode. In drop mode (inv 0)
|
// Filters: each filter block has a set of materials and a mode. In drop mode (inv 0)
|
||||||
// the chosen materials fall through and everything else rides along on top; in carry
|
// the chosen materials fall through and everything else rides along on top; in carry
|
||||||
// mode (inv 1) the chosen ones ride along and everything else falls through. The block
|
// mode (inv 1) the chosen ones ride along and everything else falls through. The block
|
||||||
|
|||||||
+1
-1
@@ -167,7 +167,7 @@ function primaryRelease(shift) {
|
|||||||
}
|
}
|
||||||
if (t === 'build' && GAME.drag) {
|
if (t === 'build' && GAME.drag) {
|
||||||
const P = piece(), b = aimBlock(), code = pieceCode(P, b);
|
const P = piece(), b = aimBlock(), code = pieceCode(P, b);
|
||||||
const list = shift ? blockRect(GAME.drag.bx, GAME.drag.by, b.bx, b.by) : blockLine(GAME.drag.bx, GAME.drag.by, b.bx, b.by, isWall(code) || isSlopeBelt(code) || code === BP_SCREW);
|
const list = shift && !lineOnly(code) ? blockRect(GAME.drag.bx, GAME.drag.by, b.bx, b.by) : blockLine(GAME.drag.bx, GAME.drag.by, b.bx, b.by, isWall(code) || isSlopeBelt(code) || code === BP_SCREW);
|
||||||
const dd = dragDirFor(P, GAME.drag, b);
|
const dd = dragDirFor(P, GAME.drag, b);
|
||||||
if (dd >= 0) GAME.pieceDir[P.id] = dd;
|
if (dd >= 0) GAME.pieceDir[P.id] = dd;
|
||||||
const v = pieceV(P), ex = pieceExtra(P);
|
const v = pieceV(P), ex = pieceExtra(P);
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ function renderBuildBar() {
|
|||||||
if (!tip) return;
|
if (!tip) return;
|
||||||
const size = tip.kind === 'machine' ? `${tip.bw}×${tip.bh} blocks` : tip.kind === 'mold' ? `${MOLDS[tip.mold].bw}×${MOLDS[tip.mold].bh} blocks` : '1 block';
|
const size = tip.kind === 'machine' ? `${tip.bw}×${tip.bh} blocks` : tip.kind === 'mold' ? `${MOLDS[tip.mold].bw}×${MOLDS[tip.mold].bh} blocks` : '1 block';
|
||||||
pop.innerHTML = `<div class="bb-title">${pieceIcon(tip.id)}<b>${esc(tip.name)}</b></div><div class="bb-chips">${chipCost(pieceCostNow(tip))}<span class="chip">${size}</span>${tip.power ? `<span class="chip">${tip.power} power</span>` : ''}</div>
|
pop.innerHTML = `<div class="bb-title">${pieceIcon(tip.id)}<b>${esc(tip.name)}</b></div><div class="bb-chips">${chipCost(pieceCostNow(tip))}<span class="chip">${size}</span>${tip.power ? `<span class="chip">${tip.power} power</span>` : ''}</div>
|
||||||
<div class="bb-desc">${esc(tip.desc)}</div><div class="bb-place"><b>How to place</b> ${tip.kind === 'block' ? 'Drag for a line, Shift-drag for a rectangle; out of reach becomes ghosts.' : 'Click to place.'}${tip.dirs && tip.kind === 'block' ? ' A dragged line runs the way you drag it; a single click uses <kbd>R</kbd>.' : tip.dirs ? ' <kbd>R</kbd> turns it.' : pieceUsesWall(tip) ? ' <kbd>R</kbd> cycles materials; <kbd>F</kbd> opens the material menu.' : ''}</div>
|
<div class="bb-desc">${esc(tip.desc)}</div><div class="bb-place"><b>How to place</b> ${tip.kind === 'block' ? (lineOnly(tip.code) ? 'Drag for a line' : 'Drag for a line, Shift-drag for a rectangle') + '; out of reach becomes ghosts.' : 'Click to place.'}${tip.dirs && tip.kind === 'block' ? ' A dragged line runs the way you drag it; a single click uses <kbd>R</kbd>.' : tip.dirs ? ' <kbd>R</kbd> turns it.' : pieceUsesWall(tip) ? ' <kbd>R</kbd> cycles materials; <kbd>F</kbd> opens the material menu.' : ''}</div>
|
||||||
${tip.filter ? `<div class="bb-place">New ones will ${esc(filterSentence(GAME.filterCfg))}. <kbd>F</kbd> sets materials and mode (or click materials in the bag, or <kbd>T</kbd> over one); <kbd>F</kbd> on a placed filter changes its whole row.</div>` : ''}
|
${tip.filter ? `<div class="bb-place">New ones will ${esc(filterSentence(GAME.filterCfg))}. <kbd>F</kbd> sets materials and mode (or click materials in the bag, or <kbd>T</kbd> over one); <kbd>F</kbd> on a placed filter changes its whole row.</div>` : ''}
|
||||||
<div class="bb-place">hold <kbd>G</kbd> replace · <kbd>Ctrl</kbd>+<kbd>Z</kbd> undo · right click take back · middle mouse pick · hold <kbd>C</kbd>/<kbd>X</kbd> copy/cut · <kbd>V</kbd> paste</div>`;
|
<div class="bb-place">hold <kbd>G</kbd> replace · <kbd>Ctrl</kbd>+<kbd>Z</kbd> undo · right click take back · middle mouse pick · hold <kbd>C</kbd>/<kbd>X</kbd> copy/cut · <kbd>V</kbd> paste</div>`;
|
||||||
const tile = bar.querySelector(`[data-piece="${tip.id}"]`); if (!tile) { pop.hidden = true; return; }
|
const tile = bar.querySelector(`[data-piece="${tip.id}"]`); if (!tile) { pop.hidden = true; return; }
|
||||||
|
|||||||
+1
-1
@@ -71,7 +71,7 @@ function controlsHtml() {
|
|||||||
const tools = [
|
const tools = [
|
||||||
['1 Resonance drill', 'Hold left click to send pulses from the bot toward the cursor: rock they shake hard enough shatters and falls as rubble, ore, coal or scrap, and trees come apart into wood chunks and acorns. Q and E set the pulse width: narrow bores a tunnel fast, wide clears a big cone slowly, medium is in between. R over a material tunes the drill to it, so only that shatters (great for pulling a vein out of the rock); R again untunes. Built blocks are never harmed. Better bits dig harder rock, faster and further.'],
|
['1 Resonance drill', 'Hold left click to send pulses from the bot toward the cursor: rock they shake hard enough shatters and falls as rubble, ore, coal or scrap, and trees come apart into wood chunks and acorns. Q and E set the pulse width: narrow bores a tunnel fast, wide clears a big cone slowly, medium is in between. R over a material tunes the drill to it, so only that shatters (great for pulling a vein out of the rock); R again untunes. Built blocks are never harmed. Better bits dig harder rock, faster and further.'],
|
||||||
['2 Pneumatic nozzle', "Left drag picks up the selection, or what you click if nothing is selected. Right click blows the selection. Click a bag name or Q/E selects one; Ctrl+click mixes. Hold Ctrl to see everything found. Clear removes the selection. Bars blow alone. Blowing out the last of a material deselects it. Shift while not flying takes everything; Shift + right click blows everything loose in the bag."],
|
['2 Pneumatic nozzle', "Left drag picks up the selection, or what you click if nothing is selected. Right click blows the selection. Click a bag name or Q/E selects one; Ctrl+click mixes. Hold Ctrl to see everything found. Clear removes the selection. Bars blow alone. Blowing out the last of a material deselects it. Shift while not flying takes everything; Shift + right click blows everything loose in the bag."],
|
||||||
['3 Build', 'Places pieces on a grid of 4×4 blocks: wall blocks, belts, screw conveyors, filters, grates, gates, pipes, pumps, outlets, Grinders, Saws, Brick presses and Bar racks, machines (fans and silos) and molds. Drag for a line, hold Shift while dragging for a filled rectangle. A diagonal wall drag makes a sealed sloped face, solid below; T flips it. For one wall block, T cycles square and four slope corners. Diagonal belts use cleats to carry pockets up or down. Extra grains roll back. Diagonal filters always screen downhill, whichever way you drag. R leaves a picked sloped filter downhill. Right click takes a piece back. Your bot flies through anything you build.'],
|
['3 Build', 'Places pieces on a grid of 4×4 blocks: wall blocks, belts, screw conveyors, filters, grates, gates, pipes, pumps, outlets, Grinders, Saws, Brick presses and Bar racks, machines (fans and silos) and molds. Drag for a line, hold Shift while dragging for a filled rectangle (belts, screw conveyors, filters, shafts and pipes always draw a line). A diagonal wall drag makes a sealed sloped face, solid below; T flips it. For one wall block, T cycles square and four slope corners. Uphill belts use cleats to carry pockets up; downhill they carry like a flat belt. Extra grains roll back. Diagonal filters always screen downhill, whichever way you drag. R leaves a picked sloped filter downhill. Right click takes a piece back. Your bot flies through anything you build.'],
|
||||||
['4 Igniter', 'Heats a small spot to 640°C, and its flame reaches a few grains into a pile. Enough to light coal and wood that touch air.'],
|
['4 Igniter', 'Heats a small spot to 640°C, and its flame reaches a few grains into a pile. Enough to light coal and wood that touch air.'],
|
||||||
['Copy, cut and paste', 'Hold C (copy) or X (cut) and drag a box over what you built; let go and it is picked up, ready to paste. Cut takes it down and refunds it to your bag. Click to place ghosts: your bot builds them from your bag when it is close. R flips, V pastes again, right click or Esc stops. Ctrl+Z undoes building. The notebook (B) keeps saved blueprints and a few starter designs.'],
|
['Copy, cut and paste', 'Hold C (copy) or X (cut) and drag a box over what you built; let go and it is picked up, ready to paste. Cut takes it down and refunds it to your bag. Click to place ghosts: your bot builds them from your bag when it is close. R flips, V pastes again, right click or Esc stops. Ctrl+Z undoes building. The notebook (B) keeps saved blueprints and a few starter designs.'],
|
||||||
];
|
];
|
||||||
|
|||||||
+1
-1
@@ -105,7 +105,7 @@ function drawPreviews() {
|
|||||||
if (P.kind === 'block') {
|
if (P.kind === 'block') {
|
||||||
const v = pieceV(P);
|
const v = pieceV(P);
|
||||||
col = previewColor(code, v);
|
col = previewColor(code, v);
|
||||||
cells = GAME.drag ? (modShift() ? blockRect(GAME.drag.bx, GAME.drag.by, b.bx, b.by) : blockLine(GAME.drag.bx, GAME.drag.by, b.bx, b.by, isWall(code) || isSlopeBelt(code) || code === BP_SCREW)) : [[b.bx, b.by]];
|
cells = GAME.drag ? (modShift() && !lineOnly(code) ? blockRect(GAME.drag.bx, GAME.drag.by, b.bx, b.by) : blockLine(GAME.drag.bx, GAME.drag.by, b.bx, b.by, isWall(code) || isSlopeBelt(code) || code === BP_SCREW)) : [[b.bx, b.by]];
|
||||||
const dd = GAME.drag ? dragDirFor(P, GAME.drag, b) : -1;
|
const dd = GAME.drag ? dragDirFor(P, GAME.drag, b) : -1;
|
||||||
if (dd !== GAME.dragDir) { GAME.dragDir = dd; hudDirty = true; }
|
if (dd !== GAME.dragDir) { GAME.dragDir = dd; hudDirty = true; }
|
||||||
const dIdx = dd >= 0 ? dd : (GAME.pieceDir[P.id] || 0);
|
const dIdx = dd >= 0 ? dd : (GAME.pieceDir[P.id] || 0);
|
||||||
|
|||||||
+2
-1
@@ -99,7 +99,8 @@ function pieceCostNow(P, m = GAME.wallMat) {
|
|||||||
function pieceCode(P, end = aimBlock()) {
|
function pieceCode(P, end = aimBlock()) {
|
||||||
if (P.id === 'belt' || P.filter) {
|
if (P.id === 'belt' || P.filter) {
|
||||||
const a = GAME.drag || end;
|
const a = GAME.drag || end;
|
||||||
if (GAME.drag && diagonalDrag(end.bx - a.bx, end.by - a.by) && !(typeof modShift === 'function' && modShift()))
|
// Shift changes nothing here: belts and filters only ever draw a line
|
||||||
|
if (GAME.drag && diagonalDrag(end.bx - a.bx, end.by - a.by))
|
||||||
return (P.filter ? BP_FILTER_UP : BP_BELT_UP) + ((end.bx - a.bx) * (end.by - a.by) > 0 ? 1 : 0);
|
return (P.filter ? BP_FILTER_UP : BP_BELT_UP) + ((end.bx - a.bx) * (end.by - a.by) > 0 ? 1 : 0);
|
||||||
if (end.bx === a.bx && end.by === a.by) return GAME.pieceShape && GAME.pieceShape[P.id] || P.code;
|
if (end.bx === a.bx && end.by === a.by) return GAME.pieceShape && GAME.pieceShape[P.id] || P.code;
|
||||||
return P.code;
|
return P.code;
|
||||||
|
|||||||
@@ -663,6 +663,12 @@ with sync_playwright() as p:
|
|||||||
drag(lambda: blk(bbx - 10, bby - 8), lambda: blk(bbx - 8, bby - 6), 4, True)
|
drag(lambda: blk(bbx - 10, bby - 8), lambda: blk(bbx - 8, bby - 6), 4, True)
|
||||||
nb2 = ev('blockP.reduce((a, v) => a + (v === BP_WALL), 0)')
|
nb2 = ev('blockP.reduce((a, v) => a + (v === BP_WALL), 0)')
|
||||||
check('Shift-drag fills a 3×3 rectangle', nb2 - nb1 == 9, nb2 - nb1)
|
check('Shift-drag fills a 3×3 rectangle', nb2 - nb1 == 9, nb2 - nb1)
|
||||||
|
ev("GAME.pieceIdx = PIECE_BY_ID.belt.index; for (const [m, n] of PIECE_BY_ID.belt.cost) bag[m] += n * 10; hudDirty = true")
|
||||||
|
drag(lambda: blk(bbx + 3, bby - 10), lambda: blk(bbx + 5, bby - 8), 4, True)
|
||||||
|
belts = ev('[blockP.reduce((a, v) => a + isBelt(v), 0), blockP.reduce((a, v) => a + isSlopeBelt(v), 0), ghostBlocks.size]')
|
||||||
|
check('Shift-drag with a belt still lays a sloped line, not a rectangle', belts == [3, 3, 0], f'{belts}, {ev("GAME.status")}')
|
||||||
|
ev('doUndo()'); settle(30)
|
||||||
|
ev("GAME.pieceIdx = PIECE_BY_ID.wall.index; hudDirty = true")
|
||||||
r0 = ev('bag[RSTONE]')
|
r0 = ev('bag[RSTONE]')
|
||||||
pg.mouse.move(*blk(bbx + 3, bby - 4)); pg.mouse.down(button='right'); settle(120); pg.mouse.up(button='right'); settle(80)
|
pg.mouse.move(*blk(bbx + 3, bby - 4)); pg.mouse.down(button='right'); settle(120); pg.mouse.up(button='right'); settle(80)
|
||||||
check('right click takes a block back with a refund', ev('bag[RSTONE]') - r0 == 16 and ev('blockP.reduce((a, v) => a + (v === BP_WALL), 0)') == nb2 - 1, ev('bag[RSTONE]') - r0)
|
check('right click takes a block back with a refund', ev('bag[RSTONE]') - r0 == 16 and ev('blockP.reduce((a, v) => a + (v === BP_WALL), 0)') == nb2 - 1, ev('bag[RSTONE]') - r0)
|
||||||
|
|||||||
Reference in New Issue
Block a user