diff --git a/CLAUDE.md b/CLAUDE.md index 62b720b..440711e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,12 +4,13 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## What this is -CHROMA SOLSTICE — a grid-based color-puzzle game written in Lua for the [LÖVE](https://love2d.org) framework. There is no build step, no test suite, and no package manifest; the whole game is the tree of `.lua` files loaded by `main.lua`. +CHROMA SOLSTICE — a grid-based color-puzzle game written in Lua for the [LÖVE](https://love2d.org) framework. There is no build step or package manifest; the whole game is the tree of `.lua` files loaded by `main.lua`. ## Running ```sh love . # run from the project root +lua tests/test_movement.lua # run the pure matrix-movement tests ``` `love` is not installed in this environment — you cannot run the game here; reason about the code statically. diff --git a/art/_ase_orig/jorge_idiot.xcf b/art/_ase_orig/jorge_idiot.xcf new file mode 100644 index 0000000..74fda9e Binary files /dev/null and b/art/_ase_orig/jorge_idiot.xcf differ diff --git a/art/npc/jorge.png b/art/npc/jorge.png new file mode 100644 index 0000000..f846edc Binary files /dev/null and b/art/npc/jorge.png differ diff --git a/art/npc/jorge_b.png b/art/npc/jorge_b.png new file mode 100644 index 0000000..cf0b407 Binary files /dev/null and b/art/npc/jorge_b.png differ diff --git a/art/npc/jorge_g.png b/art/npc/jorge_g.png new file mode 100644 index 0000000..f6af09b Binary files /dev/null and b/art/npc/jorge_g.png differ diff --git a/art/npc/jorge_r.png b/art/npc/jorge_r.png new file mode 100644 index 0000000..cefe93b Binary files /dev/null and b/art/npc/jorge_r.png differ diff --git a/art/npc/jorge_reduced.png b/art/npc/jorge_reduced.png new file mode 100644 index 0000000..7392401 Binary files /dev/null and b/art/npc/jorge_reduced.png differ diff --git a/box_variants.lua b/box_variants.lua new file mode 100644 index 0000000..ebce311 --- /dev/null +++ b/box_variants.lua @@ -0,0 +1,37 @@ +local BoxVariants = {} + +-- Add directional sticky-puller, rigid skewer, and soft all-edge spiky variants +-- for every authored moveable box. All share sprites/collision with their base. +function BoxVariants.addTo(assets) + local baseBoxes = {} + for name, properties in pairs(assets) do + if properties.class == "moveable" and name:match("^box") then + table.insert(baseBoxes, {name = name, properties = properties}) + end + end + + local function addVariant(base, prefix, behavior, directory, visualFlag) + local name = prefix .. base.name + local properties = { + class = behavior, + directory = directory, + sprites = base.properties.sprites, + cells = base.properties.cells, + preload = base.properties.preload, + synthetic = true, + baseAsset = base.name, + } + properties[visualFlag] = true + assets[name] = properties + end + + for _, base in ipairs(baseBoxes) do + addVariant(base, "sticky_", "sticky", "sticky", "goopy") + addVariant(base, "skewer_", "skewer", "skewer", "skewer") + addVariant(base, "spiky_", "spiky", "spiky", "spiky") + end + + return assets +end + +return BoxVariants diff --git a/entity.lua b/entity.lua index fc2adb2..e7ebb9b 100644 --- a/entity.lua +++ b/entity.lua @@ -14,6 +14,9 @@ function Entity:initialize(t) self.name = t.name self.color = Color:new(t.color) self.collision = t.collision --"none", "moveable", "unmoveable" + self.sticky = t.sticky or false + self.skewer = t.skewer or false + self.spiky = t.spiky or false self.sprite = repSprite self.shaAmount = t.sha or 1 -- onBump is a method (see Entity:onBump) so mixins like Dialogable can @@ -134,6 +137,18 @@ function Entity:canMove() return false end +function Entity:isSticky() + return self.sticky +end + +function Entity:isSkewer() + return self.skewer +end + +function Entity:isSpiky() + return self.spiky +end + function Entity:canPassOver() if self:getCollision() == "none" then return true diff --git a/generic_skewer.lua b/generic_skewer.lua new file mode 100644 index 0000000..19dea5d --- /dev/null +++ b/generic_skewer.lua @@ -0,0 +1,92 @@ +require "entity" + +GenericSkewer = class("GenericSkewer", Entity) + +local edgeDirections = { + {x = 1, y = 0}, {x = -1, y = 0}, + {x = 0, y = 1}, {x = 0, y = -1}, +} + +local function shapeHasCell(shape, x, y) + for _, cell in ipairs(shape) do + if cell.x == x and cell.y == y then return true end + end + return false +end + +-- Draw two teeth on every exposed cell edge. The art remains synthetic: the +-- underlying box sprite and its collision shape are still the authored base. +function drawSpikes(cellShape, x, y, scale) + cellShape = cellShape or {{x = 1, y = 1}} + local cellSize = 16 * scale + local inset = scale + local reach = 3 * scale + local halfBase = 1.5 * scale + + for _, cell in ipairs(cellShape) do + local left = x + (cell.x - 1) * cellSize + local top = y + (cell.y - 1) * cellSize + for _, direction in ipairs(edgeDirections) do + if not shapeHasCell(cellShape, cell.x + direction.x, cell.y + direction.y) then + for _, along in ipairs({5, 11}) do + if direction.x ~= 0 then + local edgeX = direction.x > 0 and left + cellSize - inset or left + inset + local centerY = top + along * scale + love.graphics.polygon("fill", + edgeX, centerY - halfBase, + edgeX + direction.x * reach, centerY, + edgeX, centerY + halfBase + ) + else + local edgeY = direction.y > 0 and top + cellSize - inset or top + inset + local centerX = left + along * scale + love.graphics.polygon("fill", + centerX - halfBase, edgeY, + centerX, edgeY + direction.y * reach, + centerX + halfBase, edgeY + ) + end + end + end + end + end +end + +function drawSkewerSprite(sprite, cellShape, x, y, scale) + drawSpikes(cellShape, x, y, scale) + love.graphics.draw(sprite, x, y, 0, scale, scale) +end + +function GenericSkewer:initialize(x, y, color, sprite, name, cellShape) + Entity.initialize(self, { + name = name, + x = x, + y = y, + color = color, + collision = "moveable", + skewer = true, + sprite = sprite, + cellShape = cellShape + }) +end + +function GenericSkewer:update() + +end + +function GenericSkewer:draw(channel) + local sprite = self.sprites[channel] + if not sprite then return end + love.graphics.setColor(gColor[channel]:set()) + local p = self:getDrawPos() + drawSkewerSprite( + sprite, self:getCellShape(), + p.x + self.drawOffset.x * drawScale, + p.y + self.drawOffset.y * drawScale, + drawScale + ) +end + +function GenericSkewer:tick() + +end diff --git a/generic_spiky.lua b/generic_spiky.lua new file mode 100644 index 0000000..73d25be --- /dev/null +++ b/generic_spiky.lua @@ -0,0 +1,46 @@ +require "entity" +require "generic_skewer" + +GenericSpiky = class("GenericSpiky", Entity) + +function drawSpikySprite(sprite, _, x, y, scale) + if drawGoopySprite then + drawGoopySprite(sprite, x, y, scale) + else + love.graphics.draw(sprite, x, y, 0, scale, scale) + end +end + +function GenericSpiky:initialize(x, y, color, sprite, name, cellShape) + Entity.initialize(self, { + name = name, + x = x, + y = y, + color = color, + collision = "moveable", + spiky = true, + sprite = sprite, + cellShape = cellShape + }) +end + +function GenericSpiky:update() + +end + +function GenericSpiky:draw(channel) + local sprite = self.sprites[channel] + if not sprite then return end + love.graphics.setColor(gColor[channel]:set()) + local p = self:getDrawPos() + drawSpikySprite( + sprite, self:getCellShape(), + p.x + self.drawOffset.x * drawScale, + p.y + self.drawOffset.y * drawScale, + drawScale + ) +end + +function GenericSpiky:tick() + +end diff --git a/generic_sticky.lua b/generic_sticky.lua new file mode 100644 index 0000000..98b8717 --- /dev/null +++ b/generic_sticky.lua @@ -0,0 +1,42 @@ +require "entity" + +GenericSticky = class("GenericSticky", Entity) + +function GenericSticky:initialize(x, y, color, sprite, name, cellShape) + Entity.initialize(self, { + name = name, + x = x, + y = y, + color = color, + collision = "moveable", + sticky = true, + sprite = sprite, + cellShape = cellShape + }) +end + +function GenericSticky:update() + +end + +function GenericSticky:draw(channel) + local sprite = self.sprites[channel] + if not sprite then return end + if not drawGoopySprite then + Entity.draw(self, channel) + return + end + + love.graphics.setColor(gColor[channel]:set()) + local p = self:getDrawPos() + drawGoopySprite( + sprite, + p.x + self.drawOffset.x * drawScale, + p.y + self.drawOffset.y * drawScale, + drawScale + ) +end + +function GenericSticky:tick() + +end diff --git a/level_editor/editor.lua b/level_editor/editor.lua index 524b9a5..c242840 100644 --- a/level_editor/editor.lua +++ b/level_editor/editor.lua @@ -3,7 +3,7 @@ require "level_editor/gui" require "level_editor/layout" editorView = "room" --can be "off", "room", "world", "asset" -selectedColor = "red" +selectedColor = "white" local bacSprite = love.graphics.newImage("art/_ui/bac.png") local folderSprite = love.graphics.newImage("art/_ui/folder.png") @@ -34,8 +34,6 @@ local roomNameField = nil local editorStatus = nil local clearSaveConfirmationExpires = 0 local clearSaveConfirmationScope = nil -local worldSeedConfirmationExpires = 0 -local worldMode = "place" local worldRoomButtons = {} local worldControls = {} local worldPage = 1 @@ -44,6 +42,61 @@ local assetSearchText = "" local assetSearchButtons = {} local worldSearchText = "" local worldSearchBox = { x = 10, y = 34, w = 0, h = 28 } +local cloneSourceRoom = nil +local roomBrush = nil +local boxPaletteOpen = false +local boxPaletteScroll = { scroll = 0 } +local boxPaletteSections = {} + +-- Convert a pointer position into a valid room cell. Keeping brush state in +-- cell coordinates means a click that jitters within a tile cannot place or +-- 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 + 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:attemptPlace(selectedAsset, gameAssets[selectedAsset], x, y, selectedColor) + elseif button == 2 then + currentRoom:attemptDelete(x, y, selectedColor) + end +end + +local function paintRoomLine(from, to, button) + -- Bresenham keeps a fast mouse movement from leaving holes between the + -- cells that happened to receive mouse-move events. + local x, y = from.x, from.y + local dx, dy = math.abs(to.x - x), math.abs(to.y - y) + local stepX = x < to.x and 1 or -1 + local stepY = y < to.y and 1 or -1 + local err = dx - dy + + while true do + if x ~= from.x or y ~= from.y then paintRoomCell({ x = x, y = y }, button) end + if x == to.x and y == to.y then break end + local twiceErr = err * 2 + if twiceErr > -dy then err = err - dy; x = x + stepX end + if twiceErr < dx then err = err + dx; y = y + stepY end + end +end + +local function beginRoomBrush(x, y, button) + if button ~= 1 and button ~= 2 then return end + if button == 1 and not selectedAsset then return end + local cell = roomCellAt(x, y) + if not cell then return end + paintRoomCell(cell, button) + roomBrush = { button = button, lastCell = cell } +end -- ── Room-view sidebar layout ──────────────────────────────────────────────── -- Declared up here (not next to editorDraw) so editorMouseHandler, defined @@ -56,6 +109,120 @@ local function currentRoomList() else return assetListButtons end end +local function rebuildBoxPaletteSections() + boxPaletteSections = {} + for _, prefix in ipairs({ "box", "spiky", "sticky", "skewer" }) do + local names = {} + local pattern = prefix == "box" and "^box" or "^" .. prefix .. "_box" + for name in pairs(gameAssets) do + if name:match(pattern) then table.insert(names, name) end + end + table.sort(names) + table.insert(boxPaletteSections, { prefix = prefix, names = names }) + end +end + +local function buildBoxPicker(rect) + local gap, cellSize, headerH = 4, 51, 18 + local function contentMetrics(size) + local columns = math.max(1, math.floor((rect.w + gap) / (size + gap))) + local height = 0 + for _, section in ipairs(boxPaletteSections) do + height = height + headerH + math.ceil(#section.names / columns) * (size + gap) + gap + end + return columns, height + end + + -- Keep the picker to one screen when the sidebar is tall enough, while + -- preserving a usable minimum tile size for unusually short sidebars. + local columns, contentHeight = contentMetrics(cellSize) + while cellSize > 20 and contentHeight > rect.h do + cellSize = cellSize - 1 + columns, contentHeight = contentMetrics(cellSize) + end + local contentY, sections, items = 0, {}, {} + + for _, section in ipairs(boxPaletteSections) do + table.insert(sections, { prefix = section.prefix, y = contentY }) + contentY = contentY + headerH + for index, name in ipairs(section.names) do + local column = (index - 1) % columns + local row = math.floor((index - 1) / columns) + table.insert(items, { + name = name, + x = rect.x + column * (cellSize + gap), + y = contentY + row * (cellSize + gap), + w = cellSize, + h = cellSize, + }) + end + contentY = contentY + math.ceil(#section.names / columns) * (cellSize + gap) + gap + end + + local maxScroll = math.max(0, contentY - rect.h) + boxPaletteScroll.scroll = math.max(0, math.min(boxPaletteScroll.scroll or 0, maxScroll)) + local picker = { rect = rect, sections = sections, items = items, maxScroll = maxScroll, scroll = boxPaletteScroll.scroll } + function picker.at(x, y) + if not Layout.hit(rect, x, y) then return nil end + local contentYAtMouse = y - rect.y + picker.scroll + for _, item in ipairs(items) do + if x >= item.x and x < item.x + item.w and contentYAtMouse >= item.y and contentYAtMouse < item.y + item.h then + return item.name + end + end + end + return picker +end + +local function drawPaletteAsset(name, x, y, size) + local props = gameAssets[name] + if not props or not props.sprites then return end + local maxW, maxH = 1, 1 + for _, path in pairs(props.sprites) do + local sprite = loadSprite(path) + maxW, maxH = math.max(maxW, sprite:getWidth()), math.max(maxH, sprite:getHeight()) + end + local scale = math.min((size - 6) / maxW, (size - 6) / maxH) + local drawX = x + (size - maxW * scale) / 2 + local drawY = y + (size - maxH * scale) / 2 + for color, path in pairs(props.sprites) do + local sprite = loadSprite(path) + love.graphics.setColor(gColor[color]:set()) + if props.goopy and drawGoopySprite then + drawGoopySprite(sprite, drawX, drawY, scale) + elseif props.skewer and drawSkewerSprite then + drawSkewerSprite(sprite, props.cells and props.cells[color], drawX, drawY, scale) + elseif props.spiky and drawSpikySprite then + drawSpikySprite(sprite, props.cells and props.cells[color], drawX, drawY, scale) + else + love.graphics.draw(sprite, drawX, drawY, 0, scale, scale) + end + end +end + +local function drawBoxPicker(picker) + Layout.clip(picker.rect) + for _, section in ipairs(picker.sections) do + love.graphics.setColor(gColor.white:set()) + love.graphics.print(section.prefix, picker.rect.x, picker.rect.y + section.y - picker.scroll) + end + for _, item in ipairs(picker.items) do + local y = picker.rect.y + item.y - picker.scroll + if y + item.h > picker.rect.y and y < picker.rect.y + picker.rect.h then + love.graphics.setColor(1, 1, 1, 0.45) + love.graphics.rectangle("line", item.x, y, item.w, item.h) + drawPaletteAsset(item.name, item.x, y, item.w) + if item.name == selectedAsset then + love.graphics.setColor(1, 0.85, 0.2, 1) + love.graphics.setLineWidth(2) + love.graphics.rectangle("line", item.x + 1, y + 1, item.w - 2, item.h - 2) + end + end + end + Layout.unclip() + Layout.scrollbar(picker) +end + -- Carve the sidebar into fixed, non-overlapping "divs": a search header pinned -- to the top, a control cluster pinned to the bottom, a status strip above it, -- and a flexible list filling whatever is left. Recomputed every frame so it @@ -63,7 +230,7 @@ end local function roomSections() local pad = 10 local w = math.max(0, sb.w - pad * 2) - local controlsH = 104 + local controlsH = 130 local statusH = 44 local search = { x = pad, y = pad, w = w, h = 34 } local controls = { x = pad, y = sb.h - pad - controlsH, w = w, h = controlsH } @@ -92,10 +259,17 @@ local function layoutRoomControls(c, s) -- lives here instead of being scattered across the creation calls. local function sizeBtn(name, target) local b = uiButtons[name] - if b and b.sprite then - b.scale = target / b.sprite:getHeight() - b.w = b.sprite:getWidth() * b.scale - b.h = b.sprite:getHeight() * b.scale + if b and b.sprite then + b.scale = target / b.sprite:getHeight() + b.w = b.sprite:getWidth() * b.scale + b.h = b.sprite:getHeight() * b.scale + elseif b and b.sprites then + local spriteW, spriteH = 1, 1 + for _, sprite in pairs(b.sprites) do + spriteW, spriteH = math.max(spriteW, sprite:getWidth()), math.max(spriteH, sprite:getHeight()) + end + b.scale = math.min(target / spriteW, target / spriteH) + b.w, b.h = spriteW * b.scale, spriteH * b.scale end return b end @@ -119,6 +293,7 @@ local function layoutRoomControls(c, s) end placeRow({ "white", "red", "green", "blue" }, 22) + placeRow({ "quick_player", "quick_static_wall", "quick_switch", "quick_door", "quick_box" }, 22) placeRow({ "save", "clearSaves", "world" }, 28) end @@ -127,7 +302,7 @@ end local function buildRoomLayout() local s = roomSections() - local showBack = assetSearchText ~= "" or selectedFolder + local showBack = assetSearchText ~= "" or selectedFolder or boxPaletteOpen local sx, sw = s.search.x, s.search.w if showBack then s.back = { x = s.search.x, y = s.search.y, w = s.search.h, h = s.search.h } @@ -136,8 +311,12 @@ local function buildRoomLayout() end s.searchBox = { x = sx, y = s.search.y, w = sw, h = s.search.h } - s.items = currentRoomList() - s.list = Layout.list(listScroll, s.listRect, 40, #s.items, 2) + if boxPaletteOpen then + s.boxPicker = buildBoxPicker(s.listRect) + else + s.items = currentRoomList() + s.list = Layout.list(listScroll, s.listRect, 40, #s.items, 2) + end layoutRoomControls(s.controls, s) return s @@ -145,7 +324,8 @@ end -- Mouse wheel scrolls the room list; clamped by Layout.list next frame. function editorScrollRoomList(dy) - listScroll.scroll = math.max(0, (listScroll.scroll or 0) - dy * 40) + local scroll = boxPaletteOpen and boxPaletteScroll or listScroll + scroll.scroll = math.max(0, (scroll.scroll or 0) - dy * 40) end -- ──────────────────────────────────────────────────────────────────────────── @@ -182,6 +362,10 @@ local function rebuildAssetSearchButtons() for color, location in pairs(gameAssets[asset].sprites) do sprites[color] = love.graphics.newImage(location) end table.insert(assetSearchButtons, createUIElement{ sprites = sprites, + goopy = gameAssets[asset].goopy, + skewer = gameAssets[asset].skewer, + spiky = gameAssets[asset].spiky, + cells = gameAssets[asset].cells, name = "asset", text = asset, x = 30, @@ -210,21 +394,6 @@ local function rebuildWorldRoomButtons() table.insert(worldRoomButtons, { name = roomName, x = 10, y = 70 + row * 68, w = sb.w - 20, h = 60 }) end worldControls = { - { text = worldMode == "place" and "MODE: PLACE ROOMS" or "MODE: OPEN LEVELS", x = 10, y = sb.h - 194, w = sb.w - 20, h = 34, - onClic = function() worldMode = worldMode == "place" and "jump" or "place"; rebuildWorldRoomButtons() end }, - { text = "RESEED OLD EXITS", x = 10, y = sb.h - 152, w = sb.w - 20, h = 34, - onClic = function() - local now = love.timer.getTime() - if now > worldSeedConfirmationExpires then - worldSeedConfirmationExpires = now + 3 - editorStatus = "Click RESEED OLD EXITS again within 3 seconds to replace the current map." - return - end - worldSeedConfirmationExpires = 0 - local result = seedWorldFromLegacyExits(gameWorld) - editorStatus = "Seeded " .. result.placed .. " rooms; " .. result.links .. " legacy links (" .. result.conflicts .. " conflicts kept separate)." - rebuildWorldRoomButtons() - end }, { text = "< PAGE " .. worldPage .. "/" .. pages .. " >", x = 10, y = sb.h - 110, w = sb.w - 20, h = 34, onClic = function(buttonX) if buttonX < sb.w / 2 then worldPage = math.max(1, worldPage - 1) else worldPage = math.min(pages, worldPage + 1) end @@ -235,10 +404,20 @@ end local function drawWorldSidebar() love.graphics.setColor(gColor.white:set()) - love.graphics.printf("ROOMS — " .. (worldMode == "place" and "select to place; re-click to clear" or "click a map room to open"), 8, 6, sb.w - 16, "center") worldSearchBox.w = sb.w - 20 - love.graphics.rectangle("line", worldSearchBox.x, worldSearchBox.y, worldSearchBox.w, worldSearchBox.h) - love.graphics.printf("SEARCH: " .. worldSearchText, worldSearchBox.x + 6, worldSearchBox.y + 7, worldSearchBox.w - 12, "left") + if activeField == "cloneName" then + love.graphics.printf("CLONE '" .. cloneSourceRoom .. "' AS:", 8, 6, sb.w - 16, "center") + love.graphics.rectangle("line", worldSearchBox.x, worldSearchBox.y, worldSearchBox.w, worldSearchBox.h) + love.graphics.printf(inputText, worldSearchBox.x + 6, worldSearchBox.y + 7, sb.w - 32, "left") + love.graphics.printf("Press Enter to create and select the clone. Esc cancels.", 8, worldSearchBox.y + 34, sb.w - 16, "center") + else + local instructions = selectedRoom + and "placing '" .. selectedRoom .. "' — click a map cell" + or "click a map cell to open or create; select a room below to place it" + love.graphics.printf("ROOMS — " .. instructions, 8, 6, sb.w - 16, "center") + love.graphics.rectangle("line", worldSearchBox.x, worldSearchBox.y, worldSearchBox.w, worldSearchBox.h) + love.graphics.printf("SEARCH: " .. worldSearchText, worldSearchBox.x + 6, worldSearchBox.y + 7, worldSearchBox.w - 12, "left") + end for _, button in ipairs(worldRoomButtons) do love.graphics.setColor(button.name == selectedRoom and 1 or 100 / 255, button.name == selectedRoom and 1 or 100 / 255, button.name == selectedRoom and 1 or 100 / 255, 1) love.graphics.rectangle("line", button.x, button.y, button.w, button.h) @@ -290,8 +469,8 @@ local function saveRoomFromEditor() return end - local savePlayerPositions = love.keyboard.isDown("lshift", "rshift") - if not currentRoom:saveToSource(name, savePlayerPositions, oldName) then + local savePlayerPositions = not love.keyboard.isDown("lshift", "rshift") + if not currentRoom:saveToSource(name, savePlayerPositions) then editorStatus = "Could not save '" .. name .. "'." return end @@ -302,13 +481,18 @@ local function saveRoomFromEditor() removeFromSource("rooms/" .. oldName .. ".sav") gameWorld:renameRoom(oldName, name) end + -- The project source is now authoritative. Drop any runtime copy so it + -- cannot shadow this editor save the next time the game starts. + clearRuntimeSaveData(name) + if oldName and oldName ~= name then clearRuntimeSaveData(oldName) end + suppressRuntimeAutosave = true gameWorld:invalidatePreview(name) if editorView == "world" then rebuildWorldRoomButtons() end currentRoom.name = name editorRoomName = name roomNameField:editText(name) activeField = nil - editorStatus = "Saved source level '" .. name .. "'" .. (savePlayerPositions and " with player positions." or ".") + editorStatus = "Saved source level '" .. name .. "'" .. (savePlayerPositions and " with player positions." or " without player positions.") end local function clearRuntimeSaves() @@ -328,6 +512,7 @@ local function clearRuntimeSaves() end local removed = clearRuntimeSaveData(clearAll and nil or roomName) + suppressRuntimeAutosave = true clearSaveConfirmationExpires = 0 clearSaveConfirmationScope = nil if roomName then @@ -342,6 +527,7 @@ end function _initLevelEditor() gameAssets = getAllAssets() + rebuildBoxPaletteSections() editorRoomName = "" --create folder buttons @@ -440,6 +626,25 @@ function _initLevelEditor() }, color) end + for _, asset in ipairs({ "player", "static_wall", "switch", "door", "box" }) do + local properties = gameAssets[asset] + if properties then + local sprites = {} + for color, path in pairs(properties.sprites) do sprites[color] = love.graphics.newImage(path) end + _addUIButton(createUIElement{ + name = "quick_" .. asset, + sprites = sprites, + goopy = properties.goopy, + skewer = properties.skewer, + spiky = properties.spiky, + cells = properties.cells, + onClic = { left = function() selectQuickAsset(asset) end }, + x = 0, + y = 0, + }, "quick_" .. asset) + end + end + roomNameField = createUIElement{ name = "roomName", text = editorRoomName, @@ -464,6 +669,7 @@ end function selectFolder(folder) selectedFolder = folder + boxPaletteOpen = false listScroll.scroll = 0 assetListButtons = {} @@ -478,13 +684,19 @@ function selectFolder(folder) -- each frame from the list section (see buildRoomLayout). table.insert(assetListButtons, createUIElement{ sprites = sprites, + goopy = gameAssets[asset].goopy, + skewer = gameAssets[asset].skewer, + spiky = gameAssets[asset].spiky, + cells = gameAssets[asset].cells, name = "asset", text = asset, x = 30, y = 0, onClic = { left = function() selectAsset(asset) end, - right = function() editAsset(asset) end, + right = function() + if not gameAssets[asset].synthetic then editAsset(asset) end + end, } }) end @@ -496,6 +708,12 @@ function selectAsset(asset) print(selectedAsset) end +function selectQuickAsset(asset) + selectAsset(asset) + boxPaletteOpen = asset == "box" + boxPaletteScroll.scroll = 0 +end + function editAsset(asset) inputText = "" editorView = "asset" @@ -541,6 +759,10 @@ function editAsset(asset) local assetButton = createUIElement{ name = asset, sprites = assetSprites, + goopy = assetProperties.goopy, + skewer = assetProperties.skewer, + spiky = assetProperties.spiky, + cells = assetProperties.cells, x = sb.w / 2 - 18, y = 80, } @@ -619,7 +841,8 @@ function worldView() editorView = "world" activeField = nil selectedFolder = nil - worldMode = "place" + selectedRoom = nil + cloneSourceRoom = nil worldPage = 1 rebuildWorldRoomButtons() end @@ -634,6 +857,36 @@ local function newWorldRoomName(cellX, cellY) return name end +local function cloneWorldRoom(sourceName, cloneName) + local source = readFromSource("rooms/" .. sourceName .. ".sav") + if not source then + editorStatus = "Could not find source level '" .. sourceName .. "'." + return false + end + if readFromSource("rooms/" .. cloneName .. ".sav") then + editorStatus = "A level named '" .. cloneName .. "' already exists." + return false + end + if not writeToSource("rooms/" .. cloneName .. ".sav", source) then + editorStatus = "Could not create clone '" .. cloneName .. "'." + return false + end + + gameWorld:invalidatePreview(cloneName) + selectedRoom = cloneName + rebuildWorldRoomButtons() + editorStatus = "Cloned '" .. sourceName .. "' as '" .. cloneName .. "'. Click a map cell to place it." + return true +end + +local function beginCloneDialog(sourceName) + cloneSourceRoom = sourceName + activeField = "cloneName" + inputText = "" + response = "" + editorStatus = "Enter a name for the clone." +end + local function openWorldRoom(cellX, cellY) local name = gameWorld:roomAt(cellX, cellY) if not name then @@ -673,24 +926,36 @@ function editorMouseHandler(x, y, button) rebuildAssetSearchButtons() elseif selectedFolder then folderView() + elseif boxPaletteOpen then + boxPaletteOpen = false + boxPaletteScroll.scroll = 0 end return end if Layout.hit(s.searchBox, x, y) then + boxPaletteOpen = false beginSearch("assetSearch") return end - -- scrolling list item - local i = s.list.at(x, y) - if i and s.items[i] then - s.items[i]:onClic(button) - return + if s.boxPicker then + local asset = s.boxPicker.at(x, y) + if asset then + if button == 1 then selectAsset(asset) end + return + end + else + -- scrolling list item + local i = s.list.at(x, y) + if i and s.items[i] then + s.items[i]:onClic(button) + return + end end -- control cluster (only the buttons that live there) - for _, name in ipairs({ "roomName", "white", "red", "green", "blue", "save", "clearSaves", "world" }) do + for _, name in ipairs({ "roomName", "white", "red", "green", "blue", "quick_player", "quick_static_wall", "quick_switch", "quick_door", "quick_box", "save", "clearSaves", "world" }) do local b = uiButtons[name] if b and b:clicIsInBox(x, y) then b:onClic(button) @@ -704,18 +969,20 @@ function editorMouseHandler(x, y, button) end end elseif editorView == "world" then + if activeField == "cloneName" then return end if buttonContains(worldSearchBox, x, y) then beginSearch("worldSearch") return end for _, roomButton in ipairs(worldRoomButtons) do if buttonContains(roomButton, x, y) then + if button ~= 1 then return end if selectedRoom == roomButton.name then selectedRoom = nil - editorStatus = "Room brush cleared. Click the map to open or create a level." + editorStatus = "Placement cancelled. Click the map to open or create a level." else selectedRoom = roomButton.name - editorStatus = "Selected '" .. selectedRoom .. "' for placement. Click it again to clear." + editorStatus = "Selected '" .. selectedRoom .. "'. Click a map cell to place it." end return end @@ -730,24 +997,53 @@ function editorMouseHandler(x, y, button) end else -- click landed on the grid (game area): place the selected asset - if editorView == "room" and button == 1 and selectedAsset then - currentRoom:attemptPlace(selectedAsset, gameAssets[selectedAsset], x, y, selectedColor) + if editorView == "room" then + beginRoomBrush(x, y, button) elseif editorView == "world" then local cellX, cellY = gameWorld:getCellFromMousePos(x, y) if not gameWorld:isInBounds(cellX, cellY) then return end if button == 2 then - local removed, name = gameWorld:removeRoom(cellX, cellY) - if removed then editorStatus = "Removed '" .. name .. "' from the world." end - elseif worldMode == "jump" or not selectedRoom then - openWorldRoom(cellX, cellY) + local name = gameWorld:roomAt(cellX, cellY) + if name then beginCloneDialog(name) end elseif selectedRoom then - gameWorld:placeRoom(selectedRoom, cellX, cellY) - editorStatus = "Placed '" .. selectedRoom .. "' at " .. cellX .. ", " .. cellY .. "." + local placedRoom = selectedRoom + if gameWorld:placeRoom(placedRoom, cellX, cellY) then + selectedRoom = nil + editorStatus = "Placed '" .. placedRoom .. "' at " .. cellX .. ", " .. cellY .. "." + else + editorStatus = "Could not place '" .. placedRoom .. "'." + end + else + openWorldRoom(cellX, cellY) end end end end +function editorMouseMoved(x, y) + if not roomBrush then return end + if editorView ~= "room" then + roomBrush = nil + return + end + + local cell = roomCellAt(x, y) + if not cell then + -- Leaving the grid ends this stroke; re-entering should not draw a line + -- across the sidebar or outside of the level. + roomBrush = nil + return + end + if cell.x == roomBrush.lastCell.x and cell.y == roomBrush.lastCell.y then return end + + paintRoomLine(roomBrush.lastCell, cell, roomBrush.button) + roomBrush.lastCell = cell +end + +function editorMouseReleased(_, _, button) + if roomBrush and roomBrush.button == button then roomBrush = nil end +end + function editorTextHandler(text) if editorView == "asset" and activeField then inputText = text @@ -764,6 +1060,8 @@ function editorTextHandler(text) worldSearchText = text worldPage = 1 rebuildWorldRoomButtons() + elseif editorView == "world" and activeField == "cloneName" then + inputText = text end end @@ -776,10 +1074,32 @@ function editorCompleteResponse() assetSearchText = inputText elseif editorView == "world" and activeField == "worldSearch" then worldSearchText = inputText + elseif editorView == "world" and activeField == "cloneName" then + local cloneName, err = validRoomName(inputText) + if not cloneName then + editorStatus = err + return + end + local sourceName = cloneSourceRoom + if cloneWorldRoom(sourceName, cloneName) then + cloneSourceRoom = nil + activeField = nil + end + return end activeField = nil end +function editorCancelResponse() + if editorView ~= "world" or activeField ~= "cloneName" then return false end + activeField = nil + cloneSourceRoom = nil + inputText = "" + response = "" + editorStatus = "Clone cancelled." + return true +end + function sortAllAssets() setAll() end @@ -796,29 +1116,51 @@ function editorDraw() -- header: optional back button + search box if s.back then love.graphics.rectangle("line", s.back.x, s.back.y, s.back.w, s.back.h) - local sc = (s.back.h - 8) / bacSprite:getHeight() - love.graphics.draw(bacSprite, s.back.x + 4, s.back.y + 4, 0, sc, sc) - end - love.graphics.rectangle("line", s.searchBox.x, s.searchBox.y, s.searchBox.w, s.searchBox.h) - love.graphics.printf("SEARCH: " .. assetSearchText, s.searchBox.x + 6, s.searchBox.y + 9, s.searchBox.w - 12, "left") - - -- scrolling list, clipped to its section so nothing bleeds into others - Layout.clip(s.listRect) - for i, item in ipairs(s.items) do - if s.list.visible(i) then - item.x, item.y = s.list.pos(i) - item.w = s.listRect.w - item:draw() + if boxPaletteOpen then + love.graphics.printf("X", s.back.x, s.back.y + 9, s.back.w, "center") + else + local sc = (s.back.h - 8) / bacSprite:getHeight() + love.graphics.draw(bacSprite, s.back.x + 4, s.back.y + 4, 0, sc, sc) end end - Layout.unclip() - Layout.scrollbar(s.list) + love.graphics.rectangle("line", s.searchBox.x, s.searchBox.y, s.searchBox.w, s.searchBox.h) + love.graphics.printf(boxPaletteOpen and "BOX VARIANTS" or "SEARCH: " .. assetSearchText, s.searchBox.x + 6, s.searchBox.y + 9, s.searchBox.w - 12, "left") + + if s.boxPicker then + drawBoxPicker(s.boxPicker) + else + -- Scrolling list, clipped to its section so nothing bleeds into others. + Layout.clip(s.listRect) + for i, item in ipairs(s.items) do + if s.list.visible(i) then + item.x, item.y = s.list.pos(i) + item.w = s.listRect.w + item:draw() + if item.name == "asset" and item.text == selectedAsset then + love.graphics.setColor(1, 0.85, 0.2, 1) + love.graphics.setLineWidth(3) + love.graphics.rectangle("line", item.x + 1, item.y + 1, item.w - 2, item.h - 2) + end + end + end + Layout.unclip() + Layout.scrollbar(s.list) + end -- control cluster love.graphics.setColor(gColor.white:set()) love.graphics.printf("LEVEL NAME", s.controls.x, s.labelY, s.controls.w, "center") - for _, name in ipairs({ "roomName", "white", "red", "green", "blue", "save", "clearSaves", "world" }) do - if uiButtons[name] then uiButtons[name]:draw() end + for _, name in ipairs({ "roomName", "white", "red", "green", "blue", "quick_player", "quick_static_wall", "quick_switch", "quick_door", "quick_box", "save", "clearSaves", "world" }) do + local button = uiButtons[name] + if button then + button:draw() + local asset = name:match("^quick_(.+)$") + if asset and selectedAsset == asset then + love.graphics.setColor(1, 0.85, 0.2, 1) + love.graphics.setLineWidth(2) + love.graphics.rectangle("line", button.x - 1, button.y - 1, button.w + 2, button.h + 2) + end + end end -- status strip between the list and the controls diff --git a/level_editor/gui.lua b/level_editor/gui.lua index 55db806..1008ed7 100644 --- a/level_editor/gui.lua +++ b/level_editor/gui.lua @@ -9,6 +9,10 @@ function GUI:initialize(t) self.offset = {x = 0, y = 0} self.name = t.name self.text = t.text + self.goopy = t.goopy or false + self.skewer = t.skewer or false + self.spiky = t.spiky or false + self.cells = t.cells if not t.onClic then t.onClic = {} @@ -99,7 +103,15 @@ function GUI:draw() if self.sprites then for color, sprite in pairs(self.sprites) do love.graphics.setColor(gColor[color]:set()) - love.graphics.draw(sprite, box.x, box.y, 0, self.scale, self.scale) + if self.goopy and drawGoopySprite then + drawGoopySprite(sprite, box.x, box.y, self.scale) + elseif self.skewer and drawSkewerSprite then + drawSkewerSprite(sprite, self.cells and self.cells[color], box.x, box.y, self.scale) + elseif self.spiky and drawSpikySprite then + drawSpikySprite(sprite, self.cells and self.cells[color], box.x, box.y, self.scale) + else + love.graphics.draw(sprite, box.x, box.y, 0, self.scale, self.scale) + end end end diff --git a/level_editor/object_attributes.lua b/level_editor/object_attributes.lua index 71f0a64..9cab6c9 100644 --- a/level_editor/object_attributes.lua +++ b/level_editor/object_attributes.lua @@ -1,5 +1,7 @@ require "libs/TSerial" +local BoxVariants = require "box_variants" + local targetFolder = "art" local reanalyzeCells = true @@ -57,5 +59,5 @@ function getAllAssets() end end - return globalAssetProperties + return BoxVariants.addTo(globalAssetProperties) end diff --git a/main.lua b/main.lua index cde834c..2d0b76a 100644 --- a/main.lua +++ b/main.lua @@ -23,6 +23,7 @@ require "level_editor/editor" love.filesystem.setRequirePath(love.filesystem.getRequirePath() .. ";libs/narrator/?.lua") narrator = require "narrator.narrator" startSignBook = require "stories.start_sign" +jorgeBook = require "stories.jorge" function love.load() globalAssetProperties = {} -- rebuilt from the filesystem (art/ + .meta) by getAllAssets @@ -31,6 +32,7 @@ function love.load() _initGridVars() _initSounds() _initGlobalColors() + _initAccessibility() gameWorld = World:new() _initLevelEditor() @@ -54,7 +56,9 @@ end -- Autosave on close so a position reached by moving within a room (short of a -- room-to-room transition, which already autosaves in nextRoom) survives. function love.quit() - if currentRoom then + -- An explicit editor save/clear removes the runtime copy intentionally; + -- don't immediately recreate it while shutting down. + if currentRoom and not suppressRuntimeAutosave then currentRoom:save() if gameWorld then gameWorld:setLastRoom(currentRoom.name) end end @@ -116,16 +120,42 @@ function love.draw() love.graphics.pop() love.graphics.setCanvas() + -- Collect every visible layer before the accessibility pass. Applying the + -- shader here also covers the editor sidebar, FPS display, and dialogue, + -- rather than only recolouring the room sprites. + love.graphics.setCanvas(presentationCanvas) + love.graphics.clear() love.graphics.setBlendMode("alpha") love.graphics.setColor(1, 1, 1, 1) 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) - Dialogue.draw() + love.graphics.setCanvas() + + love.graphics.setColor(1, 1, 1, 1) + local filter = accessibilityModes[accessibilityModeIndex] + if filter.shader then + filter.shader:send("accessibilityTime", love.timer.getTime()) + love.graphics.setShader(filter.shader) + end + love.graphics.draw(presentationCanvas, 0, 0) + love.graphics.setShader() + + if accessibilityMessage and love.timer.getTime() < accessibilityMessageExpires then + love.graphics.setColor(1, 1, 1, 1) + love.graphics.printf(accessibilityMessage, 0, 30, love.graphics.getWidth(), "center") + end end function love.keypressed(key) + -- 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 + cycleAccessibilityMode() + return + end + -- Talking to a sign captures input: navigate/choose, don't move the player. if Dialogue.isOpen() then Dialogue.keypressed(key) @@ -150,6 +180,8 @@ function love.keypressed(key) if key == "return" then response = "" editorCompleteResponse() + elseif key == "escape" and editorCancelResponse() then + return elseif key == "backspace" then local byteoffset = utf8.offset(response, -1) @@ -163,12 +195,17 @@ function love.keypressed(key) end function love.mousepressed(x, y, button) - if editorView == "room" and button == 2 then - currentRoom:attemptDelete(x, y, selectedColor) - end editorMouseHandler(x, y, button) end +function love.mousemoved(x, y) + editorMouseMoved(x, y) +end + +function love.mousereleased(x, y, button) + editorMouseReleased(x, y, button) +end + function love.textinput(t) response = response .. t editorTextHandler(response) @@ -237,6 +274,7 @@ end function _initCanvases() gameCanvas = love.graphics.newCanvas() finalCanvas = love.graphics.newCanvas() + presentationCanvas = 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 @@ -253,6 +291,37 @@ function _initGlobalColors() gColor.red, gColor.green, gColor.blue, gColor.white = Color:new("red"), Color:new("green"), Color:new("blue"), Color:new("white") end +function _initAccessibility() + accessibilityModes = { + { id = "normal", label = "Normal", shader = nil }, + { id = "deuteranopia", label = "Deuteranopia", shader = accessibilityColorShader }, + } + accessibilityModeIndex = 1 + + local savedMode = love.filesystem.read("accessibility_mode.txt") + if savedMode then + savedMode = savedMode:match("[%w_]+") + if savedMode == "deuteranopia_high_contrast" then savedMode = "deuteranopia" end + for index, mode in ipairs(accessibilityModes) do + if mode.id == savedMode then + accessibilityModeIndex = index + break + end + end + end + local mode = accessibilityModes[accessibilityModeIndex] + accessibilityMessage = "Color filter: " .. mode.label .. " (F4 to change)" + accessibilityMessageExpires = love.timer.getTime() + 4 +end + +function cycleAccessibilityMode() + accessibilityModeIndex = accessibilityModeIndex % #accessibilityModes + 1 + local mode = accessibilityModes[accessibilityModeIndex] + love.filesystem.write("accessibility_mode.txt", mode.id) + accessibilityMessage = "Color filter: " .. mode.label .. " (F4 to change)" + accessibilityMessageExpires = love.timer.getTime() + 2.5 +end + function _initSounds() staticWave = sfxr.newSound() staticWave.waveform = sfxr.WAVEFORM.NOISE -- was `wavetype = 3`; field renamed in this sfxr diff --git a/movement.lua b/movement.lua new file mode 100644 index 0000000..b21fe6d --- /dev/null +++ b/movement.lua @@ -0,0 +1,143 @@ +-- Finds the complete set of blocks that must move together for one grid step. +-- A block joins the set when it is in another block's destination (ordinary +-- pushing), is softly grabbed by sticky/spiky, or touches a rigid skewer. +local Movement = {} + +local adjacentDirections = { + {x = 1, y = 0}, + {x = -1, y = 0}, + {x = 0, y = 1}, + {x = 0, y = -1}, +} + +local function isSticky(entity) + return entity.isSticky and entity:isSticky() +end + +local function isPassable(entity) + return entity.canPassOver and entity:canPassOver() +end + +local function isSkewer(entity) + return entity.isSkewer and entity:isSkewer() +end + +local function isSpiky(entity) + return entity.isSpiky and entity:isSpiky() +end + +-- Build one rigid component: ordinary pushes are required, and skewers join +-- along every edge. `alreadyMoving` contains cells that will be vacated during +-- this same step, so a later pulled component may move into them. +local function findRigidGroup(startCells, direction, entityAt, isInBounds, alreadyMoving) + local entities = {} + local pendingCells = {} + for _, cell in ipairs(startCells) do + table.insert(pendingCells, cell) + end + + local nextCell = 1 + while nextCell <= #pendingCells do + local cell = pendingCells[nextCell] + nextCell = nextCell + 1 + + if not isInBounds(cell) then + return false, entities + end + + local entity = entityAt(cell) + if entity and not isPassable(entity) and not entities[entity] and + not (alreadyMoving and alreadyMoving[entity]) then + if not entity:canMove() then + return false, entities + end + + entities[entity] = entity + + -- Anything occupying this block's destination must be pushed too. + for _, projectedCell in ipairs(entity:getOccupiedCells(direction)) do + table.insert(pendingCells, projectedCell) + end + + -- Skewers make every edge contact part of this rigid component. + for _, occupiedCell in ipairs(entity:getOccupiedCells()) do + for _, adjacentDirection in ipairs(adjacentDirections) do + local adjacentCell = { + x = occupiedCell.x + adjacentDirection.x, + y = occupiedCell.y + adjacentDirection.y, + } + if isInBounds(adjacentCell) then + local adjacentEntity = entityAt(adjacentCell) + local attached = adjacentEntity and ( + isSkewer(entity) or isSkewer(adjacentEntity) + ) + if attached and adjacentEntity ~= entity and adjacentEntity:canMove() and + not (alreadyMoving and alreadyMoving[adjacentEntity]) then + table.insert(pendingCells, adjacentCell) + end + end + end + end + end + end + + return true, entities +end + +function Movement.findMovableGroup(startCells, direction, entityAt, isInBounds) + local possible, entities = findRigidGroup( + startCells, direction, entityAt, isInBounds + ) + if not possible then return false, entities end + + local movingQueue = {} + for entity in pairs(entities) do table.insert(movingQueue, entity) end + local attemptedPulls = {} + local nextMover = 1 + + while nextMover <= #movingQueue do + local entity = movingQueue[nextMover] + nextMover = nextMover + 1 + + -- Sticky contact is soft only on the trailing face. Spiky contact is soft + -- on every face. Either kind simply releases a blocked rigid component, + -- without cancelling this entity or another independently pulled branch. + for _, occupiedCell in ipairs(entity:getOccupiedCells()) do + for _, adjacentDirection in ipairs(adjacentDirections) do + local adjacentCell = { + x = occupiedCell.x + adjacentDirection.x, + y = occupiedCell.y + adjacentDirection.y, + } + if isInBounds(adjacentCell) then + local adjacentEntity = entityAt(adjacentCell) + local trailing = adjacentDirection.x == -direction.x and + adjacentDirection.y == -direction.y + local softContact = adjacentEntity and ( + isSpiky(entity) or isSpiky(adjacentEntity) or + (trailing and (isSticky(entity) or isSticky(adjacentEntity))) + ) + if softContact and adjacentEntity ~= entity and + not entities[adjacentEntity] and not attemptedPulls[adjacentEntity] and + adjacentEntity:canMove() then + attemptedPulls[adjacentEntity] = true + local canPull, pulled = findRigidGroup( + {adjacentCell}, direction, entityAt, isInBounds, entities + ) + if canPull then + for pulledEntity in pairs(pulled) do + if not entities[pulledEntity] then + entities[pulledEntity] = pulledEntity + table.insert(movingQueue, pulledEntity) + end + end + end + end + end + end + end + end + + return true, entities +end + +return Movement diff --git a/npc.lua b/npc.lua index 8ed69ec..4df840d 100644 --- a/npc.lua +++ b/npc.lua @@ -20,3 +20,21 @@ function Sign:initialize(x, y) }, }) end + +Jorge = class("Jorge", Entity) +Jorge:include(Dialogable) + +function Jorge:initialize(x, y) + self.book = jorgeBook + self.saveClass = "jorge" + Entity.initialize(self, { + x = x, y = y, + color = "red", + collision = "unmoveable", + sprites = { + red = loadSprite("art/npc/jorge_r.png"), + green = loadSprite("art/npc/jorge_g.png"), + blue = loadSprite("art/npc/jorge_b.png"), + }, + }) +end diff --git a/room.lua b/room.lua index 69c1314..7a68ac5 100644 --- a/room.lua +++ b/room.lua @@ -10,8 +10,13 @@ require "switch" require "door" require "dialogue_manager" require "generic_moveable" +require "generic_sticky" +require "generic_skewer" +require "generic_spiky" require "generic_unmoveable" +local Movement = require "movement" + function Room:initialize(t) self.player = {} self.switches = { red = {}, green = {}, blue = {} } @@ -202,7 +207,7 @@ function Room:movePlayer(key) end local move = true - -- PUSHHHHHHHHHHHHHHHHHHHHHH--------------------- + -- PUSH --------------------------------------------------------------- local initialTargetCell = { x = pos.x + dir.x, y = pos.y + dir.y @@ -219,104 +224,24 @@ function Room:movePlayer(key) if not self:isInBounds(initialTargetCell) then -- let's us move out of bounds to Change Rooms without pulling a bloc_ move = true - elseif initialTargetEntity and initialTargetEntity:canPassOver() then - --we should put this in the else statement actually - move = true else - local targetCells - - targetCells = {initialTargetCell} -- ...we start with our attempted movement... - local doneSearching - while not doneSearching do - nextTargetCells = {} -- ...then we create this array to save our next group of cells - local emptyCells = {} - for _, cell in pairs(targetCells) do - if self:isInBounds(cell) then - local entity = self:getCellInMatrix(self.collidableMatrices[color], cell) - if entity then - --something is here!! - if not entitiesToPush[entity] then --if the entity hasnt been found already - if entity:canMove() then - local projectedCells = entity:getOccupiedCells(dir) -- we project the movement here - entitiesToPush[entity] = entity - for _, projectedCell in ipairs(projectedCells) do - table.insert(nextTargetCells, projectedCell) - end - else - move = false - doneSearching = true - end - end - else - --there's nothin there!! - table.insert(emptyCells, cell) - end - else - --we are out of bounds now - move = false - doneSearching = true - end - end - - --if every projected cell is empty then we can do the move - if #emptyCells == #targetCells then - move = true - doneSearching = true - end - - targetCells = nextTargetCells - end - --let's get out of this loop b/c if we can't move one color we can't move at all + move, entitiesToPush = Movement.findMovableGroup( + {initialTargetCell}, dir, + function(cell) return self:getCellInMatrix(self.collidableMatrices[color], cell) end, + function(cell) return self:isInBounds(cell) end + ) end - - ---PULL CHEC + -- PULL --------------------------------------------------------------- local initialTargetCell = {x = pos.x - dir.x, y = pos.y - dir.y} - - local targetCells - - local pull - --for each color... - targetCells = {initialTargetCell} -- ...we start with our attempted movement... - local doneSearching - while not doneSearching do - nextTargetCells = {} -- ...then we create this array to save our next group of cells - local emptyCells = {} - for _, cell in pairs(targetCells) do - if self:isInBounds(cell) then - local entity = self:getCellInMatrix(self.collidableMatrices[color], cell) - if entity then - --something is here!! - if not entitiesToPull[entity] then --if the entity hasnt been found already - if entity:canMove() then - local projectedCells = entity:getOccupiedCells(dir) -- we project the movement here - entitiesToPull[entity] = entity - for _, projectedCell in ipairs(projectedCells) do - table.insert(nextTargetCells, projectedCell) - end - else - pull = false - doneSearching = true - end - end - else - --there's nothin there!! - table.insert(emptyCells, cell) - end - else - --we are out of bounds now - doneSearching = true - end - end - - --if every projected cell is empty then we can do the move - if #emptyCells == #targetCells then - pull = true - doneSearching = true - end - - targetCells = nextTargetCells + local pull = false + if self:isInBounds(initialTargetCell) then + pull, entitiesToPull = Movement.findMovableGroup( + {initialTargetCell}, dir, + function(cell) return self:getCellInMatrix(self.collidableMatrices[color], cell) end, + function(cell) return self:isInBounds(cell) end + ) end if move then @@ -325,7 +250,11 @@ function Room:movePlayer(key) end if pull == true then for _, entity in pairs(entitiesToPull) do - entity:move(axis, dir[axis]) + -- A connected component can wrap around the player and be found by + -- both searches. Every entity still moves exactly one grid cell. + if not entitiesToPush[entity] then + entity:move(axis, dir[axis]) + end end end self.player[color]:move(axis, dir[axis]) @@ -341,21 +270,21 @@ function Room:movePlayer(key) end function Room:switchPlayerColor(color) - local canSwitch + -- Number keys can request a colour the player has not collected yet. Do + -- nothing in that case: there is no corresponding player object to switch + -- to (or use as the sound source). + local targetPlayer = self.player[color] + if not targetPlayer then return false end - if self:onlyColorIsActive(color) then - canSwitch = false - else - for _, c in pairs(self:getPossibleColors()) do - if c == color then - self:setActiveColor(c, true) - else - self:setActiveColor(c, false) - end + local canSwitch = not self:onlyColorIsActive(color) + if canSwitch then + for _, c in ipairs(self:getPossibleColors()) do + self:setActiveColor(c, c == color) end end - self.player[color]:playSwitchSound(canSwitch) + targetPlayer:playSwitchSound(canSwitch) + return canSwitch end function Room:setActiveColor(color, bool) @@ -537,7 +466,7 @@ end -- Instantiate one object from the flat {class,color,x,y} schema. `class` names an -- art asset, and its .meta declares the behaviour ("door"/"switch"/"player"/ --- "moveable"); anything without a .meta defaults to immoveable. npc is the one +-- "moveable"/"sticky"/"skewer"/"spiky"); anything without a .meta defaults to immoveable. npc is the one -- keyword handled directly since it has no art. function Room:createEntity(class, color, x, y) if class == "npc" then @@ -545,6 +474,11 @@ function Room:createEntity(class, color, x, y) self:registerNpc(entity) return entity end + if class == "jorge" then + local entity = Jorge:new(x, y) + self:registerNpc(entity) + return entity + end local props = globalAssetProperties and globalAssetProperties[class] local behavior = props and props.class or "immoveable" @@ -577,6 +511,12 @@ function Room:createEntity(class, color, x, y) if cellShape and #cellShape == 0 then cellShape = nil end if behavior == "moveable" then entity = GenericMoveable:new(x, y, color, sprite, class, cellShape) + elseif behavior == "sticky" then + entity = GenericSticky:new(x, y, color, sprite, class, cellShape) + elseif behavior == "skewer" then + entity = GenericSkewer:new(x, y, color, sprite, class, cellShape) + elseif behavior == "spiky" then + entity = GenericSpiky:new(x, y, color, sprite, class, cellShape) else entity = GenericUnmoveable:new(x, y, color, sprite, cellShape) end @@ -664,12 +604,25 @@ function Room:attemptDelete(mouseX, mouseY, color) for index = #self.doors, 1, -1 do if removedEntities[self.doors[index]] then table.remove(self.doors, index) end end + -- NPCs are stamped into every collision layer, but are kept in their own + -- registry rather than in self.collideables. Remove them directly so a + -- right-click works no matter which editor colour is currently selected. + for index = #self.npcs, 1, -1 do + if self.npcs[index]:occupiesCell(cell) then table.remove(self.npcs, index) end + end self:tick() end function Room:attemptPlace(name, props, mouseX, mouseY, color) if not props or not props.sprites 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 + self:createEntity(name, nil, cell.x, cell.y) + self:tick() + return + end -- "white" (or nil) means every channel; otherwise just the picked channel local colors @@ -727,32 +680,9 @@ end -- This is intentionally separate from Room:save. It is the editor's explicit -- "write this level into the project" action; gameplay autosaves must never -- call it. -function Room:saveToSource(name, savePlayerPositions, playerSourceName) +function Room:saveToSource(name, savePlayerPositions) name = name or self.name or "test" local saveTable = self:serialize(savePlayerPositions ~= false) - if savePlayerPositions == false then - -- A normal editor save keeps the authored spawn positions from the - -- existing source level. During a rename that source is still oldName. - local sourceName = playerSourceName or name - local existing = readFromSource("rooms/" .. sourceName .. ".sav") - local keptPlayer = false - if existing then - local previous = TSerial.unpack(existing) - for _, object in ipairs(previous.objects or {}) do - if object.class == "player" then - table.insert(saveTable.objects, object) - keptPlayer = true - end - end - end - -- A newly named blank level has no prior source spawn to retain. - if not keptPlayer then - for color, player in pairs(self.player) do - local pos = player:getGridPos() - table.insert(saveTable.objects, { class = "player", color = color, x = pos.x, y = pos.y }) - end - end - end local room = TSerial.pack(saveTable, nil, true) return writeToSource("rooms/" .. name .. ".sav", room) end @@ -791,7 +721,7 @@ function Room:serialize(includePlayers) end for _, npc in ipairs(self.npcs) do - table.insert(objects, { class = "npc", x = npc.x, y = npc.y }) + table.insert(objects, { class = npc.saveClass or "npc", x = npc.x, y = npc.y }) end return { objects = objects } diff --git a/rooms/corner_trimino_test.sav b/rooms/corner_trimino_test.sav new file mode 100644 index 0000000..48025ea --- /dev/null +++ b/rooms/corner_trimino_test.sav @@ -0,0 +1,1159 @@ +{ +objects={ + { + class="static_wall", + color="red", + y=1, + x=11 + }, + { + class="static_wall", + color="red", + y=2, + x=11 + }, + { + class="static_wall", + color="red", + y=3, + x=11 + }, + { + class="static_wall", + color="red", + y=1, + x=11 + }, + { + class="static_wall", + color="red", + y=2, + x=11 + }, + { + class="static_wall", + color="red", + y=3, + x=11 + }, + { + class="static_wall", + color="red", + y=4, + x=11 + }, + { + class="static_wall", + color="red", + y=5, + x=11 + }, + { + class="static_wall", + color="red", + y=7, + x=11 + }, + { + class="static_wall", + color="red", + y=9, + x=11 + }, + { + class="static_wall", + color="red", + y=10, + x=11 + }, + { + class="static_wall", + color="red", + y=11, + x=10 + }, + { + class="static_wall", + color="red", + y=11, + x=9 + }, + { + class="static_wall", + color="red", + y=11, + x=8 + }, + { + class="static_wall", + color="red", + y=11, + x=7 + }, + { + class="static_wall", + color="red", + y=11, + x=6 + }, + { + class="static_wall", + color="red", + y=11, + x=5 + }, + { + class="static_wall", + color="red", + y=11, + x=4 + }, + { + class="static_wall", + color="red", + y=11, + x=3 + }, + { + class="static_wall", + color="red", + y=11, + x=2 + }, + { + class="static_wall", + color="red", + y=11, + x=1 + }, + { + class="static_wall", + color="red", + y=10, + x=1 + }, + { + class="static_wall", + color="red", + y=9, + x=1 + }, + { + class="static_wall", + color="red", + y=8, + x=1 + }, + { + class="static_wall", + color="red", + y=7, + x=1 + }, + { + class="static_wall", + color="red", + y=5, + x=1 + }, + { + class="static_wall", + color="red", + y=4, + x=1 + }, + { + class="static_wall", + color="red", + y=3, + x=1 + }, + { + class="static_wall", + color="red", + y=1, + x=2 + }, + { + class="static_wall", + color="red", + y=1, + x=1 + }, + { + class="static_wall", + color="red", + y=2, + x=1 + }, + { + class="static_wall", + color="red", + y=1, + x=1 + }, + { + class="static_wall", + color="red", + y=1, + x=2 + }, + { + class="static_wall", + color="red", + y=1, + x=3 + }, + { + class="static_wall", + color="red", + y=1, + x=4 + }, + { + class="static_wall", + color="red", + y=1, + x=5 + }, + { + class="static_wall", + color="red", + y=1, + x=6 + }, + { + class="static_wall", + color="red", + y=1, + x=7 + }, + { + class="static_wall", + color="red", + y=1, + x=8 + }, + { + class="static_wall", + color="red", + y=1, + x=9 + }, + { + class="static_wall", + color="red", + y=1, + x=10 + }, + { + class="static_wall", + color="red", + y=1, + x=11 + }, + { + class="static_wall", + color="red", + y=8, + x=11 + }, + { + class="static_wall", + color="red", + y=9, + x=11 + }, + { + class="static_wall", + color="red", + y=10, + x=11 + }, + { + class="static_wall", + color="red", + y=11, + x=11 + }, + { + class="static_wall", + color="red", + y=2, + x=7 + }, + { + class="door", + color="red", + y=6, + x=11 + }, + { + class="static_wall", + color="red", + y=2, + x=4 + }, + { + class="static_wall", + color="red", + y=3, + x=4 + }, + { + class="static_wall", + color="red", + y=3, + x=7 + }, + { + class="static_wall", + color="red", + y=4, + x=4 + }, + { + class="static_wall", + color="red", + y=5, + x=4 + }, + { + class="static_wall", + color="red", + y=7, + x=7 + }, + { + class="static_wall", + color="red", + y=8, + x=4 + }, + { + class="static_wall", + color="red", + y=9, + x=4 + }, + { + class="static_wall", + color="red", + y=8, + x=7 + }, + { + class="static_wall", + color="red", + y=9, + x=7 + }, + { + class="static_wall", + color="red", + y=4, + x=7 + }, + { + class="box", + color="red", + y=3, + x=9 + }, + { + class="smile_dog", + color="red", + y=6, + x=3 + }, + { + class="box_2x2_01-11", + color="red", + y=2, + x=5 + }, + { + class="static_wall", + color="green", + y=1, + x=11 + }, + { + class="static_wall", + color="green", + y=2, + x=11 + }, + { + class="static_wall", + color="green", + y=3, + x=11 + }, + { + class="static_wall", + color="green", + y=4, + x=11 + }, + { + class="static_wall", + color="green", + y=5, + x=11 + }, + { + class="static_wall", + color="green", + y=7, + x=11 + }, + { + class="static_wall", + color="green", + y=9, + x=11 + }, + { + class="static_wall", + color="green", + y=10, + x=11 + }, + { + class="static_wall", + color="green", + y=11, + x=10 + }, + { + class="static_wall", + color="green", + y=11, + x=9 + }, + { + class="static_wall", + color="green", + y=11, + x=8 + }, + { + class="static_wall", + color="green", + y=11, + x=7 + }, + { + class="static_wall", + color="green", + y=11, + x=6 + }, + { + class="static_wall", + color="green", + y=11, + x=5 + }, + { + class="static_wall", + color="green", + y=11, + x=4 + }, + { + class="static_wall", + color="green", + y=11, + x=3 + }, + { + class="static_wall", + color="green", + y=11, + x=2 + }, + { + class="static_wall", + color="green", + y=11, + x=1 + }, + { + class="static_wall", + color="green", + y=10, + x=1 + }, + { + class="static_wall", + color="green", + y=9, + x=1 + }, + { + class="static_wall", + color="green", + y=8, + x=1 + }, + { + class="static_wall", + color="green", + y=7, + x=1 + }, + { + class="static_wall", + color="green", + y=5, + x=1 + }, + { + class="static_wall", + color="green", + y=4, + x=1 + }, + { + class="static_wall", + color="green", + y=3, + x=1 + }, + { + class="static_wall", + color="green", + y=1, + x=2 + }, + { + class="static_wall", + color="green", + y=1, + x=1 + }, + { + class="static_wall", + color="green", + y=2, + x=1 + }, + { + class="static_wall", + color="green", + y=1, + x=1 + }, + { + class="static_wall", + color="green", + y=1, + x=2 + }, + { + class="static_wall", + color="green", + y=1, + x=3 + }, + { + class="static_wall", + color="green", + y=1, + x=4 + }, + { + class="static_wall", + color="green", + y=1, + x=5 + }, + { + class="static_wall", + color="green", + y=1, + x=6 + }, + { + class="static_wall", + color="green", + y=1, + x=7 + }, + { + class="static_wall", + color="green", + y=1, + x=8 + }, + { + class="static_wall", + color="green", + y=1, + x=9 + }, + { + class="static_wall", + color="green", + y=1, + x=10 + }, + { + class="static_wall", + color="green", + y=1, + x=11 + }, + { + class="static_wall", + color="green", + y=8, + x=11 + }, + { + class="static_wall", + color="green", + y=9, + x=11 + }, + { + class="static_wall", + color="green", + y=10, + x=11 + }, + { + class="static_wall", + color="green", + y=11, + x=11 + }, + { + class="static_wall", + color="green", + y=2, + x=7 + }, + { + class="door", + color="green", + y=6, + x=11 + }, + { + class="static_wall", + color="green", + y=2, + x=4 + }, + { + class="static_wall", + color="green", + y=3, + x=4 + }, + { + class="static_wall", + color="green", + y=3, + x=7 + }, + { + class="static_wall", + color="green", + y=4, + x=4 + }, + { + class="static_wall", + color="green", + y=5, + x=4 + }, + { + class="static_wall", + color="green", + y=7, + x=7 + }, + { + class="static_wall", + color="green", + y=8, + x=4 + }, + { + class="static_wall", + color="green", + y=9, + x=4 + }, + { + class="static_wall", + color="green", + y=8, + x=7 + }, + { + class="static_wall", + color="green", + y=9, + x=7 + }, + { + class="static_wall", + color="green", + y=4, + x=7 + }, + { + class="box", + color="green", + y=3, + x=9 + }, + { + class="smile_dog", + color="green", + y=6, + x=3 + }, + { + class="box_2x2_01-11", + color="green", + y=2, + x=5 + }, + { + class="static_wall", + color="blue", + y=1, + x=11 + }, + { + class="static_wall", + color="blue", + y=2, + x=11 + }, + { + class="static_wall", + color="blue", + y=3, + x=11 + }, + { + class="static_wall", + color="blue", + y=4, + x=11 + }, + { + class="static_wall", + color="blue", + y=5, + x=11 + }, + { + class="static_wall", + color="blue", + y=7, + x=11 + }, + { + class="static_wall", + color="blue", + y=9, + x=11 + }, + { + class="static_wall", + color="blue", + y=10, + x=11 + }, + { + class="static_wall", + color="blue", + y=11, + x=10 + }, + { + class="static_wall", + color="blue", + y=11, + x=9 + }, + { + class="static_wall", + color="blue", + y=11, + x=8 + }, + { + class="static_wall", + color="blue", + y=11, + x=7 + }, + { + class="static_wall", + color="blue", + y=11, + x=6 + }, + { + class="static_wall", + color="blue", + y=11, + x=5 + }, + { + class="static_wall", + color="blue", + y=11, + x=4 + }, + { + class="static_wall", + color="blue", + y=11, + x=3 + }, + { + class="static_wall", + color="blue", + y=11, + x=2 + }, + { + class="static_wall", + color="blue", + y=11, + x=1 + }, + { + class="static_wall", + color="blue", + y=10, + x=1 + }, + { + class="static_wall", + color="blue", + y=9, + x=1 + }, + { + class="static_wall", + color="blue", + y=8, + x=1 + }, + { + class="static_wall", + color="blue", + y=7, + x=1 + }, + { + class="static_wall", + color="blue", + y=5, + x=1 + }, + { + class="static_wall", + color="blue", + y=4, + x=1 + }, + { + class="static_wall", + color="blue", + y=3, + x=1 + }, + { + class="static_wall", + color="blue", + y=1, + x=2 + }, + { + class="static_wall", + color="blue", + y=1, + x=1 + }, + { + class="static_wall", + color="blue", + y=2, + x=1 + }, + { + class="static_wall", + color="blue", + y=1, + x=1 + }, + { + class="static_wall", + color="blue", + y=1, + x=2 + }, + { + class="static_wall", + color="blue", + y=1, + x=3 + }, + { + class="static_wall", + color="blue", + y=1, + x=4 + }, + { + class="static_wall", + color="blue", + y=1, + x=5 + }, + { + class="static_wall", + color="blue", + y=1, + x=6 + }, + { + class="static_wall", + color="blue", + y=1, + x=7 + }, + { + class="static_wall", + color="blue", + y=1, + x=8 + }, + { + class="static_wall", + color="blue", + y=1, + x=9 + }, + { + class="static_wall", + color="blue", + y=1, + x=10 + }, + { + class="static_wall", + color="blue", + y=1, + x=11 + }, + { + class="static_wall", + color="blue", + y=8, + x=11 + }, + { + class="static_wall", + color="blue", + y=9, + x=11 + }, + { + class="static_wall", + color="blue", + y=10, + x=11 + }, + { + class="static_wall", + color="blue", + y=11, + x=11 + }, + { + class="static_wall", + color="blue", + y=2, + x=7 + }, + { + class="door", + color="blue", + y=6, + x=11 + }, + { + class="static_wall", + color="blue", + y=2, + x=4 + }, + { + class="static_wall", + color="blue", + y=3, + x=4 + }, + { + class="static_wall", + color="blue", + y=3, + x=7 + }, + { + class="static_wall", + color="blue", + y=4, + x=4 + }, + { + class="static_wall", + color="blue", + y=5, + x=4 + }, + { + class="static_wall", + color="blue", + y=7, + x=7 + }, + { + class="static_wall", + color="blue", + y=8, + x=4 + }, + { + class="static_wall", + color="blue", + y=9, + x=4 + }, + { + class="static_wall", + color="blue", + y=8, + x=7 + }, + { + class="static_wall", + color="blue", + y=9, + x=7 + }, + { + class="static_wall", + color="blue", + y=4, + x=7 + }, + { + class="box", + color="blue", + y=3, + x=9 + }, + { + class="smile_dog", + color="blue", + y=6, + x=3 + }, + { + class="box_2x2_01-11", + color="blue", + y=2, + x=5 + }, + { + class="switch", + color="red", + y=2, + x=5 + }, + { + class="switch", + color="red", + y=9, + x=9 + }, + { + class="switch", + color="red", + y=8, + x=10 + }, + { + class="switch", + color="green", + y=2, + x=5 + }, + { + class="switch", + color="green", + y=9, + x=9 + }, + { + class="switch", + color="green", + y=8, + x=10 + }, + { + class="switch", + color="blue", + y=2, + x=5 + }, + { + class="switch", + color="blue", + y=9, + x=9 + }, + { + class="switch", + color="blue", + y=8, + x=10 + }, + { + active=true, + color="red", + x=5, + y=9, + class="player" + }, + { + active=true, + color="green", + x=5, + y=9, + class="player" + }, + { + active=true, + color="blue", + x=5, + y=9, + class="player" + } +} +} \ No newline at end of file diff --git a/rooms/corner_trimino_test_copy.sav b/rooms/corner_trimino_test_copy.sav new file mode 100644 index 0000000..9a2bf82 --- /dev/null +++ b/rooms/corner_trimino_test_copy.sav @@ -0,0 +1,1159 @@ +{ +objects={ + { + y=1, + x=11, + class="static_wall", + color="red" + }, + { + y=2, + x=11, + class="static_wall", + color="red" + }, + { + y=3, + x=11, + class="static_wall", + color="red" + }, + { + y=1, + x=11, + class="static_wall", + color="red" + }, + { + y=2, + x=11, + class="static_wall", + color="red" + }, + { + y=3, + x=11, + class="static_wall", + color="red" + }, + { + y=4, + x=11, + class="static_wall", + color="red" + }, + { + y=5, + x=11, + class="static_wall", + color="red" + }, + { + y=7, + x=11, + class="static_wall", + color="red" + }, + { + y=9, + x=11, + class="static_wall", + color="red" + }, + { + y=10, + x=11, + class="static_wall", + color="red" + }, + { + y=11, + x=10, + class="static_wall", + color="red" + }, + { + y=11, + x=9, + class="static_wall", + color="red" + }, + { + y=11, + x=8, + class="static_wall", + color="red" + }, + { + y=11, + x=7, + class="static_wall", + color="red" + }, + { + y=11, + x=6, + class="static_wall", + color="red" + }, + { + y=11, + x=5, + class="static_wall", + color="red" + }, + { + y=11, + x=4, + class="static_wall", + color="red" + }, + { + y=11, + x=3, + class="static_wall", + color="red" + }, + { + y=11, + x=2, + class="static_wall", + color="red" + }, + { + y=11, + x=1, + class="static_wall", + color="red" + }, + { + y=10, + x=1, + class="static_wall", + color="red" + }, + { + y=9, + x=1, + class="static_wall", + color="red" + }, + { + y=8, + x=1, + class="static_wall", + color="red" + }, + { + y=7, + x=1, + class="static_wall", + color="red" + }, + { + y=5, + x=1, + class="static_wall", + color="red" + }, + { + y=4, + x=1, + class="static_wall", + color="red" + }, + { + y=3, + x=1, + class="static_wall", + color="red" + }, + { + y=1, + x=2, + class="static_wall", + color="red" + }, + { + y=1, + x=1, + class="static_wall", + color="red" + }, + { + y=2, + x=1, + class="static_wall", + color="red" + }, + { + y=1, + x=1, + class="static_wall", + color="red" + }, + { + y=1, + x=2, + class="static_wall", + color="red" + }, + { + y=1, + x=3, + class="static_wall", + color="red" + }, + { + y=1, + x=4, + class="static_wall", + color="red" + }, + { + y=1, + x=5, + class="static_wall", + color="red" + }, + { + y=1, + x=6, + class="static_wall", + color="red" + }, + { + y=1, + x=7, + class="static_wall", + color="red" + }, + { + y=1, + x=8, + class="static_wall", + color="red" + }, + { + y=1, + x=9, + class="static_wall", + color="red" + }, + { + y=1, + x=10, + class="static_wall", + color="red" + }, + { + y=1, + x=11, + class="static_wall", + color="red" + }, + { + y=8, + x=11, + class="static_wall", + color="red" + }, + { + y=9, + x=11, + class="static_wall", + color="red" + }, + { + y=10, + x=11, + class="static_wall", + color="red" + }, + { + y=11, + x=11, + class="static_wall", + color="red" + }, + { + y=2, + x=7, + class="static_wall", + color="red" + }, + { + y=6, + x=11, + class="door", + color="red" + }, + { + y=2, + x=4, + class="static_wall", + color="red" + }, + { + y=3, + x=4, + class="static_wall", + color="red" + }, + { + y=3, + x=7, + class="static_wall", + color="red" + }, + { + y=4, + x=4, + class="static_wall", + color="red" + }, + { + y=5, + x=4, + class="static_wall", + color="red" + }, + { + y=7, + x=7, + class="static_wall", + color="red" + }, + { + y=8, + x=4, + class="static_wall", + color="red" + }, + { + y=9, + x=4, + class="static_wall", + color="red" + }, + { + y=8, + x=7, + class="static_wall", + color="red" + }, + { + y=9, + x=7, + class="static_wall", + color="red" + }, + { + y=4, + x=7, + class="static_wall", + color="red" + }, + { + y=5, + x=6, + class="box_2x2_01-11", + color="red" + }, + { + y=3, + x=9, + class="box", + color="red" + }, + { + y=6, + x=3, + class="smile_dog", + color="red" + }, + { + y=1, + x=11, + class="static_wall", + color="green" + }, + { + y=2, + x=11, + class="static_wall", + color="green" + }, + { + y=3, + x=11, + class="static_wall", + color="green" + }, + { + y=4, + x=11, + class="static_wall", + color="green" + }, + { + y=5, + x=11, + class="static_wall", + color="green" + }, + { + y=7, + x=11, + class="static_wall", + color="green" + }, + { + y=9, + x=11, + class="static_wall", + color="green" + }, + { + y=10, + x=11, + class="static_wall", + color="green" + }, + { + y=11, + x=10, + class="static_wall", + color="green" + }, + { + y=11, + x=9, + class="static_wall", + color="green" + }, + { + y=11, + x=8, + class="static_wall", + color="green" + }, + { + y=11, + x=7, + class="static_wall", + color="green" + }, + { + y=11, + x=6, + class="static_wall", + color="green" + }, + { + y=11, + x=5, + class="static_wall", + color="green" + }, + { + y=11, + x=4, + class="static_wall", + color="green" + }, + { + y=11, + x=3, + class="static_wall", + color="green" + }, + { + y=11, + x=2, + class="static_wall", + color="green" + }, + { + y=11, + x=1, + class="static_wall", + color="green" + }, + { + y=10, + x=1, + class="static_wall", + color="green" + }, + { + y=9, + x=1, + class="static_wall", + color="green" + }, + { + y=8, + x=1, + class="static_wall", + color="green" + }, + { + y=7, + x=1, + class="static_wall", + color="green" + }, + { + y=5, + x=1, + class="static_wall", + color="green" + }, + { + y=4, + x=1, + class="static_wall", + color="green" + }, + { + y=3, + x=1, + class="static_wall", + color="green" + }, + { + y=1, + x=2, + class="static_wall", + color="green" + }, + { + y=1, + x=1, + class="static_wall", + color="green" + }, + { + y=2, + x=1, + class="static_wall", + color="green" + }, + { + y=1, + x=1, + class="static_wall", + color="green" + }, + { + y=1, + x=2, + class="static_wall", + color="green" + }, + { + y=1, + x=3, + class="static_wall", + color="green" + }, + { + y=1, + x=4, + class="static_wall", + color="green" + }, + { + y=1, + x=5, + class="static_wall", + color="green" + }, + { + y=1, + x=6, + class="static_wall", + color="green" + }, + { + y=1, + x=7, + class="static_wall", + color="green" + }, + { + y=1, + x=8, + class="static_wall", + color="green" + }, + { + y=1, + x=9, + class="static_wall", + color="green" + }, + { + y=1, + x=10, + class="static_wall", + color="green" + }, + { + y=1, + x=11, + class="static_wall", + color="green" + }, + { + y=8, + x=11, + class="static_wall", + color="green" + }, + { + y=9, + x=11, + class="static_wall", + color="green" + }, + { + y=10, + x=11, + class="static_wall", + color="green" + }, + { + y=11, + x=11, + class="static_wall", + color="green" + }, + { + y=2, + x=7, + class="static_wall", + color="green" + }, + { + y=6, + x=11, + class="door", + color="green" + }, + { + y=2, + x=4, + class="static_wall", + color="green" + }, + { + y=3, + x=4, + class="static_wall", + color="green" + }, + { + y=3, + x=7, + class="static_wall", + color="green" + }, + { + y=4, + x=4, + class="static_wall", + color="green" + }, + { + y=5, + x=4, + class="static_wall", + color="green" + }, + { + y=7, + x=7, + class="static_wall", + color="green" + }, + { + y=8, + x=4, + class="static_wall", + color="green" + }, + { + y=9, + x=4, + class="static_wall", + color="green" + }, + { + y=8, + x=7, + class="static_wall", + color="green" + }, + { + y=9, + x=7, + class="static_wall", + color="green" + }, + { + y=4, + x=7, + class="static_wall", + color="green" + }, + { + y=5, + x=6, + class="box_2x2_01-11", + color="green" + }, + { + y=3, + x=9, + class="box", + color="green" + }, + { + y=6, + x=3, + class="smile_dog", + color="green" + }, + { + y=1, + x=11, + class="static_wall", + color="blue" + }, + { + y=2, + x=11, + class="static_wall", + color="blue" + }, + { + y=3, + x=11, + class="static_wall", + color="blue" + }, + { + y=4, + x=11, + class="static_wall", + color="blue" + }, + { + y=5, + x=11, + class="static_wall", + color="blue" + }, + { + y=7, + x=11, + class="static_wall", + color="blue" + }, + { + y=9, + x=11, + class="static_wall", + color="blue" + }, + { + y=10, + x=11, + class="static_wall", + color="blue" + }, + { + y=11, + x=10, + class="static_wall", + color="blue" + }, + { + y=11, + x=9, + class="static_wall", + color="blue" + }, + { + y=11, + x=8, + class="static_wall", + color="blue" + }, + { + y=11, + x=7, + class="static_wall", + color="blue" + }, + { + y=11, + x=6, + class="static_wall", + color="blue" + }, + { + y=11, + x=5, + class="static_wall", + color="blue" + }, + { + y=11, + x=4, + class="static_wall", + color="blue" + }, + { + y=11, + x=3, + class="static_wall", + color="blue" + }, + { + y=11, + x=2, + class="static_wall", + color="blue" + }, + { + y=11, + x=1, + class="static_wall", + color="blue" + }, + { + y=10, + x=1, + class="static_wall", + color="blue" + }, + { + y=9, + x=1, + class="static_wall", + color="blue" + }, + { + y=8, + x=1, + class="static_wall", + color="blue" + }, + { + y=7, + x=1, + class="static_wall", + color="blue" + }, + { + y=5, + x=1, + class="static_wall", + color="blue" + }, + { + y=4, + x=1, + class="static_wall", + color="blue" + }, + { + y=3, + x=1, + class="static_wall", + color="blue" + }, + { + y=1, + x=2, + class="static_wall", + color="blue" + }, + { + y=1, + x=1, + class="static_wall", + color="blue" + }, + { + y=2, + x=1, + class="static_wall", + color="blue" + }, + { + y=1, + x=1, + class="static_wall", + color="blue" + }, + { + y=1, + x=2, + class="static_wall", + color="blue" + }, + { + y=1, + x=3, + class="static_wall", + color="blue" + }, + { + y=1, + x=4, + class="static_wall", + color="blue" + }, + { + y=1, + x=5, + class="static_wall", + color="blue" + }, + { + y=1, + x=6, + class="static_wall", + color="blue" + }, + { + y=1, + x=7, + class="static_wall", + color="blue" + }, + { + y=1, + x=8, + class="static_wall", + color="blue" + }, + { + y=1, + x=9, + class="static_wall", + color="blue" + }, + { + y=1, + x=10, + class="static_wall", + color="blue" + }, + { + y=1, + x=11, + class="static_wall", + color="blue" + }, + { + y=8, + x=11, + class="static_wall", + color="blue" + }, + { + y=9, + x=11, + class="static_wall", + color="blue" + }, + { + y=10, + x=11, + class="static_wall", + color="blue" + }, + { + y=11, + x=11, + class="static_wall", + color="blue" + }, + { + y=2, + x=7, + class="static_wall", + color="blue" + }, + { + y=6, + x=11, + class="door", + color="blue" + }, + { + y=2, + x=4, + class="static_wall", + color="blue" + }, + { + y=3, + x=4, + class="static_wall", + color="blue" + }, + { + y=3, + x=7, + class="static_wall", + color="blue" + }, + { + y=4, + x=4, + class="static_wall", + color="blue" + }, + { + y=5, + x=4, + class="static_wall", + color="blue" + }, + { + y=7, + x=7, + class="static_wall", + color="blue" + }, + { + y=8, + x=4, + class="static_wall", + color="blue" + }, + { + y=9, + x=4, + class="static_wall", + color="blue" + }, + { + y=8, + x=7, + class="static_wall", + color="blue" + }, + { + y=9, + x=7, + class="static_wall", + color="blue" + }, + { + y=4, + x=7, + class="static_wall", + color="blue" + }, + { + y=5, + x=6, + class="box_2x2_01-11", + color="blue" + }, + { + y=3, + x=9, + class="box", + color="blue" + }, + { + y=6, + x=3, + class="smile_dog", + color="blue" + }, + { + y=2, + x=5, + class="switch", + color="red" + }, + { + y=9, + x=9, + class="switch", + color="red" + }, + { + y=8, + x=10, + class="switch", + color="red" + }, + { + y=2, + x=5, + class="switch", + color="green" + }, + { + y=9, + x=9, + class="switch", + color="green" + }, + { + y=8, + x=10, + class="switch", + color="green" + }, + { + y=2, + x=5, + class="switch", + color="blue" + }, + { + y=9, + x=9, + class="switch", + color="blue" + }, + { + y=8, + x=10, + class="switch", + color="blue" + }, + { + y=9, + active=true, + x=5, + class="player", + color="red" + }, + { + y=9, + active=true, + x=5, + class="player", + color="green" + }, + { + y=9, + active=true, + x=5, + class="player", + color="blue" + } +} +} \ No newline at end of file diff --git a/rooms/jorge2.sav b/rooms/jorge2.sav new file mode 100644 index 0000000..1af74b5 --- /dev/null +++ b/rooms/jorge2.sav @@ -0,0 +1,1408 @@ +{ +objects={ + { + class="player", + color="red", + x=1, + y=2, + active=true + }, + { + class="player", + color="green", + x=1, + y=2, + active=true + }, + { + class="player", + color="blue", + x=1, + y=2, + active=true + }, + { + class="slime_woman", + color="red", + y=8, + x=4 + }, + { + class="slime_woman", + color="red", + y=7, + x=4 + }, + { + class="slime_woman", + color="red", + y=6, + x=4 + }, + { + class="slime_woman", + color="red", + y=3, + x=4 + }, + { + class="slime_woman", + color="red", + y=2, + x=4 + }, + { + class="slime_woman", + color="red", + y=2, + x=5 + }, + { + class="slime_woman", + color="red", + y=2, + x=6 + }, + { + class="slime_woman", + color="red", + y=2, + x=7 + }, + { + class="slime_woman", + color="red", + y=2, + x=8 + }, + { + class="slime_woman", + color="red", + y=4, + x=6 + }, + { + class="slime_woman", + color="red", + y=3, + x=1 + }, + { + class="slime_woman", + color="red", + y=3, + x=2 + }, + { + class="slime_woman", + color="red", + y=1, + x=3 + }, + { + class="slime_woman", + color="red", + y=1, + x=2 + }, + { + class="slime_woman", + color="red", + y=1, + x=1 + }, + { + class="slime_woman", + color="red", + y=7, + x=6 + }, + { + class="slime_woman", + color="red", + y=8, + x=6 + }, + { + class="box_2x2_01-11", + color="red", + y=5, + x=6 + }, + { + class="slime_woman", + color="red", + y=5, + x=8 + }, + { + class="slime_woman", + color="red", + y=11, + x=10 + }, + { + class="slime_woman", + color="red", + y=11, + x=9 + }, + { + class="slime_woman", + color="red", + y=11, + x=8 + }, + { + class="slime_woman", + color="red", + y=11, + x=7 + }, + { + class="slime_woman", + color="red", + y=11, + x=6 + }, + { + class="slime_woman", + color="red", + y=11, + x=5 + }, + { + class="slime_woman", + color="red", + y=11, + x=4 + }, + { + class="slime_woman", + color="red", + y=10, + x=3 + }, + { + class="slime_woman", + color="red", + y=11, + x=3 + }, + { + class="slime_woman", + color="red", + y=11, + x=2 + }, + { + class="slime_woman", + color="red", + y=11, + x=1 + }, + { + class="slime_woman", + color="red", + y=10, + x=1 + }, + { + class="slime_woman", + color="red", + y=9, + x=1 + }, + { + class="slime_woman", + color="red", + y=8, + x=1 + }, + { + class="slime_woman", + color="red", + y=7, + x=1 + }, + { + class="slime_woman", + color="red", + y=6, + x=1 + }, + { + class="slime_woman", + color="red", + y=5, + x=1 + }, + { + class="slime_woman", + color="red", + y=4, + x=1 + }, + { + class="slime_woman", + color="red", + y=3, + x=1 + }, + { + class="slime_woman", + color="red", + y=1, + x=3 + }, + { + class="slime_woman", + color="red", + y=1, + x=4 + }, + { + class="slime_woman", + color="red", + y=1, + x=5 + }, + { + class="slime_woman", + color="red", + y=1, + x=6 + }, + { + class="slime_woman", + color="red", + y=1, + x=7 + }, + { + class="slime_woman", + color="red", + y=1, + x=8 + }, + { + class="slime_woman", + color="red", + y=2, + x=8 + }, + { + class="slime_woman", + color="red", + y=2, + x=9 + }, + { + class="slime_woman", + color="red", + y=1, + x=9 + }, + { + class="slime_woman", + color="red", + y=1, + x=10 + }, + { + class="slime_woman", + color="red", + y=1, + x=11 + }, + { + class="slime_woman", + color="red", + y=2, + x=10 + }, + { + class="slime_woman", + color="red", + y=3, + x=10 + }, + { + class="slime_woman", + color="red", + y=3, + x=9 + }, + { + class="box", + color="red", + y=5, + x=6 + }, + { + class="door", + color="red", + y=6, + x=11 + }, + { + class="slime_woman", + color="red", + y=2, + x=11 + }, + { + class="slime_woman", + color="red", + y=3, + x=11 + }, + { + class="slime_woman", + color="red", + y=4, + x=11 + }, + { + class="slime_woman", + color="red", + y=5, + x=11 + }, + { + class="slime_woman", + color="red", + y=4, + x=11 + }, + { + class="slime_woman", + color="red", + y=4, + x=10 + }, + { + class="slime_woman", + color="red", + y=5, + x=10 + }, + { + class="slime_woman", + color="red", + y=7, + x=11 + }, + { + class="slime_woman", + color="red", + y=8, + x=11 + }, + { + class="slime_woman", + color="red", + y=9, + x=11 + }, + { + class="slime_woman", + color="red", + y=10, + x=11 + }, + { + class="slime_woman", + color="red", + y=10, + x=11 + }, + { + class="slime_woman", + color="red", + y=11, + x=11 + }, + { + class="slime_woman", + color="red", + y=10, + x=11 + }, + { + class="slime_woman", + color="red", + y=9, + x=11 + }, + { + class="slime_woman", + color="red", + y=8, + x=11 + }, + { + class="slime_woman", + color="red", + y=8, + x=10 + }, + { + class="slime_woman", + color="red", + y=8, + x=10 + }, + { + class="slime_woman", + color="red", + y=8, + x=9 + }, + { + class="slime_woman", + color="red", + y=6, + x=8 + }, + { + class="slime_woman", + color="green", + y=8, + x=4 + }, + { + class="slime_woman", + color="green", + y=7, + x=4 + }, + { + class="slime_woman", + color="green", + y=6, + x=4 + }, + { + class="slime_woman", + color="green", + y=3, + x=4 + }, + { + class="slime_woman", + color="green", + y=2, + x=4 + }, + { + class="slime_woman", + color="green", + y=2, + x=5 + }, + { + class="slime_woman", + color="green", + y=2, + x=6 + }, + { + class="slime_woman", + color="green", + y=2, + x=7 + }, + { + class="slime_woman", + color="green", + y=2, + x=8 + }, + { + class="slime_woman", + color="green", + y=4, + x=6 + }, + { + class="slime_woman", + color="green", + y=3, + x=1 + }, + { + class="slime_woman", + color="green", + y=3, + x=2 + }, + { + class="slime_woman", + color="green", + y=1, + x=3 + }, + { + class="slime_woman", + color="green", + y=1, + x=2 + }, + { + class="slime_woman", + color="green", + y=1, + x=1 + }, + { + class="slime_woman", + color="green", + y=7, + x=6 + }, + { + class="slime_woman", + color="green", + y=8, + x=6 + }, + { + class="box_2x2_01-11", + color="green", + y=5, + x=6 + }, + { + class="slime_woman", + color="green", + y=5, + x=8 + }, + { + class="slime_woman", + color="green", + y=11, + x=10 + }, + { + class="slime_woman", + color="green", + y=11, + x=9 + }, + { + class="slime_woman", + color="green", + y=11, + x=8 + }, + { + class="slime_woman", + color="green", + y=11, + x=7 + }, + { + class="slime_woman", + color="green", + y=11, + x=6 + }, + { + class="slime_woman", + color="green", + y=11, + x=5 + }, + { + class="slime_woman", + color="green", + y=11, + x=4 + }, + { + class="slime_woman", + color="green", + y=10, + x=3 + }, + { + class="slime_woman", + color="green", + y=11, + x=3 + }, + { + class="slime_woman", + color="green", + y=11, + x=2 + }, + { + class="slime_woman", + color="green", + y=11, + x=1 + }, + { + class="slime_woman", + color="green", + y=10, + x=1 + }, + { + class="slime_woman", + color="green", + y=9, + x=1 + }, + { + class="slime_woman", + color="green", + y=8, + x=1 + }, + { + class="slime_woman", + color="green", + y=7, + x=1 + }, + { + class="slime_woman", + color="green", + y=6, + x=1 + }, + { + class="slime_woman", + color="green", + y=5, + x=1 + }, + { + class="slime_woman", + color="green", + y=4, + x=1 + }, + { + class="slime_woman", + color="green", + y=3, + x=1 + }, + { + class="slime_woman", + color="green", + y=1, + x=3 + }, + { + class="slime_woman", + color="green", + y=1, + x=4 + }, + { + class="slime_woman", + color="green", + y=1, + x=5 + }, + { + class="slime_woman", + color="green", + y=1, + x=6 + }, + { + class="slime_woman", + color="green", + y=1, + x=7 + }, + { + class="slime_woman", + color="green", + y=1, + x=8 + }, + { + class="slime_woman", + color="green", + y=2, + x=8 + }, + { + class="slime_woman", + color="green", + y=2, + x=9 + }, + { + class="slime_woman", + color="green", + y=1, + x=9 + }, + { + class="slime_woman", + color="green", + y=1, + x=10 + }, + { + class="slime_woman", + color="green", + y=1, + x=11 + }, + { + class="slime_woman", + color="green", + y=2, + x=10 + }, + { + class="slime_woman", + color="green", + y=3, + x=10 + }, + { + class="slime_woman", + color="green", + y=3, + x=9 + }, + { + class="box", + color="green", + y=5, + x=6 + }, + { + class="door", + color="green", + y=6, + x=11 + }, + { + class="slime_woman", + color="green", + y=2, + x=11 + }, + { + class="slime_woman", + color="green", + y=3, + x=11 + }, + { + class="slime_woman", + color="green", + y=4, + x=11 + }, + { + class="slime_woman", + color="green", + y=5, + x=11 + }, + { + class="slime_woman", + color="green", + y=4, + x=11 + }, + { + class="slime_woman", + color="green", + y=4, + x=10 + }, + { + class="slime_woman", + color="green", + y=5, + x=10 + }, + { + class="slime_woman", + color="green", + y=7, + x=11 + }, + { + class="slime_woman", + color="green", + y=8, + x=11 + }, + { + class="slime_woman", + color="green", + y=9, + x=11 + }, + { + class="slime_woman", + color="green", + y=10, + x=11 + }, + { + class="slime_woman", + color="green", + y=10, + x=11 + }, + { + class="slime_woman", + color="green", + y=11, + x=11 + }, + { + class="slime_woman", + color="green", + y=10, + x=11 + }, + { + class="slime_woman", + color="green", + y=9, + x=11 + }, + { + class="slime_woman", + color="green", + y=8, + x=11 + }, + { + class="slime_woman", + color="green", + y=8, + x=10 + }, + { + class="slime_woman", + color="green", + y=8, + x=10 + }, + { + class="slime_woman", + color="green", + y=8, + x=9 + }, + { + class="slime_woman", + color="green", + y=6, + x=8 + }, + { + class="slime_woman", + color="blue", + y=8, + x=4 + }, + { + class="slime_woman", + color="blue", + y=7, + x=4 + }, + { + class="slime_woman", + color="blue", + y=6, + x=4 + }, + { + class="slime_woman", + color="blue", + y=3, + x=4 + }, + { + class="slime_woman", + color="blue", + y=2, + x=4 + }, + { + class="slime_woman", + color="blue", + y=2, + x=5 + }, + { + class="slime_woman", + color="blue", + y=2, + x=6 + }, + { + class="slime_woman", + color="blue", + y=2, + x=7 + }, + { + class="slime_woman", + color="blue", + y=2, + x=8 + }, + { + class="slime_woman", + color="blue", + y=4, + x=6 + }, + { + class="slime_woman", + color="blue", + y=3, + x=1 + }, + { + class="slime_woman", + color="blue", + y=3, + x=2 + }, + { + class="slime_woman", + color="blue", + y=1, + x=3 + }, + { + class="slime_woman", + color="blue", + y=1, + x=2 + }, + { + class="slime_woman", + color="blue", + y=1, + x=1 + }, + { + class="slime_woman", + color="blue", + y=7, + x=6 + }, + { + class="slime_woman", + color="blue", + y=8, + x=6 + }, + { + class="box_2x2_01-11", + color="blue", + y=5, + x=6 + }, + { + class="slime_woman", + color="blue", + y=5, + x=8 + }, + { + class="slime_woman", + color="blue", + y=11, + x=10 + }, + { + class="slime_woman", + color="blue", + y=11, + x=9 + }, + { + class="slime_woman", + color="blue", + y=11, + x=8 + }, + { + class="slime_woman", + color="blue", + y=11, + x=7 + }, + { + class="slime_woman", + color="blue", + y=11, + x=6 + }, + { + class="slime_woman", + color="blue", + y=11, + x=5 + }, + { + class="slime_woman", + color="blue", + y=11, + x=4 + }, + { + class="slime_woman", + color="blue", + y=10, + x=3 + }, + { + class="slime_woman", + color="blue", + y=11, + x=3 + }, + { + class="slime_woman", + color="blue", + y=11, + x=2 + }, + { + class="slime_woman", + color="blue", + y=11, + x=1 + }, + { + class="slime_woman", + color="blue", + y=10, + x=1 + }, + { + class="slime_woman", + color="blue", + y=9, + x=1 + }, + { + class="slime_woman", + color="blue", + y=8, + x=1 + }, + { + class="slime_woman", + color="blue", + y=7, + x=1 + }, + { + class="slime_woman", + color="blue", + y=6, + x=1 + }, + { + class="slime_woman", + color="blue", + y=5, + x=1 + }, + { + class="slime_woman", + color="blue", + y=4, + x=1 + }, + { + class="slime_woman", + color="blue", + y=3, + x=1 + }, + { + class="slime_woman", + color="blue", + y=1, + x=3 + }, + { + class="slime_woman", + color="blue", + y=1, + x=4 + }, + { + class="slime_woman", + color="blue", + y=1, + x=5 + }, + { + class="slime_woman", + color="blue", + y=1, + x=6 + }, + { + class="slime_woman", + color="blue", + y=1, + x=7 + }, + { + class="slime_woman", + color="blue", + y=1, + x=8 + }, + { + class="slime_woman", + color="blue", + y=2, + x=8 + }, + { + class="slime_woman", + color="blue", + y=2, + x=9 + }, + { + class="slime_woman", + color="blue", + y=1, + x=9 + }, + { + class="slime_woman", + color="blue", + y=1, + x=10 + }, + { + class="slime_woman", + color="blue", + y=1, + x=11 + }, + { + class="slime_woman", + color="blue", + y=2, + x=10 + }, + { + class="slime_woman", + color="blue", + y=3, + x=10 + }, + { + class="slime_woman", + color="blue", + y=3, + x=9 + }, + { + class="box", + color="blue", + y=5, + x=6 + }, + { + class="door", + color="blue", + y=6, + x=11 + }, + { + class="slime_woman", + color="blue", + y=2, + x=11 + }, + { + class="slime_woman", + color="blue", + y=3, + x=11 + }, + { + class="slime_woman", + color="blue", + y=4, + x=11 + }, + { + class="slime_woman", + color="blue", + y=5, + x=11 + }, + { + class="slime_woman", + color="blue", + y=4, + x=11 + }, + { + class="slime_woman", + color="blue", + y=4, + x=10 + }, + { + class="slime_woman", + color="blue", + y=5, + x=10 + }, + { + class="slime_woman", + color="blue", + y=7, + x=11 + }, + { + class="slime_woman", + color="blue", + y=8, + x=11 + }, + { + class="slime_woman", + color="blue", + y=9, + x=11 + }, + { + class="slime_woman", + color="blue", + y=10, + x=11 + }, + { + class="slime_woman", + color="blue", + y=10, + x=11 + }, + { + class="slime_woman", + color="blue", + y=11, + x=11 + }, + { + class="slime_woman", + color="blue", + y=10, + x=11 + }, + { + class="slime_woman", + color="blue", + y=9, + x=11 + }, + { + class="slime_woman", + color="blue", + y=8, + x=11 + }, + { + class="slime_woman", + color="blue", + y=8, + x=10 + }, + { + class="slime_woman", + color="blue", + y=8, + x=10 + }, + { + class="slime_woman", + color="blue", + y=8, + x=9 + }, + { + class="slime_woman", + color="blue", + y=6, + x=8 + }, + { + class="switch", + color="red", + y=3, + x=8 + }, + { + class="switch", + color="red", + y=4, + x=7 + }, + { + class="switch", + color="green", + y=3, + x=8 + }, + { + class="switch", + color="green", + y=4, + x=7 + }, + { + class="switch", + color="blue", + y=3, + x=8 + }, + { + class="switch", + color="blue", + y=4, + x=7 + }, + { + class="jorge", + y=9, + x=9 + }, + { + class="jorge", + y=9, + x=9 + }, + { + class="jorge", + y=9, + x=9 + } +} +} \ No newline at end of file diff --git a/rooms/ok.sav b/rooms/ok.sav new file mode 100644 index 0000000..2ab39e4 --- /dev/null +++ b/rooms/ok.sav @@ -0,0 +1,760 @@ +{ +objects={ + { + x=11, + y=11, + class="static_wall", + color="green" + }, + { + x=11, + y=10, + class="static_wall", + color="green" + }, + { + x=11, + y=9, + class="static_wall", + color="green" + }, + { + x=11, + y=8, + class="static_wall", + color="green" + }, + { + x=11, + y=7, + class="static_wall", + color="green" + }, + { + x=11, + y=6, + class="static_wall", + color="green" + }, + { + x=11, + y=4, + class="static_wall", + color="green" + }, + { + x=11, + y=3, + class="static_wall", + color="green" + }, + { + x=11, + y=2, + class="static_wall", + color="green" + }, + { + x=11, + y=1, + class="static_wall", + color="green" + }, + { + x=10, + y=1, + class="static_wall", + color="green" + }, + { + x=9, + y=1, + class="static_wall", + color="green" + }, + { + x=8, + y=1, + class="static_wall", + color="green" + }, + { + x=7, + y=1, + class="static_wall", + color="green" + }, + { + x=6, + y=1, + class="static_wall", + color="green" + }, + { + x=5, + y=1, + class="static_wall", + color="green" + }, + { + x=4, + y=1, + class="static_wall", + color="green" + }, + { + x=3, + y=1, + class="static_wall", + color="green" + }, + { + x=2, + y=1, + class="static_wall", + color="green" + }, + { + x=1, + y=1, + class="static_wall", + color="green" + }, + { + x=1, + y=2, + class="static_wall", + color="green" + }, + { + x=1, + y=3, + class="static_wall", + color="green" + }, + { + x=1, + y=4, + class="static_wall", + color="green" + }, + { + x=1, + y=5, + class="static_wall", + color="green" + }, + { + x=1, + y=6, + class="static_wall", + color="green" + }, + { + x=1, + y=7, + class="static_wall", + color="green" + }, + { + x=1, + y=8, + class="static_wall", + color="green" + }, + { + x=1, + y=9, + class="static_wall", + color="green" + }, + { + x=1, + y=10, + class="static_wall", + color="green" + }, + { + x=1, + y=11, + class="static_wall", + color="green" + }, + { + x=2, + y=11, + class="static_wall", + color="green" + }, + { + x=3, + y=11, + class="static_wall", + color="green" + }, + { + x=4, + y=11, + class="static_wall", + color="green" + }, + { + x=5, + y=11, + class="static_wall", + color="green" + }, + { + x=6, + y=11, + class="static_wall", + color="green" + }, + { + x=7, + y=11, + class="static_wall", + color="green" + }, + { + x=8, + y=11, + class="static_wall", + color="green" + }, + { + x=9, + y=11, + class="static_wall", + color="green" + }, + { + x=10, + y=11, + class="static_wall", + color="green" + }, + { + x=11, + y=5, + class="static_wall", + color="green" + }, + { + x=5, + y=7, + class="box", + color="green" + }, + { + x=11, + y=11, + class="static_wall", + color="blue" + }, + { + x=11, + y=10, + class="static_wall", + color="blue" + }, + { + x=11, + y=9, + class="static_wall", + color="blue" + }, + { + x=11, + y=8, + class="static_wall", + color="blue" + }, + { + x=11, + y=7, + class="static_wall", + color="blue" + }, + { + x=11, + y=6, + class="static_wall", + color="blue" + }, + { + x=11, + y=4, + class="static_wall", + color="blue" + }, + { + x=11, + y=3, + class="static_wall", + color="blue" + }, + { + x=11, + y=2, + class="static_wall", + color="blue" + }, + { + x=11, + y=1, + class="static_wall", + color="blue" + }, + { + x=10, + y=1, + class="static_wall", + color="blue" + }, + { + x=9, + y=1, + class="static_wall", + color="blue" + }, + { + x=8, + y=1, + class="static_wall", + color="blue" + }, + { + x=7, + y=1, + class="static_wall", + color="blue" + }, + { + x=6, + y=1, + class="static_wall", + color="blue" + }, + { + x=5, + y=1, + class="static_wall", + color="blue" + }, + { + x=4, + y=1, + class="static_wall", + color="blue" + }, + { + x=3, + y=1, + class="static_wall", + color="blue" + }, + { + x=2, + y=1, + class="static_wall", + color="blue" + }, + { + x=1, + y=1, + class="static_wall", + color="blue" + }, + { + x=1, + y=2, + class="static_wall", + color="blue" + }, + { + x=1, + y=3, + class="static_wall", + color="blue" + }, + { + x=1, + y=4, + class="static_wall", + color="blue" + }, + { + x=1, + y=5, + class="static_wall", + color="blue" + }, + { + x=1, + y=6, + class="static_wall", + color="blue" + }, + { + x=1, + y=7, + class="static_wall", + color="blue" + }, + { + x=1, + y=8, + class="static_wall", + color="blue" + }, + { + x=1, + y=9, + class="static_wall", + color="blue" + }, + { + x=1, + 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=4, + 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=5, + class="static_wall", + color="blue" + }, + { + x=6, + y=6, + class="box", + color="blue" + }, + { + x=11, + y=11, + class="static_wall", + color="red" + }, + { + x=11, + y=10, + class="static_wall", + color="red" + }, + { + x=11, + y=9, + class="static_wall", + color="red" + }, + { + x=11, + y=8, + class="static_wall", + color="red" + }, + { + x=11, + y=7, + class="static_wall", + color="red" + }, + { + x=11, + y=6, + class="static_wall", + color="red" + }, + { + x=11, + y=4, + class="static_wall", + color="red" + }, + { + x=11, + y=3, + class="static_wall", + color="red" + }, + { + x=11, + y=2, + class="static_wall", + color="red" + }, + { + x=11, + y=1, + class="static_wall", + color="red" + }, + { + x=10, + y=1, + class="static_wall", + color="red" + }, + { + x=9, + y=1, + class="static_wall", + color="red" + }, + { + x=8, + y=1, + class="static_wall", + color="red" + }, + { + x=7, + y=1, + class="static_wall", + color="red" + }, + { + x=6, + y=1, + class="static_wall", + color="red" + }, + { + x=5, + y=1, + class="static_wall", + color="red" + }, + { + x=4, + y=1, + class="static_wall", + color="red" + }, + { + x=3, + y=1, + class="static_wall", + color="red" + }, + { + x=2, + y=1, + class="static_wall", + color="red" + }, + { + x=1, + y=1, + class="static_wall", + color="red" + }, + { + x=1, + y=2, + class="static_wall", + color="red" + }, + { + x=1, + y=3, + class="static_wall", + color="red" + }, + { + x=1, + y=4, + class="static_wall", + color="red" + }, + { + x=1, + y=5, + class="static_wall", + color="red" + }, + { + x=1, + y=6, + class="static_wall", + color="red" + }, + { + x=1, + y=7, + class="static_wall", + color="red" + }, + { + x=1, + y=8, + class="static_wall", + color="red" + }, + { + x=1, + y=9, + class="static_wall", + color="red" + }, + { + x=1, + 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=4, + 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=5, + class="static_wall", + color="red" + }, + { + x=5, + y=6, + class="box", + color="red" + }, + { + x=6, + y=8, + class="player", + color="green" + }, + { + x=6, + y=8, + class="player", + color="blue" + }, + { + x=6, + y=8, + class="player", + color="red" + } +} +} \ No newline at end of file diff --git a/rooms/room_01_05.sav b/rooms/room_01_05.sav new file mode 100644 index 0000000..3e784f7 --- /dev/null +++ b/rooms/room_01_05.sav @@ -0,0 +1,4 @@ +{ +objects={ +} +} \ No newline at end of file diff --git a/rooms/room_05_09.sav b/rooms/room_05_09.sav new file mode 100644 index 0000000..3e784f7 --- /dev/null +++ b/rooms/room_05_09.sav @@ -0,0 +1,4 @@ +{ +objects={ +} +} \ No newline at end of file diff --git a/rooms/room_05_18.sav b/rooms/room_05_18.sav new file mode 100644 index 0000000..3e784f7 --- /dev/null +++ b/rooms/room_05_18.sav @@ -0,0 +1,4 @@ +{ +objects={ +} +} \ No newline at end of file diff --git a/rooms/room_07_07.sav b/rooms/room_07_07.sav new file mode 100644 index 0000000..3e784f7 --- /dev/null +++ b/rooms/room_07_07.sav @@ -0,0 +1,4 @@ +{ +objects={ +} +} \ No newline at end of file diff --git a/rooms/start.sav b/rooms/spiky_test.sav similarity index 76% rename from rooms/start.sav rename to rooms/spiky_test.sav index 363e52d..76f2e74 100644 --- a/rooms/start.sav +++ b/rooms/spiky_test.sav @@ -1,782 +1,1015 @@ { objects={ { - class="player", + y=1, + class="static_wall", + color="red", + x=11 + }, + { + y=2, + class="static_wall", + color="red", + x=11 + }, + { + y=3, + class="static_wall", + color="red", + x=11 + }, + { + y=1, + class="static_wall", + color="red", + x=11 + }, + { + y=2, + class="static_wall", + color="red", + x=11 + }, + { + y=3, + class="static_wall", + color="red", + x=11 + }, + { + y=4, + class="static_wall", + color="red", + x=11 + }, + { + y=5, + class="static_wall", + color="red", + x=11 + }, + { + y=7, + class="static_wall", + color="red", + x=11 + }, + { y=9, + class="static_wall", + color="red", + x=11 + }, + { + y=10, + class="static_wall", + color="red", + x=11 + }, + { + y=11, + class="static_wall", + color="red", + x=10 + }, + { + y=11, + class="static_wall", + color="red", + x=9 + }, + { + y=11, + class="static_wall", + color="red", + x=8 + }, + { + y=11, + class="static_wall", + color="red", + x=7 + }, + { + y=11, + class="static_wall", color="red", x=6 }, { + y=11, + class="static_wall", + color="red", + x=5 + }, + { + y=11, + class="static_wall", + color="red", + x=4 + }, + { + y=11, + class="static_wall", + color="red", + x=3 + }, + { + y=11, + class="static_wall", + color="red", + x=2 + }, + { + y=11, + class="static_wall", + color="red", + x=1 + }, + { + y=10, + class="static_wall", + color="red", + x=1 + }, + { + y=9, + class="static_wall", + color="red", + x=1 + }, + { + y=8, + class="static_wall", + color="red", + x=1 + }, + { + y=7, + class="static_wall", + color="red", + x=1 + }, + { + y=6, + class="static_wall", + color="red", + x=1 + }, + { + y=5, + class="static_wall", + color="red", + x=1 + }, + { + y=4, + class="static_wall", + color="red", + x=1 + }, + { + y=3, + class="static_wall", + color="red", + x=1 + }, + { + y=1, + class="static_wall", + color="red", + x=2 + }, + { + y=1, + class="static_wall", + color="red", + x=1 + }, + { + y=2, + class="static_wall", + color="red", + x=1 + }, + { + y=1, + class="static_wall", + color="red", + x=1 + }, + { + y=1, + class="static_wall", + color="red", + x=2 + }, + { + y=1, + class="static_wall", + color="red", + x=3 + }, + { + y=1, + class="static_wall", + color="red", + x=4 + }, + { + y=1, + class="static_wall", + color="red", + x=5 + }, + { + y=1, + class="static_wall", + color="red", + x=6 + }, + { + y=1, + class="static_wall", + color="red", + x=7 + }, + { + y=1, + class="static_wall", + color="red", + x=8 + }, + { + y=1, + class="static_wall", + color="red", + x=9 + }, + { + y=1, + class="static_wall", + color="red", + x=10 + }, + { + y=1, + class="static_wall", + color="red", + x=11 + }, + { + y=8, + class="static_wall", + color="red", + x=11 + }, + { + y=9, + class="static_wall", + color="red", + x=11 + }, + { + y=10, + class="static_wall", + color="red", + x=11 + }, + { + y=11, + class="static_wall", + color="red", + x=11 + }, + { + y=2, + class="static_wall", + color="red", + x=7 + }, + { + y=6, class="door", - y=1, - x=6 - }, - { - class="static_wall", - y=9, - color="red", - x=1 - }, - { - class="static_wall", - y=11, - color="red", - x=2 - }, - { - class="static_wall", - y=6, - color="red", - x=5 - }, - { - class="static_wall", - y=1, - color="red", - x=1 - }, - { - class="static_wall", - y=3, - color="red", - x=1 - }, - { - class="static_wall", - y=1, - color="red", - x=3 - }, - { - class="static_wall", - y=10, - color="red", - x=1 - }, - { - class="static_wall", - y=1, - color="red", - x=2 - }, - { - class="static_wall", - y=1, - color="red", - x=4 - }, - { - class="static_wall", - y=3, color="red", x=11 }, { - class="static_wall", - y=1, - color="red", - x=5 - }, - { - class="static_wall", - y=11, - color="red", - x=3 - }, - { - class="static_wall", - y=11, - color="red", - x=5 - }, - { - class="static_wall", y=4, + class="static_wall", color="red", - x=11 + x=5 }, { + y=4, class="static_wall", - y=1, color="red", x=7 }, { + y=2, class="static_wall", - y=10, color="red", - x=11 + x=4 }, { + y=3, class="static_wall", - y=8, color="red", - x=1 + x=4 }, { - class="static_wall", - y=1, - color="red", - x=9 - }, - { - class="static_wall", - y=11, - color="red", - x=11 - }, - { - class="static_wall", - y=5, - color="red", - x=11 - }, - { - class="static_wall", - y=11, - color="red", - x=9 - }, - { - class="static_wall", y=6, - color="red", - x=8 - }, - { - class="static_wall", - y=11, + class="spiky_box_1x2_1-1", color="red", x=6 }, { - class="static_wall", - y=6, - color="red", - x=7 - }, - { - class="static_wall", - y=1, - color="red", - x=8 - }, - { - class="static_wall", - y=11, - color="red", - x=1 - }, - { - class="static_wall", - y=6, - color="red", - x=11 - }, - { - class="static_wall", - y=6, - color="red", - x=2 - }, - { - class="static_wall", - y=11, - color="red", - x=10 - }, - { - class="static_wall", - y=6, - color="red", - x=1 - }, - { - class="static_wall", - y=6, - color="red", - x=10 - }, - { - class="static_wall", - y=7, - color="red", - x=1 - }, - { - class="static_wall", - y=6, - color="red", - x=9 - }, - { - class="static_wall", - y=6, - color="red", - x=3 - }, - { - class="static_wall", - y=11, - color="red", - x=8 - }, - { - class="static_wall", - y=7, - color="red", - x=11 - }, - { - class="static_wall", - y=4, - color="red", - x=1 - }, - { - class="static_wall", - y=5, - color="red", - x=1 - }, - { - class="static_wall", y=2, - color="red", - x=1 - }, - { - class="static_wall", - y=6, - color="red", - x=4 - }, - { - class="static_wall", - y=2, - color="red", - x=11 - }, - { - class="static_wall", - y=11, - color="red", - x=7 - }, - { - class="static_wall", - y=1, - color="red", - x=11 - }, - { - class="static_wall", - y=1, - color="red", - x=10 - }, - { - class="static_wall", - y=9, - color="red", - x=11 - }, - { - class="static_wall", - y=8, - color="red", - x=11 - }, - { - class="static_wall", - y=11, - color="red", - x=4 - }, - { class="box", - y=6, color="red", + x=5 + }, + { + y=1, + class="static_wall", + color="green", + x=11 + }, + { + y=2, + class="static_wall", + color="green", + x=11 + }, + { + y=3, + class="static_wall", + color="green", + x=11 + }, + { + y=4, + class="static_wall", + color="green", + x=11 + }, + { + y=5, + class="static_wall", + color="green", + x=11 + }, + { + y=7, + class="static_wall", + color="green", + x=11 + }, + { + y=9, + class="static_wall", + color="green", + x=11 + }, + { + y=10, + class="static_wall", + color="green", + x=11 + }, + { + y=11, + class="static_wall", + color="green", + x=10 + }, + { + y=11, + class="static_wall", + color="green", + x=9 + }, + { + y=11, + class="static_wall", + color="green", + x=8 + }, + { + y=11, + class="static_wall", + color="green", + x=7 + }, + { + y=11, + class="static_wall", + color="green", x=6 }, { + y=11, + class="static_wall", + color="green", + x=5 + }, + { + y=11, + class="static_wall", + color="green", + x=4 + }, + { + y=11, + class="static_wall", + color="green", + x=3 + }, + { + y=11, + class="static_wall", + color="green", + x=2 + }, + { + y=11, + class="static_wall", + color="green", + x=1 + }, + { + y=10, + class="static_wall", + color="green", + x=1 + }, + { + y=9, + class="static_wall", + color="green", + x=1 + }, + { + y=8, + class="static_wall", + color="green", + x=1 + }, + { + y=7, + class="static_wall", + color="green", + x=1 + }, + { + y=6, + class="static_wall", + color="green", + x=1 + }, + { + y=5, + class="static_wall", + color="green", + x=1 + }, + { + y=4, + class="static_wall", + color="green", + x=1 + }, + { + y=3, + class="static_wall", + color="green", + x=1 + }, + { + y=1, + class="static_wall", + color="green", + x=2 + }, + { + y=1, + class="static_wall", + color="green", + x=1 + }, + { + y=2, + class="static_wall", + color="green", + x=1 + }, + { + y=1, + class="static_wall", + color="green", + x=1 + }, + { + y=1, + class="static_wall", + color="green", + x=2 + }, + { + y=1, + class="static_wall", + color="green", + x=3 + }, + { + y=1, + class="static_wall", + color="green", + x=4 + }, + { + y=1, + class="static_wall", + color="green", + x=5 + }, + { + y=1, + class="static_wall", + color="green", + x=6 + }, + { + y=1, + class="static_wall", + color="green", + x=7 + }, + { + y=1, + class="static_wall", + color="green", + x=8 + }, + { + y=1, + class="static_wall", + color="green", + x=9 + }, + { + y=1, + class="static_wall", + color="green", + x=10 + }, + { + y=1, + class="static_wall", + color="green", + x=11 + }, + { + y=8, + class="static_wall", + color="green", + x=11 + }, + { + y=9, + class="static_wall", + color="green", + x=11 + }, + { + y=10, + class="static_wall", + color="green", + x=11 + }, + { + y=11, + class="static_wall", + color="green", + x=11 + }, + { + y=2, + class="static_wall", + color="green", + x=7 + }, + { + y=6, + class="door", + color="green", + x=11 + }, + { + y=4, + class="static_wall", + color="green", + x=5 + }, + { + y=4, + class="static_wall", + color="green", + x=7 + }, + { + y=2, + class="static_wall", + color="green", + x=4 + }, + { + y=3, + class="static_wall", + color="green", + x=4 + }, + { + y=6, + class="spiky_box_1x2_1-1", + color="green", + x=6 + }, + { + y=2, + class="box", + color="green", + x=5 + }, + { + y=1, + class="static_wall", + color="blue", + x=11 + }, + { + y=2, + class="static_wall", + color="blue", + x=11 + }, + { + y=3, + class="static_wall", + color="blue", + x=11 + }, + { + y=4, + class="static_wall", + color="blue", + x=11 + }, + { + y=5, + class="static_wall", + color="blue", + x=11 + }, + { + y=7, + class="static_wall", + color="blue", + x=11 + }, + { + y=9, + class="static_wall", + color="blue", + x=11 + }, + { + y=10, + class="static_wall", + color="blue", + x=11 + }, + { + y=11, + class="static_wall", + color="blue", + x=10 + }, + { + y=11, + class="static_wall", + color="blue", + x=9 + }, + { + y=11, + class="static_wall", + color="blue", + x=8 + }, + { + y=11, + class="static_wall", + color="blue", + x=7 + }, + { + y=11, + class="static_wall", + color="blue", + x=6 + }, + { + y=11, + class="static_wall", + color="blue", + x=5 + }, + { + y=11, + class="static_wall", + color="blue", + x=4 + }, + { + y=11, + class="static_wall", + color="blue", + x=3 + }, + { + y=11, + class="static_wall", + color="blue", + x=2 + }, + { + y=11, + class="static_wall", + color="blue", + x=1 + }, + { + y=10, + class="static_wall", + color="blue", + x=1 + }, + { + y=9, + class="static_wall", + color="blue", + x=1 + }, + { + y=8, + class="static_wall", + color="blue", + x=1 + }, + { + y=7, + class="static_wall", + color="blue", + x=1 + }, + { + y=6, + class="static_wall", + color="blue", + x=1 + }, + { + y=5, + class="static_wall", + color="blue", + x=1 + }, + { + y=4, + class="static_wall", + color="blue", + x=1 + }, + { + y=3, + class="static_wall", + color="blue", + x=1 + }, + { + y=1, + class="static_wall", + color="blue", + x=2 + }, + { + y=1, + class="static_wall", + color="blue", + x=1 + }, + { + y=2, + class="static_wall", + color="blue", + x=1 + }, + { + y=1, + class="static_wall", + color="blue", + x=1 + }, + { + y=1, + class="static_wall", + color="blue", + x=2 + }, + { + y=1, + class="static_wall", + color="blue", + x=3 + }, + { + y=1, + class="static_wall", + color="blue", + x=4 + }, + { + y=1, + class="static_wall", + color="blue", + x=5 + }, + { + y=1, + class="static_wall", + color="blue", + x=6 + }, + { + y=1, + class="static_wall", + color="blue", + x=7 + }, + { + y=1, + class="static_wall", + color="blue", + x=8 + }, + { + y=1, + class="static_wall", + color="blue", + x=9 + }, + { + y=1, + class="static_wall", + color="blue", + x=10 + }, + { + y=1, + class="static_wall", + color="blue", + x=11 + }, + { + y=8, + class="static_wall", + color="blue", + x=11 + }, + { + y=9, + class="static_wall", + color="blue", + x=11 + }, + { + y=10, + class="static_wall", + color="blue", + x=11 + }, + { + y=11, + class="static_wall", + color="blue", + x=11 + }, + { + y=2, + class="static_wall", + color="blue", + x=7 + }, + { + y=6, + class="door", + color="blue", + x=11 + }, + { + y=4, + class="static_wall", + color="blue", + x=5 + }, + { + y=4, + class="static_wall", + color="blue", + x=7 + }, + { + y=2, + class="static_wall", + color="blue", + x=4 + }, + { + y=3, + class="static_wall", + color="blue", + x=4 + }, + { + y=6, + class="spiky_box_1x2_1-1", + color="blue", + x=6 + }, + { + y=2, + class="box", + color="blue", + x=5 + }, + { + y=3, class="switch", - y=4, color="red", x=6 }, { - class="static_wall", - y=9, - color="green", - x=1 - }, - { - class="static_wall", - y=11, - color="green", - x=2 - }, - { - class="static_wall", - y=1, - color="green", - x=1 - }, - { - class="static_wall", - y=2, - color="green", - x=11 - }, - { - class="static_wall", - y=10, - color="green", - x=1 - }, - { - class="static_wall", - y=1, - color="green", - x=2 - }, - { - class="static_wall", - y=1, - color="green", - x=4 - }, - { - class="static_wall", y=3, - color="green", - x=11 - }, - { - class="static_wall", - y=1, - color="green", - x=5 - }, - { - class="static_wall", - y=1, - color="green", - x=10 - }, - { - class="static_wall", - y=11, - color="green", - x=5 - }, - { - class="static_wall", - y=4, - color="green", - x=11 - }, - { - class="static_wall", - y=1, - color="green", - x=7 - }, - { - class="static_wall", - y=10, - color="green", - x=11 - }, - { - class="static_wall", - y=8, - color="green", - x=1 - }, - { - class="static_wall", - y=11, - color="green", - x=11 - }, - { - class="static_wall", - y=5, - color="green", - x=11 - }, - { - class="static_wall", - y=11, - color="green", + class="switch", + color="red", x=9 }, { - class="static_wall", - y=11, + y=3, + class="switch", color="green", x=6 }, { - class="static_wall", - y=1, + y=3, + class="switch", color="green", x=9 }, { - class="static_wall", y=3, - color="green", - x=1 - }, - { - class="static_wall", - y=11, - color="green", - x=1 - }, - { - class="static_wall", - y=6, - color="green", - x=11 - }, - { - class="static_wall", - y=6, - color="green", - x=1 - }, - { - class="static_wall", - y=11, - color="green", - x=10 - }, - { - class="static_wall", - y=1, - color="green", - x=11 - }, - { - class="static_wall", - y=7, - color="green", - x=1 - }, - { - class="static_wall", - y=9, - color="green", - x=11 - }, - { - class="static_wall", - y=7, - color="green", - x=11 - }, - { - class="static_wall", - y=4, - color="green", - x=1 - }, - { - class="static_wall", - y=5, - color="green", - x=1 - }, - { - class="static_wall", - y=2, - color="green", - x=1 - }, - { - class="static_wall", - y=1, - color="green", - x=3 - }, - { - class="static_wall", - y=11, - color="green", - x=7 - }, - { - class="static_wall", - y=1, - color="green", - x=8 - }, - { - class="static_wall", - y=11, - color="green", - x=8 - }, - { - class="static_wall", - y=11, - color="green", - x=3 - }, - { - class="static_wall", - y=8, - color="green", - x=11 - }, - { - class="static_wall", - y=11, - color="green", - x=4 - }, - { - class="static_wall", - y=9, - color="blue", - x=1 - }, - { - class="static_wall", - y=11, - color="blue", - x=2 - }, - { - class="static_wall", - y=1, - color="blue", - x=1 - }, - { - class="static_wall", - y=2, - color="blue", - x=11 - }, - { - class="static_wall", - y=10, - color="blue", - x=1 - }, - { - class="static_wall", - y=1, - color="blue", - x=2 - }, - { - class="static_wall", - y=1, - color="blue", - x=4 - }, - { - class="static_wall", - y=3, - color="blue", - x=11 - }, - { - class="static_wall", - y=1, - color="blue", - x=5 - }, - { - class="static_wall", - y=1, - color="blue", - x=10 - }, - { - class="static_wall", - y=11, - color="blue", - x=5 - }, - { - class="static_wall", - y=4, - color="blue", - x=11 - }, - { - class="static_wall", - y=1, - color="blue", - x=7 - }, - { - class="static_wall", - y=10, - color="blue", - x=11 - }, - { - class="static_wall", - y=8, - color="blue", - x=1 - }, - { - class="static_wall", - y=11, - color="blue", - x=11 - }, - { - class="static_wall", - y=5, - color="blue", - x=11 - }, - { - class="static_wall", - y=11, - color="blue", - x=9 - }, - { - class="static_wall", - y=11, + class="switch", color="blue", x=6 }, { - class="static_wall", - y=1, + y=3, + class="switch", color="blue", x=9 }, { - class="static_wall", - y=3, - color="blue", - x=1 - }, - { - class="static_wall", - y=11, - 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=11, - color="blue", - x=10 - }, - { - class="static_wall", - y=1, - color="blue", - x=11 - }, - { - class="static_wall", - y=7, - color="blue", - x=1 - }, - { - class="static_wall", + x=5, y=9, - color="blue", - x=11 + class="player", + active=true, + color="red" }, { - class="static_wall", - y=7, - color="blue", - x=11 + x=5, + y=9, + class="player", + active=true, + color="green" }, { - class="static_wall", - y=4, - color="blue", - x=1 - }, - { - class="static_wall", - y=5, - color="blue", - x=1 - }, - { - class="static_wall", - y=2, - color="blue", - x=1 - }, - { - class="static_wall", - y=1, - color="blue", - x=3 - }, - { - class="static_wall", - y=11, - color="blue", - x=7 - }, - { - class="static_wall", - y=1, - color="blue", - x=8 - }, - { - class="static_wall", - y=11, - color="blue", - x=8 - }, - { - class="static_wall", - y=11, - color="blue", - x=3 - }, - { - class="static_wall", - y=8, - color="blue", - x=11 - }, - { - class="static_wall", - y=11, - color="blue", - x=4 - }, - { - class="npc", - y=8, - x=4 + x=5, + y=9, + class="player", + active=true, + color="blue" } } } \ No newline at end of file diff --git a/rooms/spiky_test_2.sav b/rooms/spiky_test_2.sav new file mode 100644 index 0000000..53e8f9d --- /dev/null +++ b/rooms/spiky_test_2.sav @@ -0,0 +1,1159 @@ +{ +objects={ + { + x=1, + y=6, + active=true, + color="blue", + class="player" + }, + { + x=1, + y=6, + active=true, + color="red", + class="player" + }, + { + x=1, + y=6, + active=true, + color="green", + class="player" + }, + { + y=1, + x=11, + class="static_wall", + color="blue" + }, + { + y=2, + x=11, + class="static_wall", + color="blue" + }, + { + y=3, + x=11, + class="static_wall", + color="blue" + }, + { + y=4, + x=11, + class="static_wall", + color="blue" + }, + { + y=5, + x=11, + class="static_wall", + color="blue" + }, + { + y=7, + x=11, + class="static_wall", + color="blue" + }, + { + y=9, + x=11, + class="static_wall", + color="blue" + }, + { + y=10, + x=11, + class="static_wall", + color="blue" + }, + { + y=11, + x=10, + class="static_wall", + color="blue" + }, + { + y=11, + x=9, + class="static_wall", + color="blue" + }, + { + y=11, + x=8, + class="static_wall", + color="blue" + }, + { + y=11, + x=7, + class="static_wall", + color="blue" + }, + { + y=11, + x=6, + class="static_wall", + color="blue" + }, + { + y=11, + x=5, + class="static_wall", + color="blue" + }, + { + y=11, + x=4, + class="static_wall", + color="blue" + }, + { + y=11, + x=3, + class="static_wall", + color="blue" + }, + { + y=11, + x=2, + class="static_wall", + color="blue" + }, + { + y=11, + x=1, + class="static_wall", + color="blue" + }, + { + y=10, + x=1, + class="static_wall", + color="blue" + }, + { + y=9, + x=1, + class="static_wall", + color="blue" + }, + { + y=8, + x=1, + class="static_wall", + color="blue" + }, + { + y=7, + x=1, + class="static_wall", + color="blue" + }, + { + y=5, + x=1, + class="static_wall", + color="blue" + }, + { + y=4, + x=1, + class="static_wall", + color="blue" + }, + { + y=3, + x=1, + class="static_wall", + color="blue" + }, + { + y=1, + x=2, + class="static_wall", + color="blue" + }, + { + y=1, + x=1, + class="static_wall", + color="blue" + }, + { + y=2, + x=1, + class="static_wall", + color="blue" + }, + { + y=1, + x=1, + class="static_wall", + color="blue" + }, + { + y=1, + x=2, + class="static_wall", + color="blue" + }, + { + y=1, + x=3, + class="static_wall", + color="blue" + }, + { + y=1, + x=4, + class="static_wall", + color="blue" + }, + { + y=1, + x=5, + class="static_wall", + color="blue" + }, + { + y=1, + x=6, + class="static_wall", + color="blue" + }, + { + y=1, + x=7, + class="static_wall", + color="blue" + }, + { + y=1, + x=8, + class="static_wall", + color="blue" + }, + { + y=1, + x=9, + class="static_wall", + color="blue" + }, + { + y=1, + x=10, + class="static_wall", + color="blue" + }, + { + y=1, + x=11, + class="static_wall", + color="blue" + }, + { + y=8, + x=11, + class="static_wall", + color="blue" + }, + { + y=9, + x=11, + class="static_wall", + color="blue" + }, + { + y=10, + x=11, + class="static_wall", + color="blue" + }, + { + y=11, + x=11, + class="static_wall", + color="blue" + }, + { + y=2, + x=7, + class="static_wall", + color="blue" + }, + { + y=6, + x=11, + class="door", + color="blue" + }, + { + y=4, + x=7, + class="static_wall", + color="blue" + }, + { + y=2, + x=4, + class="static_wall", + color="blue" + }, + { + y=3, + x=4, + class="static_wall", + color="blue" + }, + { + y=4, + x=4, + class="static_wall", + color="blue" + }, + { + y=5, + x=4, + class="static_wall", + color="blue" + }, + { + y=6, + x=4, + class="static_wall", + color="blue" + }, + { + y=4, + x=5, + class="static_wall", + color="blue" + }, + { + y=6, + x=5, + class="box", + color="blue" + }, + { + y=6, + x=7, + class="static_wall", + color="blue" + }, + { + y=7, + x=7, + class="static_wall", + color="blue" + }, + { + y=7, + x=5, + class="static_wall", + color="blue" + }, + { + y=4, + x=7, + class="static_wall", + color="blue" + }, + { + y=3, + x=7, + class="static_wall", + color="blue" + }, + { + y=8, + x=6, + class="spiky_box_1x2_1-1", + color="blue" + }, + { + y=2, + x=5, + class="box", + color="blue" + }, + { + y=1, + x=11, + class="static_wall", + color="red" + }, + { + y=2, + x=11, + class="static_wall", + color="red" + }, + { + y=3, + x=11, + class="static_wall", + color="red" + }, + { + y=1, + x=11, + class="static_wall", + color="red" + }, + { + y=2, + x=11, + class="static_wall", + color="red" + }, + { + y=3, + x=11, + class="static_wall", + color="red" + }, + { + y=4, + x=11, + class="static_wall", + color="red" + }, + { + y=5, + x=11, + class="static_wall", + color="red" + }, + { + y=7, + x=11, + class="static_wall", + color="red" + }, + { + y=9, + x=11, + class="static_wall", + color="red" + }, + { + y=10, + x=11, + class="static_wall", + color="red" + }, + { + y=11, + x=10, + class="static_wall", + color="red" + }, + { + y=11, + x=9, + class="static_wall", + color="red" + }, + { + y=11, + x=8, + class="static_wall", + color="red" + }, + { + y=11, + x=7, + class="static_wall", + color="red" + }, + { + y=11, + x=6, + class="static_wall", + color="red" + }, + { + y=11, + x=5, + class="static_wall", + color="red" + }, + { + y=11, + x=4, + class="static_wall", + color="red" + }, + { + y=11, + x=3, + class="static_wall", + color="red" + }, + { + y=11, + x=2, + class="static_wall", + color="red" + }, + { + y=11, + x=1, + class="static_wall", + color="red" + }, + { + y=10, + x=1, + class="static_wall", + color="red" + }, + { + y=9, + x=1, + class="static_wall", + color="red" + }, + { + y=8, + x=1, + class="static_wall", + color="red" + }, + { + y=7, + x=1, + class="static_wall", + color="red" + }, + { + y=5, + x=1, + class="static_wall", + color="red" + }, + { + y=4, + x=1, + class="static_wall", + color="red" + }, + { + y=3, + x=1, + class="static_wall", + color="red" + }, + { + y=1, + x=2, + class="static_wall", + color="red" + }, + { + y=1, + x=1, + class="static_wall", + color="red" + }, + { + y=2, + x=1, + class="static_wall", + color="red" + }, + { + y=1, + x=1, + class="static_wall", + color="red" + }, + { + y=1, + x=2, + class="static_wall", + color="red" + }, + { + y=1, + x=3, + class="static_wall", + color="red" + }, + { + y=1, + x=4, + class="static_wall", + color="red" + }, + { + y=1, + x=5, + class="static_wall", + color="red" + }, + { + y=1, + x=6, + class="static_wall", + color="red" + }, + { + y=1, + x=7, + class="static_wall", + color="red" + }, + { + y=1, + x=8, + class="static_wall", + color="red" + }, + { + y=1, + x=9, + class="static_wall", + color="red" + }, + { + y=1, + x=10, + class="static_wall", + color="red" + }, + { + y=1, + x=11, + class="static_wall", + color="red" + }, + { + y=8, + x=11, + class="static_wall", + color="red" + }, + { + y=9, + x=11, + class="static_wall", + color="red" + }, + { + y=10, + x=11, + class="static_wall", + color="red" + }, + { + y=11, + x=11, + class="static_wall", + color="red" + }, + { + y=2, + x=7, + class="static_wall", + color="red" + }, + { + y=6, + x=11, + class="door", + color="red" + }, + { + y=4, + x=7, + class="static_wall", + color="red" + }, + { + y=2, + x=4, + class="static_wall", + color="red" + }, + { + y=3, + x=4, + class="static_wall", + color="red" + }, + { + y=4, + x=4, + class="static_wall", + color="red" + }, + { + y=5, + x=4, + class="static_wall", + color="red" + }, + { + y=6, + x=4, + class="static_wall", + color="red" + }, + { + y=4, + x=5, + class="static_wall", + color="red" + }, + { + y=6, + x=5, + class="box", + color="red" + }, + { + y=6, + x=7, + class="static_wall", + color="red" + }, + { + y=7, + x=7, + class="static_wall", + color="red" + }, + { + y=7, + x=5, + class="static_wall", + color="red" + }, + { + y=4, + x=7, + class="static_wall", + color="red" + }, + { + y=3, + x=7, + class="static_wall", + color="red" + }, + { + y=8, + x=6, + class="spiky_box_1x2_1-1", + color="red" + }, + { + y=2, + x=5, + class="box", + color="red" + }, + { + y=1, + x=11, + class="static_wall", + color="green" + }, + { + y=2, + x=11, + class="static_wall", + color="green" + }, + { + y=3, + x=11, + class="static_wall", + color="green" + }, + { + y=4, + x=11, + class="static_wall", + color="green" + }, + { + y=5, + x=11, + class="static_wall", + color="green" + }, + { + y=7, + x=11, + class="static_wall", + color="green" + }, + { + y=9, + x=11, + class="static_wall", + color="green" + }, + { + y=10, + x=11, + class="static_wall", + color="green" + }, + { + y=11, + x=10, + class="static_wall", + color="green" + }, + { + y=11, + x=9, + class="static_wall", + color="green" + }, + { + y=11, + x=8, + class="static_wall", + color="green" + }, + { + y=11, + x=7, + class="static_wall", + color="green" + }, + { + y=11, + x=6, + class="static_wall", + color="green" + }, + { + y=11, + x=5, + class="static_wall", + color="green" + }, + { + y=11, + x=4, + class="static_wall", + color="green" + }, + { + y=11, + x=3, + class="static_wall", + color="green" + }, + { + y=11, + x=2, + class="static_wall", + color="green" + }, + { + y=11, + x=1, + class="static_wall", + color="green" + }, + { + y=10, + x=1, + class="static_wall", + color="green" + }, + { + y=9, + x=1, + class="static_wall", + color="green" + }, + { + y=8, + x=1, + class="static_wall", + color="green" + }, + { + y=7, + x=1, + class="static_wall", + color="green" + }, + { + y=5, + x=1, + class="static_wall", + color="green" + }, + { + y=4, + x=1, + class="static_wall", + color="green" + }, + { + y=3, + x=1, + class="static_wall", + color="green" + }, + { + y=1, + x=2, + class="static_wall", + color="green" + }, + { + y=1, + x=1, + class="static_wall", + color="green" + }, + { + y=2, + x=1, + class="static_wall", + color="green" + }, + { + y=1, + x=1, + class="static_wall", + color="green" + }, + { + y=1, + x=2, + class="static_wall", + color="green" + }, + { + y=1, + x=3, + class="static_wall", + color="green" + }, + { + y=1, + x=4, + class="static_wall", + color="green" + }, + { + y=1, + x=5, + class="static_wall", + color="green" + }, + { + y=1, + x=6, + class="static_wall", + color="green" + }, + { + y=1, + x=7, + class="static_wall", + color="green" + }, + { + y=1, + x=8, + class="static_wall", + color="green" + }, + { + y=1, + x=9, + class="static_wall", + color="green" + }, + { + y=1, + x=10, + class="static_wall", + color="green" + }, + { + y=1, + x=11, + class="static_wall", + color="green" + }, + { + y=8, + x=11, + class="static_wall", + color="green" + }, + { + y=9, + x=11, + class="static_wall", + color="green" + }, + { + y=10, + x=11, + class="static_wall", + color="green" + }, + { + y=11, + x=11, + class="static_wall", + color="green" + }, + { + y=2, + x=7, + class="static_wall", + color="green" + }, + { + y=6, + x=11, + class="door", + color="green" + }, + { + y=4, + x=7, + class="static_wall", + color="green" + }, + { + y=2, + x=4, + class="static_wall", + color="green" + }, + { + y=3, + x=4, + class="static_wall", + color="green" + }, + { + y=4, + x=4, + class="static_wall", + color="green" + }, + { + y=5, + x=4, + class="static_wall", + color="green" + }, + { + y=6, + x=4, + class="static_wall", + color="green" + }, + { + y=4, + x=5, + class="static_wall", + color="green" + }, + { + y=6, + x=5, + class="box", + color="green" + }, + { + y=6, + x=7, + class="static_wall", + color="green" + }, + { + y=7, + x=7, + class="static_wall", + color="green" + }, + { + y=7, + x=5, + class="static_wall", + color="green" + }, + { + y=4, + x=7, + class="static_wall", + color="green" + }, + { + y=3, + x=7, + class="static_wall", + color="green" + }, + { + y=8, + x=6, + class="spiky_box_1x2_1-1", + color="green" + }, + { + y=2, + x=5, + class="box", + color="green" + }, + { + y=5, + x=5, + class="switch", + color="blue" + }, + { + y=3, + x=5, + class="switch", + color="blue" + }, + { + y=5, + x=5, + class="switch", + color="red" + }, + { + y=3, + x=5, + class="switch", + color="red" + }, + { + y=5, + x=5, + class="switch", + color="green" + }, + { + y=3, + x=5, + class="switch", + color="green" + } +} +} \ No newline at end of file diff --git a/rooms/spiky_test_3.sav b/rooms/spiky_test_3.sav new file mode 100644 index 0000000..32aaabc --- /dev/null +++ b/rooms/spiky_test_3.sav @@ -0,0 +1,1249 @@ +{ +objects={ + { + x=1, + y=6, + active=true, + color="blue", + class="player" + }, + { + x=1, + y=6, + active=true, + color="red", + class="player" + }, + { + x=1, + y=6, + active=true, + color="green", + class="player" + }, + { + y=1, + x=11, + class="static_wall", + color="blue" + }, + { + y=2, + x=11, + class="static_wall", + color="blue" + }, + { + y=3, + x=11, + class="static_wall", + color="blue" + }, + { + y=4, + x=11, + class="static_wall", + color="blue" + }, + { + y=5, + x=11, + class="static_wall", + color="blue" + }, + { + y=7, + x=11, + class="static_wall", + color="blue" + }, + { + y=9, + x=11, + class="static_wall", + color="blue" + }, + { + y=10, + x=11, + class="static_wall", + color="blue" + }, + { + y=11, + x=10, + class="static_wall", + color="blue" + }, + { + y=11, + x=9, + class="static_wall", + color="blue" + }, + { + y=11, + x=8, + class="static_wall", + color="blue" + }, + { + y=11, + x=7, + class="static_wall", + color="blue" + }, + { + y=11, + x=6, + class="static_wall", + color="blue" + }, + { + y=11, + x=5, + class="static_wall", + color="blue" + }, + { + y=11, + x=4, + class="static_wall", + color="blue" + }, + { + y=11, + x=3, + class="static_wall", + color="blue" + }, + { + y=11, + x=2, + class="static_wall", + color="blue" + }, + { + y=11, + x=1, + class="static_wall", + color="blue" + }, + { + y=10, + x=1, + class="static_wall", + color="blue" + }, + { + y=9, + x=1, + class="static_wall", + color="blue" + }, + { + y=8, + x=1, + class="static_wall", + color="blue" + }, + { + y=7, + x=1, + class="static_wall", + color="blue" + }, + { + y=5, + x=1, + class="static_wall", + color="blue" + }, + { + y=4, + x=1, + class="static_wall", + color="blue" + }, + { + y=3, + x=1, + class="static_wall", + color="blue" + }, + { + y=1, + x=2, + class="static_wall", + color="blue" + }, + { + y=1, + x=1, + class="static_wall", + color="blue" + }, + { + y=2, + x=1, + class="static_wall", + color="blue" + }, + { + y=1, + x=1, + class="static_wall", + color="blue" + }, + { + y=1, + x=2, + class="static_wall", + color="blue" + }, + { + y=1, + x=3, + class="static_wall", + color="blue" + }, + { + y=1, + x=4, + class="static_wall", + color="blue" + }, + { + y=1, + x=5, + class="static_wall", + color="blue" + }, + { + y=1, + x=6, + class="static_wall", + color="blue" + }, + { + y=1, + x=7, + class="static_wall", + color="blue" + }, + { + y=1, + x=8, + class="static_wall", + color="blue" + }, + { + y=1, + x=9, + class="static_wall", + color="blue" + }, + { + y=1, + x=10, + class="static_wall", + color="blue" + }, + { + y=1, + x=11, + class="static_wall", + color="blue" + }, + { + y=8, + x=11, + class="static_wall", + color="blue" + }, + { + y=9, + x=11, + class="static_wall", + color="blue" + }, + { + y=10, + x=11, + class="static_wall", + color="blue" + }, + { + y=11, + x=11, + class="static_wall", + color="blue" + }, + { + y=2, + x=7, + class="static_wall", + color="blue" + }, + { + y=6, + x=11, + class="door", + color="blue" + }, + { + y=4, + x=7, + class="static_wall", + color="blue" + }, + { + y=2, + x=4, + class="static_wall", + color="blue" + }, + { + y=3, + x=4, + class="static_wall", + color="blue" + }, + { + y=4, + x=4, + class="static_wall", + color="blue" + }, + { + y=5, + x=4, + class="static_wall", + color="blue" + }, + { + y=6, + x=4, + class="static_wall", + color="blue" + }, + { + y=4, + x=5, + class="static_wall", + color="blue" + }, + { + y=6, + x=5, + class="box", + color="blue" + }, + { + y=7, + x=7, + class="static_wall", + color="blue" + }, + { + y=4, + x=7, + class="static_wall", + color="blue" + }, + { + y=2, + x=5, + class="box", + color="blue" + }, + { + y=8, + x=5, + class="static_wall", + color="blue" + }, + { + y=8, + x=7, + class="static_wall", + color="blue" + }, + { + y=7, + x=6, + class="spiky_box_1x2_1-1", + color="blue" + }, + { + y=5, + x=7, + class="static_wall", + color="blue" + }, + { + y=5, + x=7, + class="static_wall", + color="blue" + }, + { + y=6, + x=7, + class="static_wall", + color="blue" + }, + { + y=10, + x=4, + class="static_wall", + color="blue" + }, + { + y=10, + x=7, + class="static_wall", + color="blue" + }, + { + y=1, + x=11, + class="static_wall", + color="red" + }, + { + y=2, + x=11, + class="static_wall", + color="red" + }, + { + y=3, + x=11, + class="static_wall", + color="red" + }, + { + y=1, + x=11, + class="static_wall", + color="red" + }, + { + y=2, + x=11, + class="static_wall", + color="red" + }, + { + y=3, + x=11, + class="static_wall", + color="red" + }, + { + y=4, + x=11, + class="static_wall", + color="red" + }, + { + y=5, + x=11, + class="static_wall", + color="red" + }, + { + y=7, + x=11, + class="static_wall", + color="red" + }, + { + y=9, + x=11, + class="static_wall", + color="red" + }, + { + y=10, + x=11, + class="static_wall", + color="red" + }, + { + y=11, + x=10, + class="static_wall", + color="red" + }, + { + y=11, + x=9, + class="static_wall", + color="red" + }, + { + y=11, + x=8, + class="static_wall", + color="red" + }, + { + y=11, + x=7, + class="static_wall", + color="red" + }, + { + y=11, + x=6, + class="static_wall", + color="red" + }, + { + y=11, + x=5, + class="static_wall", + color="red" + }, + { + y=11, + x=4, + class="static_wall", + color="red" + }, + { + y=11, + x=3, + class="static_wall", + color="red" + }, + { + y=11, + x=2, + class="static_wall", + color="red" + }, + { + y=11, + x=1, + class="static_wall", + color="red" + }, + { + y=10, + x=1, + class="static_wall", + color="red" + }, + { + y=9, + x=1, + class="static_wall", + color="red" + }, + { + y=8, + x=1, + class="static_wall", + color="red" + }, + { + y=7, + x=1, + class="static_wall", + color="red" + }, + { + y=5, + x=1, + class="static_wall", + color="red" + }, + { + y=4, + x=1, + class="static_wall", + color="red" + }, + { + y=3, + x=1, + class="static_wall", + color="red" + }, + { + y=1, + x=2, + class="static_wall", + color="red" + }, + { + y=1, + x=1, + class="static_wall", + color="red" + }, + { + y=2, + x=1, + class="static_wall", + color="red" + }, + { + y=1, + x=1, + class="static_wall", + color="red" + }, + { + y=1, + x=2, + class="static_wall", + color="red" + }, + { + y=1, + x=3, + class="static_wall", + color="red" + }, + { + y=1, + x=4, + class="static_wall", + color="red" + }, + { + y=1, + x=5, + class="static_wall", + color="red" + }, + { + y=1, + x=6, + class="static_wall", + color="red" + }, + { + y=1, + x=7, + class="static_wall", + color="red" + }, + { + y=1, + x=8, + class="static_wall", + color="red" + }, + { + y=1, + x=9, + class="static_wall", + color="red" + }, + { + y=1, + x=10, + class="static_wall", + color="red" + }, + { + y=1, + x=11, + class="static_wall", + color="red" + }, + { + y=8, + x=11, + class="static_wall", + color="red" + }, + { + y=9, + x=11, + class="static_wall", + color="red" + }, + { + y=10, + x=11, + class="static_wall", + color="red" + }, + { + y=11, + x=11, + class="static_wall", + color="red" + }, + { + y=2, + x=7, + class="static_wall", + color="red" + }, + { + y=6, + x=11, + class="door", + color="red" + }, + { + y=4, + x=7, + class="static_wall", + color="red" + }, + { + y=2, + x=4, + class="static_wall", + color="red" + }, + { + y=3, + x=4, + class="static_wall", + color="red" + }, + { + y=4, + x=4, + class="static_wall", + color="red" + }, + { + y=5, + x=4, + class="static_wall", + color="red" + }, + { + y=6, + x=4, + class="static_wall", + color="red" + }, + { + y=4, + x=5, + class="static_wall", + color="red" + }, + { + y=6, + x=5, + class="box", + color="red" + }, + { + y=7, + x=7, + class="static_wall", + color="red" + }, + { + y=4, + x=7, + class="static_wall", + color="red" + }, + { + y=2, + x=5, + class="box", + color="red" + }, + { + y=8, + x=5, + class="static_wall", + color="red" + }, + { + y=8, + x=7, + class="static_wall", + color="red" + }, + { + y=7, + x=6, + class="spiky_box_1x2_1-1", + color="red" + }, + { + y=5, + x=7, + class="static_wall", + color="red" + }, + { + y=5, + x=7, + class="static_wall", + color="red" + }, + { + y=6, + x=7, + class="static_wall", + color="red" + }, + { + y=10, + x=4, + class="static_wall", + color="red" + }, + { + y=10, + x=7, + class="static_wall", + color="red" + }, + { + y=1, + x=11, + class="static_wall", + color="green" + }, + { + y=2, + x=11, + class="static_wall", + color="green" + }, + { + y=3, + x=11, + class="static_wall", + color="green" + }, + { + y=4, + x=11, + class="static_wall", + color="green" + }, + { + y=5, + x=11, + class="static_wall", + color="green" + }, + { + y=7, + x=11, + class="static_wall", + color="green" + }, + { + y=9, + x=11, + class="static_wall", + color="green" + }, + { + y=10, + x=11, + class="static_wall", + color="green" + }, + { + y=11, + x=10, + class="static_wall", + color="green" + }, + { + y=11, + x=9, + class="static_wall", + color="green" + }, + { + y=11, + x=8, + class="static_wall", + color="green" + }, + { + y=11, + x=7, + class="static_wall", + color="green" + }, + { + y=11, + x=6, + class="static_wall", + color="green" + }, + { + y=11, + x=5, + class="static_wall", + color="green" + }, + { + y=11, + x=4, + class="static_wall", + color="green" + }, + { + y=11, + x=3, + class="static_wall", + color="green" + }, + { + y=11, + x=2, + class="static_wall", + color="green" + }, + { + y=11, + x=1, + class="static_wall", + color="green" + }, + { + y=10, + x=1, + class="static_wall", + color="green" + }, + { + y=9, + x=1, + class="static_wall", + color="green" + }, + { + y=8, + x=1, + class="static_wall", + color="green" + }, + { + y=7, + x=1, + class="static_wall", + color="green" + }, + { + y=5, + x=1, + class="static_wall", + color="green" + }, + { + y=4, + x=1, + class="static_wall", + color="green" + }, + { + y=3, + x=1, + class="static_wall", + color="green" + }, + { + y=1, + x=2, + class="static_wall", + color="green" + }, + { + y=1, + x=1, + class="static_wall", + color="green" + }, + { + y=2, + x=1, + class="static_wall", + color="green" + }, + { + y=1, + x=1, + class="static_wall", + color="green" + }, + { + y=1, + x=2, + class="static_wall", + color="green" + }, + { + y=1, + x=3, + class="static_wall", + color="green" + }, + { + y=1, + x=4, + class="static_wall", + color="green" + }, + { + y=1, + x=5, + class="static_wall", + color="green" + }, + { + y=1, + x=6, + class="static_wall", + color="green" + }, + { + y=1, + x=7, + class="static_wall", + color="green" + }, + { + y=1, + x=8, + class="static_wall", + color="green" + }, + { + y=1, + x=9, + class="static_wall", + color="green" + }, + { + y=1, + x=10, + class="static_wall", + color="green" + }, + { + y=1, + x=11, + class="static_wall", + color="green" + }, + { + y=8, + x=11, + class="static_wall", + color="green" + }, + { + y=9, + x=11, + class="static_wall", + color="green" + }, + { + y=10, + x=11, + class="static_wall", + color="green" + }, + { + y=11, + x=11, + class="static_wall", + color="green" + }, + { + y=2, + x=7, + class="static_wall", + color="green" + }, + { + y=6, + x=11, + class="door", + color="green" + }, + { + y=4, + x=7, + class="static_wall", + color="green" + }, + { + y=2, + x=4, + class="static_wall", + color="green" + }, + { + y=3, + x=4, + class="static_wall", + color="green" + }, + { + y=4, + x=4, + class="static_wall", + color="green" + }, + { + y=5, + x=4, + class="static_wall", + color="green" + }, + { + y=6, + x=4, + class="static_wall", + color="green" + }, + { + y=4, + x=5, + class="static_wall", + color="green" + }, + { + y=6, + x=5, + class="box", + color="green" + }, + { + y=7, + x=7, + class="static_wall", + color="green" + }, + { + y=4, + x=7, + class="static_wall", + color="green" + }, + { + y=2, + x=5, + class="box", + color="green" + }, + { + y=8, + x=5, + class="static_wall", + color="green" + }, + { + y=8, + x=7, + class="static_wall", + color="green" + }, + { + y=7, + x=6, + class="spiky_box_1x2_1-1", + color="green" + }, + { + y=5, + x=7, + class="static_wall", + color="green" + }, + { + y=5, + x=7, + class="static_wall", + color="green" + }, + { + y=6, + x=7, + class="static_wall", + color="green" + }, + { + y=10, + x=4, + class="static_wall", + color="green" + }, + { + y=10, + x=7, + class="static_wall", + color="green" + }, + { + y=5, + x=5, + class="switch", + color="blue" + }, + { + y=3, + x=5, + class="switch", + color="blue" + }, + { + y=4, + x=6, + class="switch", + color="blue" + }, + { + y=5, + x=5, + class="switch", + color="red" + }, + { + y=3, + x=5, + class="switch", + color="red" + }, + { + y=4, + x=6, + class="switch", + color="red" + }, + { + y=5, + x=5, + class="switch", + color="green" + }, + { + y=3, + x=5, + class="switch", + color="green" + }, + { + y=4, + x=6, + class="switch", + color="green" + } +} +} \ No newline at end of file diff --git a/rooms/tetromino_loop_t.sav b/rooms/tetromino_loop_t.sav new file mode 100644 index 0000000..0d67484 --- /dev/null +++ b/rooms/tetromino_loop_t.sav @@ -0,0 +1,994 @@ +{ +objects={ + { + y=10, + x=11, + class="static_wall", + color="red" + }, + { + y=9, + x=11, + class="static_wall", + color="red" + }, + { + y=8, + x=11, + class="static_wall", + color="red" + }, + { + y=7, + x=11, + class="static_wall", + color="red" + }, + { + y=5, + x=11, + class="static_wall", + color="red" + }, + { + y=4, + x=11, + class="static_wall", + color="red" + }, + { + y=3, + x=11, + class="static_wall", + color="red" + }, + { + y=2, + x=11, + class="static_wall", + color="red" + }, + { + y=1, + x=11, + class="static_wall", + color="red" + }, + { + y=1, + x=10, + class="static_wall", + color="red" + }, + { + y=1, + x=9, + class="static_wall", + color="red" + }, + { + y=1, + x=8, + class="static_wall", + color="red" + }, + { + y=1, + x=7, + class="static_wall", + color="red" + }, + { + y=1, + x=6, + class="static_wall", + color="red" + }, + { + y=1, + x=5, + class="static_wall", + color="red" + }, + { + y=1, + x=4, + class="static_wall", + color="red" + }, + { + y=1, + x=3, + class="static_wall", + color="red" + }, + { + y=1, + x=2, + class="static_wall", + color="red" + }, + { + y=1, + x=1, + class="static_wall", + color="red" + }, + { + y=2, + x=1, + class="static_wall", + color="red" + }, + { + y=3, + x=1, + class="static_wall", + color="red" + }, + { + y=4, + x=1, + class="static_wall", + color="red" + }, + { + y=5, + x=1, + class="static_wall", + color="red" + }, + { + y=6, + x=1, + class="static_wall", + color="red" + }, + { + y=8, + x=1, + class="static_wall", + color="red" + }, + { + y=9, + x=1, + class="static_wall", + color="red" + }, + { + y=10, + x=1, + 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=6, + 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="red" + }, + { + y=2, + x=8, + class="static_wall", + color="red" + }, + { + y=3, + x=9, + class="static_wall", + color="red" + }, + { + y=4, + x=2, + class="static_wall", + color="red" + }, + { + y=2, + x=2, + class="static_wall", + color="red" + }, + { + y=2, + x=3, + class="static_wall", + color="red" + }, + { + y=5, + x=5, + class="static_wall", + color="red" + }, + { + y=2, + x=4, + class="static_wall", + color="red" + }, + { + y=2, + x=5, + class="static_wall", + color="red" + }, + { + y=2, + x=6, + class="static_wall", + color="red" + }, + { + y=2, + x=7, + class="static_wall", + color="red" + }, + { + y=3, + x=5, + class="box_3x2_111-010", + color="red" + }, + { + y=3, + x=8, + class="static_wall", + color="red" + }, + { + y=5, + x=4, + class="static_wall", + color="red" + }, + { + y=5, + x=6, + class="static_wall", + color="red" + }, + { + y=6, + x=11, + class="door", + color="red" + }, + { + y=10, + x=11, + class="static_wall", + color="green" + }, + { + y=9, + x=11, + class="static_wall", + color="green" + }, + { + y=8, + x=11, + class="static_wall", + color="green" + }, + { + y=7, + x=11, + class="static_wall", + color="green" + }, + { + y=5, + x=11, + class="static_wall", + color="green" + }, + { + y=4, + x=11, + class="static_wall", + color="green" + }, + { + y=3, + x=11, + class="static_wall", + color="green" + }, + { + y=2, + x=11, + class="static_wall", + color="green" + }, + { + y=1, + x=11, + class="static_wall", + color="green" + }, + { + y=1, + x=10, + class="static_wall", + color="green" + }, + { + y=1, + x=9, + class="static_wall", + color="green" + }, + { + y=1, + x=8, + class="static_wall", + color="green" + }, + { + y=1, + x=7, + class="static_wall", + color="green" + }, + { + y=1, + x=6, + class="static_wall", + color="green" + }, + { + y=1, + x=5, + class="static_wall", + color="green" + }, + { + y=1, + x=4, + class="static_wall", + color="green" + }, + { + y=1, + x=3, + class="static_wall", + color="green" + }, + { + y=1, + x=2, + class="static_wall", + color="green" + }, + { + y=1, + x=1, + class="static_wall", + color="green" + }, + { + y=2, + x=1, + class="static_wall", + color="green" + }, + { + y=3, + x=1, + class="static_wall", + color="green" + }, + { + y=4, + x=1, + class="static_wall", + color="green" + }, + { + y=5, + x=1, + class="static_wall", + color="green" + }, + { + y=6, + x=1, + class="static_wall", + color="green" + }, + { + y=8, + x=1, + class="static_wall", + color="green" + }, + { + y=9, + x=1, + class="static_wall", + color="green" + }, + { + y=10, + x=1, + class="static_wall", + color="green" + }, + { + y=11, + x=1, + class="static_wall", + color="green" + }, + { + y=11, + x=2, + class="static_wall", + color="green" + }, + { + y=11, + x=3, + class="static_wall", + color="green" + }, + { + y=11, + x=4, + class="static_wall", + color="green" + }, + { + y=11, + x=5, + class="static_wall", + color="green" + }, + { + y=11, + x=6, + class="static_wall", + color="green" + }, + { + y=11, + x=7, + class="static_wall", + color="green" + }, + { + y=11, + x=8, + class="static_wall", + color="green" + }, + { + y=11, + x=9, + class="static_wall", + color="green" + }, + { + y=11, + x=10, + class="static_wall", + color="green" + }, + { + y=11, + x=11, + class="static_wall", + color="green" + }, + { + y=2, + x=8, + class="static_wall", + color="green" + }, + { + y=3, + x=9, + class="static_wall", + color="green" + }, + { + y=4, + x=2, + class="static_wall", + color="green" + }, + { + y=2, + x=2, + class="static_wall", + color="green" + }, + { + y=2, + x=3, + class="static_wall", + color="green" + }, + { + y=5, + x=5, + class="static_wall", + color="green" + }, + { + y=2, + x=4, + class="static_wall", + color="green" + }, + { + y=2, + x=5, + class="static_wall", + color="green" + }, + { + y=2, + x=6, + class="static_wall", + color="green" + }, + { + y=2, + x=7, + class="static_wall", + color="green" + }, + { + y=3, + x=5, + class="box_3x2_111-010", + color="green" + }, + { + y=3, + x=8, + class="static_wall", + color="green" + }, + { + y=5, + x=4, + class="static_wall", + color="green" + }, + { + y=5, + x=6, + class="static_wall", + color="green" + }, + { + y=6, + x=11, + class="door", + color="green" + }, + { + y=10, + x=11, + class="static_wall", + color="blue" + }, + { + y=9, + x=11, + class="static_wall", + color="blue" + }, + { + y=8, + x=11, + class="static_wall", + color="blue" + }, + { + y=7, + x=11, + class="static_wall", + color="blue" + }, + { + y=5, + x=11, + class="static_wall", + color="blue" + }, + { + y=4, + x=11, + class="static_wall", + color="blue" + }, + { + y=3, + x=11, + class="static_wall", + color="blue" + }, + { + y=2, + x=11, + class="static_wall", + color="blue" + }, + { + y=1, + x=11, + class="static_wall", + color="blue" + }, + { + y=1, + x=10, + class="static_wall", + color="blue" + }, + { + y=1, + x=9, + class="static_wall", + color="blue" + }, + { + y=1, + x=8, + class="static_wall", + color="blue" + }, + { + y=1, + x=7, + class="static_wall", + color="blue" + }, + { + y=1, + x=6, + class="static_wall", + color="blue" + }, + { + y=1, + x=5, + class="static_wall", + color="blue" + }, + { + y=1, + x=4, + class="static_wall", + color="blue" + }, + { + y=1, + x=3, + class="static_wall", + color="blue" + }, + { + y=1, + x=2, + class="static_wall", + color="blue" + }, + { + y=1, + x=1, + class="static_wall", + color="blue" + }, + { + y=2, + x=1, + class="static_wall", + color="blue" + }, + { + y=3, + x=1, + class="static_wall", + color="blue" + }, + { + y=4, + x=1, + class="static_wall", + color="blue" + }, + { + y=5, + x=1, + class="static_wall", + color="blue" + }, + { + y=6, + x=1, + class="static_wall", + color="blue" + }, + { + y=8, + x=1, + class="static_wall", + color="blue" + }, + { + y=9, + x=1, + class="static_wall", + color="blue" + }, + { + y=10, + x=1, + class="static_wall", + color="blue" + }, + { + y=11, + x=1, + class="static_wall", + color="blue" + }, + { + y=11, + x=2, + class="static_wall", + color="blue" + }, + { + y=11, + x=3, + class="static_wall", + color="blue" + }, + { + y=11, + x=4, + class="static_wall", + color="blue" + }, + { + y=11, + x=5, + class="static_wall", + color="blue" + }, + { + y=11, + x=6, + class="static_wall", + color="blue" + }, + { + y=11, + x=7, + class="static_wall", + color="blue" + }, + { + y=11, + x=8, + class="static_wall", + color="blue" + }, + { + y=11, + x=9, + class="static_wall", + color="blue" + }, + { + y=11, + x=10, + class="static_wall", + color="blue" + }, + { + y=11, + x=11, + class="static_wall", + color="blue" + }, + { + y=2, + x=8, + class="static_wall", + color="blue" + }, + { + y=3, + x=9, + class="static_wall", + color="blue" + }, + { + y=4, + x=2, + class="static_wall", + color="blue" + }, + { + y=2, + x=2, + class="static_wall", + color="blue" + }, + { + y=2, + x=3, + class="static_wall", + color="blue" + }, + { + y=5, + x=5, + class="static_wall", + color="blue" + }, + { + y=2, + x=4, + class="static_wall", + color="blue" + }, + { + y=2, + x=5, + class="static_wall", + color="blue" + }, + { + y=2, + x=6, + class="static_wall", + color="blue" + }, + { + y=2, + x=7, + class="static_wall", + color="blue" + }, + { + y=3, + x=5, + class="box_3x2_111-010", + color="blue" + }, + { + y=3, + x=8, + class="static_wall", + color="blue" + }, + { + y=5, + x=4, + class="static_wall", + color="blue" + }, + { + y=5, + x=6, + class="static_wall", + color="blue" + }, + { + y=6, + x=11, + class="door", + color="blue" + }, + { + y=3, + x=2, + class="switch", + color="red" + }, + { + y=3, + x=2, + class="switch", + color="green" + }, + { + y=3, + x=2, + class="switch", + color="blue" + }, + { + y=4, + x=4, + class="player", + color="red" + }, + { + y=4, + x=4, + class="player", + color="green" + }, + { + y=4, + x=4, + class="player", + color="blue" + } +} +} \ No newline at end of file diff --git a/rooms/village_start.sav b/rooms/village_start.sav new file mode 100644 index 0000000..9d77dda --- /dev/null +++ b/rooms/village_start.sav @@ -0,0 +1,795 @@ +{ +objects={ + { + y=1, + x=6, + class="door", + color="red" + }, + { + y=9, + x=1, + class="static_wall", + color="red" + }, + { + y=11, + x=2, + class="static_wall", + color="red" + }, + { + y=6, + x=5, + class="static_wall", + color="red" + }, + { + y=1, + x=1, + class="static_wall", + color="red" + }, + { + y=3, + x=1, + class="static_wall", + color="red" + }, + { + y=1, + x=3, + class="static_wall", + color="red" + }, + { + y=10, + x=1, + class="static_wall", + color="red" + }, + { + y=1, + x=2, + class="static_wall", + color="red" + }, + { + y=1, + x=4, + class="static_wall", + color="red" + }, + { + y=3, + x=11, + class="static_wall", + color="red" + }, + { + y=1, + x=5, + class="static_wall", + color="red" + }, + { + y=11, + x=3, + class="static_wall", + color="red" + }, + { + y=11, + x=5, + class="static_wall", + color="red" + }, + { + y=4, + x=11, + class="static_wall", + color="red" + }, + { + y=1, + x=7, + class="static_wall", + color="red" + }, + { + y=10, + x=11, + class="static_wall", + color="red" + }, + { + y=8, + x=1, + class="static_wall", + color="red" + }, + { + y=1, + x=9, + class="static_wall", + color="red" + }, + { + y=11, + x=11, + class="static_wall", + color="red" + }, + { + y=5, + x=11, + class="static_wall", + color="red" + }, + { + y=11, + x=9, + class="static_wall", + color="red" + }, + { + y=6, + x=8, + class="static_wall", + color="red" + }, + { + y=11, + x=6, + class="static_wall", + color="red" + }, + { + y=6, + x=7, + class="static_wall", + color="red" + }, + { + y=1, + x=8, + class="static_wall", + color="red" + }, + { + y=11, + x=1, + class="static_wall", + color="red" + }, + { + y=6, + x=11, + class="static_wall", + color="red" + }, + { + y=6, + x=2, + class="static_wall", + color="red" + }, + { + y=11, + x=10, + class="static_wall", + color="red" + }, + { + y=6, + x=1, + class="static_wall", + color="red" + }, + { + y=6, + x=10, + class="static_wall", + color="red" + }, + { + y=7, + x=1, + class="static_wall", + color="red" + }, + { + y=6, + x=9, + class="static_wall", + color="red" + }, + { + y=6, + x=3, + class="static_wall", + color="red" + }, + { + y=11, + x=8, + class="static_wall", + color="red" + }, + { + y=7, + x=11, + class="static_wall", + color="red" + }, + { + y=4, + x=1, + class="static_wall", + color="red" + }, + { + y=5, + x=1, + class="static_wall", + color="red" + }, + { + y=2, + x=1, + class="static_wall", + color="red" + }, + { + y=6, + x=4, + class="static_wall", + color="red" + }, + { + y=2, + x=11, + class="static_wall", + color="red" + }, + { + y=11, + x=7, + class="static_wall", + color="red" + }, + { + y=1, + x=11, + class="static_wall", + color="red" + }, + { + y=1, + x=10, + class="static_wall", + color="red" + }, + { + y=9, + x=11, + class="static_wall", + color="red" + }, + { + y=8, + x=11, + class="static_wall", + color="red" + }, + { + y=11, + x=4, + class="static_wall", + color="red" + }, + { + y=6, + x=6, + class="box", + color="red" + }, + { + y=1, + x=6, + class="door", + color="green" + }, + { + y=9, + x=1, + class="static_wall", + color="green" + }, + { + y=11, + x=2, + class="static_wall", + color="green" + }, + { + y=1, + x=1, + class="static_wall", + color="green" + }, + { + y=2, + x=11, + class="static_wall", + color="green" + }, + { + y=10, + x=1, + class="static_wall", + color="green" + }, + { + y=1, + x=2, + class="static_wall", + color="green" + }, + { + y=1, + x=4, + class="static_wall", + color="green" + }, + { + y=3, + x=11, + class="static_wall", + color="green" + }, + { + y=1, + x=5, + class="static_wall", + color="green" + }, + { + y=1, + x=10, + class="static_wall", + color="green" + }, + { + y=11, + x=5, + class="static_wall", + color="green" + }, + { + y=4, + x=11, + class="static_wall", + color="green" + }, + { + y=1, + x=7, + class="static_wall", + color="green" + }, + { + y=10, + x=11, + class="static_wall", + color="green" + }, + { + y=8, + x=1, + class="static_wall", + color="green" + }, + { + y=11, + x=11, + class="static_wall", + color="green" + }, + { + y=5, + x=11, + class="static_wall", + color="green" + }, + { + y=11, + x=9, + class="static_wall", + color="green" + }, + { + y=11, + x=6, + class="static_wall", + color="green" + }, + { + y=1, + x=9, + class="static_wall", + color="green" + }, + { + y=3, + x=1, + class="static_wall", + color="green" + }, + { + y=11, + x=1, + class="static_wall", + color="green" + }, + { + y=6, + x=11, + class="static_wall", + color="green" + }, + { + y=6, + x=1, + class="static_wall", + color="green" + }, + { + y=11, + x=10, + class="static_wall", + color="green" + }, + { + y=1, + x=11, + class="static_wall", + color="green" + }, + { + y=7, + x=1, + class="static_wall", + color="green" + }, + { + y=9, + x=11, + class="static_wall", + color="green" + }, + { + y=7, + x=11, + class="static_wall", + color="green" + }, + { + y=4, + x=1, + class="static_wall", + color="green" + }, + { + y=5, + x=1, + class="static_wall", + color="green" + }, + { + y=2, + x=1, + class="static_wall", + color="green" + }, + { + y=1, + x=3, + class="static_wall", + color="green" + }, + { + y=11, + x=7, + class="static_wall", + color="green" + }, + { + y=1, + x=8, + class="static_wall", + color="green" + }, + { + y=11, + x=8, + class="static_wall", + color="green" + }, + { + y=11, + x=3, + class="static_wall", + color="green" + }, + { + y=8, + x=11, + class="static_wall", + color="green" + }, + { + y=11, + x=4, + class="static_wall", + color="green" + }, + { + y=1, + x=6, + class="door", + color="blue" + }, + { + y=9, + x=1, + class="static_wall", + color="blue" + }, + { + y=11, + x=2, + class="static_wall", + color="blue" + }, + { + y=1, + x=1, + class="static_wall", + color="blue" + }, + { + y=2, + x=11, + class="static_wall", + color="blue" + }, + { + y=10, + x=1, + class="static_wall", + color="blue" + }, + { + y=1, + x=2, + class="static_wall", + color="blue" + }, + { + y=1, + x=4, + class="static_wall", + color="blue" + }, + { + y=3, + x=11, + class="static_wall", + color="blue" + }, + { + y=1, + x=5, + class="static_wall", + color="blue" + }, + { + y=1, + x=10, + class="static_wall", + color="blue" + }, + { + y=11, + x=5, + class="static_wall", + color="blue" + }, + { + y=4, + x=11, + class="static_wall", + color="blue" + }, + { + y=1, + x=7, + class="static_wall", + color="blue" + }, + { + y=10, + x=11, + class="static_wall", + color="blue" + }, + { + y=8, + x=1, + class="static_wall", + color="blue" + }, + { + y=11, + x=11, + class="static_wall", + color="blue" + }, + { + y=5, + x=11, + class="static_wall", + color="blue" + }, + { + y=11, + x=9, + class="static_wall", + color="blue" + }, + { + y=11, + x=6, + class="static_wall", + color="blue" + }, + { + y=1, + x=9, + class="static_wall", + color="blue" + }, + { + y=3, + x=1, + class="static_wall", + color="blue" + }, + { + y=11, + x=1, + class="static_wall", + color="blue" + }, + { + y=6, + x=11, + class="static_wall", + color="blue" + }, + { + y=6, + x=1, + class="static_wall", + color="blue" + }, + { + y=11, + x=10, + class="static_wall", + color="blue" + }, + { + y=1, + x=11, + class="static_wall", + color="blue" + }, + { + y=7, + x=1, + class="static_wall", + color="blue" + }, + { + y=9, + x=11, + class="static_wall", + color="blue" + }, + { + y=7, + x=11, + class="static_wall", + color="blue" + }, + { + y=4, + x=1, + class="static_wall", + color="blue" + }, + { + y=5, + x=1, + class="static_wall", + color="blue" + }, + { + y=2, + x=1, + class="static_wall", + color="blue" + }, + { + y=1, + x=3, + class="static_wall", + color="blue" + }, + { + y=11, + x=7, + class="static_wall", + color="blue" + }, + { + y=1, + x=8, + class="static_wall", + color="blue" + }, + { + y=11, + x=8, + class="static_wall", + color="blue" + }, + { + y=11, + x=3, + class="static_wall", + color="blue" + }, + { + y=8, + x=11, + class="static_wall", + color="blue" + }, + { + y=11, + x=4, + class="static_wall", + color="blue" + }, + { + y=4, + x=6, + class="switch", + color="red" + }, + { + x=4, + class="npc", + y=8 + }, + { + x=6, + color="red", + class="player", + y=9 + } +} +} \ No newline at end of file diff --git a/rooms/world.sav b/rooms/world.sav index fb9521d..a0be8d2 100644 --- a/rooms/world.sav +++ b/rooms/world.sav @@ -1,157 +1,207 @@ { +width=18, +height=18, rooms={ { - name="start", - y=11, - x=9 - }, - { + 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 - }, - { - name="village_2", - y=8, - x=12 + y=9 }, { + x=13, name="village_3", - y=8, - x=13 + y=8 }, { + 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=2, + name="ok", + y=8 + }, + { + x=5, + name="room_05_18", + y=18 + }, + { + x=9, + name="village_start", + y=11 + }, + { + x=4, + name="spiky_test", + y=8 + }, + { + x=5, + name="corner_trimino_test", + y=7 + }, + { + x=6, + name="tetromino_loop_t", + y=7 + }, + { + x=5, + name="corner_trimino_test_copy", + y=6 + }, + { + x=7, + name="room_07_07", + y=7 + }, + { + x=5, + name="spiky_test_2", + y=8 + }, + { + x=5, + name="spiky_test_3", + y=9 + }, + { + x=3, + name="jorge2", + y=14 } }, -lastRoom="yellow_4", -width=18, -height=18 +lastRoom="jorge2" } \ No newline at end of file diff --git a/shaders.lua b/shaders.lua index a08f415..491bac7 100644 --- a/shaders.lua +++ b/shaders.lua @@ -57,4 +57,122 @@ glow = love.graphics.newShader[[ } return pixel_me; } - ]] \ No newline at end of file + ]] + +-- Sticky boxes reuse the authored box textures. This shader only wobbles their +-- sampling; the draw helper adds a tiny squash-and-stretch bounce around center. +goopShader = love.graphics.newShader[[ + extern number goopTime; + extern vec2 sourceSize; + + float goopHash(float value) { + return fract(sin(value * 91.3458) * 47453.5453); + } + + vec4 effect(vec4 color, Image texture, vec2 textureCoords, vec2 screenCoords) { + float sourceY = textureCoords.y; + float pixelWidth = 1.0 / sourceSize.x; + float pixelHeight = 1.0 / sourceSize.y; + float column = floor(textureCoords.x * sourceSize.x / 2.0); + float seed = goopHash(column); + + // Two gentle, out-of-phase waves make the surface feel soft and viscous. + // Both stay sub-pixel so the authored silhouette remains recognizable. + float horizontalWave = sin(goopTime * 1.7 + sourceY * 10.0 + seed * 6.2831); + float verticalWave = sin(goopTime * 1.3 + textureCoords.x * 12.0 + seed * 3.1415); + float sourceX = clamp(textureCoords.x + horizontalWave * pixelWidth * 0.45, + pixelWidth * 0.5, 1.0 - pixelWidth * 0.5); + float wobbledY = clamp(sourceY + verticalWave * pixelHeight * 0.28, + pixelHeight * 0.5, 1.0 - pixelHeight * 0.5); + + return Texel(texture, vec2(sourceX, wobbledY)) * color; + } +]] + +function drawGoopySprite(sprite, x, y, scale) + local w, h = sprite:getWidth(), sprite:getHeight() + local time = love.timer.getTime() + local bounce = math.sin(time * 2.4 + w * .17 + h * .11) * .035 + local scaleX = scale * (1 + bounce) + local scaleY = scale * (1 - bounce) + local drawX = x - w * (scaleX - scale) / 2 + local drawY = y - h * (scaleY - scale) / 2 + + goopShader:send("goopTime", time) + goopShader:send("sourceSize", {w, h}) + local previousShader = love.graphics.getShader() + love.graphics.setShader(goopShader) + love.graphics.draw(sprite, drawX, drawY, 0, scaleX, scaleY) + love.graphics.setShader(previousShader) +end + +-- Accessibility post-process. The puzzle's RGB channels are normally also +-- its visual language, so this runs only after the entire scene has been +-- composed. It leaves neutral UI/text alone and remaps saturated colours to +-- a palette whose red, green, and yellow accents remain distinct for people +-- with deuteranopia. +accessibilityColorShader = love.graphics.newShader[[ + extern number accessibilityTime; + + vec3 rgbToHsv(vec3 c) { + float maximum = max(c.r, max(c.g, c.b)); + float minimum = min(c.r, min(c.g, c.b)); + float delta = maximum - minimum; + float hue = 0.0; + + if (delta > 0.0001) { + if (maximum == c.r) { + hue = mod((c.g - c.b) / delta, 6.0); + } else if (maximum == c.g) { + hue = ((c.b - c.r) / delta) + 2.0; + } else { + hue = ((c.r - c.g) / delta) + 4.0; + } + hue = hue / 6.0; + if (hue < 0.0) hue += 1.0; + } + + float saturation = maximum <= 0.0 ? 0.0 : delta / maximum; + return vec3(hue, saturation, maximum); + } + + vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords) { + vec4 pixel = Texel(texture, texture_coords) * color; + vec3 hsv = rgbToHsv(pixel.rgb); + + // Preserve greys, white (including additive RGB overlap), and near-black + // background detail. Only colourful puzzle elements are recoloured. + if (hsv.y < 0.22 || hsv.z < 0.06) return pixel; + + // Keep every additive pair in its own bucket. In particular, magenta + // (red + blue) must not become the same colour as red, and cyan + // (green + blue) must not become the same colour as green. + vec3 replacement; + float pattern = 0.0; + // Advance in whole pixels so the texture stays crisp instead of swimming. + float ditherStep = floor(accessibilityTime * 1.5); + if (hsv.x < 0.055 || hsv.x >= 0.94) { + replacement = vec3(0.93, 0.18, 0.50); // red: pink + } else if (hsv.x < 0.19) { + replacement = vec3(1.00, 0.78, 0.08); // red + green: gold + vec2 cell = mod(floor(screen_coords + vec2(ditherStep, 0.0)), vec2(9.0)); + pattern = length(cell - vec2(4.0)) < 1.6 ? 1.0 : 0.0; // dithered dots + } else if (hsv.x < 0.43) { + replacement = vec3(0.00, 0.72, 0.62); // green: turquoise + } else if (hsv.x < 0.58) { + replacement = vec3(0.12, 0.55, 0.96); // green + blue: sky blue + pattern = mod(floor(screen_coords.x + screen_coords.y + ditherStep), 10.0) < 2.0 ? 1.0 : 0.0; // dithered slashes + } else if (hsv.x < 0.77) { + replacement = vec3(0.38, 0.32, 0.96); // blue: indigo + } else { + replacement = vec3(0.72, 0.25, 0.92); // red + blue: purple + pattern = mod(floor((screen_coords.x + ditherStep) / 4.0) + floor(screen_coords.y / 4.0), 2.0); // dithered checker + } + + // Secondary colours get a gently animated dither cue, so they are + // identifiable even when their hue is hard to perceive. Lighting and + // fades remain. + replacement = mix(replacement, vec3(1.0), pattern * 0.55); + return vec4(replacement * hsv.z, pixel.a); + } +]] diff --git a/stories/jorge.ink b/stories/jorge.ink new file mode 100644 index 0000000..8aad2e8 --- /dev/null +++ b/stories/jorge.ink @@ -0,0 +1,7 @@ +Jorge: I'm Jorge. I'm LGBTQ+, and I spent too long hiding that. + +* [Be kind] I'm glad you told me. + Jorge smiles. "Thank you. Being met with kindness makes this place feel safer." +* [Mistreat Jorge] That's not something I respect. + Jorge's smile fades. "You can choose cruelty, but you don't get to define me." +- -> END diff --git a/stories/jorge.lua b/stories/jorge.lua new file mode 100644 index 0000000..bf52bfc --- /dev/null +++ b/stories/jorge.lua @@ -0,0 +1 @@ +return {["constants"]={},["tree"]={["_"]={["_"]={"Jorge: I'm Jorge. I'm LGBTQ+, and I spent too long hiding that.",{["node"]={"Jorge smiles. \"Thank you. Being met with kindness makes this place feel safer.\""},["choice"]="Be kind",["text"]="I'm glad you told me."},{["node"]={"Jorge's smile fades. \"You can choose cruelty, but you don't get to define me.\""},["choice"]="Mistreat Jorge",["text"]="That's not something I respect."},{["divert"]={["path"]="END",["tunnel"]=false}}}}},["inclusions"]={},["params"]={},["version"]={["tree"]=1,["engine"]=2},["variables"]={},["lists"]={}} \ No newline at end of file diff --git a/tests/test_movement.lua b/tests/test_movement.lua new file mode 100644 index 0000000..3f0395a --- /dev/null +++ b/tests/test_movement.lua @@ -0,0 +1,548 @@ +package.path = "./?.lua;" .. package.path + +local Movement = require "movement" + +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 assertIn(group, entity, message) + if group[entity] ~= entity then error(message or "expected entity in movement group", 2) end +end + +local function assertNotIn(group, entity, message) + if group[entity] then error(message or "expected entity outside movement group", 2) end +end + +local function movable(x, y, sticky, shape, skewer, spiky) + local entity = { + x = x, y = y, + sticky = sticky or false, + skewer = skewer or false, + spiky = spiky or false, + shape = shape or {{x = 0, y = 0}}, + } + function entity:canMove() return true end + function entity:canPassOver() return false end + function entity:isSticky() return self.sticky end + function entity:isSkewer() return self.skewer end + function entity:isSpiky() return self.spiky end + function entity:bump() end + function entity:move(axis, amount) self[axis] = self[axis] + amount end + function entity:getGridPos() return {x = self.x, y = self.y} end + function entity:getOccupiedCells(offset) + offset = offset or {x = 0, y = 0} + local cells = {} + for _, cell in ipairs(self.shape) do + table.insert(cells, {x = self.x + cell.x + offset.x, y = self.y + cell.y + offset.y}) + end + return cells + end + return entity +end + +local function wall(x, y) + local entity = movable(x, y) + function entity:canMove() return false end + return entity +end + +local function world(entities, width, height) + width, height = width or 8, height or 8 + local cells = {} + for _, entity in ipairs(entities) do + for _, cell in ipairs(entity:getOccupiedCells()) do + cells[cell.y .. ":" .. cell.x] = entity + end + end + return function(cell) + return cells[cell.y .. ":" .. cell.x] + end, function(cell) + return cell.x >= 1 and cell.x <= width and cell.y >= 1 and cell.y <= height + end +end + +local function plan(entities, startCell, direction, width, height) + local entityAt, inBounds = world(entities, width, height) + return Movement.findMovableGroup({startCell}, direction, entityAt, inBounds) +end + +test("ordinary pull only drags the block touching the player", function() + -- regular, regular, player; moving right + local rear = movable(2, 3) + local touching = movable(3, 3) + local possible, group = plan({rear, touching}, {x = 3, y = 3}, {x = 1, y = 0}) + assertTrue(possible) + assertIn(group, touching) + assertNotIn(group, rear) +end) + +test("a trailing sticky block joins a horizontal pull", function() + -- sticky, regular, player; moving right + local sticky = movable(2, 3, true) + local regular = movable(3, 3) + local possible, group = plan({sticky, regular}, {x = 3, y = 3}, {x = 1, y = 0}) + assertTrue(possible) + assertIn(group, regular) + assertIn(group, sticky) +end) + +test("a moving sticky block pulls a regular block behind it", function() + -- regular, sticky, player; moving right + local regular = movable(2, 3) + local sticky = movable(3, 3, true) + local possible, group = plan({regular, sticky}, {x = 3, y = 3}, {x = 1, y = 0}) + assertTrue(possible) + assertIn(group, sticky) + assertIn(group, regular) +end) + +test("sticky pull chains work vertically", function() + -- player moves down, pulling the two blocks above it + local sticky = movable(4, 2, true) + local regular = movable(4, 3) + local possible, group = plan({sticky, regular}, {x = 4, y = 3}, {x = 0, y = 1}) + assertTrue(possible) + assertIn(group, regular) + assertIn(group, sticky) +end) + +test("sticky pulls are symmetric in all four directions", function() + for _, direction in ipairs({ + {x = 1, y = 0}, {x = -1, y = 0}, + {x = 0, y = 1}, {x = 0, y = -1}, + }) do + local player = {x = 4, y = 4} + local regular = movable(player.x - direction.x, player.y - direction.y) + local sticky = movable(player.x - direction.x * 2, player.y - direction.y * 2, true) + local possible, group = plan( + {sticky, regular}, + {x = regular.x, y = regular.y}, + direction + ) + assertTrue(possible) + assertIn(group, regular) + assertIn(group, sticky) + end +end) + +test("a sticky block shears off during orthogonal movement", function() + -- The regular block moves right; the sticky block above it stays behind. + local regular = movable(3, 4) + local stickyBranch = movable(3, 3, true) + local possible, group = plan({regular, stickyBranch}, {x = 3, y = 4}, {x = 1, y = 0}) + assertTrue(possible) + assertIn(group, regular) + assertNotIn(group, stickyBranch) +end) + +test("a blocked sheared sticky block does not stop movement", function() + local regular = movable(3, 4) + local stickyBranch = movable(3, 3, true) + local blockingWall = wall(4, 3) + local possible, group = plan({regular, stickyBranch, blockingWall}, {x = 3, y = 4}, {x = 1, y = 0}) + assertTrue(possible) + assertIn(group, regular) + assertNotIn(group, stickyBranch) +end) + +test("a skewer carries an orthogonal branch", function() + local regular = movable(3, 4) + local skewerBranch = movable(3, 3, false, nil, true) + local possible, group = plan({regular, skewerBranch}, {x = 3, y = 4}, {x = 1, y = 0}) + assertTrue(possible) + assertIn(group, regular) + assertIn(group, skewerBranch) +end) + +test("a blocked skewer branch stops its rigid movement group", function() + local regular = movable(3, 4) + local skewerBranch = movable(3, 3, false, nil, true) + local blockingWall = wall(4, 3) + local possible = plan({regular, skewerBranch, blockingWall}, {x = 3, y = 4}, {x = 1, y = 0}) + assertFalse(possible) +end) + +test("a spiky block pulls both orthogonal side blocks", function() + local spiky = movable(4, 4, false, nil, false, true) + local upper = movable(4, 3) + local lower = movable(4, 5) + local possible, group = plan( + {spiky, upper, lower}, {x = 4, y = 4}, {x = 1, y = 0} + ) + + assertTrue(possible) + assertIn(group, spiky) + assertIn(group, upper) + assertIn(group, lower) +end) + +test("a spiky block releases one blocked side while pulling the other", function() + local spiky = movable(4, 4, false, nil, false, true) + local blockedUpper = movable(4, 3) + local freeLower = movable(4, 5) + local blockingWall = wall(5, 3) + local possible, group = plan( + {spiky, blockedUpper, freeLower, blockingWall}, + {x = 4, y = 4}, {x = 1, y = 0} + ) + + assertTrue(possible) + assertIn(group, spiky) + assertNotIn(group, blockedUpper) + assertIn(group, freeLower) +end) + +test("ordinary pushing still propagates through regular blocks", function() + local first = movable(3, 3) + local second = movable(4, 3) + local possible, group = plan({first, second}, {x = 3, y = 3}, {x = 1, y = 0}) + assertTrue(possible) + assertIn(group, first) + assertIn(group, second) +end) + +test("diagonal blocks do not stick", function() + local regular = movable(3, 3) + local diagonalSticky = movable(2, 2, true) + local possible, group = plan({regular, diagonalSticky}, {x = 3, y = 3}, {x = 1, y = 0}) + assertTrue(possible) + assertIn(group, regular) + assertNotIn(group, diagonalSticky) +end) + +test("multi-cell sticky blocks pull from every trailing occupied cell", function() + local tallRegular = movable(3, 3, false, {{x = 0, y = 0}, {x = 0, y = 1}}) + local sticky = movable(2, 4, true) + local possible, group = plan({tallRegular, sticky}, {x = 3, y = 3}, {x = 1, y = 0}) + assertTrue(possible) + assertIn(group, tallRegular) + assertIn(group, sticky) +end) + +test("an L-shaped sticky pulls from its trailing face in every direction", function() + local lShape = {{x = 0, y = 0}, {x = 1, y = 0}, {x = 0, y = 1}} + local cases = { + {direction = {x = 1, y = 0}, trailing = {x = 2, y = 3}}, + {direction = {x = -1, y = 0}, trailing = {x = 5, y = 3}}, + {direction = {x = 0, y = 1}, trailing = {x = 3, y = 2}}, + {direction = {x = 0, y = -1}, trailing = {x = 3, y = 5}}, + } + + for _, case in ipairs(cases) do + local stickyL = movable(3, 3, true, lShape) + local trailing = movable(case.trailing.x, case.trailing.y) + local possible, group = plan( + {stickyL, trailing}, {x = 3, y = 3}, case.direction + ) + assertTrue(possible) + assertIn(group, stickyL) + assertIn(group, trailing) + end +end) + +test("an L-shaped sticky can release one blocked pull while completing another", function() + -- Moving right, the two exposed trailing cells touch separate objects. The + -- upper object is pinned against a wall; the lower one is free to follow. + local stickyL = movable(3, 3, true, { + {x = 0, y = 0}, {x = 1, y = 0}, {x = 0, y = 1}, + }) + local pinned = movable(2, 2, false, {{x = 0, y = 0}, {x = 0, y = 1}}) + local free = movable(2, 4) + local blockingWall = wall(3, 2) + local possible, group = plan( + {stickyL, pinned, free, blockingWall}, + {x = 3, y = 3}, {x = 1, y = 0} + ) + + assertTrue(possible) + assertIn(group, stickyL) + assertIn(group, free) + assertNotIn(group, pinned) +end) + +test("a T-shaped sticky pulls independently across a notched trailing face", function() + -- Moving up, three exposed lower faces pull into cells vacated by the T. + local stickyT = movable(3, 3, true, { + {x = 0, y = 0}, {x = 1, y = 0}, {x = 2, y = 0}, + {x = 1, y = 1}, + }) + local trailingLeft = movable(3, 4) + local trailingRight = movable(5, 4) + local trailingStem = movable(4, 5) + local possible, group = plan( + {stickyT, trailingLeft, trailingRight, trailingStem}, + {x = 3, y = 3}, {x = 0, y = -1} + ) + + assertTrue(possible) + assertIn(group, stickyT) + assertIn(group, trailingLeft) + assertIn(group, trailingRight) + assertIn(group, trailingStem) +end) + +test("an L-shaped spiky block grabs moveables across several exposed faces", function() + local spikyL = movable(3, 3, false, { + {x = 0, y = 0}, {x = 1, y = 0}, {x = 0, y = 1}, + }, false, true) + local above = movable(3, 2) + local below = movable(3, 5) + local behind = movable(2, 3) + local possible, group = plan( + {spikyL, above, below, behind}, + {x = 3, y = 3}, {x = 1, y = 0} + ) + + assertTrue(possible) + assertIn(group, spikyL) + assertIn(group, above) + assertIn(group, below) + assertIn(group, behind) +end) + +test("production sticky, skewer, and spiky blocks advertise distinct behavior", function() + class = require "libs/middleclass" + Color = class("TestColor") + function Color:initialize(name) self.name = name end + function Color:getname() return self.name end + + require "generic_moveable" + require "generic_sticky" + require "generic_skewer" + require "generic_spiky" + local sprite = {getWidth = function() return 16 end, getHeight = function() return 16 end} + local regular = GenericMoveable:new(2, 2, "red", sprite, "box") + local sticky = GenericSticky:new(3, 2, "red", sprite, "sticky_box") + local skewer = GenericSkewer:new(4, 2, "red", sprite, "skewer_box") + local spiky = GenericSpiky:new(5, 2, "red", sprite, "spiky_box") + + assertTrue(regular:canMove()) + assertFalse(regular:isSticky()) + assertTrue(sticky:canMove()) + assertTrue(sticky:isSticky()) + assertFalse(sticky:isSkewer()) + assertTrue(skewer:canMove()) + assertFalse(skewer:isSticky()) + assertTrue(skewer:isSkewer()) + assertFalse(skewer:isSpiky()) + assertTrue(spiky:canMove()) + assertFalse(spiky:isSticky()) + assertFalse(spiky:isSkewer()) + assertTrue(spiky:isSpiky()) +end) + +local function loadRoomClass() + love = { + audio = { + newSource = function() + return {stop = function() end, play = function() end} + end, + }, + } + require "room" +end + +local function roomWith(player, entities, width, height) + gridWidth, gridHeight = width or 8, height or 8 + local matrix = {} + for y = 1, gridHeight do + matrix[y] = {} + for x = 1, gridWidth do matrix[y][x] = false end + end + for _, entity in ipairs(entities) do + for _, cell in ipairs(entity:getOccupiedCells()) do + matrix[cell.y][cell.x] = entity + end + end + + local room = setmetatable({ + activeColors = {red = true}, + colorsPlayerHas = {"red"}, + player = {red = player}, + collidableMatrices = {red = matrix}, + }, {__index = Room}) + room.playerJoinCheck = function() end + room.tick = function() end + return room +end + +test("Room applies the sticky-regular-player pull", function() + loadRoomClass() + local sticky = movable(2, 3, true) + local regular = movable(3, 3) + local player = movable(4, 3) + local room = roomWith(player, {sticky, regular}) + + room:movePlayer("right") + + assertTrue(sticky.x == 3, "sticky block should move one cell right") + assertTrue(regular.x == 4, "regular block should move one cell right") + assertTrue(player.x == 5, "player should move one cell right") +end) + +test("Room pulls sticky out of a pinned concave moveable", function() + loadRoomClass() + -- Before: ___ After: p__ + -- px_ sx_ + -- sm_ _m_ + -- mm_ mm_ + local player = movable(1, 2) + local wall = wall(2, 2) + local sticky = movable(1, 3, true) + local concave = movable(1, 3, false, { + {x = 1, y = 0}, + {x = 0, y = 1}, {x = 1, y = 1}, + }) + local room = roomWith(player, {wall, sticky, concave}) + + room:movePlayer("up") + + assertTrue(player.x == 1 and player.y == 1) + assertTrue(sticky.x == 1 and sticky.y == 2, "sticky should peel away from the concave block") + assertTrue(concave.x == 1 and concave.y == 3, "pinned concave block should stay put") + assertTrue(wall.x == 2 and wall.y == 2) +end) + +test("Room moves an L-shaped sticky and both available trailing pulls", function() + loadRoomClass() + local player = movable(3, 2) + local stickyL = movable(3, 3, true, { + {x = 0, y = 0}, {x = 1, y = 0}, {x = 0, y = 1}, + }) + local trailingLeft = movable(3, 5) + local trailingRight = movable(4, 4) + local room = roomWith(player, {stickyL, trailingLeft, trailingRight}) + + room:movePlayer("up") + + assertTrue(player.x == 3 and player.y == 1) + assertTrue(stickyL.x == 3 and stickyL.y == 2) + assertTrue(trailingLeft.x == 3 and trailingLeft.y == 4) + assertTrue(trailingRight.x == 4 and trailingRight.y == 3) +end) + +test("Room shears a lateral sticky contact", function() + loadRoomClass() + local sticky = movable(3, 2, true) + local regular = movable(3, 3) + local player = movable(4, 3) + local room = roomWith(player, {sticky, regular}) + + room:movePlayer("right") + + assertTrue(sticky.x == 3, "lateral sticky block should shear and stay behind") + assertTrue(regular.x == 4) + assertTrue(player.x == 5) +end) + +test("Room never moves a component found by push and pull twice", function() + loadRoomClass() + local player = movable(4, 4) + local front = movable(5, 4) + local bridgeRight = movable(5, 3, false, nil, true) + local bridgeMiddle = movable(4, 3, false, nil, true) + local bridgeLeft = movable(3, 3, false, nil, true) + local rear = movable(3, 4) + local component = {front, bridgeRight, bridgeMiddle, bridgeLeft, rear} + local room = roomWith(player, component) + + room:movePlayer("right") + + for _, entity in ipairs(component) do + assertTrue(entity.x <= 6, "an entity in the shared component moved more than once") + end + assertTrue(front.x == 6) + assertTrue(bridgeRight.x == 6) + assertTrue(bridgeMiddle.x == 5) + assertTrue(bridgeLeft.x == 4) + assertTrue(rear.x == 4) + assertTrue(player.x == 5) +end) + +test("Room pushes spiky onward while a blocked side shears off", function() + loadRoomClass() + local player = movable(3, 4) + local spiky = movable(4, 4, false, nil, false, true) + local blockedUpper = movable(4, 3) + local freeLower = movable(4, 5) + local blockingWall = wall(5, 3) + local room = roomWith(player, {spiky, blockedUpper, freeLower, blockingWall}) + + room:movePlayer("right") + + assertTrue(player.x == 4 and player.y == 4) + assertTrue(spiky.x == 5 and spiky.y == 4) + assertTrue(blockedUpper.x == 4 and blockedUpper.y == 3) + assertTrue(freeLower.x == 5 and freeLower.y == 5) + assertTrue(blockingWall.x == 5 and blockingWall.y == 3) +end) + +test("every moveable base box gets all three synthetic behavior variants", function() + local BoxVariants = require "box_variants" + local boxSprites = {red = "box_r.png"} + local boxCells = {red = {{x = 1, y = 1}}} + local shapeSprites = {blue = "box_shape_b.png"} + local shapeCells = {blue = {{x = 1, y = 1}, {x = 2, y = 1}}} + local lSprites = {green = "box_l_g.png"} + local lCells = {green = {{x = 1, y = 1}, {x = 1, y = 2}, {x = 2, y = 2}}} + local assets = { + box = {class = "moveable", sprites = boxSprites, cells = boxCells}, + ["box_2x1_11"] = {class = "moveable", sprites = shapeSprites, cells = shapeCells}, + ["box_2x2_10-11"] = {class = "moveable", sprites = lSprites, cells = lCells}, + box_statue = {class = "immoveable", sprites = {}}, + beer_mug = {class = "moveable", sprites = {}}, + } + + BoxVariants.addTo(assets) + + assertTrue(assets.sticky_box.class == "sticky") + assertTrue(assets.sticky_box.directory == "sticky") + assertTrue(assets.sticky_box.synthetic) + assertTrue(assets.sticky_box.goopy) + assertTrue(assets.sticky_box.sprites == boxSprites, "variant should share base sprites") + assertTrue(assets.sticky_box.cells == boxCells, "variant should share collision cells") + assertTrue(assets["sticky_box_2x1_11"].sprites == shapeSprites) + assertTrue(assets["sticky_box_2x1_11"].cells == shapeCells) + assertTrue(assets["sticky_box_2x2_10-11"].sprites == lSprites) + assertTrue(assets["sticky_box_2x2_10-11"].cells == lCells) + assertTrue(assets.skewer_box.class == "skewer") + assertTrue(assets.skewer_box.directory == "skewer") + assertTrue(assets.skewer_box.synthetic) + assertTrue(assets.skewer_box.skewer) + assertTrue(assets.skewer_box.sprites == boxSprites) + assertTrue(assets.skewer_box.cells == boxCells) + assertTrue(assets["skewer_box_2x1_11"].sprites == shapeSprites) + assertTrue(assets["skewer_box_2x2_10-11"].cells == lCells) + assertTrue(assets.spiky_box.class == "spiky") + assertTrue(assets.spiky_box.directory == "spiky") + assertTrue(assets.spiky_box.synthetic) + assertTrue(assets.spiky_box.spiky) + assertTrue(assets.spiky_box.sprites == boxSprites) + assertTrue(assets.spiky_box.cells == boxCells) + assertTrue(assets["spiky_box_2x1_11"].sprites == shapeSprites) + assertTrue(assets["spiky_box_2x2_10-11"].cells == lCells) + assertFalse(assets.sticky_box_statue) + assertFalse(assets.sticky_beer_mug) + assertFalse(assets.skewer_box_statue) + assertFalse(assets.skewer_beer_mug) + assertFalse(assets.spiky_box_statue) + assertFalse(assets.spiky_beer_mug) +end) + +print("movement/block-variant tests passed: " .. passed) diff --git a/world.lua b/world.lua index 7204cb1..7a4abe7 100644 --- a/world.lua +++ b/world.lua @@ -171,7 +171,16 @@ function World:drawRoomPreview(name, x, y, size) local path = props.sprites[color] if path then love.graphics.setColor(gColor[color]:set()) - love.graphics.draw(loadSprite(path), x + (object.x - 1) * 16 * scale, y + (object.y - 1) * 16 * scale, 0, scale, scale) + local sprite = loadSprite(path) + if props.goopy and drawGoopySprite then + drawGoopySprite(sprite, x + (object.x - 1) * 16 * scale, y + (object.y - 1) * 16 * scale, scale) + elseif props.skewer and drawSkewerSprite then + drawSkewerSprite(sprite, props.cells and props.cells[color], x + (object.x - 1) * 16 * scale, y + (object.y - 1) * 16 * scale, scale) + elseif props.spiky and drawSpikySprite then + drawSpikySprite(sprite, props.cells and props.cells[color], x + (object.x - 1) * 16 * scale, y + (object.y - 1) * 16 * scale, scale) + else + love.graphics.draw(sprite, x + (object.x - 1) * 16 * scale, y + (object.y - 1) * 16 * scale, 0, scale, scale) + end end end end @@ -180,6 +189,30 @@ function World:drawRoomPreview(name, x, y, size) love.graphics.setScissor() end +function World:drawHoveredRoomName() + local mouseX, mouseY = love.mouse.getPosition() + local cellX, cellY = self:getCellFromMousePos(mouseX, mouseY) + local name = self:isInBounds(cellX, cellY) and self:roomAt(cellX, cellY) + if not name then return end + + local font = love.graphics.getFont() + local padding = 6 + local tooltipW = math.min(font:getWidth(name) + padding * 2, width - 8) + local tooltipH = font:getHeight() + padding * 2 + local tooltipX = math.min(mouseX + 14, width - tooltipW - 4) + local tooltipY = math.min(mouseY + 14, height - tooltipH - 4) + tooltipX = math.max(4, tooltipX) + tooltipY = math.max(4, tooltipY) + + -- Keep the label anchored beside the pointer, while keeping it entirely in + -- the playable map rather than allowing it to spill into the editor panel. + love.graphics.setColor(0, 0, 0, 0.9) + love.graphics.rectangle("fill", tooltipX, tooltipY, tooltipW, tooltipH) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.rectangle("line", tooltipX, tooltipY, tooltipW, tooltipH) + love.graphics.printf(name, tooltipX + padding, tooltipY + padding, tooltipW - padding * 2, "left") +end + function World:draw() local cell = width / self.width love.graphics.setColor(12 / 255, 12 / 255, 20 / 255, 1) @@ -193,4 +226,5 @@ function World:draw() love.graphics.rectangle("line", screenX, screenY, cell, cell) end end + self:drawHoveredRoomName() end