wired switches and doors

This commit is contained in:
Your Name 2026-08-11 22:55:58 -04:00
parent ee7d36e72b
commit bc4976b324
16 changed files with 2575 additions and 835 deletions

206
tests/test_wire.lua Normal file
View file

@ -0,0 +1,206 @@
package.path = "./?.lua;" .. package.path
class = require "libs/middleclass"
local Wire = require "wire"
require "world"
gridWidth, gridHeight = 2, 2
local passed = 0
local function test(name, fn)
local ok, err = pcall(fn)
if not ok then
io.stderr:write("FAIL: " .. name .. "\n" .. err .. "\n")
os.exit(1)
end
passed = passed + 1
end
local function assertTrue(value, message)
if not value then error(message or "expected true", 2) end
end
local function assertFalse(value, message)
if value then error(message or "expected false", 2) end
end
local function switch(color, x, y)
local entity = {x = x, y = y, activated = false}
entity.color = {getname = function() return color end}
function entity:getGridPos() return {x = self.x, y = self.y} end
function entity:activate() self.activated = true end
function entity:deactivate() self.activated = false end
return entity
end
local function door(circuitId, x, y)
local entity = {circuitId = circuitId, x = x, y = y, powered = false}
function entity:getGridPos() return {x = self.x, y = self.y} end
function entity:setPowered(powered) self.powered = powered end
return entity
end
local function makeWorld(secondSwitch)
local blueSwitch = switch("blue", 2, 1)
local wiredDoor = door("circuit_a", 1, 1)
local roomA = {
name = "a", player = {}, wiredSwitches = {}, wiredDoors = {wiredDoor},
wires = {[1] = {
[1] = {circuit_a = Wire.EAST},
[2] = {circuit_a = Wire.WEST + Wire.EAST},
}},
}
local roomB = {
name = "b", player = {}, wiredSwitches = {blueSwitch}, wiredDoors = {},
wires = {[1] = {
[1] = {circuit_a = Wire.WEST + Wire.EAST},
[2] = {circuit_a = Wire.WEST},
}},
}
local function wireCircuitAt(room, cell)
local tracks = room.wires[cell.y] and room.wires[cell.y][cell.x]
for circuitId in pairs(tracks or {}) do return circuitId end
end
roomA.wireCircuitAt = wireCircuitAt
roomB.wireCircuitAt = wireCircuitAt
if secondSwitch then table.insert(roomB.wiredSwitches, secondSwitch) end
local instance = setmetatable({
levels = {a = roomA, b = roomB},
roomByName = {a = {name = "a", x = 1, y = 1}, b = {name = "b", x = 2, y = 1}},
collidableMatrices = {red = {}, green = {}, blue = {}},
}, {__index = World})
function instance:roomCell(cell)
if cell.x <= gridWidth then return roomA, {x = cell.x, y = cell.y} end
return roomB, {x = cell.x - gridWidth, y = cell.y}
end
local function wireTracksAt(room, cell, create)
local row = room.wires[cell.y]
if not row and create then row = {}; room.wires[cell.y] = row end
local tracks = row and row[cell.x]
if not tracks and create then tracks = {}; row[cell.x] = tracks end
return tracks
end
roomA.wireTracksAt = wireTracksAt
roomB.wireTracksAt = wireTracksAt
return instance, roomA, roomB, wiredDoor, blueSwitch
end
test("direction masks add and remove without duplicating bits", function()
local mask = Wire.add(0, Wire.EAST)
mask = Wire.add(mask, Wire.EAST)
assertTrue(mask == Wire.EAST)
assertTrue(Wire.has(mask, Wire.EAST))
assertFalse(Wire.has(mask, Wire.WEST))
assertTrue(Wire.remove(mask, Wire.EAST) == 0)
end)
test("orphaned and overlapping wire cells remain selectable without a door", function()
local world, roomA = makeWorld()
roomA.wires[1][1].orphan_b = Wire.SOUTH
local top = world:circuitAt({x = 1, y = 1})
assertTrue(top == "orphan_b", "top orphaned circuit was not selectable")
local preferred = world:circuitAt({x = 1, y = 1}, "circuit_a")
assertTrue(preferred == "circuit_a", "selected overlapping circuit was not preferred")
end)
test("a white switch powers every layer of a white door", function()
local world, roomA, roomB = makeWorld()
roomA.wiredDoors = {
door("circuit_a", 1, 1),
door("old_green_id", 1, 1),
door("old_blue_id", 1, 1),
}
roomB.wiredSwitches = {
switch("red", 2, 1),
switch("green", 2, 1),
switch("blue", 2, 1),
}
world.collidableMatrices.red[1] = {[4] = {}}
world.collidableMatrices.green[1] = {[4] = {}}
world.collidableMatrices.blue[1] = {[4] = {}}
world:resolveCircuits()
for _, wiredDoor in ipairs(roomA.wiredDoors) do
assertTrue(wiredDoor.circuitId == "circuit_a", "door layer did not adopt terminal circuit")
assertTrue(world.circuitState.doorPowered[wiredDoor], "white door layer remained locked")
end
local color = world:wireColorAt(roomA, {x = 1, y = 1}, "circuit_a")
assertTrue(color[1] == 1 and color[2] == 1 and color[3] == 1, "white switch did not produce white wire")
local redGreenOnly = world:wireColorAt(roomA, {x = 1, y = 1}, "circuit_a", {red = true, green = true})
assertTrue(redGreenOnly[1] == 1 and redGreenOnly[2] == 1 and redGreenOnly[3] == 0,
"white wire did not obey the room's visible player channels")
end)
test("world matrices join a circuit across a room boundary", function()
local world, _, _, wiredDoor, blueSwitch = makeWorld()
world.collidableMatrices.blue[1] = {[4] = {}}
world:resolveCircuits()
assertTrue(world.wireMatrix[1][2].circuit_a ~= nil)
assertTrue(world.wireMatrix[1][3].circuit_a ~= nil)
assertTrue(world.wiredDoorMatrix[1][1][1].entity == wiredDoor)
assertTrue(world.wiredSwitchMatrix[1][4][1].entity == blueSwitch)
assertTrue(world.circuitState.switchPressed[blueSwitch])
assertTrue(world.circuitState.doorPowered[wiredDoor])
assertTrue(wiredDoor.powered)
assertTrue(world:wireColorAt(world.levels.a, {x = 1, y = 1}, "circuit_a", {red = true, green = true}) == nil,
"blue wire leaked into a room without a blue player channel")
local visibleBlue = world:wireColorAt(world.levels.a, {x = 1, y = 1}, "circuit_a", {blue = true})
assertTrue(visibleBlue[1] == 0 and visibleBlue[2] == 0 and visibleBlue[3] == 1,
"blue wire did not render in a room with a blue player channel")
end)
test("wire color is re-derived when its terminal switch changes", function()
local world, roomA, roomB = makeWorld()
world:resolveCircuits()
local colors = world:wireSwitchColorsAt(roomA, {x = 1, y = 1}, "circuit_a")
assertTrue(colors.blue and not colors.red)
roomB.wiredSwitches = {switch("red", 2, 1)}
world:resolveCircuits()
colors = world:wireSwitchColorsAt(roomA, {x = 1, y = 1}, "circuit_a")
assertTrue(colors.red and not colors.blue, "wire retained the deleted terminal switch color")
end)
test("a switchless wire component has no gameplay color", function()
local world, roomA, roomB = makeWorld()
roomB.wiredSwitches = {}
world:resolveCircuits()
assertTrue(world:wireSwitchColorsAt(roomA, {x = 1, y = 1}, "circuit_a") == nil)
assertTrue(world:wireColorAt(roomA, {x = 1, y = 1}, "circuit_a") == nil)
end)
test("a door requires every independent switch run at its terminal", function()
local greenSwitch = switch("green", 1, 2)
local world, roomA, _, wiredDoor = makeWorld()
table.insert(roomA.wiredSwitches, greenSwitch)
roomA.wires[1][1].circuit_b = Wire.SOUTH
roomA.wires[2] = {[1] = {circuit_b = Wire.NORTH}}
world.collidableMatrices.blue[1] = {[4] = {}}
world:resolveCircuits()
assertFalse(world.circuitState.doorPowered[wiredDoor])
world.collidableMatrices.green[2] = {[1] = {}}
world:resolveCircuits()
assertTrue(world.circuitState.doorPowered[wiredDoor])
end)
test("one run cannot terminate at two different switches", function()
local second = switch("red", 1, 2)
local world, _, roomB = makeWorld(second)
world:resolveCircuits()
local rooms, err = world:addWireConnection({x = 3, y = 1}, {x = 3, y = 2}, "circuit_a")
assertTrue(#rooms == 0 and err ~= nil, "second switch terminal was accepted")
assertTrue(roomB.wires[2] == nil or roomB.wires[2][1] == nil,
"rejected second terminal left a connected wire cell")
local colors = world:wireSwitchColorsAt(world.levels.a, {x = 1, y = 1}, "circuit_a")
assertTrue(colors.blue and not colors.red, "run stopped deriving color from its sole terminal switch")
end)
test("matching IDs do not bridge a gap or one-sided room edge", function()
local world, _, roomB, wiredDoor = makeWorld()
world.collidableMatrices.blue[1] = {[4] = {}}
roomB.wires[1][1].circuit_a = Wire.EAST -- no reciprocal WEST edge
world:resolveCircuits()
assertFalse(world.circuitState.doorPowered[wiredDoor])
end)
io.write("PASS: " .. passed .. " wire tests\n")