diff --git a/public/tide-pool-world.js b/public/tide-pool-world.js
index 69f1639..a4f1d6b 100644
--- a/public/tide-pool-world.js
+++ b/public/tide-pool-world.js
@@ -1225,7 +1225,7 @@ function thinkArtificer(world, c) {
if (!project) {
const next = plan(world, c);
if (next) {
- project = { id: world.nextMachine++, ...next, need: MACHINES[next.kind].need, have: 0, charge: 0, spin: 0, lit: 0, shut: 0, owner: c.id, angle: world.random() * Math.PI };
+ project = { id: world.nextMachine++, ...next, need: MACHINES[next.kind].need, have: 0, charge: 0, spin: 0, lit: 0, shut: 0, owner: c.id, angle: world.random() * Math.PI, touched: world.time };
world.machines.push(project);
c.project = project.id;
event(world, 'plan', c, next.kind);
@@ -1255,6 +1255,15 @@ function setGate(world, m, height) {
// Finished machines work every step.
function machinery(world, dt) {
structuresStep(world, dt);
+ // A machine left half-built falls apart: once nobody has fitted a part for a while, a part comes loose, then another,
+ // until nothing is left standing.
+ for (const m of [...world.machines]) {
+ if (m.have >= m.need || world.time - (m.touched ?? world.time) < 90) continue;
+ m.touched = world.time - 70;
+ m.have -= 1;
+ if (m.have > 0) addObject(world, 'scrap', m.x + (world.random() - .5) * .6, m.z + (world.random() - .5) * .6, { height: .4 });
+ else { if (m.kind === 'gate') setGate(world, m, 0); world.machines.splice(world.machines.indexOf(m), 1); }
+ }
const rising = tideRising(world.time), rate = Math.abs(Math.cos(world.time / TIDE_PERIOD * Math.PI * 2 + TIDE_PHASE));
const night = daylight(world) < .45;
for (const m of world.machines) {
@@ -1495,6 +1504,7 @@ function finish(world, c) {
const m = machineById(world, c.project);
if (held && m && m.have < m.need) {
m.have = Math.min(m.need, m.have + (held.kind === 'brass' ? 2 : 1));
+ m.touched = world.time;
c.carrying = null;
removeObject(world, held);
c.gesture = .3;
diff --git a/public/tide-pool.js b/public/tide-pool.js
index 4a4e05b..60789d8 100644
--- a/public/tide-pool.js
+++ b/public/tide-pool.js
@@ -1,7 +1,7 @@
import {
createWorld, advanceWorld, offerObject, SPECIES, SPECIES_ORDER, CELL, COLS, ROWS, X0, Z0, X1, Z1, START_POOL, waterLevel, daylight,
heightAt, surfaceAt, depthAt, onShelf, bodyAt, tideOf, tideRising, label, goalText, describeWorld, creatureById, MACHINES, BLOCK, BLOCK_Y0, blockKey, footAt, debrisAt, footing,
-} from './tide-pool-world.js?v=25';
+} from './tide-pool-world.js?v=26';
const root = document.querySelector('[data-tide-pool]');
const status = document.querySelector('#tide-status');
@@ -1083,17 +1083,18 @@ async function initialize() {
const floor = S.kind === 'swimmer' ? c.y : footAt(world, c), surface = surfaceAt(world, c.x, c.z);
if (surface - heightAt(world, c.x, c.z) < .02 || c.alt != null && c.alt > surface) continue;
const top = c.sp === 'pylon' ? floor + (c.size + 1) * .15 * (.6 + .4 * (c.open ?? 1)) + .1 : floor + HEIGHT[c.sp];
+ // A ring only where a body breaks the surface; whatever is wholly under water leaves the surface alone.
const breaks = top > surface && floor < surface;
- if (S.kind === 'swimmer' && surface - c.y > .12) continue;
- const y = breaks ? surface + .004 : floor + .012;
+ if (!breaks) continue;
+ const y = surface + .004;
const r = S.radius * (c.sp === 'tab' ? 1.6 : 1.25);
- const strength = breaks ? .16 : .05;
+ const strength = .14;
put(P.contact, m4.compose(v1.set(c.x, y, c.z), q.identity(), s3.set(r, 1, r)), ringColor.copy(ringBase).multiplyScalar(strength));
if (c.speed > .08) {
const t = (c.phase * .12 + c.id * .37) % 1;
const wide = r * (1 + t * 1.6);
put(P.contact, m4.compose(v1.set(c.x, y, c.z), q.identity(), s3.set(wide, 1, wide)),
- ringColor.copy(ringBase).multiplyScalar(strength * (1 - t) * Math.min(1, c.speed * 2)));
+ ringColor.copy(ringBase).multiplyScalar(strength * .8 * (1 - t) * Math.min(1, c.speed * 2)));
}
}
}
diff --git a/src/components/tide-pool.tsx b/src/components/tide-pool.tsx
index 3b1eab7..feffe89 100644
--- a/src/components/tide-pool.tsx
+++ b/src/components/tide-pool.tsx
@@ -141,7 +141,7 @@ export function TidePoolContent() {
{/* Lets the three.js add-ons resolve the same pinned module the page already uses. */}
-
+
);
}