Skip to content
Fungi

Breaking structures

Let a game rule tear down a finished wall, door or station with no worker.

Workers deconstruct finished structures: they stand at the structure and carry its salvage away. Some games also need a structure to simply break, say a door smashed by a horde, a wall hit by a cannonball, or a dock that burns. breakStructure(site) does that from any rule or behavior action. It runs the same native teardown as deconstruction (ports, dependents, geometry and indexes, all or nothing), with no worker involved.

The engine keeps no hit points. Your game decides when a structure breaks. Put an integrity component on the buildable; the engine installs it on the finished site. Your own rule lowers it, then breaks the site at zero:

TS
import { breakStructure, buildable, component, query, system } from "vishnu";
const Integrity = component<{ value: number; max: number }>("acorn.integrity", {
version: 1,
fields: { value: "number", max: "number" },
});
// Every finished fence starts with 60 integrity.
export const fence = buildable("acorn.fence", {
name: "fence",
sprites: "acorn.fence",
geometry: { kind: "wall", height: 2 },
materials: [{ kind: "wood", quantity: 2 }],
workSeconds: 3,
workReachBelowCells: 0,
onRemove: { salvage: [{ kind: "wood", quantity: 1 }] },
}).with(Integrity, { value: 60, max: 60 });
// A world rule: whatever wore a fence down to nothing breaks it.
export const collapse = system({
id: "acorn.collapse",
version: 1,
reads: [Integrity],
writes: [],
run(context) {
for (const row of context.query(query(Integrity)))
if (row.get(Integrity).value <= 0) context.action(breakStructure(row.id));
},
});

The action is refused, and the world is left unchanged, if the site isn’t finished or something still stands on it. Salvage declared in onRemove lands as a pile of ground stock where the structure stood. With no salvage declared, nothing is left behind.

A world can begin with finished structures: a town, a harbour, a starter base. prebuildStructures(party, plans) plans them and finishes them at once, with no work and no materials. The same buildables the player builds make up the town, so everything in it can later be deconstructed or broken. Build the plans with your construction extension’s candidates, from the ground cells you want:

TS
import { prebuildStructures, query, system } from "vishnu";
import { acornConstruction } from "./building";
const founding = system({
id: "acorn.founding",
version: 1,
reads: [Town],
writes: [Town],
run(context) {
const town = context.query(query(Town))[0];
if (!town || town.get(Town).founded) return;
context.action(
prebuildStructures(
town.get(Town).party,
acornConstruction.candidates({
catalog: "acorn.fence",
target: { edges: [{ cell: [0, 12, 0], axis: "x" }] },
}),
),
);
context.write(Town, town.id, { ...town.get(Town), founded: true });
},
});

Issue it once. A saved flag like founded, or the world’s opening actions, keeps a restored world from building it twice. All the plans stand, or none do: if one structure can’t stand (someone is in the way, or it overlaps another), the world stays as it was.

An aperture finishes open by default: a gap anyone can walk through. Give a door closed: true in its geometry and it finishes shut, whether it is built by work or prebuilt. setStructureOpen then opens and closes it as usual:

TS
geometry: { kind: "aperture", height: 4, openingBottom: 0, openingHeight: 3, closed: true },