a
This commit is contained in:
parent
d163ceb291
commit
f6d7412744
94 changed files with 3836 additions and 1226 deletions
|
|
@ -5,7 +5,7 @@
|
|||
const WIRE_TYPES = new Set(["wire", "insulated_wire"]);
|
||||
const LINK_TYPES = new Set(["rope", "rod", "spring", "wire", "insulated_wire"]);
|
||||
const SIGNAL_SOURCE_TYPES = new Set(["pressure_switch"]);
|
||||
const DIRECT_SIGNAL_SINK_TYPES = new Set(["rotator", "reciprocator", "robot_cleaner", "gate_fence", "fan", "stove", "dry_ice", "duplicator"]);
|
||||
const DIRECT_SIGNAL_SINK_TYPES = new Set(["rotator", "reciprocator", "robot_cleaner", "gate_fence", "fan", "stove", "dry_ice", "duplicator", "leakage_device"]);
|
||||
const DETECTOR_METRICS = Object.freeze({
|
||||
tarinai_count: { label: "\u305f\u308a\u306a\u3044\u6570", defaultThreshold: 1 },
|
||||
hunger_avg: { label: "\u5e73\u5747\u7a7a\u8179", defaultThreshold: 70 },
|
||||
|
|
@ -154,9 +154,10 @@
|
|||
return actors.length;
|
||||
}
|
||||
|
||||
function updatePressureSwitches(worldRef) {
|
||||
function updatePressureSwitches(worldRef, pressureSwitches = null) {
|
||||
const minute = currentMinuteOfDay(worldRef);
|
||||
for (const item of worldRef.itemsOfType?.("pressure_switch") || []) {
|
||||
const switches = pressureSwitches || worldRef.itemsOfType?.("pressure_switch") || [];
|
||||
for (const item of switches) {
|
||||
if (!item || item.dead) continue;
|
||||
item.pressureTarget = normalizePressureTarget(item.pressureTarget);
|
||||
const defaultThreshold = PRESSURE_TARGETS[item.pressureTarget]?.defaultThreshold ?? 1;
|
||||
|
|
@ -205,7 +206,62 @@
|
|||
}
|
||||
}
|
||||
|
||||
function buildSignalNetwork(worldRef) {
|
||||
function collectSignalSinks(worldRef, out) {
|
||||
if (!worldRef || !out) return out;
|
||||
if (typeof worldRef.itemsOfType === "function") {
|
||||
for (const type of DIRECT_SIGNAL_SINK_TYPES) {
|
||||
const bucket = worldRef.itemsOfType(type) || [];
|
||||
if (bucket.length) out.sinks.push(...bucket);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
for (const item of worldRef.items || []) {
|
||||
if (item && !item.dead && DIRECT_SIGNAL_SINK_TYPES.has(item.type)) out.sinks.push(item);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function collectSignalBuckets(worldRef, includeSinks = true) {
|
||||
const out = { pressureSwitches: [], boards: [], wires: [], sinks: [] };
|
||||
if (!worldRef) return out;
|
||||
if (typeof worldRef.itemsOfType === "function") {
|
||||
out.pressureSwitches = worldRef.itemsOfType("pressure_switch") || [];
|
||||
out.boards = worldRef.itemsOfType("circuit_board") || [];
|
||||
out.wires = [
|
||||
...(worldRef.itemsOfType("wire") || []),
|
||||
...(worldRef.itemsOfType("insulated_wire") || []),
|
||||
];
|
||||
if (includeSinks) collectSignalSinks(worldRef, out);
|
||||
return out;
|
||||
}
|
||||
// Compatibility fallback for lightweight test worlds that do not expose
|
||||
// item buckets. Production worlds use the branch above and avoid a full
|
||||
// world.items scan entirely.
|
||||
for (const item of worldRef.items || []) {
|
||||
if (!item || item.dead) continue;
|
||||
if (item.type === "pressure_switch") out.pressureSwitches.push(item);
|
||||
else if (item.type === "circuit_board") out.boards.push(item);
|
||||
if (WIRE_TYPES.has(item.type)) out.wires.push(item);
|
||||
if (includeSinks && DIRECT_SIGNAL_SINK_TYPES.has(item.type)) out.sinks.push(item);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function clearSignalSinks(worldRef, sinks) {
|
||||
let changed = false;
|
||||
for (const item of sinks || []) {
|
||||
if (!item || item.dead) continue;
|
||||
if (item._signalDriven || item._signalOn || item._wireSignalDriven || item._wireSignalOn) changed = true;
|
||||
item._wireSignalDriven = false;
|
||||
item._wireSignalOn = false;
|
||||
setEffectivePower(item, false, false, worldRef);
|
||||
}
|
||||
if (changed) worldRef.drawListDirty = true;
|
||||
return changed;
|
||||
}
|
||||
|
||||
function buildSignalNetwork(worldRef, signalBuckets = null) {
|
||||
const buckets = signalBuckets || collectSignalBuckets(worldRef);
|
||||
const adjacency = new Map();
|
||||
const connectedNodes = new Set();
|
||||
const wires = [];
|
||||
|
|
@ -219,20 +275,19 @@
|
|||
connectedNodes.add(a); connectedNodes.add(b);
|
||||
};
|
||||
const boards = [];
|
||||
for (const item of worldRef.items || []) {
|
||||
for (const item of buckets.sinks || []) {
|
||||
if (!item || item.dead) continue;
|
||||
if (DIRECT_SIGNAL_SINK_TYPES.has(item.type)) {
|
||||
item._wireSignalDriven = false; item._wireSignalOn = false;
|
||||
item._directSignalDriven = false; item._directSignalOn = false;
|
||||
}
|
||||
if (item.type === "circuit_board") {
|
||||
circuit?.ensureConfig?.(item);
|
||||
item._circuitInputState = Object.create(null);
|
||||
if (!item._circuitOutputState || typeof item._circuitOutputState !== "object") circuit?.evaluate?.(item, item._circuitInputState);
|
||||
boards.push(item);
|
||||
}
|
||||
item._wireSignalDriven = false; item._wireSignalOn = false;
|
||||
item._directSignalDriven = false; item._directSignalOn = false;
|
||||
}
|
||||
for (const wire of worldRef.items || []) {
|
||||
for (const item of buckets.boards || []) {
|
||||
if (!item || item.dead) continue;
|
||||
circuit?.ensureConfig?.(item);
|
||||
item._circuitInputState = Object.create(null);
|
||||
if (!item._circuitOutputState || typeof item._circuitOutputState !== "object") circuit?.evaluate?.(item, item._circuitInputState);
|
||||
boards.push(item);
|
||||
}
|
||||
for (const wire of buckets.wires || []) {
|
||||
if (!isWire(wire)) continue;
|
||||
const pb = global.TarinaiPhysicsBodySystem;
|
||||
const endpointA = pb?.endpoint?.(wire, 0);
|
||||
|
|
@ -324,13 +379,10 @@
|
|||
global.TarinaiAchievements?.recordCircuitBoardSignalTransfer?.(sourceBoard, targetBoard, entry.wire, { world: worldRef });
|
||||
}
|
||||
|
||||
for (const item of worldRef.items || []) {
|
||||
if (!item || item.dead) continue;
|
||||
if (DIRECT_SIGNAL_SINK_TYPES.has(item.type) && !componentOf.has(item)) {
|
||||
item._wireSignalDriven = false; item._wireSignalOn = false;
|
||||
setEffectivePower(item, false, false, worldRef);
|
||||
}
|
||||
if (isWire(item) && !wires.some(entry => entry.wire === item)) item.signalActive = false;
|
||||
for (const item of buckets.sinks || []) {
|
||||
if (!item || item.dead || componentOf.has(item)) continue;
|
||||
item._wireSignalDriven = false; item._wireSignalOn = false;
|
||||
setEffectivePower(item, false, false, worldRef);
|
||||
}
|
||||
if (wireGeometryMoved) {
|
||||
worldRef.drawListDirty = true;
|
||||
|
|
@ -339,8 +391,6 @@
|
|||
return wires;
|
||||
}
|
||||
|
||||
const distanceToSegment = (px, py, ax, ay, bx, by) => global.TarinaiGeometry.pointSegmentDistance(px, py, ax, ay, bx, by);
|
||||
|
||||
function shockTarget(worldRef, wire, target, now, { connected = false } = {}) {
|
||||
if (!target || target.dead) return false;
|
||||
if (!wire._shockCooldowns || typeof wire._shockCooldowns.get !== "function") wire._shockCooldowns = new WeakMap();
|
||||
|
|
@ -391,13 +441,13 @@
|
|||
const near = worldRef.nearbyTarinai?.(cx, cy, radius, true) || worldRef.tarinai || [];
|
||||
for (const t of near) {
|
||||
if (!t || t.dead || worldRef.isTarinaiHiddenInNestBox?.(t)) continue;
|
||||
if (distanceToSegment(t.x, t.y, pointA.x, pointA.y, pointB.x, pointB.y) > Math.max(8, num(t.radius, 20) * 0.48)) continue;
|
||||
if (global.TarinaiGeometry.pointSegmentDistance(t.x, t.y, pointA.x, pointA.y, pointB.x, pointB.y) > Math.max(8, num(t.radius, 20) * 0.48)) continue;
|
||||
shockTarget(worldRef, wire, t, now, { connected: false });
|
||||
}
|
||||
const ants = worldRef.nearbyAnts?.(cx, cy, radius, true) || worldRef.ants || [];
|
||||
for (const ant of ants) {
|
||||
if (!ant || ant.dead) continue;
|
||||
if (distanceToSegment(ant.x, ant.y, pointA.x, pointA.y, pointB.x, pointB.y) > Math.max(5, num(ant.r, 6) * 0.9)) continue;
|
||||
if (global.TarinaiGeometry.pointSegmentDistance(ant.x, ant.y, pointA.x, pointA.y, pointB.x, pointB.y) > Math.max(5, num(ant.r, 6) * 0.9)) continue;
|
||||
shockTarget(worldRef, wire, ant, now, { connected: false });
|
||||
}
|
||||
}
|
||||
|
|
@ -409,10 +459,30 @@
|
|||
}
|
||||
|
||||
function updateWorld(worldRef, dt = 0.016) {
|
||||
if (!worldRef?.items) return false;
|
||||
updatePressureSwitches(worldRef);
|
||||
const wires = buildSignalNetwork(worldRef);
|
||||
damageFromWires(worldRef, wires);
|
||||
if (!worldRef) return false;
|
||||
const buckets = collectSignalBuckets(worldRef, false);
|
||||
const hasSwitches = buckets.pressureSwitches.length > 0;
|
||||
const hasNetwork = buckets.wires.length > 0 || buckets.boards.length > 0;
|
||||
|
||||
// Normal worlds with no signal controllers stop after four O(1) bucket
|
||||
// lookups. Sink buckets are only touched while a network exists or once
|
||||
// when a removed network needs to clear stale power flags.
|
||||
if (!hasSwitches && !hasNetwork && !worldRef._signalSystemHadNetwork) return false;
|
||||
|
||||
if (hasSwitches) updatePressureSwitches(worldRef, buckets.pressureSwitches);
|
||||
if (!hasNetwork) {
|
||||
if (worldRef._signalSystemHadNetwork) {
|
||||
collectSignalSinks(worldRef, buckets);
|
||||
clearSignalSinks(worldRef, buckets.sinks);
|
||||
}
|
||||
worldRef._signalSystemHadNetwork = false;
|
||||
return hasSwitches;
|
||||
}
|
||||
|
||||
collectSignalSinks(worldRef, buckets);
|
||||
const wires = buildSignalNetwork(worldRef, buckets);
|
||||
worldRef._signalSystemHadNetwork = true;
|
||||
if (wires.length) damageFromWires(worldRef, wires);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -429,5 +499,6 @@
|
|||
DETECTOR_METRICS,
|
||||
PRESSURE_TARGETS,
|
||||
detectorMetricValue,
|
||||
normalizeMinute,
|
||||
});
|
||||
})(typeof window !== "undefined" ? window : globalThis);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue