Compare commits
No commits in common. "38eaba2fa61cbccbe44ae964838efa7d2e07f733" and "bc4976b324f35a59e9548f3aef687fc299a46b9b" have entirely different histories.
38eaba2fa6
...
bc4976b324
29 changed files with 7269 additions and 11177 deletions
5
door.lua
5
door.lua
|
|
@ -11,7 +11,6 @@ function Door:initialize(x, y, color)
|
|||
collision = "unmoveable",
|
||||
sprite = loadSprite("art/game/door_" .. color:sub(1, 1) .. ".png"),
|
||||
})
|
||||
self.isDoor = true
|
||||
self.locked = true
|
||||
self:refreshSprites()
|
||||
end
|
||||
|
|
@ -28,10 +27,10 @@ function Door:refreshSprites()
|
|||
self.sprites = { [self.doorColor] = sprite }
|
||||
end
|
||||
|
||||
function Door:setColors(colors, canClose)
|
||||
function Door:setColors(colors)
|
||||
if colors[self.doorColor] then
|
||||
if self.locked then self:unlock() end
|
||||
elseif canClose ~= false then
|
||||
else
|
||||
if not self.locked then self:lock() end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -58,14 +58,21 @@ local boxPaletteSections = {}
|
|||
-- erase that tile more than once.
|
||||
local function roomCellAt(x, y)
|
||||
if x < 0 or x >= width or y < 0 or y >= height then return nil end
|
||||
return currentRoom:getCellFromMousePos(x, y)
|
||||
local cell = currentRoom:getCellFromMousePos(x, y)
|
||||
cell.x = constrain(cell.x, 1, gridWidth)
|
||||
cell.y = constrain(cell.y, 1, gridHeight)
|
||||
return cell
|
||||
end
|
||||
|
||||
local function paintRoomCell(cell, button)
|
||||
-- Use the centre of the cell so Room's existing pointer-based edit helpers
|
||||
-- perform the same operation as a normal click.
|
||||
local x = (cell.x - .5) * width / gridWidth
|
||||
local y = (cell.y - .5) * height / gridHeight
|
||||
if button == 1 and selectedAsset then
|
||||
currentRoom:attemptPlaceAtCell(selectedAsset, gameAssets[selectedAsset], cell, selectedColor)
|
||||
currentRoom:attemptPlace(selectedAsset, gameAssets[selectedAsset], x, y, selectedColor)
|
||||
elseif button == 2 then
|
||||
currentRoom:attemptDeleteAtCell(cell, selectedColor)
|
||||
currentRoom:attemptDelete(x, y, selectedColor)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -931,7 +938,7 @@ function wireView()
|
|||
wireDirtyRooms = {}
|
||||
editorStatus = selectedCircuitId
|
||||
and "Circuit selected. Drag to draw; right-drag erases; arrow keys pan."
|
||||
or "Drag from a wired door and release on a switch."
|
||||
or "Click a wired door to select its circuit, then drag to its switches."
|
||||
end
|
||||
|
||||
function worldView()
|
||||
|
|
@ -1020,12 +1027,10 @@ local function beginWireBrush(x, y, button)
|
|||
end
|
||||
end
|
||||
if not selectedCircuitId then
|
||||
editorStatus = "Start by dragging from a wired door."
|
||||
editorStatus = "Start by clicking a wired door."
|
||||
return
|
||||
end
|
||||
-- Do not materialize a wire until this stroke actually crosses into an
|
||||
-- adjacent cell. Previously a click on a door wrote a zero-length track,
|
||||
-- which later behaved like an orphaned circuit underneath that door.
|
||||
rememberWireRooms(gameWorld:ensureWireAt(cell, selectedCircuitId))
|
||||
else
|
||||
-- Prefer the selected circuit when several routes overlap here; otherwise
|
||||
-- adopt the top route. Repeated right-clicks can therefore remove every
|
||||
|
|
@ -1434,7 +1439,7 @@ function editorDraw()
|
|||
love.graphics.printf("No circuit selected", 10, 54, sb.w - 20, "center")
|
||||
end
|
||||
love.graphics.printf(
|
||||
"Drag from a door to start a new run, or drag from a wire to edit that run. Release on a switch to terminate it; start another run from the door for another switch.\n\nLeft-drag draws. Right-drag erases. Independent wires may share a cell without connecting.\n\nArrow keys pan by one room.",
|
||||
"Click a door to start a new run, or a wire to edit that run. Each run ends at one switch; start another run from the door for another switch.\n\nLeft-drag draws. Right-drag erases. Independent wires may share a cell without connecting.\n\nArrow keys pan by one room.",
|
||||
24, 100, sb.w - 48, "left"
|
||||
)
|
||||
if editorStatus then
|
||||
|
|
|
|||
20
main.lua
20
main.lua
|
|
@ -8,7 +8,6 @@ require "libs/TSerial"
|
|||
require "_debug_helpers"
|
||||
require "_helpers"
|
||||
require "input"
|
||||
require "profiler"
|
||||
require "color"
|
||||
require "room"
|
||||
require "world"
|
||||
|
|
@ -129,10 +128,7 @@ function love.draw()
|
|||
-- Blitting the canvas 1:1 afterwards means no rescaling of the final image
|
||||
-- (crisp, nearest-neighbor throughout — nothing is averaged).
|
||||
love.graphics.setCanvas(sideBarCanvas)
|
||||
-- The gameplay view now intentionally extends beyond its old room bounds.
|
||||
-- Keep the editor panel opaque so that neighbourhood preview never shows
|
||||
-- through empty areas of the UI.
|
||||
love.graphics.clear(0, 0, 0, 1)
|
||||
love.graphics.clear()
|
||||
love.graphics.push()
|
||||
love.graphics.scale(editorRenderScale, editorRenderScale)
|
||||
editorDraw()
|
||||
|
|
@ -149,7 +145,6 @@ function love.draw()
|
|||
love.graphics.draw(finalCanvas, 0, 0)
|
||||
love.graphics.draw(sideBarCanvas, sideBarBox.x, sideBarBox.y)
|
||||
love.graphics.print("Current FPS: "..tostring(love.timer.getFPS( )), 10, 10)
|
||||
PerfProfiler:draw()
|
||||
Dialogue.draw()
|
||||
love.graphics.setCanvas()
|
||||
|
||||
|
|
@ -169,13 +164,6 @@ function love.draw()
|
|||
end
|
||||
|
||||
function love.keypressed(key)
|
||||
-- Developer CPU sampling: record a representative moving sequence, then
|
||||
-- press F9 again to write folded stacks for flamegraph.pl.
|
||||
if key == "f9" then
|
||||
PerfProfiler:toggle()
|
||||
return
|
||||
end
|
||||
|
||||
-- Available even while a dialogue is open, so the player never has to
|
||||
-- dismiss something important just to change the colour treatment.
|
||||
if key == "f4" then
|
||||
|
|
@ -197,8 +185,6 @@ function love.keypressed(key)
|
|||
elseif editorView ~= "world" and editorView ~= "wire" and Input.isPlayerSwitch(key) then
|
||||
local c = Input.playerColor(key)
|
||||
gameWorld:switchPlayerColor(currentRoom, c)
|
||||
elseif editorView ~= "world" and editorView ~= "wire" and gameWorld:browseRoom(currentRoom, key) then
|
||||
return
|
||||
end
|
||||
|
||||
-- if key == "w" then
|
||||
|
|
@ -306,10 +292,6 @@ function _initCanvases()
|
|||
gameCanvas = love.graphics.newCanvas()
|
||||
finalCanvas = love.graphics.newCanvas()
|
||||
presentationCanvas = love.graphics.newCanvas()
|
||||
-- Reused for each cardinal neighbour's alternate real-colour view at the
|
||||
-- porous room boundary. Full-screen dimensions keep it pixel-aligned with
|
||||
-- the gameplay canvas during shader compositing.
|
||||
porousRoomCanvas = love.graphics.newCanvas()
|
||||
sideBarCanvas = love.graphics.newCanvas(math.max(1, sideBarBox.w), math.max(1, sideBarBox.h))
|
||||
sideBarCanvas:setFilter("nearest", "nearest") -- never average when sampled
|
||||
end
|
||||
|
|
|
|||
59
profiler.lua
59
profiler.lua
|
|
@ -1,59 +0,0 @@
|
|||
-- Developer-only CPU sampler. It is inert until F9 is pressed.
|
||||
--
|
||||
-- On stop it writes `chroma-solstice.folded` in LÖVE's save directory. The
|
||||
-- file uses Brendan Gregg's folded-stack format and can be given directly to
|
||||
-- FlameGraph's flamegraph.pl.
|
||||
PerfProfiler = {
|
||||
active = false,
|
||||
samples = {},
|
||||
status = "F9: start CPU profile",
|
||||
}
|
||||
|
||||
local ok, profile = pcall(require, "jit.profile")
|
||||
PerfProfiler.available = ok
|
||||
if not ok then
|
||||
PerfProfiler.status = "LuaJIT sampler unavailable"
|
||||
end
|
||||
|
||||
local function sample(thread, count, vmstate)
|
||||
-- Negative depth produces caller -> callee order, which is what folded
|
||||
-- flamegraphs expect. Function-level samples keep the output compact.
|
||||
local stack = profile.dumpstack(thread, "pF;", -64):gsub(";$", "")
|
||||
if stack ~= "" then
|
||||
PerfProfiler.samples[stack] = (PerfProfiler.samples[stack] or 0) + count
|
||||
end
|
||||
end
|
||||
|
||||
function PerfProfiler:toggle()
|
||||
if not self.available then return false end
|
||||
if not self.active then
|
||||
self.samples = {}
|
||||
profile.start("fi2", sample)
|
||||
self.active = true
|
||||
self.status = "CPU profile recording (F9 to write)"
|
||||
return true
|
||||
end
|
||||
|
||||
profile.stop()
|
||||
self.active = false
|
||||
local lines, sampleCount = {}, 0
|
||||
for stack, count in pairs(self.samples) do
|
||||
table.insert(lines, stack .. " " .. count)
|
||||
sampleCount = sampleCount + count
|
||||
end
|
||||
table.sort(lines)
|
||||
local path = "chroma-solstice.folded"
|
||||
local saved = love.filesystem.write(path, table.concat(lines, "\n") .. "\n")
|
||||
local directory = love.filesystem.getSaveDirectory()
|
||||
self.status = saved and ("CPU profile saved (" .. sampleCount .. " samples); see terminal")
|
||||
or "Could not write CPU profile"
|
||||
if saved then print("CPU profile: " .. directory .. "/" .. path) else print(self.status) end
|
||||
return saved
|
||||
end
|
||||
|
||||
function PerfProfiler:draw()
|
||||
if not self.active and self.status == "F9: start CPU profile" then return end
|
||||
love.graphics.setColor(self.active and 1 or 0.6, self.active and 0.75 or 1, self.active and 0.2 or 0.6, 1)
|
||||
love.graphics.print(self.active and "PROFILING: F9 to save flamegraph data" or self.status, 10, 28)
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
end
|
||||
121
room.lua
121
room.lua
|
|
@ -130,40 +130,16 @@ function Room:update(dt)
|
|||
end
|
||||
end
|
||||
|
||||
-- A room's view is defined by the colour player copies that are in that room,
|
||||
-- independent of which of those copies is currently being controlled. A caller
|
||||
-- may supply another set for World's porous boundary without altering sprites
|
||||
-- or colour blending.
|
||||
function Room:getRenderChannels()
|
||||
if gameWorld and gameWorld.roomBrowseMode then return {"red", "green", "blue"} end
|
||||
local channels = {}
|
||||
for _, color in ipairs({"red", "green", "blue"}) do
|
||||
if self.player[color] then table.insert(channels, color) end
|
||||
end
|
||||
return channels
|
||||
end
|
||||
function Room:draw()
|
||||
self:drawWiresAt(0, 0, width / gridWidth, nil, false)
|
||||
|
||||
function Room:draw(drawChannels)
|
||||
if gameWorld and gameWorld.levels and gameWorld.levels[self.name] == self and
|
||||
not gameWorld.drawingRoomNeighborhood then
|
||||
return gameWorld:drawRoomNeighborhood(self)
|
||||
end
|
||||
drawChannels = drawChannels or self:getRenderChannels()
|
||||
self:drawWiresAt(0, 0, width / gridWidth, nil, false, drawChannels)
|
||||
|
||||
-- Draw only the channels active in this view. Each object just exposes sprites per
|
||||
-- draw only the channels the player has. Each object just exposes sprites per
|
||||
-- channel via Entity:draw(channel); a door registered on all three channels
|
||||
-- naturally draws its red sprite on the red pass, etc. No per-object logic.
|
||||
for _, channel in ipairs(drawChannels) do
|
||||
for _, channel in ipairs(self.colorsPlayerHas) do
|
||||
if self.player[channel] then self.player[channel]:draw(channel) end
|
||||
for _, entity in pairs(self.collideables[channel]) do entity:draw(channel) end
|
||||
-- The zoomed-out neighbourhood already draws every room directly. Calling
|
||||
-- the legacy seam helper from each miniature room duplicates foreign
|
||||
-- entities, which can screen-blend red and green into a false yellow.
|
||||
if gameWorld and gameWorld.levels and gameWorld.levels[self.name] == self and
|
||||
not gameWorld.drawingRoomNeighborhood then
|
||||
gameWorld:drawOverlaps(self, channel)
|
||||
end
|
||||
if gameWorld and gameWorld.levels and gameWorld.levels[self.name] == self then gameWorld:drawOverlaps(self, channel) end
|
||||
for _, blocker in pairs(self.playerBlockers[channel]) do blocker:draw(channel) end
|
||||
for _, switch in pairs(self.switches[channel]) do switch:draw(channel) end
|
||||
for _, switch in ipairs(self.wiredSwitches) do switch:draw(channel) end
|
||||
|
|
@ -203,7 +179,7 @@ function Room:removeWire(cell, circuitId)
|
|||
return true
|
||||
end
|
||||
|
||||
function Room:drawWiresAt(originX, originY, cellSize, selectedCircuit, editorColors, renderChannels)
|
||||
function Room:drawWiresAt(originX, originY, cellSize, selectedCircuit, editorColors)
|
||||
local ids = {}
|
||||
for _, row in pairs(self.wires) do
|
||||
for _, tracks in pairs(row) do
|
||||
|
|
@ -215,11 +191,8 @@ function Room:drawWiresAt(originX, originY, cellSize, selectedCircuit, editorCol
|
|||
table.sort(ordered)
|
||||
|
||||
love.graphics.setBlendMode("alpha")
|
||||
local showAllChannels = gameWorld and gameWorld.roomBrowseMode
|
||||
local visibleColors = {red = showAllChannels, green = showAllChannels, blue = showAllChannels}
|
||||
if not showAllChannels then
|
||||
for _, color in ipairs(renderChannels or self:getRenderChannels()) do visibleColors[color] = true end
|
||||
end
|
||||
local visibleColors = {red = false, green = false, blue = false}
|
||||
for _, color in ipairs(self.colorsPlayerHas or {}) do visibleColors[color] = true end
|
||||
local editorIsOn = editorView ~= nil and editorView ~= "off"
|
||||
for _, circuitId in ipairs(ordered) do
|
||||
local selected = not selectedCircuit or selectedCircuit == circuitId
|
||||
|
|
@ -266,21 +239,12 @@ function Room:drawWiresAt(originX, originY, cellSize, selectedCircuit, editorCol
|
|||
for _, line in ipairs(lines) do love.graphics.line(line) end
|
||||
local wireBlend = (editorColors or not switchColors) and "alpha" or "screen"
|
||||
love.graphics.setBlendMode(wireBlend)
|
||||
local previousShader = love.graphics.getShader()
|
||||
if not editorColors and switchColors and wireNeonShader then
|
||||
local powered = gameWorld:wirePoweredAt(self, localCell, circuitId)
|
||||
wireNeonShader:send("wirePower", powered and 1 or 0)
|
||||
wireNeonShader:send("wireTime", love.timer.getTime())
|
||||
wireNeonShader:send("wirePhase", (#circuitId * 0.137) + x * 0.071 + y * 0.113)
|
||||
love.graphics.setShader(wireNeonShader)
|
||||
end
|
||||
love.graphics.setLineWidth(math.max(1, cellSize * 0.045))
|
||||
for _, color in ipairs(drawColors) do
|
||||
love.graphics.setColor(color[1], color[2], color[3], selected and 1 or 0.32)
|
||||
for _, line in ipairs(lines) do love.graphics.line(line) end
|
||||
love.graphics.circle("fill", cx, cy, math.max(0.75, cellSize * 0.0275))
|
||||
end
|
||||
love.graphics.setShader(previousShader)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -476,24 +440,8 @@ function Room:switchPlayerColorLocal(color)
|
|||
local targetPlayer = self.player[color]
|
||||
if not targetPlayer then return false end
|
||||
|
||||
local activeColors = self:getActiveColors()
|
||||
local canJoin = not self:colorIsActive(color) and #activeColors > 0
|
||||
if canJoin then
|
||||
local target = targetPlayer:getGridPos()
|
||||
for _, activeColor in ipairs(activeColors) do
|
||||
local activePlayer = self.player[activeColor]
|
||||
local activePos = activePlayer and activePlayer:getGridPos()
|
||||
if not activePos or activePos.x ~= target.x or activePos.y ~= target.y then
|
||||
canJoin = false
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local canSwitch = canJoin or not self:onlyColorIsActive(color)
|
||||
if canJoin then
|
||||
self:setActiveColor(color, true)
|
||||
elseif canSwitch then
|
||||
local canSwitch = not self:onlyColorIsActive(color)
|
||||
if canSwitch then
|
||||
for _, c in ipairs(self:getPossibleColors()) do
|
||||
self:setActiveColor(c, c == color)
|
||||
end
|
||||
|
|
@ -590,29 +538,10 @@ end
|
|||
function Room:resolveSwitchesAndDoors()
|
||||
local setDoorColors = self:switchCheck()
|
||||
for _, door in pairs(self.doors) do
|
||||
door:setColors(setDoorColors, self:doorCanClose(door))
|
||||
door:setColors(setDoorColors)
|
||||
end
|
||||
end
|
||||
|
||||
-- Match World:doorCanClose for ordinary room-local doors. All colour layers
|
||||
-- count, while other layers of the same doorway do not obstruct each other.
|
||||
function Room:doorCanClose(door)
|
||||
for _, cell in ipairs(door:getOccupiedCells()) do
|
||||
for _, player in pairs(self.player or {}) do
|
||||
if player:occupiesCell(cell) then return false end
|
||||
end
|
||||
for _, entities in pairs(self.collideables or {}) do
|
||||
for _, entity in ipairs(entities) do
|
||||
if entity ~= door and not entity.isDoor and entity:occupiesCell(cell) and
|
||||
not (entity.canPassOver and entity:canPassOver()) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function Room:playerJoinCheck(previousPositions, newPositions)
|
||||
local activate = {}
|
||||
local deactivate = {}
|
||||
|
|
@ -854,18 +783,14 @@ function Room:registerNpc(entity)
|
|||
end
|
||||
|
||||
function Room:getCellFromMousePos(mouseX, mouseY)
|
||||
if gameWorld and gameWorld.levels and gameWorld.levels[self.name] == self and
|
||||
not gameWorld.drawingRoomNeighborhood then
|
||||
return gameWorld:screenCellInRoom(self, mouseX, mouseY)
|
||||
end
|
||||
return {
|
||||
x = math.floor(mouseX * gridWidth / width) + 1,
|
||||
y = math.floor(mouseY * gridHeight / height) + 1,
|
||||
}
|
||||
local cell = {}
|
||||
cell.x = math.ceil(mouseX * gridWidth / width)
|
||||
cell.y = math.ceil(mouseY * gridHeight / height)
|
||||
return cell
|
||||
end
|
||||
|
||||
function Room:attemptDeleteAtCell(cell, color)
|
||||
if not cell then return end
|
||||
function Room:attemptDelete(mouseX, mouseY, color)
|
||||
local cell = self:getCellFromMousePos(mouseX, mouseY)
|
||||
|
||||
-- "white" (or nil) deletes every channel; otherwise just the picked one
|
||||
local colors
|
||||
|
|
@ -932,13 +857,9 @@ function Room:attemptDeleteAtCell(cell, color)
|
|||
self:tick()
|
||||
end
|
||||
|
||||
function Room:attemptDelete(mouseX, mouseY, color)
|
||||
return self:attemptDeleteAtCell(self:getCellFromMousePos(mouseX, mouseY), color)
|
||||
end
|
||||
|
||||
function Room:attemptPlaceAtCell(name, props, cell, color)
|
||||
function Room:attemptPlace(name, props, mouseX, mouseY, color)
|
||||
if not props or not props.sprites then return end
|
||||
if not cell then return end
|
||||
local cell = self:getCellFromMousePos(mouseX, mouseY)
|
||||
-- Jorge is one dialogable NPC with three display channels, not three
|
||||
-- independently placeable color-layer entities.
|
||||
if name == "jorge" then
|
||||
|
|
@ -965,10 +886,6 @@ function Room:attemptPlaceAtCell(name, props, cell, color)
|
|||
self:tick()
|
||||
end
|
||||
|
||||
function Room:attemptPlace(name, props, mouseX, mouseY, color)
|
||||
return self:attemptPlaceAtCell(name, props, self:getCellFromMousePos(mouseX, mouseY), color)
|
||||
end
|
||||
|
||||
function Room:load(name, preferRuntime)
|
||||
-- Editor/startup loads must use the project source level. Runtime saves are
|
||||
-- only consulted for an in-progress room-to-room game transition, otherwise
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
1491
rooms/jorge2.sav
1491
rooms/jorge2.sav
File diff suppressed because it is too large
Load diff
|
|
@ -1,60 +1,76 @@
|
|||
{
|
||||
wires={
|
||||
},
|
||||
objects={
|
||||
{
|
||||
color="red",
|
||||
y=4,
|
||||
x=8,
|
||||
class="toilet",
|
||||
y=4
|
||||
class="toilet"
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
y=4,
|
||||
x=6,
|
||||
class="toilet",
|
||||
y=4
|
||||
class="toilet"
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
y=4,
|
||||
x=4,
|
||||
class="toilet",
|
||||
y=4
|
||||
class="toilet"
|
||||
},
|
||||
{
|
||||
color="green",
|
||||
y=4,
|
||||
x=8,
|
||||
class="toilet",
|
||||
y=4
|
||||
class="toilet"
|
||||
},
|
||||
{
|
||||
color="green",
|
||||
y=4,
|
||||
x=6,
|
||||
class="toilet",
|
||||
y=4
|
||||
class="toilet"
|
||||
},
|
||||
{
|
||||
color="green",
|
||||
y=4,
|
||||
x=4,
|
||||
class="toilet",
|
||||
y=4
|
||||
class="toilet"
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
y=4,
|
||||
x=8,
|
||||
class="toilet",
|
||||
y=4
|
||||
class="toilet"
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
y=4,
|
||||
x=6,
|
||||
class="toilet",
|
||||
y=4
|
||||
class="toilet"
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
y=4,
|
||||
x=4,
|
||||
class="toilet",
|
||||
y=4
|
||||
class="toilet"
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
y=8,
|
||||
x=6,
|
||||
class="player"
|
||||
},
|
||||
{
|
||||
color="green",
|
||||
y=8,
|
||||
x=6,
|
||||
class="player"
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
y=8,
|
||||
x=6,
|
||||
class="player"
|
||||
}
|
||||
}
|
||||
}
|
||||
516
rooms/ok.sav
516
rooms/ok.sav
File diff suppressed because it is too large
Load diff
|
|
@ -1,186 +1,207 @@
|
|||
{
|
||||
wires={
|
||||
{
|
||||
circuit="wire_6a7bd969_000a",
|
||||
edges=6,
|
||||
x=4,
|
||||
y=3
|
||||
},
|
||||
{
|
||||
circuit="wire_6a7bd969_000a",
|
||||
edges=10,
|
||||
x=5,
|
||||
y=3
|
||||
},
|
||||
{
|
||||
circuit="wire_6a7bd969_000a",
|
||||
edges=10,
|
||||
x=6,
|
||||
y=3
|
||||
},
|
||||
{
|
||||
circuit="wire_6a7bd969_000a",
|
||||
edges=12,
|
||||
x=7,
|
||||
y=3
|
||||
},
|
||||
{
|
||||
circuit="wire_6a7bd969_000a",
|
||||
edges=6,
|
||||
x=10,
|
||||
y=3
|
||||
},
|
||||
{
|
||||
circuit="wire_6a7bd969_000a",
|
||||
edges=10,
|
||||
x=11,
|
||||
y=3
|
||||
},
|
||||
{
|
||||
circuit="wire_6a7bd969_000a",
|
||||
edges=2,
|
||||
x=3,
|
||||
y=4
|
||||
},
|
||||
{
|
||||
circuit="wire_6a7bd969_000a",
|
||||
edges=9,
|
||||
x=4,
|
||||
y=4
|
||||
},
|
||||
{
|
||||
circuit="wire_6a7bd969_000a",
|
||||
edges=3,
|
||||
x=7,
|
||||
y=4
|
||||
},
|
||||
{
|
||||
circuit="wire_6a7bd969_000a",
|
||||
edges=10,
|
||||
x=8,
|
||||
y=4
|
||||
},
|
||||
{
|
||||
circuit="wire_6a7bd969_000a",
|
||||
edges=10,
|
||||
x=9,
|
||||
y=4
|
||||
},
|
||||
{
|
||||
circuit="wire_6a7bd969_000a",
|
||||
edges=9,
|
||||
x=10,
|
||||
y=4
|
||||
},
|
||||
{
|
||||
circuit="wire_6a7bdb2a_0001",
|
||||
edges=2,
|
||||
x=3,
|
||||
y=9
|
||||
},
|
||||
{
|
||||
circuit="wire_6a7bdb2a_0001",
|
||||
edges=10,
|
||||
x=4,
|
||||
y=9
|
||||
},
|
||||
{
|
||||
circuit="wire_6a7bdb2a_0001",
|
||||
edges=10,
|
||||
x=5,
|
||||
y=9
|
||||
},
|
||||
{
|
||||
circuit="wire_6a7bdb2a_0001",
|
||||
edges=10,
|
||||
x=6,
|
||||
y=9
|
||||
},
|
||||
{
|
||||
circuit="wire_6a7bdb2a_0001",
|
||||
edges=10,
|
||||
x=7,
|
||||
y=9
|
||||
},
|
||||
{
|
||||
circuit="wire_6a7bdb2a_0001",
|
||||
edges=10,
|
||||
x=8,
|
||||
y=9
|
||||
},
|
||||
{
|
||||
circuit="wire_6a7bdb2a_0001",
|
||||
edges=10,
|
||||
x=9,
|
||||
y=9
|
||||
},
|
||||
{
|
||||
circuit="wire_6a7bdb2a_0001",
|
||||
edges=10,
|
||||
x=10,
|
||||
y=9
|
||||
},
|
||||
{
|
||||
circuit="wire_6a7bdb2a_0001",
|
||||
edges=10,
|
||||
x=11,
|
||||
y=9
|
||||
}
|
||||
},
|
||||
objects={
|
||||
{
|
||||
color="red",
|
||||
x=2,
|
||||
class="box",
|
||||
y=9
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=3,
|
||||
class="box",
|
||||
y=6
|
||||
},
|
||||
{
|
||||
color="green",
|
||||
x=2,
|
||||
class="box",
|
||||
y=4
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=2,
|
||||
class="box",
|
||||
y=9
|
||||
x=3,
|
||||
y=5,
|
||||
active=true,
|
||||
class="player"
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=3,
|
||||
class="box",
|
||||
y=6
|
||||
y=5,
|
||||
active=true,
|
||||
class="player"
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=3,
|
||||
class="wired_switch",
|
||||
y=9
|
||||
y=5,
|
||||
active=true,
|
||||
class="player"
|
||||
},
|
||||
{
|
||||
color="green",
|
||||
x=3,
|
||||
class="wired_switch",
|
||||
y=9
|
||||
x=2,
|
||||
y=4,
|
||||
class="box"
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=2,
|
||||
y=9,
|
||||
class="box"
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=3,
|
||||
class="wired_switch",
|
||||
y=9
|
||||
y=6,
|
||||
class="box"
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=2,
|
||||
y=9,
|
||||
class="box"
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=3,
|
||||
y=6,
|
||||
class="box"
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=3,
|
||||
y=9,
|
||||
class="wired_switch"
|
||||
},
|
||||
{
|
||||
color="green",
|
||||
x=3,
|
||||
class="wired_switch",
|
||||
y=4
|
||||
y=9,
|
||||
class="wired_switch"
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=3,
|
||||
y=9,
|
||||
class="wired_switch"
|
||||
},
|
||||
{
|
||||
color="green",
|
||||
x=3,
|
||||
y=4,
|
||||
class="wired_switch"
|
||||
}
|
||||
},
|
||||
wires={
|
||||
{
|
||||
edges=6,
|
||||
x=4,
|
||||
y=3,
|
||||
circuit="wire_6a7bd969_000a"
|
||||
},
|
||||
{
|
||||
edges=10,
|
||||
x=5,
|
||||
y=3,
|
||||
circuit="wire_6a7bd969_000a"
|
||||
},
|
||||
{
|
||||
edges=10,
|
||||
x=6,
|
||||
y=3,
|
||||
circuit="wire_6a7bd969_000a"
|
||||
},
|
||||
{
|
||||
edges=12,
|
||||
x=7,
|
||||
y=3,
|
||||
circuit="wire_6a7bd969_000a"
|
||||
},
|
||||
{
|
||||
edges=6,
|
||||
x=10,
|
||||
y=3,
|
||||
circuit="wire_6a7bd969_000a"
|
||||
},
|
||||
{
|
||||
edges=10,
|
||||
x=11,
|
||||
y=3,
|
||||
circuit="wire_6a7bd969_000a"
|
||||
},
|
||||
{
|
||||
edges=2,
|
||||
x=3,
|
||||
y=4,
|
||||
circuit="wire_6a7bd969_000a"
|
||||
},
|
||||
{
|
||||
edges=9,
|
||||
x=4,
|
||||
y=4,
|
||||
circuit="wire_6a7bd969_000a"
|
||||
},
|
||||
{
|
||||
edges=3,
|
||||
x=7,
|
||||
y=4,
|
||||
circuit="wire_6a7bd969_000a"
|
||||
},
|
||||
{
|
||||
edges=10,
|
||||
x=8,
|
||||
y=4,
|
||||
circuit="wire_6a7bd969_000a"
|
||||
},
|
||||
{
|
||||
edges=10,
|
||||
x=9,
|
||||
y=4,
|
||||
circuit="wire_6a7bd969_000a"
|
||||
},
|
||||
{
|
||||
edges=9,
|
||||
x=10,
|
||||
y=4,
|
||||
circuit="wire_6a7bd969_000a"
|
||||
},
|
||||
{
|
||||
edges=2,
|
||||
x=3,
|
||||
y=9,
|
||||
circuit="wire_6a7bdb2a_0001"
|
||||
},
|
||||
{
|
||||
edges=10,
|
||||
x=4,
|
||||
y=9,
|
||||
circuit="wire_6a7bdb2a_0001"
|
||||
},
|
||||
{
|
||||
edges=10,
|
||||
x=5,
|
||||
y=9,
|
||||
circuit="wire_6a7bdb2a_0001"
|
||||
},
|
||||
{
|
||||
edges=10,
|
||||
x=6,
|
||||
y=9,
|
||||
circuit="wire_6a7bdb2a_0001"
|
||||
},
|
||||
{
|
||||
edges=10,
|
||||
x=7,
|
||||
y=9,
|
||||
circuit="wire_6a7bdb2a_0001"
|
||||
},
|
||||
{
|
||||
edges=10,
|
||||
x=8,
|
||||
y=9,
|
||||
circuit="wire_6a7bdb2a_0001"
|
||||
},
|
||||
{
|
||||
edges=10,
|
||||
x=9,
|
||||
y=9,
|
||||
circuit="wire_6a7bdb2a_0001"
|
||||
},
|
||||
{
|
||||
edges=10,
|
||||
x=10,
|
||||
y=9,
|
||||
circuit="wire_6a7bdb2a_0001"
|
||||
},
|
||||
{
|
||||
edges=10,
|
||||
x=11,
|
||||
y=9,
|
||||
circuit="wire_6a7bdb2a_0001"
|
||||
}
|
||||
}
|
||||
}
|
||||
1012
rooms/room_10_15.sav
1012
rooms/room_10_15.sav
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
objects={
|
||||
},
|
||||
wires={
|
||||
}
|
||||
}
|
||||
1165
rooms/room_13_14.sav
1165
rooms/room_13_14.sav
File diff suppressed because it is too large
Load diff
1101
rooms/room_14_14.sav
1101
rooms/room_14_14.sav
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,600 +1,538 @@
|
|||
{
|
||||
wires={
|
||||
},
|
||||
objects={
|
||||
{
|
||||
color="red",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=1
|
||||
color="blue",
|
||||
y=1,
|
||||
x=1
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
y=1
|
||||
color="blue",
|
||||
y=1,
|
||||
x=11
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=2
|
||||
color="blue",
|
||||
y=2,
|
||||
x=1
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
y=2
|
||||
color="blue",
|
||||
y=2,
|
||||
x=11
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=3
|
||||
color="blue",
|
||||
y=3,
|
||||
x=1
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
y=3
|
||||
color="blue",
|
||||
y=3,
|
||||
x=11
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=4
|
||||
color="blue",
|
||||
y=4,
|
||||
x=1
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
y=4
|
||||
color="blue",
|
||||
y=4,
|
||||
x=11
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=5
|
||||
color="blue",
|
||||
y=5,
|
||||
x=1
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
y=5
|
||||
color="blue",
|
||||
y=6,
|
||||
x=1
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=6
|
||||
color="blue",
|
||||
y=6,
|
||||
x=11
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
y=6
|
||||
color="blue",
|
||||
y=7,
|
||||
x=1
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=7
|
||||
color="blue",
|
||||
y=7,
|
||||
x=11
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
y=7
|
||||
color="blue",
|
||||
y=8,
|
||||
x=1
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=8
|
||||
color="blue",
|
||||
y=8,
|
||||
x=11
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
y=8
|
||||
color="blue",
|
||||
y=9,
|
||||
x=1
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=9
|
||||
color="blue",
|
||||
y=9,
|
||||
x=11
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
y=9
|
||||
color="blue",
|
||||
y=10,
|
||||
x=1
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=10
|
||||
color="blue",
|
||||
y=10,
|
||||
x=11
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
y=10
|
||||
color="blue",
|
||||
y=11,
|
||||
x=1
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=11
|
||||
color="blue",
|
||||
y=11,
|
||||
x=2
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=2,
|
||||
class="static_wall",
|
||||
y=11
|
||||
color="blue",
|
||||
y=11,
|
||||
x=3
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=3,
|
||||
class="static_wall",
|
||||
y=11
|
||||
color="blue",
|
||||
y=11,
|
||||
x=4
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=4,
|
||||
class="static_wall",
|
||||
y=11
|
||||
color="blue",
|
||||
y=11,
|
||||
x=5
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=5,
|
||||
class="static_wall",
|
||||
y=11
|
||||
color="blue",
|
||||
y=11,
|
||||
x=7
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=7,
|
||||
class="static_wall",
|
||||
y=11
|
||||
color="blue",
|
||||
y=11,
|
||||
x=8
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=8,
|
||||
class="static_wall",
|
||||
y=11
|
||||
color="blue",
|
||||
y=11,
|
||||
x=9
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=9,
|
||||
class="static_wall",
|
||||
y=11
|
||||
color="blue",
|
||||
y=11,
|
||||
x=10
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=10,
|
||||
class="static_wall",
|
||||
y=11
|
||||
color="blue",
|
||||
y=11,
|
||||
x=11
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
y=11
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=9,
|
||||
class="box",
|
||||
y=1
|
||||
y=1,
|
||||
x=1
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
x=7,
|
||||
class="spiky_box_2x1_11",
|
||||
y=1
|
||||
y=1,
|
||||
x=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
x=5,
|
||||
class="spiky_box_2x1_11",
|
||||
y=1
|
||||
y=2,
|
||||
x=1
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
y=2,
|
||||
x=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
y=3,
|
||||
x=1
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
y=3,
|
||||
x=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
y=4,
|
||||
x=1
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
y=4,
|
||||
x=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
y=5,
|
||||
x=1
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
y=5,
|
||||
x=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
y=6,
|
||||
x=1
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
y=6,
|
||||
x=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
y=7,
|
||||
x=1
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
y=7,
|
||||
x=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
y=8,
|
||||
x=1
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
y=8,
|
||||
x=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
y=9,
|
||||
x=1
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
y=9,
|
||||
x=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
y=10,
|
||||
x=1
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
y=10,
|
||||
x=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
y=11,
|
||||
x=1
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
y=11,
|
||||
x=2
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
y=11,
|
||||
x=3
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
y=11,
|
||||
x=4
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
y=11,
|
||||
x=5
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
y=11,
|
||||
x=7
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
y=11,
|
||||
x=8
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
y=11,
|
||||
x=9
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
y=11,
|
||||
x=10
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
y=11,
|
||||
x=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=1
|
||||
y=1,
|
||||
x=1
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
y=1
|
||||
y=1,
|
||||
x=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=2
|
||||
y=2,
|
||||
x=1
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
y=2
|
||||
y=2,
|
||||
x=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=3
|
||||
y=3,
|
||||
x=1
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
y=3
|
||||
y=3,
|
||||
x=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=4
|
||||
y=4,
|
||||
x=1
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
y=4
|
||||
y=4,
|
||||
x=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=5
|
||||
y=5,
|
||||
x=1
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
y=5
|
||||
y=5,
|
||||
x=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=6
|
||||
y=6,
|
||||
x=1
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
y=6
|
||||
y=6,
|
||||
x=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=7
|
||||
y=7,
|
||||
x=1
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
y=7
|
||||
y=7,
|
||||
x=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=8
|
||||
y=8,
|
||||
x=1
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
y=8
|
||||
y=8,
|
||||
x=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=9
|
||||
y=9,
|
||||
x=1
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
y=9
|
||||
y=9,
|
||||
x=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=10
|
||||
y=10,
|
||||
x=1
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
y=10
|
||||
y=10,
|
||||
x=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=11
|
||||
y=11,
|
||||
x=1
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=2,
|
||||
class="static_wall",
|
||||
y=11
|
||||
y=11,
|
||||
x=2
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=3,
|
||||
class="static_wall",
|
||||
y=11
|
||||
y=11,
|
||||
x=3
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=4,
|
||||
class="static_wall",
|
||||
y=11
|
||||
y=11,
|
||||
x=4
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=5,
|
||||
class="static_wall",
|
||||
y=11
|
||||
y=11,
|
||||
x=5
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=7,
|
||||
class="static_wall",
|
||||
y=11
|
||||
y=11,
|
||||
x=7
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=8,
|
||||
class="static_wall",
|
||||
y=11
|
||||
y=11,
|
||||
x=8
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=9,
|
||||
class="static_wall",
|
||||
y=11
|
||||
y=11,
|
||||
x=9
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=10,
|
||||
class="static_wall",
|
||||
y=11
|
||||
y=11,
|
||||
x=10
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
y=11
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=1
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
y=1
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=2
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
y=2
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=3
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
y=3
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=4
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
y=4
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=5
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=6
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
y=6
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=7
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
y=7
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=8
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
y=8
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=9
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
y=9
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=10
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
y=10
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=11
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=2,
|
||||
class="static_wall",
|
||||
y=11
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=3,
|
||||
class="static_wall",
|
||||
y=11
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=4,
|
||||
class="static_wall",
|
||||
y=11
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=5,
|
||||
class="static_wall",
|
||||
y=11
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=7,
|
||||
class="static_wall",
|
||||
y=11
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=8,
|
||||
class="static_wall",
|
||||
y=11
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=9,
|
||||
class="static_wall",
|
||||
y=11
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=10,
|
||||
class="static_wall",
|
||||
y=11
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
y=11
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=9,
|
||||
class="spiky_box_2x1_11",
|
||||
y=10
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=7,
|
||||
class="spiky_box_2x1_11",
|
||||
y=10
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=9,
|
||||
class="spiky_box_2x1_11",
|
||||
y=9
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=8,
|
||||
class="box_2x2_11-10",
|
||||
y=8
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=3,
|
||||
class="spiky_box_2x1_11",
|
||||
y=10
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=5,
|
||||
class="spiky_box_2x1_11",
|
||||
y=10
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=2,
|
||||
class="box_2x2_11-10",
|
||||
y=9
|
||||
y=11,
|
||||
x=11
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,586 +1,548 @@
|
|||
{
|
||||
wires={
|
||||
},
|
||||
objects={
|
||||
{
|
||||
color="red",
|
||||
class="static_wall",
|
||||
color="blue",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=1
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
class="static_wall",
|
||||
color="blue",
|
||||
x=2,
|
||||
class="static_wall",
|
||||
y=1
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
class="static_wall",
|
||||
color="blue",
|
||||
x=3,
|
||||
class="static_wall",
|
||||
y=1
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
class="static_wall",
|
||||
color="blue",
|
||||
x=4,
|
||||
class="static_wall",
|
||||
y=1
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
class="static_wall",
|
||||
color="blue",
|
||||
x=5,
|
||||
class="static_wall",
|
||||
y=1
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
class="static_wall",
|
||||
color="blue",
|
||||
x=6,
|
||||
class="static_wall",
|
||||
y=1
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
class="static_wall",
|
||||
color="blue",
|
||||
x=7,
|
||||
class="static_wall",
|
||||
y=1
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
class="static_wall",
|
||||
color="blue",
|
||||
x=8,
|
||||
class="static_wall",
|
||||
y=1
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
class="static_wall",
|
||||
color="blue",
|
||||
x=9,
|
||||
class="static_wall",
|
||||
y=1
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
class="static_wall",
|
||||
color="blue",
|
||||
x=10,
|
||||
class="static_wall",
|
||||
y=1
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
color="blue",
|
||||
x=11,
|
||||
y=1
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
color="blue",
|
||||
x=11,
|
||||
y=2
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
color="blue",
|
||||
x=11,
|
||||
y=3
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
color="blue",
|
||||
x=11,
|
||||
y=4
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
color="blue",
|
||||
x=11,
|
||||
y=5
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
color="blue",
|
||||
x=11,
|
||||
y=6
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
color="blue",
|
||||
x=11,
|
||||
y=7
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
color="blue",
|
||||
x=11,
|
||||
y=8
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
color="blue",
|
||||
x=11,
|
||||
y=9
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
color="blue",
|
||||
x=11,
|
||||
y=10
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="blue",
|
||||
x=1,
|
||||
y=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="blue",
|
||||
x=2,
|
||||
y=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="blue",
|
||||
x=3,
|
||||
y=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="blue",
|
||||
x=5,
|
||||
y=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="blue",
|
||||
x=6,
|
||||
y=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="blue",
|
||||
x=7,
|
||||
y=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="blue",
|
||||
x=8,
|
||||
y=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="blue",
|
||||
x=9,
|
||||
y=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="blue",
|
||||
x=10,
|
||||
y=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="blue",
|
||||
x=11,
|
||||
y=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=11
|
||||
y=1
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
x=2,
|
||||
class="static_wall",
|
||||
y=11
|
||||
y=1
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
x=3,
|
||||
y=1
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
y=11
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=5,
|
||||
class="static_wall",
|
||||
y=11
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=6,
|
||||
class="static_wall",
|
||||
y=11
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=7,
|
||||
class="static_wall",
|
||||
y=11
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=8,
|
||||
class="static_wall",
|
||||
y=11
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=9,
|
||||
class="static_wall",
|
||||
y=11
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=10,
|
||||
class="static_wall",
|
||||
y=11
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
y=11
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=8,
|
||||
class="box",
|
||||
y=4
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=7,
|
||||
class="spiky_box_2x1_11",
|
||||
y=3
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=6,
|
||||
class="spiky_box_2x1_11",
|
||||
y=4
|
||||
},
|
||||
{
|
||||
color="red",
|
||||
x=4,
|
||||
class="spiky_box_2x1_11",
|
||||
y=4
|
||||
y=1
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
x=3,
|
||||
class="box_2x2_11-10",
|
||||
y=3
|
||||
},
|
||||
{
|
||||
color="green",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=1
|
||||
},
|
||||
{
|
||||
color="green",
|
||||
x=2,
|
||||
class="static_wall",
|
||||
y=1
|
||||
},
|
||||
{
|
||||
color="green",
|
||||
x=3,
|
||||
class="static_wall",
|
||||
y=1
|
||||
},
|
||||
{
|
||||
color="green",
|
||||
x=4,
|
||||
class="static_wall",
|
||||
y=1
|
||||
},
|
||||
{
|
||||
color="green",
|
||||
x=5,
|
||||
class="static_wall",
|
||||
y=1
|
||||
},
|
||||
{
|
||||
color="green",
|
||||
class="static_wall",
|
||||
color="red",
|
||||
x=6,
|
||||
class="static_wall",
|
||||
y=1
|
||||
},
|
||||
{
|
||||
color="green",
|
||||
class="static_wall",
|
||||
color="red",
|
||||
x=7,
|
||||
class="static_wall",
|
||||
y=1
|
||||
},
|
||||
{
|
||||
color="green",
|
||||
class="static_wall",
|
||||
color="red",
|
||||
x=8,
|
||||
class="static_wall",
|
||||
y=1
|
||||
},
|
||||
{
|
||||
color="green",
|
||||
class="static_wall",
|
||||
color="red",
|
||||
x=9,
|
||||
class="static_wall",
|
||||
y=1
|
||||
},
|
||||
{
|
||||
color="green",
|
||||
class="static_wall",
|
||||
color="red",
|
||||
x=10,
|
||||
class="static_wall",
|
||||
y=1
|
||||
},
|
||||
{
|
||||
color="green",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
color="red",
|
||||
x=11,
|
||||
y=1
|
||||
},
|
||||
{
|
||||
color="green",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
color="red",
|
||||
x=11,
|
||||
y=2
|
||||
},
|
||||
{
|
||||
color="green",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
color="red",
|
||||
x=11,
|
||||
y=3
|
||||
},
|
||||
{
|
||||
color="green",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
color="red",
|
||||
x=11,
|
||||
y=4
|
||||
},
|
||||
{
|
||||
color="green",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
color="red",
|
||||
x=11,
|
||||
y=5
|
||||
},
|
||||
{
|
||||
color="green",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
color="red",
|
||||
x=11,
|
||||
y=6
|
||||
},
|
||||
{
|
||||
color="green",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
color="red",
|
||||
x=11,
|
||||
y=7
|
||||
},
|
||||
{
|
||||
color="green",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
color="red",
|
||||
x=11,
|
||||
y=8
|
||||
},
|
||||
{
|
||||
color="green",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
color="red",
|
||||
x=11,
|
||||
y=9
|
||||
},
|
||||
{
|
||||
color="green",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
color="red",
|
||||
x=11,
|
||||
y=10
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
x=1,
|
||||
y=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
x=2,
|
||||
y=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
x=3,
|
||||
y=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
x=5,
|
||||
y=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
x=6,
|
||||
y=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
x=7,
|
||||
y=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
x=8,
|
||||
y=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
x=9,
|
||||
y=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
x=10,
|
||||
y=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="red",
|
||||
x=11,
|
||||
y=11
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=11
|
||||
y=1
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=2,
|
||||
class="static_wall",
|
||||
y=11
|
||||
y=1
|
||||
},
|
||||
{
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=3,
|
||||
class="static_wall",
|
||||
y=11
|
||||
y=1
|
||||
},
|
||||
{
|
||||
color="green",
|
||||
x=5,
|
||||
class="static_wall",
|
||||
y=11
|
||||
},
|
||||
{
|
||||
color="green",
|
||||
x=6,
|
||||
class="static_wall",
|
||||
y=11
|
||||
},
|
||||
{
|
||||
color="green",
|
||||
x=7,
|
||||
class="static_wall",
|
||||
y=11
|
||||
},
|
||||
{
|
||||
color="green",
|
||||
x=8,
|
||||
class="static_wall",
|
||||
y=11
|
||||
},
|
||||
{
|
||||
color="green",
|
||||
x=9,
|
||||
class="static_wall",
|
||||
y=11
|
||||
},
|
||||
{
|
||||
color="green",
|
||||
x=10,
|
||||
class="static_wall",
|
||||
y=11
|
||||
},
|
||||
{
|
||||
color="green",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
y=11
|
||||
},
|
||||
{
|
||||
color="green",
|
||||
x=4,
|
||||
class="box",
|
||||
y=3
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=1
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=2,
|
||||
class="static_wall",
|
||||
y=1
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=3,
|
||||
class="static_wall",
|
||||
y=1
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=4,
|
||||
class="static_wall",
|
||||
y=1
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
color="green",
|
||||
x=5,
|
||||
class="static_wall",
|
||||
y=1
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=6,
|
||||
class="static_wall",
|
||||
y=1
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=7,
|
||||
class="static_wall",
|
||||
y=1
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=8,
|
||||
class="static_wall",
|
||||
y=1
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=9,
|
||||
class="static_wall",
|
||||
y=1
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=10,
|
||||
class="static_wall",
|
||||
y=1
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=11,
|
||||
y=1
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=11,
|
||||
y=2
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=11,
|
||||
y=3
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=11,
|
||||
y=4
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=11,
|
||||
y=5
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=11,
|
||||
y=6
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=11,
|
||||
y=7
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=11,
|
||||
y=8
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=11,
|
||||
y=9
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=11,
|
||||
y=10
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=1,
|
||||
class="static_wall",
|
||||
y=11
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=2,
|
||||
class="static_wall",
|
||||
y=11
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=3,
|
||||
class="static_wall",
|
||||
y=11
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=5,
|
||||
class="static_wall",
|
||||
y=11
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=6,
|
||||
class="static_wall",
|
||||
y=11
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=7,
|
||||
class="static_wall",
|
||||
y=11
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=8,
|
||||
class="static_wall",
|
||||
y=11
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=9,
|
||||
class="static_wall",
|
||||
y=11
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=10,
|
||||
class="static_wall",
|
||||
y=11
|
||||
},
|
||||
{
|
||||
color="blue",
|
||||
class="static_wall",
|
||||
color="green",
|
||||
x=11,
|
||||
class="static_wall",
|
||||
y=11
|
||||
},
|
||||
{
|
||||
x=5,
|
||||
class="npc",
|
||||
x=5,
|
||||
y=2
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
2270
rooms/white_ok.sav
2270
rooms/white_ok.sav
File diff suppressed because it is too large
Load diff
202
rooms/world.sav
202
rooms/world.sav
|
|
@ -1,252 +1,232 @@
|
|||
{
|
||||
rooms={
|
||||
{
|
||||
x=10,
|
||||
name="3",
|
||||
y=10,
|
||||
x=10
|
||||
y=10
|
||||
},
|
||||
{
|
||||
x=12,
|
||||
name="5",
|
||||
y=10,
|
||||
x=12
|
||||
y=10
|
||||
},
|
||||
{
|
||||
x=12,
|
||||
name="village_1",
|
||||
y=9,
|
||||
x=12
|
||||
y=9
|
||||
},
|
||||
{
|
||||
x=11,
|
||||
name="village_4",
|
||||
y=8,
|
||||
x=11
|
||||
y=8
|
||||
},
|
||||
{
|
||||
x=11,
|
||||
name="yellow_1",
|
||||
y=7,
|
||||
x=11
|
||||
y=7
|
||||
},
|
||||
{
|
||||
x=11,
|
||||
name="yellow_3",
|
||||
y=6,
|
||||
x=11
|
||||
y=6
|
||||
},
|
||||
{
|
||||
x=12,
|
||||
name="yellow_2",
|
||||
y=7,
|
||||
x=12
|
||||
y=7
|
||||
},
|
||||
{
|
||||
x=11,
|
||||
name="yellow_4",
|
||||
y=5,
|
||||
x=11
|
||||
y=5
|
||||
},
|
||||
{
|
||||
x=11,
|
||||
name="yellow_5",
|
||||
y=4,
|
||||
x=11
|
||||
y=4
|
||||
},
|
||||
{
|
||||
x=10,
|
||||
name="yellow_6",
|
||||
y=5,
|
||||
x=10
|
||||
y=5
|
||||
},
|
||||
{
|
||||
x=1,
|
||||
name="default",
|
||||
y=1,
|
||||
x=1
|
||||
y=1
|
||||
},
|
||||
{
|
||||
x=3,
|
||||
name="old_yellow_3",
|
||||
y=1,
|
||||
x=3
|
||||
y=1
|
||||
},
|
||||
{
|
||||
x=5,
|
||||
name="test_patt",
|
||||
y=1,
|
||||
x=5
|
||||
y=1
|
||||
},
|
||||
{
|
||||
x=7,
|
||||
name="test_patt_update",
|
||||
y=1,
|
||||
x=7
|
||||
y=1
|
||||
},
|
||||
{
|
||||
x=9,
|
||||
name="white_asymmetrical",
|
||||
y=1,
|
||||
x=9
|
||||
y=1
|
||||
},
|
||||
{
|
||||
x=11,
|
||||
name="white_ok",
|
||||
y=1,
|
||||
x=11
|
||||
y=1
|
||||
},
|
||||
{
|
||||
x=13,
|
||||
name="white_primary",
|
||||
y=1,
|
||||
x=13
|
||||
y=1
|
||||
},
|
||||
{
|
||||
x=15,
|
||||
name="yellow_arches",
|
||||
y=1,
|
||||
x=15
|
||||
y=1
|
||||
},
|
||||
{
|
||||
x=17,
|
||||
name="yellow_asymmetrical",
|
||||
y=1,
|
||||
x=17
|
||||
y=1
|
||||
},
|
||||
{
|
||||
x=1,
|
||||
name="yellow_cc_moustache",
|
||||
y=3,
|
||||
x=1
|
||||
y=3
|
||||
},
|
||||
{
|
||||
x=3,
|
||||
name="yellow_color_changing_levvel_1",
|
||||
y=3,
|
||||
x=3
|
||||
y=3
|
||||
},
|
||||
{
|
||||
x=7,
|
||||
name="yellow_smile",
|
||||
y=3,
|
||||
x=7
|
||||
y=3
|
||||
},
|
||||
{
|
||||
x=9,
|
||||
name="2",
|
||||
y=10,
|
||||
x=9
|
||||
y=10
|
||||
},
|
||||
{
|
||||
x=11,
|
||||
name="room_11_09",
|
||||
y=9,
|
||||
x=11
|
||||
y=9
|
||||
},
|
||||
{
|
||||
x=9,
|
||||
name="yellow_skull",
|
||||
y=3,
|
||||
x=9
|
||||
y=3
|
||||
},
|
||||
{
|
||||
x=5,
|
||||
name="jorge_room",
|
||||
y=5,
|
||||
x=5
|
||||
y=5
|
||||
},
|
||||
{
|
||||
x=11,
|
||||
name="4",
|
||||
y=10,
|
||||
x=11
|
||||
y=10
|
||||
},
|
||||
{
|
||||
x=1,
|
||||
name="room_01_05",
|
||||
y=5,
|
||||
x=1
|
||||
y=5
|
||||
},
|
||||
{
|
||||
x=2,
|
||||
name="ok",
|
||||
y=8,
|
||||
x=2
|
||||
y=8
|
||||
},
|
||||
{
|
||||
x=5,
|
||||
name="room_05_18",
|
||||
y=18,
|
||||
x=5
|
||||
y=18
|
||||
},
|
||||
{
|
||||
x=9,
|
||||
name="village_start",
|
||||
y=11,
|
||||
x=9
|
||||
y=11
|
||||
},
|
||||
{
|
||||
x=4,
|
||||
name="spiky_test",
|
||||
y=8,
|
||||
x=4
|
||||
y=8
|
||||
},
|
||||
{
|
||||
x=5,
|
||||
name="corner_trimino_test",
|
||||
y=7,
|
||||
x=5
|
||||
y=7
|
||||
},
|
||||
{
|
||||
x=6,
|
||||
name="tetromino_loop_t",
|
||||
y=7,
|
||||
x=6
|
||||
y=7
|
||||
},
|
||||
{
|
||||
x=5,
|
||||
name="corner_trimino_test_copy",
|
||||
y=6,
|
||||
x=5
|
||||
y=6
|
||||
},
|
||||
{
|
||||
x=7,
|
||||
name="blocker_test",
|
||||
y=7,
|
||||
x=7
|
||||
y=7
|
||||
},
|
||||
{
|
||||
x=5,
|
||||
name="spiky_test_2",
|
||||
y=8,
|
||||
x=5
|
||||
y=8
|
||||
},
|
||||
{
|
||||
x=5,
|
||||
name="spiky_test_3",
|
||||
y=9,
|
||||
x=5
|
||||
y=9
|
||||
},
|
||||
{
|
||||
x=3,
|
||||
name="jorge2",
|
||||
y=14,
|
||||
x=3
|
||||
y=14
|
||||
},
|
||||
{
|
||||
x=8,
|
||||
name="room_08_07",
|
||||
y=7,
|
||||
x=8
|
||||
y=7
|
||||
},
|
||||
{
|
||||
x=13,
|
||||
name="village_3",
|
||||
y=8,
|
||||
x=13
|
||||
y=8
|
||||
},
|
||||
{
|
||||
x=12,
|
||||
name="village_2",
|
||||
y=8,
|
||||
x=12
|
||||
y=8
|
||||
},
|
||||
{
|
||||
x=14,
|
||||
name="room_14_07",
|
||||
y=7,
|
||||
x=14
|
||||
y=7
|
||||
},
|
||||
{
|
||||
x=9,
|
||||
name="room_09_13",
|
||||
y=13,
|
||||
x=9
|
||||
y=13
|
||||
},
|
||||
{
|
||||
x=8,
|
||||
name="room_08_13",
|
||||
y=13,
|
||||
x=8
|
||||
},
|
||||
{
|
||||
name="room_10_15",
|
||||
y=15,
|
||||
x=9
|
||||
},
|
||||
{
|
||||
name="room_13_14",
|
||||
y=14,
|
||||
x=13
|
||||
},
|
||||
{
|
||||
name="room_14_14",
|
||||
y=14,
|
||||
x=14
|
||||
},
|
||||
{
|
||||
name="room_13_13",
|
||||
y=13,
|
||||
x=13
|
||||
y=13
|
||||
}
|
||||
},
|
||||
lastRoom="room_14_14",
|
||||
lastRoom="room_09_13",
|
||||
width=18,
|
||||
height=18
|
||||
}
|
||||
1176
rooms/yellow_2.sav
1176
rooms/yellow_2.sav
File diff suppressed because it is too large
Load diff
77
shaders.lua
77
shaders.lua
|
|
@ -89,83 +89,6 @@ goopShader = love.graphics.newShader[[
|
|||
}
|
||||
]]
|
||||
|
||||
-- Wires are drawn as primitives rather than textured sprites, but LÖVE still
|
||||
-- runs this shader over its default white texture. Inactive runs stay visibly
|
||||
-- connected at half brightness; powered runs get a travelling neon shimmer,
|
||||
-- occasional tube-like noise, and a sub-pixel bend rather than a global fade.
|
||||
wireNeonShader = love.graphics.newShader[[
|
||||
extern number wirePower;
|
||||
extern number wireTime;
|
||||
extern number wirePhase;
|
||||
|
||||
float wireHash(vec2 point) {
|
||||
return fract(sin(dot(point, vec2(127.1, 311.7))) * 43758.5453123);
|
||||
}
|
||||
|
||||
vec4 position(mat4 transformProjection, vec4 vertexPosition) {
|
||||
if (wirePower < 0.5) return transformProjection * vertexPosition;
|
||||
|
||||
// Every segment sharing an endpoint receives the same offset, so corners
|
||||
// stay connected while the live current gives the tube a gentle movement.
|
||||
float wave = sin(vertexPosition.x * 0.085 + vertexPosition.y * 0.13 +
|
||||
wireTime * 4.4 + wirePhase * 9.0);
|
||||
float wobble = wave * 0.32;
|
||||
vertexPosition.xy += vec2(wobble, -wobble * 0.55);
|
||||
return transformProjection * vertexPosition;
|
||||
}
|
||||
|
||||
vec4 effect(vec4 color, Image texture, vec2 textureCoords, vec2 screenCoords) {
|
||||
if (wirePower < 0.5) return vec4(color.rgb * 0.50, color.a * 0.72);
|
||||
|
||||
float travel = dot(screenCoords, vec2(0.070, 0.043)) - wireTime * 6.8 + wirePhase * 13.0;
|
||||
float shimmer = sin(travel) * 0.075 + sin(travel * 2.37 + 1.7) * 0.035;
|
||||
vec2 noiseCell = floor(screenCoords * 0.34) + floor(wireTime * 15.0) * vec2(1.0, -1.0);
|
||||
float noise = wireHash(noiseCell + wirePhase);
|
||||
float flicker = max(0.0, noise - 0.82) * 0.32;
|
||||
float brightness = 0.92 + shimmer + flicker;
|
||||
float alpha = 0.84 + shimmer * 0.80 + flicker * 0.55;
|
||||
return vec4(color.rgb * brightness, color.a * alpha);
|
||||
}
|
||||
]]
|
||||
|
||||
-- World renders a neighbouring room twice for the porous seam: once through
|
||||
-- its own active channels and once through the current room's channels. This
|
||||
-- shader only controls the alpha of that second, already-authored render, so
|
||||
-- it never approximates the game's literal RGB colour treatment.
|
||||
porousRoomBoundaryShader = love.graphics.newShader[[
|
||||
extern number porousTime;
|
||||
extern vec4 porousRoomRect;
|
||||
extern vec2 porousDirection;
|
||||
extern number porousDepth;
|
||||
|
||||
float porousWave(vec2 point) {
|
||||
float broad = sin(point.x * 0.095 + point.y * 0.071 + porousTime * 1.45);
|
||||
float fine = sin(point.x * 0.231 - point.y * 0.187 - porousTime * 2.20);
|
||||
return broad * 0.105 + fine * 0.050;
|
||||
}
|
||||
|
||||
vec4 effect(vec4 color, Image texture, vec2 textureCoords, vec2 screenCoords) {
|
||||
vec4 alternateView = Texel(texture, textureCoords) * color;
|
||||
vec2 local = screenCoords - porousRoomRect.xy;
|
||||
vec2 size = porousRoomRect.zw;
|
||||
if (local.x < 0.0 || local.y < 0.0 || local.x > size.x || local.y > size.y)
|
||||
return vec4(0.0);
|
||||
|
||||
float depth;
|
||||
if (porousDirection.x > 0.5) depth = local.x;
|
||||
else if (porousDirection.x < -0.5) depth = size.x - local.x;
|
||||
else if (porousDirection.y > 0.5) depth = local.y;
|
||||
else depth = size.y - local.y;
|
||||
|
||||
float towardSeam = 1.0 - smoothstep(0.0, porousDepth, depth);
|
||||
// Animated fingers soften the fifty-fifty transition across the visible
|
||||
// overlap while preserving the pixels of the real alternate room render.
|
||||
float mask = smoothstep(0.18, 0.82, towardSeam + porousWave(screenCoords));
|
||||
alternateView.a *= mask;
|
||||
return alternateView;
|
||||
}
|
||||
]]
|
||||
|
||||
function drawGoopySprite(sprite, x, y, scale)
|
||||
local w, h = sprite:getWidth(), sprite:getHeight()
|
||||
local time = love.timer.getTime()
|
||||
|
|
|
|||
|
|
@ -169,15 +169,6 @@ test("a switchless wire component has no gameplay color", function()
|
|||
assertTrue(world:wireColorAt(roomA, {x = 1, y = 1}, "circuit_a") == nil)
|
||||
end)
|
||||
|
||||
test("wire power follows its terminal switch", function()
|
||||
local world, roomA = makeWorld()
|
||||
world:resolveCircuits()
|
||||
assertFalse(world:wirePoweredAt(roomA, {x = 1, y = 1}, "circuit_a"))
|
||||
world.collidableMatrices.blue[1] = {[4] = {}}
|
||||
world:resolveCircuits()
|
||||
assertTrue(world:wirePoweredAt(roomA, {x = 1, y = 1}, "circuit_a"))
|
||||
end)
|
||||
|
||||
test("a door requires every independent switch run at its terminal", function()
|
||||
local greenSwitch = switch("green", 1, 2)
|
||||
local world, roomA, _, wiredDoor = makeWorld()
|
||||
|
|
@ -192,220 +183,6 @@ test("a door requires every independent switch run at its terminal", function()
|
|||
assertTrue(world.circuitState.doorPowered[wiredDoor])
|
||||
end)
|
||||
|
||||
test("an orphaned stub at a door does not block a valid switch run", function()
|
||||
local world, roomA, _, wiredDoor = makeWorld()
|
||||
roomA.wires[1][1].abandoned_stroke = 0
|
||||
world.collidableMatrices.blue[1] = {[4] = {}}
|
||||
world:resolveCircuits()
|
||||
assertTrue(world.circuitState.doorPowered[wiredDoor])
|
||||
assertTrue(wiredDoor.powered)
|
||||
end)
|
||||
|
||||
test("real wired and regular doors stay open while any player or collidable blocks the doorway", function()
|
||||
local oldLoadSprite = loadSprite
|
||||
loadSprite = function()
|
||||
return {getWidth = function() return 16 end, getHeight = function() return 16 end}
|
||||
end
|
||||
require "color"
|
||||
require "wired_door"
|
||||
|
||||
local function occupant(x, y)
|
||||
local entity = {x = x, y = y}
|
||||
function entity:occupiesCell(cell) return self.x == cell.x and self.y == cell.y end
|
||||
function entity:canPassOver() return false end
|
||||
return entity
|
||||
end
|
||||
|
||||
local wired = WiredDoor:new(2, 2, "blue", "circuit_a")
|
||||
local ordinary = Door:new(4, 2, "red")
|
||||
local room = {
|
||||
player = {green = occupant(2, 2)},
|
||||
collideables = {
|
||||
red = {ordinary}, green = {occupant(4, 2)}, blue = {wired},
|
||||
},
|
||||
}
|
||||
local world = setmetatable({}, {__index = World})
|
||||
|
||||
wired:setPowered(true)
|
||||
assertFalse(wired.locked, "wired door did not open")
|
||||
assertFalse(world:doorCanClose(room, wired), "green player did not block blue wired door")
|
||||
wired:setPowered(false, world:doorCanClose(room, wired))
|
||||
assertFalse(wired.locked, "wired door shut on player")
|
||||
|
||||
ordinary:setColors({red = true})
|
||||
assertFalse(ordinary.locked, "regular door did not open")
|
||||
assertFalse(world:doorCanClose(room, ordinary), "green collidable did not block red regular door")
|
||||
ordinary:setColors({red = false}, world:doorCanClose(room, ordinary))
|
||||
assertFalse(ordinary.locked, "regular door shut on collidable")
|
||||
|
||||
room.player.green.x, room.player.green.y = 1, 1
|
||||
room.collideables.green[1].x, room.collideables.green[1].y = 1, 1
|
||||
wired:setPowered(false, world:doorCanClose(room, wired))
|
||||
ordinary:setColors({red = false}, world:doorCanClose(room, ordinary))
|
||||
assertTrue(wired.locked, "wired door did not close once clear")
|
||||
assertTrue(ordinary.locked, "regular door did not close once clear")
|
||||
loadSprite = oldLoadSprite
|
||||
end)
|
||||
|
||||
test("circuit resolution passes doorway occupancy to a wired door", function()
|
||||
local world, roomA, _, wiredDoor = makeWorld()
|
||||
local player = {x = 1, y = 1}
|
||||
function player:occupiesCell(cell) return self.x == cell.x and self.y == cell.y end
|
||||
roomA.player.green = player
|
||||
function wiredDoor:setPowered(powered, canClose)
|
||||
self.powered, self.canClose = powered, canClose
|
||||
end
|
||||
|
||||
world:resolveCircuits()
|
||||
assertFalse(wiredDoor.powered, "unpressed switch unexpectedly powered door")
|
||||
assertFalse(wiredDoor.canClose, "resolver omitted player doorway obstruction")
|
||||
end)
|
||||
|
||||
test("room switch resolution keeps a regular door open around an occupant", function()
|
||||
local oldLove, oldLoadSprite = love, loadSprite
|
||||
love = {audio = {newSource = function()
|
||||
return {stop = function() end, play = function() end}
|
||||
end}}
|
||||
loadSprite = function()
|
||||
return {getWidth = function() return 16 end, getHeight = function() return 16 end}
|
||||
end
|
||||
require "room"
|
||||
local door = Door:new(2, 2, "red")
|
||||
local player, block = {x = 2, y = 2}, {x = 1, y = 1}
|
||||
function player:occupiesCell(cell) return self.x == cell.x and self.y == cell.y end
|
||||
function block:occupiesCell(cell) return self.x == cell.x and self.y == cell.y end
|
||||
function block:canPassOver() return false end
|
||||
local room = setmetatable({
|
||||
player = {blue = player}, doors = {door},
|
||||
collideables = {red = {door}, green = {block}, blue = {}},
|
||||
}, {__index = Room})
|
||||
room.switchCheck = function() return {red = true} end
|
||||
room:resolveSwitchesAndDoors()
|
||||
assertFalse(door.locked, "switch did not open regular door")
|
||||
room.switchCheck = function() return {red = false} end
|
||||
room:resolveSwitchesAndDoors()
|
||||
assertFalse(door.locked, "regular door shut through player during room resolution")
|
||||
room.player.blue.x, room.player.blue.y = 1, 1
|
||||
room.collideables.green[1].x, room.collideables.green[1].y = 2, 2
|
||||
room:resolveSwitchesAndDoors()
|
||||
assertFalse(door.locked, "regular door shut through collidable during room resolution")
|
||||
room.collideables.green[1].x, room.collideables.green[1].y = 1, 1
|
||||
room:resolveSwitchesAndDoors()
|
||||
assertTrue(door.locked, "regular door did not close once clear")
|
||||
love, loadSprite = oldLove, oldLoadSprite
|
||||
end)
|
||||
|
||||
test("selecting a parked colour changes to its room", function()
|
||||
local function player()
|
||||
local entity = {switched = false}
|
||||
function entity:playSwitchSound(success) self.switched = success end
|
||||
return entity
|
||||
end
|
||||
local function room(name, players, active)
|
||||
local entity = {name = name, player = players, activeColors = active, colorsPlayerHas = {}}
|
||||
for color in pairs(players) do table.insert(entity.colorsPlayerHas, color) end
|
||||
function entity:getPossibleColors() return self.colorsPlayerHas end
|
||||
function entity:setActiveColor(color, value) self.activeColors[color] = value end
|
||||
function entity:getActiveColors()
|
||||
local colors = {}
|
||||
for color, value in pairs(self.activeColors) do if value then table.insert(colors, color) end end
|
||||
return colors
|
||||
end
|
||||
return entity
|
||||
end
|
||||
local roomA = room("a", {red = player()}, {red = true, green = false, blue = false})
|
||||
local roomB = room("b", {blue = player()}, {red = false, green = false, blue = false})
|
||||
local world = setmetatable({
|
||||
levels = {a = roomA, b = roomB},
|
||||
roomByName = {a = {name = "a", x = 1, y = 1}, b = {name = "b", x = 2, y = 1}},
|
||||
}, {__index = World})
|
||||
world.flushRuntime = function(self) self.flushed = true end
|
||||
local oldCurrentRoom, oldSetEditorRoomName = currentRoom, setEditorRoomName
|
||||
currentRoom = roomA
|
||||
setEditorRoomName = function() end
|
||||
|
||||
assertTrue(world:switchPlayerColor(roomA, "blue"))
|
||||
assertTrue(currentRoom == roomB)
|
||||
assertFalse(roomA.activeColors.red)
|
||||
assertTrue(roomB.activeColors.blue)
|
||||
assertTrue(roomB.player.blue.switched)
|
||||
assertTrue(world.flushed)
|
||||
|
||||
currentRoom, setEditorRoomName = oldCurrentRoom, oldSetEditorRoomName
|
||||
end)
|
||||
|
||||
test("co-located colours join the active player selection", function()
|
||||
local function player(x, y)
|
||||
local entity = {x = x, y = y, switched = false}
|
||||
function entity:getGridPos() return {x = self.x, y = self.y} end
|
||||
function entity:playSwitchSound(success) self.switched = success end
|
||||
return entity
|
||||
end
|
||||
local room = {
|
||||
name = "a",
|
||||
player = {red = player(3, 4), green = player(3, 4), blue = player(6, 4)},
|
||||
activeColors = {red = true, green = false, blue = false},
|
||||
colorsPlayerHas = {"red", "green", "blue"},
|
||||
}
|
||||
function room:getPossibleColors() return self.colorsPlayerHas end
|
||||
function room:getActiveColors()
|
||||
local colors = {}
|
||||
for _, color in ipairs(self.colorsPlayerHas) do
|
||||
if self.activeColors[color] then table.insert(colors, color) end
|
||||
end
|
||||
return colors
|
||||
end
|
||||
function room:colorIsActive(color) return self.activeColors[color] end
|
||||
function room:setActiveColor(color, value) self.activeColors[color] = value end
|
||||
local world = setmetatable({
|
||||
levels = {a = room}, roomByName = {a = {name = "a", x = 1, y = 1}},
|
||||
}, {__index = World})
|
||||
world.flushRuntime = function() end
|
||||
|
||||
assertTrue(world:switchPlayerColor(room, "green"))
|
||||
assertTrue(room.activeColors.red and room.activeColors.green,
|
||||
"co-located red and green did not become active together")
|
||||
assertTrue(world:switchPlayerColor(room, "blue"))
|
||||
assertTrue(room.activeColors.blue and not room.activeColors.red and not room.activeColors.green,
|
||||
"separated blue player should still select by itself")
|
||||
end)
|
||||
|
||||
test("WASD room browsing changes view without moving players", function()
|
||||
local player = {x = 3, y = 4}
|
||||
local roomA = {name = "a", player = {red = player}}
|
||||
local roomB = {name = "b", player = {green = {x = 7, y = 8}}}
|
||||
local world = setmetatable({
|
||||
levels = {a = roomA, b = roomB},
|
||||
roomByName = {a = {name = "a", x = 1, y = 1}, b = {name = "b", x = 2, y = 1}},
|
||||
rooms = {{name = "a", x = 1, y = 1}, {name = "b", x = 2, y = 1}},
|
||||
}, {__index = World})
|
||||
local oldCurrentRoom, oldSetEditorRoomName = currentRoom, setEditorRoomName
|
||||
currentRoom = roomA
|
||||
setEditorRoomName = function() end
|
||||
|
||||
assertTrue(world:browseRoom(roomA, "d"))
|
||||
assertTrue(currentRoom == roomB)
|
||||
assertTrue(world.roomBrowseMode)
|
||||
assertTrue(player.x == 3 and player.y == 4, "browsing moved the player")
|
||||
|
||||
currentRoom, setEditorRoomName = oldCurrentRoom, oldSetEditorRoomName
|
||||
end)
|
||||
|
||||
test("screen-to-cell mapping uses the neighbourhood render transform", function()
|
||||
local oldWidth, oldHeight, oldGridWidth, oldGridHeight = width, height, gridWidth, gridHeight
|
||||
width, height, gridWidth, gridHeight = 110, 110, 11, 11
|
||||
local room = {name = "a"}
|
||||
local world = setmetatable({}, {__index = World})
|
||||
world.roomNeighborhoodTransform = function()
|
||||
return {zoom = 0.78, originX = 22, originY = 22, cameraX = 0, cameraY = 0}
|
||||
end
|
||||
local cell = world:screenCellInRoom(room,
|
||||
22 + width * 0.78 * (4.5 / 11), 22 + height * 0.78 * (7.5 / 11))
|
||||
assertTrue(cell.x == 5 and cell.y == 8, "rendered cell did not map back to itself")
|
||||
assertTrue(world:screenCellInRoom(room, 1, 1) == nil, "preview margin mapped into active room")
|
||||
width, height, gridWidth, gridHeight = oldWidth, oldHeight, oldGridWidth, oldGridHeight
|
||||
end)
|
||||
|
||||
test("one run cannot terminate at two different switches", function()
|
||||
local second = switch("red", 1, 2)
|
||||
local world, _, roomB = makeWorld(second)
|
||||
|
|
|
|||
|
|
@ -10,10 +10,10 @@ function WiredDoor:initialize(x, y, color, circuitId)
|
|||
self.wired = true
|
||||
end
|
||||
|
||||
function WiredDoor:setPowered(powered, canClose)
|
||||
function WiredDoor:setPowered(powered)
|
||||
if powered then
|
||||
if self.locked then self:unlock() end
|
||||
elseif canClose ~= false and not self.locked then
|
||||
elseif not self.locked then
|
||||
self:lock()
|
||||
end
|
||||
self:refreshSprites()
|
||||
|
|
|
|||
237
world.lua
237
world.lua
|
|
@ -284,28 +284,6 @@ function World:isSwitchPressed(room, switch)
|
|||
return target ~= nil or (player and player:occupiesCell(switch:getGridPos())) or false
|
||||
end
|
||||
|
||||
-- Check every rendered/colliding colour layer. A red or green player/box can
|
||||
-- visibly occupy a blue door cell, so checking only the door's own layer lets
|
||||
-- wired doors close through an apparent occupant. Other door layers at the
|
||||
-- same location are intentionally ignored: they are one layered doorway.
|
||||
function World:doorCanClose(room, door)
|
||||
local cells = door.getOccupiedCells and door:getOccupiedCells() or {door:getGridPos()}
|
||||
for _, cell in ipairs(cells) do
|
||||
for _, player in pairs(room.player or {}) do
|
||||
if player:occupiesCell(cell) then return false end
|
||||
end
|
||||
for _, entities in pairs(room.collideables or {}) do
|
||||
for _, entity in ipairs(entities) do
|
||||
if entity ~= door and not entity.isDoor and entity:occupiesCell(cell) and
|
||||
not (entity.canPassOver and entity:canPassOver()) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function World:rebuildCircuitMatrices()
|
||||
self.wireMatrix = {}
|
||||
self.wiredSwitchMatrix = {}
|
||||
|
|
@ -451,16 +429,13 @@ function World:resolveCircuits()
|
|||
local position = {x = x, y = y}
|
||||
local key = cellKey(position)
|
||||
local tracks = self.wireMatrix[y] and self.wireMatrix[y][x]
|
||||
-- A circuit can be started with a click before the author drags its
|
||||
-- first segment. Those zero-length fragments are not a completed
|
||||
-- electrical run, so they must not permanently lock a door that also
|
||||
-- has real door-to-switch routes. Only valid components participate
|
||||
-- in the door's AND condition.
|
||||
local runCount, powered = 0, true
|
||||
local runCount, powered = 0, tracks ~= nil
|
||||
for circuitId in pairs(tracks or {}) do
|
||||
runCount = runCount + 1
|
||||
local component = components[circuitId] and components[circuitId][key]
|
||||
if component and component.valid then
|
||||
runCount = runCount + 1
|
||||
if not component or not component.valid then
|
||||
powered = false
|
||||
else
|
||||
for switch in pairs(component.switches) do
|
||||
if not switchPressed[switch] then powered = false end
|
||||
end
|
||||
|
|
@ -470,7 +445,7 @@ function World:resolveCircuits()
|
|||
doorPowered[door] = powered
|
||||
-- locked/collision is a projection of world state onto the physical
|
||||
-- room entity so the existing movement renderer can consume it.
|
||||
door:setPowered(powered, self:doorCanClose(device.room, door))
|
||||
door:setPowered(powered)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -494,20 +469,6 @@ function World:wireSwitchColorsAt(room, localCell, circuitId)
|
|||
return colors
|
||||
end
|
||||
|
||||
-- A valid wire is bright only while every switch at its sole terminal cell is
|
||||
-- pressed. Rendering reads this derived state rather than entity sprite flags
|
||||
-- so every segment of a cross-room component agrees in the same frame.
|
||||
function World:wirePoweredAt(room, localCell, circuitId)
|
||||
local worldCell = self:worldCell(room, localCell)
|
||||
local component = worldCell and self.circuitComponents and
|
||||
self.circuitComponents[circuitId] and self.circuitComponents[circuitId][cellKey(worldCell)]
|
||||
if not component or not component.valid then return false end
|
||||
for switch in pairs(component.switches) do
|
||||
if not (self.circuitState and self.circuitState.switchPressed[switch]) then return false end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function World:wireColorAt(room, localCell, circuitId, visibleColors)
|
||||
local colors = self:wireSwitchColorsAt(room, localCell, circuitId)
|
||||
if not colors then return nil end
|
||||
|
|
@ -663,7 +624,6 @@ function World:playerJoinCheck(room, previousPositions, newPositions)
|
|||
end
|
||||
|
||||
function World:movePlayer(room, key)
|
||||
self.roomBrowseMode = false
|
||||
local directions = {
|
||||
up = {x = 0, y = -1, axis = "y"}, down = {x = 0, y = 1, axis = "y"},
|
||||
left = {x = -1, y = 0, axis = "x"}, right = {x = 1, y = 0, axis = "x"},
|
||||
|
|
@ -715,55 +675,11 @@ function World:movePlayer(room, key)
|
|||
end
|
||||
|
||||
function World:switchPlayerColor(room, color)
|
||||
self.roomBrowseMode = false
|
||||
local player = room.player[color]
|
||||
if not player then
|
||||
-- A colour copy can be parked in another world room. Number keys are a
|
||||
-- direct way to resume controlling it: keep every copy where it is, but
|
||||
-- make its owner the active room and select that colour there.
|
||||
local destination
|
||||
for name, candidate in pairs(self.levels or {}) do
|
||||
if self:roomLocation(name) and candidate.player[color] then
|
||||
destination = candidate
|
||||
break
|
||||
end
|
||||
end
|
||||
if not destination then return false end
|
||||
|
||||
for _, possibleColor in ipairs(room:getPossibleColors()) do
|
||||
room:setActiveColor(possibleColor, false)
|
||||
end
|
||||
for _, possibleColor in ipairs(destination:getPossibleColors()) do
|
||||
destination:setActiveColor(possibleColor, possibleColor == color)
|
||||
end
|
||||
|
||||
currentRoom = destination
|
||||
self.lastRoom = destination.name
|
||||
destination.player[color]:playSwitchSound(true)
|
||||
self:markDirty(room)
|
||||
self:markDirty(destination)
|
||||
self:flushRuntime()
|
||||
setEditorRoomName(destination.name)
|
||||
return true
|
||||
end
|
||||
if not player then return false end
|
||||
local activeColors = room:getActiveColors()
|
||||
local canJoin = not room:colorIsActive(color) and #activeColors > 0
|
||||
if canJoin then
|
||||
local target = player:getGridPos()
|
||||
for _, activeColor in ipairs(activeColors) do
|
||||
local activePlayer = room.player[activeColor]
|
||||
local activePos = activePlayer and activePlayer:getGridPos()
|
||||
if not activePos or activePos.x ~= target.x or activePos.y ~= target.y then
|
||||
canJoin = false
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local canSwitch = canJoin or #activeColors ~= 1 or activeColors[1] ~= color
|
||||
if canJoin then
|
||||
room:setActiveColor(color, true)
|
||||
elseif canSwitch then
|
||||
local canSwitch = #activeColors ~= 1 or activeColors[1] ~= color
|
||||
if canSwitch then
|
||||
for _, possibleColor in ipairs(room:getPossibleColors()) do
|
||||
room:setActiveColor(possibleColor, possibleColor == color)
|
||||
end
|
||||
|
|
@ -773,19 +689,6 @@ function World:switchPlayerColor(room, color)
|
|||
return canSwitch
|
||||
end
|
||||
|
||||
-- Developer room browser. It changes only the displayed room; players,
|
||||
-- collision, and runtime save state remain untouched.
|
||||
function World:browseRoom(room, key)
|
||||
local exits = {a = "left", d = "right", w = "top", s = "bottom"}
|
||||
local destinationName = exits[key] and self:getNeighbor(room.name, exits[key])
|
||||
local destination = destinationName and self.levels[destinationName]
|
||||
if not destination then return false end
|
||||
currentRoom = destination
|
||||
self.roomBrowseMode = true
|
||||
if setEditorRoomName then setEditorRoomName(destination.name) end
|
||||
return true
|
||||
end
|
||||
|
||||
function World:tick(room)
|
||||
room:tickLocal()
|
||||
self:rebuildCollision()
|
||||
|
|
@ -811,8 +714,6 @@ function World:nextRoom(room, pos)
|
|||
elseif pos.y > gridHeight then exit, entry.y = "bottom", 1
|
||||
elseif pos.y < 1 then exit, entry.y = "top", gridHeight end
|
||||
local nextName = self:getNeighbor(room.name, exit) or room.name
|
||||
local sourceLocation = self:roomLocation(room.name)
|
||||
local destinationLocation = self:roomLocation(nextName)
|
||||
local activeColors = room:getActiveColors()
|
||||
self:markDirty(room)
|
||||
local destination = self.levels[nextName]
|
||||
|
|
@ -834,13 +735,6 @@ function World:nextRoom(room, pos)
|
|||
end
|
||||
room.activeColors = {red = false, green = false, blue = false}
|
||||
currentRoom = destination
|
||||
if sourceLocation and destinationLocation and nextName ~= room.name then
|
||||
self.roomTransition = {
|
||||
startedAt = love.timer.getTime(), duration = 0.28,
|
||||
dx = destinationLocation.x - sourceLocation.x,
|
||||
dy = destinationLocation.y - sourceLocation.y,
|
||||
}
|
||||
end
|
||||
self:markDirty(currentRoom)
|
||||
for _, color in ipairs(activeColors) do
|
||||
currentRoom.player[color].x, currentRoom.player[color].y = entry.x, entry.y
|
||||
|
|
@ -908,119 +802,6 @@ function World:drawOverlaps(room, color)
|
|||
end
|
||||
end
|
||||
|
||||
-- The neighbourhood renderer and editor pointer mapping share this exact
|
||||
-- transform. Keeping it in one place prevents a visual zoom adjustment from
|
||||
-- silently shifting placement/deletion by a tile.
|
||||
function World:roomNeighborhoodTransform(room)
|
||||
local location = self:roomLocation(room.name)
|
||||
if not location then return nil end
|
||||
|
||||
-- Leave enough margin to read several cells of each neighbour, not merely
|
||||
-- its boundary wall. This keeps a nearby separated player discoverable.
|
||||
local zoom = 0.78
|
||||
local originX = (width - width * zoom) / 2
|
||||
local originY = (height - height * zoom) / 2
|
||||
local cameraX, cameraY = 0, 0
|
||||
local transition = self.roomTransition
|
||||
if transition then
|
||||
local progress = math.min(1, (love.timer.getTime() - transition.startedAt) / transition.duration)
|
||||
-- Smoothstep keeps the scene anchored at both ends instead of snapping
|
||||
-- into or out of its small neighbourhood preview.
|
||||
local eased = progress * progress * (3 - 2 * progress)
|
||||
cameraX = transition.dx * (1 - eased)
|
||||
cameraY = transition.dy * (1 - eased)
|
||||
if progress >= 1 then self.roomTransition = nil end
|
||||
end
|
||||
return {location = location, zoom = zoom, originX = originX, originY = originY,
|
||||
cameraX = cameraX, cameraY = cameraY}
|
||||
end
|
||||
|
||||
-- Convert a gameplay-screen coordinate to a cell in the centered room. The
|
||||
-- surrounding rooms are preview-only while editing; browse to one with WASD
|
||||
-- before changing it. Returns nil for the preview margin or any other room.
|
||||
function World:screenCellInRoom(room, mouseX, mouseY)
|
||||
local transform = self:roomNeighborhoodTransform(room)
|
||||
if not transform then return nil end
|
||||
local roomOffsetX = (mouseX - transform.originX) / (width * transform.zoom) - transform.cameraX
|
||||
local roomOffsetY = (mouseY - transform.originY) / (height * transform.zoom) - transform.cameraY
|
||||
local offsetX, offsetY = math.floor(roomOffsetX), math.floor(roomOffsetY)
|
||||
if offsetX ~= 0 or offsetY ~= 0 then return nil end
|
||||
local localX = (roomOffsetX - offsetX) * width
|
||||
local localY = (roomOffsetY - offsetY) * height
|
||||
local cell = {
|
||||
x = math.floor(localX * gridWidth / width) + 1,
|
||||
y = math.floor(localY * gridHeight / height) + 1,
|
||||
}
|
||||
if cell.x < 1 or cell.x > gridWidth or cell.y < 1 or cell.y > gridHeight then return nil end
|
||||
return cell
|
||||
end
|
||||
|
||||
-- Render the active room at a small zoom-out, together with the eight world
|
||||
-- neighbours around it. This is display-only: individual rooms still own
|
||||
-- their data, collision, and authored boundary walls.
|
||||
function World:drawRoomNeighborhood(room)
|
||||
if self.drawingRoomNeighborhood then return end
|
||||
local transform = self:roomNeighborhoodTransform(room)
|
||||
if not transform then return end
|
||||
self.drawingRoomNeighborhood = true
|
||||
local currentChannels = room:getRenderChannels()
|
||||
local roomWidth, roomHeight = width * transform.zoom, height * transform.zoom
|
||||
|
||||
local function drawAt(offsetX, offsetY, level, channels)
|
||||
love.graphics.push()
|
||||
love.graphics.translate(transform.originX + (offsetX + transform.cameraX) * roomWidth,
|
||||
transform.originY + (offsetY + transform.cameraY) * roomHeight)
|
||||
love.graphics.scale(transform.zoom, transform.zoom)
|
||||
level:draw(channels)
|
||||
love.graphics.pop()
|
||||
end
|
||||
|
||||
for roomY = -1, 1 do
|
||||
for roomX = -1, 1 do
|
||||
local name = self:roomAt(transform.location.x + roomX, transform.location.y + roomY)
|
||||
local adjacent = name and self.levels[name]
|
||||
if adjacent then
|
||||
drawAt(roomX, roomY, adjacent)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Each cardinal neighbour receives a second, real render through the active
|
||||
-- colours in the current room. The shader only chooses a wispy portion of
|
||||
-- the shared visible margin, preserving all literal RGB passes and sprites.
|
||||
if porousRoomCanvas and porousRoomBoundaryShader and #currentChannels > 0 then
|
||||
local targetCanvas = love.graphics.getCanvas()
|
||||
local directions = {
|
||||
{ x = -1, y = 0 }, { x = 1, y = 0 }, { x = 0, y = -1 }, { x = 0, y = 1 },
|
||||
}
|
||||
for _, direction in ipairs(directions) do
|
||||
local name = self:roomAt(transform.location.x + direction.x, transform.location.y + direction.y)
|
||||
local adjacent = name and self.levels[name]
|
||||
if adjacent then
|
||||
love.graphics.setCanvas(porousRoomCanvas)
|
||||
love.graphics.clear(0, 0, 0, 0)
|
||||
drawAt(direction.x, direction.y, adjacent, currentChannels)
|
||||
|
||||
love.graphics.setCanvas(targetCanvas)
|
||||
local roomLeft = transform.originX + (direction.x + transform.cameraX) * roomWidth
|
||||
local roomTop = transform.originY + (direction.y + transform.cameraY) * roomHeight
|
||||
porousRoomBoundaryShader:send("porousTime", love.timer.getTime())
|
||||
porousRoomBoundaryShader:send("porousRoomRect", {roomLeft, roomTop, roomWidth, roomHeight})
|
||||
porousRoomBoundaryShader:send("porousDirection", {direction.x, direction.y})
|
||||
-- Exactly the amount of the neighbour exposed by the zoom-out.
|
||||
porousRoomBoundaryShader:send("porousDepth", (1 - transform.zoom) * width / 2)
|
||||
love.graphics.setBlendMode("alpha")
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
love.graphics.setShader(porousRoomBoundaryShader)
|
||||
love.graphics.draw(porousRoomCanvas, 0, 0)
|
||||
love.graphics.setShader()
|
||||
end
|
||||
end
|
||||
love.graphics.setBlendMode("screen")
|
||||
end
|
||||
self.drawingRoomNeighborhood = false
|
||||
end
|
||||
|
||||
function World:getCellFromMousePos(mouseX, mouseY)
|
||||
return math.floor(mouseX / (width / self.width)) + 1, math.floor(mouseY / (height / self.height)) + 1
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue