diff --git a/art/_debug/notepad.png b/art/_debug/notepad.png new file mode 100644 index 0000000..68035d1 Binary files /dev/null and b/art/_debug/notepad.png differ diff --git a/level_editor/editor.lua b/level_editor/editor.lua index 7c957cf..2425ba7 100644 --- a/level_editor/editor.lua +++ b/level_editor/editor.lua @@ -1,6 +1,7 @@ require "level_editor/object_attributes" require "level_editor/gui" require "level_editor/layout" +require "level_editor/note_editor" editorView = "room" --can be "off", "room", "world", "asset" selectedColor = "white" @@ -10,6 +11,7 @@ local folderSprite = love.graphics.newImage("art/_ui/folder.png") local cancelSprite = love.graphics.newImage("art/_ui/cancel.png") local confirmSprite = love.graphics.newImage("art/_ui/confirm.png") local clearSavesSprite = love.graphics.newImage("art/_ui/clear_saves.png") +local notepadSprite = love.graphics.newImage("art/_debug/notepad.png") local selectedFolder = nil local selectedAsset = nil @@ -53,6 +55,12 @@ local boxPaletteOpen = false local boxPaletteScroll = { scroll = 0 } local boxPaletteSections = {} +-- Note authoring state. `noteMode` is nil normally, "create" while placing a new +-- note (click a cell to drop it and finish), or "edit" while retyping an +-- existing note (with Save / Discard). `editingNote` is the note being edited. +local noteMode = nil +local editingNote = nil + -- 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. @@ -241,6 +249,19 @@ local function roomSections() return { search = search, listRect = list, status = status, controls = controls } end +-- Save / Discard buttons for note edit mode, laid out in the status strip. Runs +-- for both drawing and hit-testing so the two never disagree. +local function noteEditButtonRects(s) + local gap = 8 + local h = math.min(28, s.status.h) + local w = (s.status.w - gap) / 2 + local y = s.status.y + (s.status.h - h) / 2 + return { + save = { x = s.status.x, y = y, w = w, h = h }, + discard = { x = s.status.x + w + gap, y = y, w = w, h = h }, + } +end + -- Position the bottom control cluster inside its section: level-name field, a -- row of colour buttons, then a row of action buttons. Runs for both drawing -- and hit-testing so the two never disagree. @@ -297,7 +318,7 @@ local function layoutRoomControls(c, s) placeRow({ "white", "red", "green", "blue" }, 22) placeRow({ "quick_player", "quick_static_wall", "quick_switch", "quick_door", "quick_wired_switch", "quick_wired_door", "quick_box" }, 22) - placeRow({ "save", "clearSaves", "world", "wire" }, 28) + placeRow({ "save", "clearSaves", "world", "wire", "note" }, 28) end -- Build the full room-view layout (sections + a scroll list + a back/search @@ -723,6 +744,16 @@ function _initLevelEditor() y = 0, }, "wire") + _addUIButton(createUIElement{ + name = "note", + sprite = notepadSprite, + onClic = { left = function() + if editorView == "room" then beginNoteCreate() end + end }, + x = 0, + y = 0, + }, "note") + roomNameField = createUIElement{ name = "roomName", text = editorRoomName, @@ -783,9 +814,50 @@ end function selectAsset(asset) print("selecting", asset) selectedAsset = asset + exitNoteMode() -- picking any real asset closes the note text field print(selectedAsset) end +-- Close the note text box and return to whatever the sidebar was showing before. +function exitNoteMode() + noteMode = nil + editingNote = nil + noteEditorBlur() +end + +-- Start authoring a new note: focus a blank text field. The author types, then +-- clicks a grid cell to drop the note there (that placement is the "done"). +function beginNoteCreate() + if editorView ~= "room" then return end + boxPaletteOpen = false + noteMode = "create" + editingNote = nil + noteEditorSetText("") + noteEditorFocus() +end + +-- Left-clicking an existing note reopens it for editing, with Save / Discard. +function beginNoteEdit(note) + noteMode = "edit" + editingNote = note + noteEditorSetText(note.text) + noteEditorFocus() +end + +function saveNoteEdit() + if editingNote then editingNote.text = noteEditorText() end + exitNoteMode() +end + +function discardNoteEdit() + exitNoteMode() +end + +-- Keyboard Escape while the field is focused: discard the edit / cancel placing. +function cancelNoteMode() + exitNoteMode() +end + function selectQuickAsset(asset) selectAsset(asset) boxPaletteOpen = asset == "box" @@ -922,6 +994,7 @@ function wireView() editorStatus = "Place this room in the world before drawing cross-room wires." return end + exitNoteMode() editorView = "wire" activeField = nil roomBrush = nil @@ -935,6 +1008,7 @@ function wireView() end function worldView() + exitNoteMode() editorView = "world" wireBrush = nil activeField = nil @@ -1169,6 +1243,22 @@ function editorMouseHandler(x, y, button) return end + -- While authoring a note, the field takes over the list area: a click + -- there positions the caret / starts a selection (its rect is set each + -- frame by noteEditorDraw). In edit mode, Save / Discard live in the + -- status strip. + if noteMode then + if noteMode == "edit" and button == 1 then + local nb = noteEditButtonRects(s) + if Layout.hit(nb.save, x, y) then saveNoteEdit(); return end + if Layout.hit(nb.discard, x, y) then discardNoteEdit(); return end + end + if noteEditorMousepressed(x, y) then return end + -- The field covers the list area; swallow other clicks there so the + -- hidden asset list underneath can't be selected by accident. + if Layout.hit(s.listRect, x, y) then return end + end + if s.boxPicker then local asset = s.boxPicker.at(x, y) if asset then @@ -1185,7 +1275,7 @@ function editorMouseHandler(x, y, button) end -- control cluster (only the buttons that live there) - for _, name in ipairs({ "roomName", "white", "red", "green", "blue", "quick_player", "quick_static_wall", "quick_switch", "quick_door", "quick_wired_switch", "quick_wired_door", "quick_box", "save", "clearSaves", "world", "wire" }) do + for _, name in ipairs({ "roomName", "white", "red", "green", "blue", "quick_player", "quick_static_wall", "quick_switch", "quick_door", "quick_wired_switch", "quick_wired_door", "quick_box", "save", "clearSaves", "world", "wire", "note" }) do local b = uiButtons[name] if b and b:clicIsInBox(x, y) then b:onClic(button) @@ -1232,6 +1322,20 @@ function editorMouseHandler(x, y, button) else -- click landed on the grid (game area): place the selected asset if editorView == "room" then + local cell = button == 1 and roomCellAt(x, y) + -- Placing a new note: drop it here carrying the typed text, then finish + -- (the drop is the "done"), returning the sidebar to its prior view. + if cell and noteMode == "create" then + currentRoom:attemptPlaceAtCell("note", nil, cell, selectedColor, noteEditorText()) + exitNoteMode() + return + end + -- Left-clicking an existing note opens it for editing instead of + -- painting over it. + if cell then + local note = currentRoom:noteAtCell(cell) + if note then beginNoteEdit(note); return end + end beginRoomBrush(x, y, button) elseif editorView == "wire" then beginWireBrush(x, y, button) @@ -1257,6 +1361,11 @@ function editorMouseHandler(x, y, button) end function editorMouseMoved(x, y) + if noteEditorActive() and x >= sideBarBox.x then + local vx = (x - sideBarBox.x) * sb.w / sideBarBox.w + local vy = y * sb.h / sideBarBox.h + if noteEditorMousemoved(vx, vy) then return end + end if wireBrush then if editorView ~= "wire" then wireBrush = nil; return end local cell = wireCellAt(x, y) @@ -1286,6 +1395,7 @@ function editorMouseMoved(x, y) end function editorMouseReleased(_, _, button) + noteEditorMousereleased() if roomBrush and roomBrush.button == button then roomBrush = nil end if wireBrush and wireBrush.button == button then wireBrush = nil end end @@ -1355,6 +1465,36 @@ function createUIElement(t) return GUI:new(t) end +-- Hover readout for note blocks, drawn in screen space over the play area (not +-- the sidebar). Mirrors World:drawHoveredRoomName's pointer-anchored tooltip so +-- it matches the overworld hover style. Only meaningful while notes are shown. +function editorDrawNoteHover() + if not (DEBUG and NOTES_VISIBLE) then return end + if editorView ~= "room" then return end + local mouseX, mouseY = love.mouse.getPosition() + if mouseX < 0 or mouseX >= width or mouseY < 0 or mouseY >= height then return end + + local note = currentRoom:noteAtCell(currentRoom:getCellFromMousePos(mouseX, mouseY)) + if not note or note.text == "" then return end + + local pad = 6 + local maxW = math.min(280, width - 8) + local _, wrapped = font:getWrap(note.text, maxW - pad * 2) + local textW = 0 + for _, line in ipairs(wrapped) do textW = math.max(textW, font:getWidth(line)) end + local tooltipW = math.min(textW + pad * 2, maxW) + local tooltipH = #wrapped * font:getHeight() + pad * 2 + + local tooltipX = math.max(4, math.min(mouseX + 14, width - tooltipW - 4)) + local tooltipY = math.max(4, math.min(mouseY + 14, height - tooltipH - 4)) + + 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(note.text, tooltipX + pad, tooltipY + pad, tooltipW - pad * 2, "left") +end + function editorDraw() if editorView == "room" then local s = buildRoomLayout() @@ -1373,7 +1513,17 @@ function editorDraw() love.graphics.rectangle("line", s.searchBox.x, s.searchBox.y, s.searchBox.w, s.searchBox.h) love.graphics.printf(boxPaletteOpen and "QUICK PALETTE" or "SEARCH: " .. assetSearchText, s.searchBox.x + 6, s.searchBox.y + 9, s.searchBox.w - 12, "left") - if s.boxPicker then + if noteMode then + -- Authoring a note: the text field replaces the asset list. In create + -- mode you click a grid cell to drop it; in edit mode Save / Discard sit + -- in the status strip below. + local labelH = 18 + local hint = noteMode == "edit" and "EDIT NOTE" or "NEW NOTE (click grid to place)" + love.graphics.setColor(gColor.white:set()) + love.graphics.printf(hint, s.listRect.x, s.listRect.y, s.listRect.w, "left") + noteEditorSetRect(s.listRect.x, s.listRect.y + labelH, s.listRect.w, s.listRect.h - labelH) + noteEditorDraw() + elseif s.boxPicker then drawBoxPicker(s.boxPicker) else -- Scrolling list, clipped to its section so nothing bleeds into others. @@ -1397,7 +1547,7 @@ function editorDraw() -- 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", "quick_player", "quick_static_wall", "quick_switch", "quick_door", "quick_wired_switch", "quick_wired_door", "quick_box", "save", "clearSaves", "world", "wire" }) do + for _, name in ipairs({ "roomName", "white", "red", "green", "blue", "quick_player", "quick_static_wall", "quick_switch", "quick_door", "quick_wired_switch", "quick_wired_door", "quick_box", "save", "clearSaves", "world", "wire", "note" }) do local button = uiButtons[name] if button then button:draw() @@ -1406,7 +1556,7 @@ function editorDraw() love.graphics.setColor(1, 1, 1, 1) love.graphics.print("W", button.x + button.w - 7, button.y - 4) end - if asset and selectedAsset == asset then + if (asset and selectedAsset == asset) or (name == "note" and noteMode ~= nil) 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) @@ -1414,8 +1564,17 @@ function editorDraw() end end - -- status strip between the list and the controls - if editorStatus then + -- status strip between the list and the controls: Save / Discard while + -- editing an existing note, otherwise the ordinary status line. + if noteMode == "edit" then + local nb = noteEditButtonRects(s) + love.graphics.setColor(gColor.white:set()) + for label, r in pairs({ SAVE = nb.save, DISCARD = nb.discard }) do + love.graphics.setLineWidth(2) + love.graphics.rectangle("line", r.x, r.y, r.w, r.h) + love.graphics.printf(label, r.x, r.y + (r.h - font:getHeight()) / 2, r.w, "center") + end + elseif editorStatus then Layout.clip(s.status) love.graphics.setColor(gColor.white:set()) love.graphics.printf(editorStatus, s.status.x, s.status.y + 4, s.status.w, "center") diff --git a/level_editor/note_editor.lua b/level_editor/note_editor.lua new file mode 100644 index 0000000..7d25155 --- /dev/null +++ b/level_editor/note_editor.lua @@ -0,0 +1,299 @@ +-- A small, self-contained multi-line text field for the level editor sidebar. +-- LÖVE ships no GUI widgets, so this rolls the minimum needed to feel like a +-- normal text box: a caret, a selection, mouse click/drag positioning, and the +-- usual keyboard shortcuts (arrows, word-jump, home/end, select-all, clipboard). +-- +-- Text is kept as an array of one-character strings (utf8-aware) with the caret +-- and selection anchor expressed as caret indices (0..#chars, a position between +-- characters). Everything else is derived from that. + +local utf8 = require("utf8") + +local pad = 6 + +local note = { + active = false, + chars = {}, -- array of single utf8 characters + caret = 0, -- 0..#chars + anchor = nil, -- selection start (caret index) or nil + rect = { x = 0, y = 0, w = 0, h = 0 }, + dragging = false, +} + +-- ── helpers ───────────────────────────────────────────────────────────────── + +local function toChars(str) + local t = {} + local i, len = 1, #str + while i <= len do + local nexti = utf8.offset(str, 2, i) or (len + 1) + t[#t + 1] = str:sub(i, nexti - 1) + i = nexti + end + return t +end + +local function clamp(v, lo, hi) + if v < lo then return lo elseif v > hi then return hi else return v end +end + +local function isWordChar(c) + return c ~= nil and c:match("[%w_]") ~= nil +end + +-- Line ranges as caret-index pairs: line covers caret indices s..e, and its text +-- is chars[s+1 .. e]. A blank final line after a trailing newline is included. +local function buildLines() + local lines, start = {}, 0 + for k = 1, #note.chars do + if note.chars[k] == "\n" then + lines[#lines + 1] = { s = start, e = k - 1 } + start = k + end + end + lines[#lines + 1] = { s = start, e = #note.chars } + return lines +end + +local function lineIndexOf(caret, lines) + for i, line in ipairs(lines) do + if caret >= line.s and caret <= line.e then return i end + end + return #lines +end + +-- Pixel width from a line's start up to `col` characters into it. +local function colWidth(line, col) + local s = table.concat(note.chars, "", line.s + 1, line.s + col) + return font:getWidth(s) +end + +-- ── selection / mutation ───────────────────────────────────────────────────── + +local function selectionRange() + if not note.anchor or note.anchor == note.caret then return nil end + return math.min(note.anchor, note.caret), math.max(note.anchor, note.caret) +end + +local function deleteRange(lo, hi) + for k = hi, lo + 1, -1 do table.remove(note.chars, k) end + note.caret = lo + note.anchor = nil +end + +local function deleteSelection() + local lo, hi = selectionRange() + if not lo then return false end + deleteRange(lo, hi) + return true +end + +local function insertText(str) + deleteSelection() + local ins = toChars(str) + for offset, c in ipairs(ins) do + table.insert(note.chars, note.caret + offset, c) + end + note.caret = note.caret + #ins + note.anchor = nil +end + +-- Move the caret, extending or clearing the selection depending on shift. +local function moveCaret(pos, keepSelection) + if keepSelection then + if not note.anchor then note.anchor = note.caret end + else + note.anchor = nil + end + note.caret = clamp(pos, 0, #note.chars) +end + +local function wordLeft(i) + local j = i + while j > 0 and not isWordChar(note.chars[j]) do j = j - 1 end + while j > 0 and isWordChar(note.chars[j]) do j = j - 1 end + return j +end + +local function wordRight(i) + local n = #note.chars + local j = i + while j < n and not isWordChar(note.chars[j + 1]) do j = j + 1 end + while j < n and isWordChar(note.chars[j + 1]) do j = j + 1 end + return j +end + +-- Map a point (sidebar-virtual coords) to the nearest caret index. +local function caretFromPoint(px, py) + local lines = buildLines() + local lineH = font:getHeight() + local row = clamp(math.floor((py - (note.rect.y + pad)) / lineH) + 1, 1, #lines) + local line = lines[row] + local target = px - (note.rect.x + pad) + local best, bestDist = 0, math.huge + for col = 0, line.e - line.s do + local dist = math.abs(colWidth(line, col) - target) + if dist < bestDist then best, bestDist = col, dist end + end + return line.s + best +end + +-- ── public API (globals, matching the editor's module style) ───────────────── + +function noteEditorActive() + return note.active and editorView == "room" +end + +function noteEditorFocus() + note.active = true +end + +function noteEditorBlur() + note.active = false + note.dragging = false +end + +function noteEditorText() + return table.concat(note.chars) +end + +function noteEditorSetText(str) + note.chars = toChars(str or "") + note.caret = #note.chars + note.anchor = nil +end + +function noteEditorSetRect(x, y, w, h) + note.rect.x, note.rect.y, note.rect.w, note.rect.h = x, y, w, h +end + +-- Click landed somewhere in the sidebar (virtual coords). Returns true if it hit +-- the field (so the caller stops looking for another control). +function noteEditorMousepressed(x, y) + local r = note.rect + if x < r.x or x > r.x + r.w or y < r.y or y > r.y + r.h then return false end + note.active = true + note.caret = caretFromPoint(x, y) + note.anchor = note.caret + note.dragging = true + return true +end + +function noteEditorMousemoved(x, y) + if not note.dragging then return false end + note.caret = caretFromPoint(x, y) + return true +end + +function noteEditorMousereleased() + note.dragging = false + if note.anchor == note.caret then note.anchor = nil end +end + +function noteEditorTextinput(t) + insertText(t) +end + +function noteEditorKeypressed(key) + local ctrl = love.keyboard.isDown("lctrl", "rctrl", "lgui", "rgui") + local shift = love.keyboard.isDown("lshift", "rshift") + + if key == "escape" then + noteEditorBlur() + elseif key == "return" or key == "kpenter" then + insertText("\n") + elseif key == "backspace" then + if not deleteSelection() then + local to = ctrl and wordLeft(note.caret) or note.caret - 1 + if to >= 0 and note.caret > 0 then deleteRange(math.max(0, to), note.caret) end + end + elseif key == "delete" then + if not deleteSelection() then + local to = ctrl and wordRight(note.caret) or note.caret + 1 + if note.caret < #note.chars then deleteRange(note.caret, math.min(#note.chars, to)) end + end + elseif key == "left" then + moveCaret(ctrl and wordLeft(note.caret) or note.caret - 1, shift) + elseif key == "right" then + moveCaret(ctrl and wordRight(note.caret) or note.caret + 1, shift) + elseif key == "up" or key == "down" then + local lines = buildLines() + local row = lineIndexOf(note.caret, lines) + local col = note.caret - lines[row].s + local target = clamp(row + (key == "up" and -1 or 1), 1, #lines) + local line = lines[target] + moveCaret(line.s + math.min(col, line.e - line.s), shift) + elseif key == "home" then + if ctrl then + moveCaret(0, shift) + else + local lines = buildLines() + moveCaret(lines[lineIndexOf(note.caret, lines)].s, shift) + end + elseif key == "end" then + if ctrl then + moveCaret(#note.chars, shift) + else + local lines = buildLines() + moveCaret(lines[lineIndexOf(note.caret, lines)].e, shift) + end + elseif ctrl and key == "a" then + note.anchor = 0 + note.caret = #note.chars + elseif ctrl and (key == "c" or key == "x") then + local lo, hi = selectionRange() + if lo then + love.system.setClipboardText(table.concat(note.chars, "", lo + 1, hi)) + if key == "x" then deleteRange(lo, hi) end + end + elseif ctrl and key == "v" then + insertText(love.system.getClipboardText() or "") + end +end + +-- Rendered inside the room-view sidebar (virtual space), clipped to its rect. +function noteEditorDraw() + local r = note.rect + local lines = buildLines() + local lineH = font:getHeight() + local ox, oy = r.x + pad, r.y + pad + + love.graphics.setColor(0, 0, 0, 0.85) + love.graphics.rectangle("fill", r.x, r.y, r.w, r.h) + love.graphics.setColor(gColor.white:set()) + love.graphics.setLineWidth(noteEditorActive() and 2 or 1) + love.graphics.rectangle("line", r.x, r.y, r.w, r.h) + + Layout.clip({ x = r.x, y = r.y, w = r.w, h = r.h }) + + -- selection highlight + local lo, hi = selectionRange() + if lo then + love.graphics.setColor(0.25, 0.45, 0.9, 0.6) + for i, line in ipairs(lines) do + local segStart, segEnd = math.max(lo, line.s), math.min(hi, line.e) + if segEnd > segStart then + local x1 = ox + colWidth(line, segStart - line.s) + local x2 = ox + colWidth(line, segEnd - line.s) + love.graphics.rectangle("fill", x1, oy + (i - 1) * lineH, x2 - x1, lineH) + end + end + end + + love.graphics.setColor(gColor.white:set()) + for i, line in ipairs(lines) do + local text = table.concat(note.chars, "", line.s + 1, line.e) + love.graphics.print(text, ox, oy + (i - 1) * lineH) + end + + -- caret (blinking) — only while focused + if noteEditorActive() and (love.timer.getTime() % 1) < 0.5 then + local row = lineIndexOf(note.caret, lines) + local cx = ox + colWidth(lines[row], note.caret - lines[row].s) + local cy = oy + (row - 1) * lineH + love.graphics.setLineWidth(1) + love.graphics.line(cx, cy, cx, cy + lineH) + end + + Layout.unclip() +end diff --git a/main.lua b/main.lua index f2c8ec2..d7d9a52 100644 --- a/main.lua +++ b/main.lua @@ -35,6 +35,10 @@ jorgeBook = require "stories.jorge" -- the DEBUG env var (DEBUG=0 to force off, DEBUG=1 to force on). DEBUG = os.getenv("DEBUG") ~= "0" +-- Whether editor "note" annotations render over the room. Toggled with Tab (see +-- love.keypressed); default on. Only ever consulted under DEBUG (see Room:draw). +NOTES_VISIBLE = true + function love.load() globalAssetProperties = {} -- rebuilt from the filesystem (art/ + .meta) by getAllAssets @@ -165,6 +169,7 @@ function love.draw() love.graphics.setBlendMode("alpha") love.graphics.setColor(1, 1, 1, 1) if DEBUG then love.graphics.draw(sideBarCanvas, sideBarBox.x, sideBarBox.y) end + if DEBUG then editorDrawNoteHover() end love.graphics.print("Current FPS: "..tostring(love.timer.getFPS( )), 10, 10) PerfProfiler:draw() Dialogue.draw() @@ -206,6 +211,19 @@ function love.keypressed(key) return end + -- The focused note text field owns the keyboard entirely: arrows navigate the + -- text instead of moving the player, Return inserts a newline, etc. + if DEBUG and noteEditorActive() then + if key == "escape" then cancelNoteMode() else noteEditorKeypressed(key) end + return + end + + -- Tab toggles the editor's note overlay (DEBUG-only; default on). + if DEBUG and key == "tab" then + NOTES_VISIBLE = not NOTES_VISIBLE + return + end + if editorView == "wire" and editorWireKeypressed(key) then return end if editorView ~= "world" and editorView ~= "wire" and Input.isPlayerMove(key) then @@ -264,6 +282,10 @@ end function love.textinput(t) if not DEBUG then return end + if noteEditorActive() then + noteEditorTextinput(t) + return + end response = response .. t editorTextHandler(response) end diff --git a/note.lua b/note.lua new file mode 100644 index 0000000..87280df --- /dev/null +++ b/note.lua @@ -0,0 +1,30 @@ +require "entity" + +-- An editor annotation dropped onto the grid. A Note is a normal Entity (so it +-- serializes, places and hit-tests like any other object) that carries a bit of +-- author text. It is deliberately non-collidable — the player passes straight +-- through it — and only ever renders as a translucent icon while the editor is +-- available (DEBUG) and notes are toggled on (see NOTES_VISIBLE / Room:draw). +Note = class("Note", Entity) + +local noteSprite = loadSprite("art/_debug/notepad.png") + +function Note:initialize(x, y, text) + self.text = text or "" + self.saveClass = "note" + Entity.initialize(self, { + x = x, y = y, + color = "white", -- representative only; Note:draw ignores channels + collision = "none", + sprite = noteSprite, + }) +end + +-- Drawn once (not per-channel) as a faint overlay. Called directly from the +-- room's note pass, so it takes no channel argument. +function Note:draw() + love.graphics.setColor(1, 1, 1, 0.85) + local p = self:getDrawPos() + love.graphics.draw(self.sprite, p.x, p.y, 0, drawScale, drawScale) + love.graphics.setColor(1, 1, 1, 1) +end diff --git a/room.lua b/room.lua index ab5ee85..d3d978f 100644 --- a/room.lua +++ b/room.lua @@ -17,6 +17,7 @@ require "generic_skewer" require "generic_spiky" require "generic_unmoveable" require "generic_player_blocker" +require "note" local Movement = require "movement" local Wire = require "wire" @@ -31,6 +32,7 @@ function Room:initialize(t) self.collideables = { red = {}, green = {}, blue = {} } self.playerBlockers = { red = {}, green = {}, blue = {} } self.npcs = {} + self.notes = {} self.activeColors = {red = false, green = false, blue = false} self.colorsPlayerHas = {} @@ -172,6 +174,16 @@ function Room:draw(drawChannels) for _, switch in ipairs(self.wiredSwitches) do switch:draw(channel) end for _, npc in ipairs(self.npcs) do npc:draw(channel) end end + + -- Notes are an editor-only overlay: shown only while the editor build is + -- running (DEBUG) and the NOTES_VISIBLE toggle is on. Drawn once (not per + -- channel) in alpha so the faint icon reads as itself instead of screen-adding. + if DEBUG and NOTES_VISIBLE and #self.notes > 0 then + local mode, alphaMode = love.graphics.getBlendMode() + love.graphics.setBlendMode("alpha") + for _, note in ipairs(self.notes) do note:draw() end + love.graphics.setBlendMode(mode, alphaMode) + end end function Room:wireTracksAt(cell, create) @@ -739,6 +751,11 @@ function Room:createEntity(class, color, x, y, data) self:registerNpc(entity) return entity end + if class == "note" then + local entity = Note:new(x, y, data.text) + self:registerNote(entity) + return entity + end local props = globalAssetProperties and globalAssetProperties[class] local behavior = props and props.class or "immoveable" @@ -857,6 +874,22 @@ function Room:registerNpc(entity) table.insert(self.npcs, entity) end +function Room:registerNote(entity) + -- Notes are like switches: a passable object kept in their own registry, so + -- serialize's note loop round-trips them and movement never sees them (their + -- "none" collision means canPassOver, so they are not stamped into a matrix). + table.insert(self.notes, entity) +end + +-- The note (if any) under a given grid cell — used by the editor's hover/click. +function Room:noteAtCell(cell) + if not cell then return nil end + for _, note in ipairs(self.notes) do + if note:occupiesCell(cell) then return note end + end + return nil +end + function Room:getCellFromMousePos(mouseX, mouseY) if gameWorld and gameWorld.levels and gameWorld.levels[self.name] == self and not gameWorld.drawingRoomNeighborhood then @@ -933,6 +966,11 @@ function Room:attemptDeleteAtCell(cell, color) for index = #self.npcs, 1, -1 do if self.npcs[index]:occupiesCell(cell) then table.remove(self.npcs, index) end end + -- Notes are non-collidable and colourless, so a right-click removes them + -- regardless of the currently selected editor colour. + for index = #self.notes, 1, -1 do + if self.notes[index]:occupiesCell(cell) then table.remove(self.notes, index) end + end self:tick() end @@ -940,7 +978,19 @@ function Room:attemptDelete(mouseX, mouseY, color) return self:attemptDeleteAtCell(self:getCellFromMousePos(mouseX, mouseY), color) end -function Room:attemptPlaceAtCell(name, props, cell, color) +function Room:attemptPlaceAtCell(name, props, cell, color, text) + -- Notes are colourless, single-instance annotations (no per-channel sprites), + -- so they place once carrying their text rather than one copy per colour. One + -- note per cell: drop any note already here before adding the new one. + if name == "note" then + if not cell then return end + for index = #self.notes, 1, -1 do + if self.notes[index]:occupiesCell(cell) then table.remove(self.notes, index) end + end + self:createEntity("note", nil, cell.x, cell.y, { text = text }) + self:tick() + return + end if not props or not props.sprites then return end if not cell then return end -- Jorge is one dialogable NPC with three display channels, not three @@ -1101,6 +1151,10 @@ function Room:serialize(includePlayers) table.insert(objects, { class = npc.saveClass or "npc", x = npc.x, y = npc.y }) end + for _, note in ipairs(self.notes) do + table.insert(objects, { class = "note", x = note.x, y = note.y, text = note.text }) + end + return { objects = objects, wires = self:serializeWires() } end diff --git a/rooms/room_05_15.sav b/rooms/room_05_15.sav new file mode 100644 index 0000000..ca21cbb --- /dev/null +++ b/rooms/room_05_15.sav @@ -0,0 +1,6 @@ +{ +objects={ +}, +wires={ +} +} \ No newline at end of file diff --git a/rooms/sticky_test_5.sav b/rooms/sticky_test_5.sav new file mode 100644 index 0000000..f4e3cf3 --- /dev/null +++ b/rooms/sticky_test_5.sav @@ -0,0 +1,711 @@ +{ +objects={ + { + class="player", + x=4, + color="green", + active=true, + y=9 + }, + { + class="player", + x=4, + color="blue", + active=true, + y=9 + }, + { + class="player", + x=4, + color="red", + active=true, + y=9 + }, + { + color="green", + y=11, + class="static_wall", + x=1 + }, + { + color="green", + y=11, + class="static_wall", + x=2 + }, + { + color="green", + y=11, + class="static_wall", + x=3 + }, + { + color="green", + y=11, + class="static_wall", + x=4 + }, + { + color="green", + y=11, + class="static_wall", + x=5 + }, + { + color="green", + y=11, + class="static_wall", + x=6 + }, + { + color="green", + y=11, + class="static_wall", + x=7 + }, + { + color="green", + y=11, + class="static_wall", + x=8 + }, + { + color="green", + y=11, + class="static_wall", + x=9 + }, + { + color="green", + y=11, + class="static_wall", + x=10 + }, + { + color="green", + y=11, + class="static_wall", + x=11 + }, + { + color="green", + y=11, + class="static_wall", + x=11 + }, + { + color="green", + y=10, + class="static_wall", + x=11 + }, + { + color="green", + y=9, + class="static_wall", + x=11 + }, + { + color="green", + y=8, + class="static_wall", + x=11 + }, + { + color="green", + y=6, + class="static_wall", + x=11 + }, + { + color="green", + y=5, + class="static_wall", + x=11 + }, + { + color="green", + y=6, + class="static_wall", + x=11 + }, + { + color="green", + y=7, + class="static_wall", + x=11 + }, + { + color="green", + y=1, + class="static_wall", + x=11 + }, + { + color="green", + y=5, + class="static_wall", + x=11 + }, + { + color="green", + y=4, + class="static_wall", + x=11 + }, + { + color="green", + y=3, + class="static_wall", + x=11 + }, + { + color="green", + y=2, + class="static_wall", + x=11 + }, + { + color="green", + y=1, + class="static_wall", + x=11 + }, + { + color="green", + y=1, + class="static_wall", + x=11 + }, + { + color="green", + y=1, + class="static_wall", + x=10 + }, + { + color="green", + y=1, + class="static_wall", + x=9 + }, + { + color="green", + y=1, + class="static_wall", + x=8 + }, + { + color="green", + y=1, + class="static_wall", + x=7 + }, + { + color="green", + y=1, + class="static_wall", + x=6 + }, + { + color="green", + y=1, + class="static_wall", + x=5 + }, + { + color="green", + y=1, + class="static_wall", + x=4 + }, + { + color="green", + y=1, + class="static_wall", + x=3 + }, + { + color="green", + y=1, + class="static_wall", + x=2 + }, + { + color="green", + y=1, + class="static_wall", + x=1 + }, + { + color="green", + y=3, + class="david_small", + x=7 + }, + { + color="green", + y=3, + class="the_scream", + x=2 + }, + { + color="blue", + y=11, + class="static_wall", + x=1 + }, + { + color="blue", + y=11, + class="static_wall", + x=2 + }, + { + color="blue", + y=11, + class="static_wall", + x=3 + }, + { + color="blue", + y=11, + class="static_wall", + x=4 + }, + { + color="blue", + y=11, + class="static_wall", + x=5 + }, + { + color="blue", + y=11, + class="static_wall", + x=6 + }, + { + color="blue", + y=11, + class="static_wall", + x=7 + }, + { + color="blue", + y=11, + class="static_wall", + x=8 + }, + { + color="blue", + y=11, + class="static_wall", + x=9 + }, + { + color="blue", + y=11, + class="static_wall", + x=10 + }, + { + color="blue", + y=11, + class="static_wall", + x=11 + }, + { + color="blue", + y=11, + class="static_wall", + x=11 + }, + { + color="blue", + y=10, + class="static_wall", + x=11 + }, + { + color="blue", + y=9, + class="static_wall", + x=11 + }, + { + color="blue", + y=8, + class="static_wall", + x=11 + }, + { + color="blue", + y=6, + class="static_wall", + x=11 + }, + { + color="blue", + y=5, + class="static_wall", + x=11 + }, + { + color="blue", + y=6, + class="static_wall", + x=11 + }, + { + color="blue", + y=7, + class="static_wall", + x=11 + }, + { + color="blue", + y=1, + class="static_wall", + x=11 + }, + { + color="blue", + y=5, + class="static_wall", + x=11 + }, + { + color="blue", + y=4, + class="static_wall", + x=11 + }, + { + color="blue", + y=3, + class="static_wall", + x=11 + }, + { + color="blue", + y=2, + class="static_wall", + x=11 + }, + { + color="blue", + y=1, + class="static_wall", + x=11 + }, + { + color="blue", + y=1, + class="static_wall", + x=11 + }, + { + color="blue", + y=1, + class="static_wall", + x=10 + }, + { + color="blue", + y=1, + class="static_wall", + x=9 + }, + { + color="blue", + y=1, + class="static_wall", + x=8 + }, + { + color="blue", + y=1, + class="static_wall", + x=7 + }, + { + color="blue", + y=1, + class="static_wall", + x=6 + }, + { + color="blue", + y=1, + class="static_wall", + x=5 + }, + { + color="blue", + y=1, + class="static_wall", + x=4 + }, + { + color="blue", + y=1, + class="static_wall", + x=3 + }, + { + color="blue", + y=1, + class="static_wall", + x=2 + }, + { + color="blue", + y=1, + class="static_wall", + x=1 + }, + { + color="blue", + y=3, + class="david_small", + x=7 + }, + { + color="blue", + y=3, + class="the_scream", + x=2 + }, + { + color="red", + y=11, + class="static_wall", + x=1 + }, + { + color="red", + y=11, + class="static_wall", + x=2 + }, + { + color="red", + y=11, + class="static_wall", + x=3 + }, + { + color="red", + y=11, + class="static_wall", + x=4 + }, + { + color="red", + y=11, + class="static_wall", + x=5 + }, + { + color="red", + y=11, + class="static_wall", + x=6 + }, + { + color="red", + y=11, + class="static_wall", + x=7 + }, + { + color="red", + y=11, + class="static_wall", + x=8 + }, + { + color="red", + y=11, + class="static_wall", + x=9 + }, + { + color="red", + y=11, + class="static_wall", + x=10 + }, + { + color="red", + y=11, + class="static_wall", + x=11 + }, + { + color="red", + y=11, + class="static_wall", + x=11 + }, + { + color="red", + y=10, + class="static_wall", + x=11 + }, + { + color="red", + y=9, + class="static_wall", + x=11 + }, + { + color="red", + y=8, + class="static_wall", + x=11 + }, + { + color="red", + y=6, + class="static_wall", + x=11 + }, + { + color="red", + y=5, + class="static_wall", + x=11 + }, + { + color="red", + y=6, + class="static_wall", + x=11 + }, + { + color="red", + y=7, + class="static_wall", + x=11 + }, + { + color="red", + y=1, + class="static_wall", + x=11 + }, + { + color="red", + y=5, + class="static_wall", + x=11 + }, + { + color="red", + y=4, + class="static_wall", + x=11 + }, + { + color="red", + y=3, + class="static_wall", + x=11 + }, + { + color="red", + y=2, + class="static_wall", + x=11 + }, + { + color="red", + y=1, + class="static_wall", + x=11 + }, + { + color="red", + y=1, + class="static_wall", + x=11 + }, + { + color="red", + y=1, + class="static_wall", + x=10 + }, + { + color="red", + y=1, + class="static_wall", + x=9 + }, + { + color="red", + y=1, + class="static_wall", + x=8 + }, + { + color="red", + y=1, + class="static_wall", + x=7 + }, + { + color="red", + y=1, + class="static_wall", + x=6 + }, + { + color="red", + y=1, + class="static_wall", + x=5 + }, + { + color="red", + y=1, + class="static_wall", + x=4 + }, + { + color="red", + y=1, + class="static_wall", + x=3 + }, + { + color="red", + y=1, + class="static_wall", + x=2 + }, + { + color="red", + y=1, + class="static_wall", + x=1 + }, + { + color="red", + y=3, + class="david_small", + x=7 + }, + { + color="red", + y=3, + class="the_scream", + x=2 + } +}, +wires={ +} +} \ No newline at end of file diff --git a/rooms/testing_sticky_3.sav b/rooms/testing_sticky_3.sav new file mode 100644 index 0000000..d5577eb --- /dev/null +++ b/rooms/testing_sticky_3.sav @@ -0,0 +1,1139 @@ +{ +wires={ +}, +objects={ + { + x=4, + y=11, + class="player", + color="blue", + active=true + }, + { + x=4, + y=11, + class="player", + color="red", + active=true + }, + { + x=4, + y=11, + class="player", + color="green", + active=true + }, + { + x=8, + color="blue", + y=1, + class="static_wall" + }, + { + x=9, + color="blue", + y=1, + class="static_wall" + }, + { + x=10, + color="blue", + y=1, + class="static_wall" + }, + { + x=11, + color="blue", + y=1, + class="static_wall" + }, + { + x=11, + color="blue", + y=11, + class="static_wall" + }, + { + x=10, + color="blue", + y=11, + class="static_wall" + }, + { + x=9, + color="blue", + y=11, + class="static_wall" + }, + { + x=8, + color="blue", + y=11, + class="static_wall" + }, + { + x=7, + color="blue", + y=11, + class="static_wall" + }, + { + x=6, + color="blue", + y=11, + class="static_wall" + }, + { + x=5, + color="blue", + y=11, + class="static_wall" + }, + { + x=3, + color="blue", + y=11, + class="static_wall" + }, + { + x=2, + color="blue", + y=11, + class="static_wall" + }, + { + x=1, + color="blue", + y=11, + class="static_wall" + }, + { + x=1, + color="blue", + y=10, + class="static_wall" + }, + { + x=1, + color="blue", + y=9, + class="static_wall" + }, + { + x=1, + color="blue", + y=8, + class="static_wall" + }, + { + x=1, + color="blue", + y=7, + class="static_wall" + }, + { + x=1, + color="blue", + y=6, + class="static_wall" + }, + { + x=1, + color="blue", + y=5, + class="static_wall" + }, + { + x=1, + color="blue", + y=4, + class="static_wall" + }, + { + x=1, + color="blue", + y=3, + class="static_wall" + }, + { + x=1, + color="blue", + y=2, + class="static_wall" + }, + { + x=1, + color="blue", + y=1, + class="static_wall" + }, + { + x=2, + color="blue", + y=1, + class="static_wall" + }, + { + x=4, + color="blue", + y=1, + class="static_wall" + }, + { + x=5, + color="blue", + y=1, + class="static_wall" + }, + { + x=6, + color="blue", + y=1, + class="static_wall" + }, + { + x=7, + color="blue", + y=1, + class="static_wall" + }, + { + x=8, + color="blue", + y=1, + class="static_wall" + }, + { + x=11, + color="blue", + y=6, + class="door" + }, + { + x=3, + color="blue", + y=3, + class="static_wall" + }, + { + x=3, + color="blue", + y=8, + class="static_wall" + }, + { + x=10, + color="blue", + y=8, + class="static_wall" + }, + { + x=11, + color="blue", + y=4, + class="static_wall" + }, + { + x=2, + color="blue", + y=7, + class="box_2x2_11-10" + }, + { + x=2, + color="blue", + y=5, + class="box_2x2_11-10" + }, + { + x=3, + color="blue", + y=1, + class="static_wall" + }, + { + x=4, + color="blue", + y=10, + class="spiky_box" + }, + { + x=8, + color="red", + y=1, + class="static_wall" + }, + { + x=9, + color="red", + y=1, + class="static_wall" + }, + { + x=10, + color="red", + y=1, + class="static_wall" + }, + { + x=11, + color="red", + y=1, + class="static_wall" + }, + { + x=11, + color="red", + y=11, + class="static_wall" + }, + { + x=10, + color="red", + y=11, + class="static_wall" + }, + { + x=9, + color="red", + y=11, + class="static_wall" + }, + { + x=8, + color="red", + y=11, + class="static_wall" + }, + { + x=7, + color="red", + y=11, + class="static_wall" + }, + { + x=6, + color="red", + y=11, + class="static_wall" + }, + { + x=5, + color="red", + y=11, + class="static_wall" + }, + { + x=3, + color="red", + y=11, + class="static_wall" + }, + { + x=2, + color="red", + y=11, + class="static_wall" + }, + { + x=1, + color="red", + y=11, + class="static_wall" + }, + { + x=1, + color="red", + y=10, + class="static_wall" + }, + { + x=1, + color="red", + y=9, + class="static_wall" + }, + { + x=1, + color="red", + y=8, + class="static_wall" + }, + { + x=1, + color="red", + y=7, + class="static_wall" + }, + { + x=1, + color="red", + y=6, + class="static_wall" + }, + { + x=1, + color="red", + y=5, + class="static_wall" + }, + { + x=1, + color="red", + y=4, + class="static_wall" + }, + { + x=1, + color="red", + y=3, + class="static_wall" + }, + { + x=1, + color="red", + y=2, + class="static_wall" + }, + { + x=1, + color="red", + y=1, + class="static_wall" + }, + { + x=2, + color="red", + y=1, + class="static_wall" + }, + { + x=4, + color="red", + y=1, + class="static_wall" + }, + { + x=5, + color="red", + y=1, + class="static_wall" + }, + { + x=6, + color="red", + y=1, + class="static_wall" + }, + { + x=7, + color="red", + y=1, + class="static_wall" + }, + { + x=8, + color="red", + y=1, + class="static_wall" + }, + { + x=11, + color="red", + y=6, + class="door" + }, + { + x=3, + color="red", + y=3, + class="static_wall" + }, + { + x=3, + color="red", + y=8, + class="static_wall" + }, + { + x=10, + color="red", + y=8, + class="static_wall" + }, + { + x=11, + color="red", + y=4, + class="static_wall" + }, + { + x=2, + color="red", + y=7, + class="box_2x2_11-10" + }, + { + x=2, + color="red", + y=5, + class="box_2x2_11-10" + }, + { + x=3, + color="red", + y=1, + class="static_wall" + }, + { + x=4, + color="red", + y=10, + class="spiky_box" + }, + { + x=8, + color="green", + y=1, + class="static_wall" + }, + { + x=9, + color="green", + y=1, + class="static_wall" + }, + { + x=10, + color="green", + y=1, + class="static_wall" + }, + { + x=11, + color="green", + y=1, + class="static_wall" + }, + { + x=11, + color="green", + y=11, + class="static_wall" + }, + { + x=10, + color="green", + y=11, + class="static_wall" + }, + { + x=9, + color="green", + y=11, + class="static_wall" + }, + { + x=8, + color="green", + y=11, + class="static_wall" + }, + { + x=7, + color="green", + y=11, + class="static_wall" + }, + { + x=6, + color="green", + y=11, + class="static_wall" + }, + { + x=5, + color="green", + y=11, + class="static_wall" + }, + { + x=3, + color="green", + y=11, + class="static_wall" + }, + { + x=2, + color="green", + y=11, + class="static_wall" + }, + { + x=1, + color="green", + y=11, + class="static_wall" + }, + { + x=1, + color="green", + y=10, + class="static_wall" + }, + { + x=1, + color="green", + y=9, + class="static_wall" + }, + { + x=1, + color="green", + y=8, + class="static_wall" + }, + { + x=1, + color="green", + y=7, + class="static_wall" + }, + { + x=1, + color="green", + y=6, + class="static_wall" + }, + { + x=1, + color="green", + y=5, + class="static_wall" + }, + { + x=1, + color="green", + y=4, + class="static_wall" + }, + { + x=1, + color="green", + y=3, + class="static_wall" + }, + { + x=1, + color="green", + y=2, + class="static_wall" + }, + { + x=1, + color="green", + y=1, + class="static_wall" + }, + { + x=2, + color="green", + y=1, + class="static_wall" + }, + { + x=4, + color="green", + y=1, + class="static_wall" + }, + { + x=5, + color="green", + y=1, + class="static_wall" + }, + { + x=6, + color="green", + y=1, + class="static_wall" + }, + { + x=7, + color="green", + y=1, + class="static_wall" + }, + { + x=8, + color="green", + y=1, + class="static_wall" + }, + { + x=11, + color="green", + y=6, + class="door" + }, + { + x=3, + color="green", + y=3, + class="static_wall" + }, + { + x=3, + color="green", + y=8, + class="static_wall" + }, + { + x=10, + color="green", + y=8, + class="static_wall" + }, + { + x=11, + color="green", + y=4, + class="static_wall" + }, + { + x=2, + color="green", + y=7, + class="box_2x2_11-10" + }, + { + x=2, + color="green", + y=5, + class="box_2x2_11-10" + }, + { + x=3, + color="green", + y=1, + class="static_wall" + }, + { + x=4, + color="green", + y=10, + class="spiky_box" + }, + { + x=8, + color="blue", + y=5, + class="player_blocker" + }, + { + x=9, + color="blue", + y=5, + class="player_blocker" + }, + { + x=10, + color="blue", + y=5, + class="player_blocker" + }, + { + x=11, + color="blue", + y=5, + class="player_blocker" + }, + { + x=8, + color="blue", + y=7, + class="player_blocker" + }, + { + x=9, + color="blue", + y=7, + class="player_blocker" + }, + { + x=10, + color="blue", + y=7, + class="player_blocker" + }, + { + x=11, + color="blue", + y=7, + class="player_blocker" + }, + { + x=7, + color="blue", + y=5, + class="player_blocker" + }, + { + x=6, + color="blue", + y=5, + class="player_blocker" + }, + { + x=6, + color="blue", + y=4, + class="player_blocker" + }, + { + x=6, + color="blue", + y=3, + class="player_blocker" + }, + { + x=6, + color="blue", + y=2, + class="player_blocker" + }, + { + x=8, + color="blue", + y=7, + class="player_blocker" + }, + { + x=7, + color="blue", + y=7, + class="player_blocker" + }, + { + x=6, + color="blue", + y=7, + class="player_blocker" + }, + { + x=6, + color="blue", + y=8, + class="player_blocker" + }, + { + x=6, + color="blue", + y=9, + class="player_blocker" + }, + { + x=6, + color="blue", + y=10, + class="player_blocker" + }, + { + x=6, + color="blue", + y=11, + class="player_blocker" + }, + { + x=8, + color="red", + y=5, + class="player_blocker" + }, + { + x=9, + color="red", + y=5, + class="player_blocker" + }, + { + x=10, + color="red", + y=5, + class="player_blocker" + }, + { + x=11, + color="red", + y=5, + class="player_blocker" + }, + { + x=8, + color="red", + y=7, + class="player_blocker" + }, + { + x=9, + color="red", + y=7, + class="player_blocker" + }, + { + x=10, + color="red", + y=7, + class="player_blocker" + }, + { + x=11, + color="red", + y=7, + class="player_blocker" + }, + { + x=7, + color="red", + y=5, + class="player_blocker" + }, + { + x=6, + color="red", + y=5, + class="player_blocker" + }, + { + x=6, + color="red", + y=4, + class="player_blocker" + }, + { + x=6, + color="red", + y=3, + class="player_blocker" + }, + { + x=6, + color="red", + y=2, + class="player_blocker" + }, + { + x=8, + color="red", + y=7, + class="player_blocker" + }, + { + x=7, + color="red", + y=7, + class="player_blocker" + }, + { + x=6, + color="red", + y=7, + class="player_blocker" + }, + { + x=6, + color="red", + y=8, + class="player_blocker" + }, + { + x=6, + color="red", + y=9, + class="player_blocker" + }, + { + x=6, + color="red", + y=10, + class="player_blocker" + }, + { + x=6, + color="red", + y=11, + class="player_blocker" + }, + { + x=8, + color="green", + y=5, + class="player_blocker" + }, + { + x=9, + color="green", + y=5, + class="player_blocker" + }, + { + x=10, + color="green", + y=5, + class="player_blocker" + }, + { + x=11, + color="green", + y=5, + class="player_blocker" + }, + { + x=8, + color="green", + y=7, + class="player_blocker" + }, + { + x=9, + color="green", + y=7, + class="player_blocker" + }, + { + x=10, + color="green", + y=7, + class="player_blocker" + }, + { + x=11, + color="green", + y=7, + class="player_blocker" + }, + { + x=7, + color="green", + y=5, + class="player_blocker" + }, + { + x=6, + color="green", + y=5, + class="player_blocker" + }, + { + x=6, + color="green", + y=4, + class="player_blocker" + }, + { + x=6, + color="green", + y=3, + class="player_blocker" + }, + { + x=6, + color="green", + y=2, + class="player_blocker" + }, + { + x=8, + color="green", + y=7, + class="player_blocker" + }, + { + x=7, + color="green", + y=7, + class="player_blocker" + }, + { + x=6, + color="green", + y=7, + class="player_blocker" + }, + { + x=6, + color="green", + y=8, + class="player_blocker" + }, + { + x=6, + color="green", + y=9, + class="player_blocker" + }, + { + x=6, + color="green", + y=10, + class="player_blocker" + }, + { + x=6, + color="green", + y=11, + class="player_blocker" + }, + { + x=9, + color="blue", + y=8, + class="switch" + }, + { + x=9, + color="blue", + y=4, + class="switch" + }, + { + x=9, + color="red", + y=8, + class="switch" + }, + { + x=9, + color="red", + y=4, + class="switch" + }, + { + x=9, + color="green", + y=8, + class="switch" + }, + { + x=9, + color="green", + y=4, + class="switch" + }, + { + x=7, + y=8, + text="this should be something else i guess\ +", + class="note" + }, + { + x=8, + y=3, + text="this should be something else i guess\ +", + class="note" + } +} +} \ No newline at end of file diff --git a/rooms/testing_sticky_4.sav b/rooms/testing_sticky_4.sav new file mode 100644 index 0000000..0661f6d --- /dev/null +++ b/rooms/testing_sticky_4.sav @@ -0,0 +1,831 @@ +{ +objects={ + { + color="red", + x=1, + class="static_wall", + y=11 + }, + { + color="red", + x=2, + class="static_wall", + y=11 + }, + { + color="red", + x=3, + class="static_wall", + y=11 + }, + { + color="red", + x=4, + class="static_wall", + y=11 + }, + { + color="red", + x=5, + class="static_wall", + y=11 + }, + { + color="red", + x=6, + class="static_wall", + y=11 + }, + { + color="red", + x=7, + class="static_wall", + y=11 + }, + { + color="red", + x=8, + class="static_wall", + y=11 + }, + { + color="red", + x=9, + class="static_wall", + y=11 + }, + { + color="red", + x=10, + class="static_wall", + y=11 + }, + { + color="red", + x=11, + class="static_wall", + y=11 + }, + { + color="red", + x=11, + class="static_wall", + y=10 + }, + { + color="red", + x=11, + class="static_wall", + y=8 + }, + { + color="red", + x=11, + class="static_wall", + y=7 + }, + { + color="red", + x=11, + class="static_wall", + y=6 + }, + { + color="red", + x=11, + class="static_wall", + y=3 + }, + { + color="red", + x=11, + class="static_wall", + y=2 + }, + { + color="red", + x=11, + class="static_wall", + y=3 + }, + { + color="red", + x=11, + class="static_wall", + y=4 + }, + { + color="red", + x=11, + class="static_wall", + y=5 + }, + { + color="red", + x=11, + class="static_wall", + y=4 + }, + { + color="red", + x=11, + class="static_wall", + y=3 + }, + { + color="red", + x=11, + class="static_wall", + y=2 + }, + { + color="red", + x=11, + class="static_wall", + y=1 + }, + { + color="red", + x=10, + class="static_wall", + y=1 + }, + { + color="red", + x=9, + class="static_wall", + y=1 + }, + { + color="red", + x=8, + class="static_wall", + y=1 + }, + { + color="red", + x=7, + class="static_wall", + y=1 + }, + { + color="red", + x=5, + class="static_wall", + y=1 + }, + { + color="red", + x=4, + class="static_wall", + y=1 + }, + { + color="red", + x=3, + class="static_wall", + y=1 + }, + { + color="red", + x=2, + class="static_wall", + y=1 + }, + { + color="red", + x=1, + class="static_wall", + y=1 + }, + { + color="red", + x=11, + class="door", + y=9 + }, + { + color="red", + x=2, + class="static_wall", + y=5 + }, + { + color="red", + x=2, + class="static_wall", + y=9 + }, + { + color="red", + x=6, + class="static_wall", + y=1 + }, + { + color="green", + x=1, + class="static_wall", + y=11 + }, + { + color="green", + x=2, + class="static_wall", + y=11 + }, + { + color="green", + x=3, + class="static_wall", + y=11 + }, + { + color="green", + x=4, + class="static_wall", + y=11 + }, + { + color="green", + x=5, + class="static_wall", + y=11 + }, + { + color="green", + x=6, + class="static_wall", + y=11 + }, + { + color="green", + x=7, + class="static_wall", + y=11 + }, + { + color="green", + x=8, + class="static_wall", + y=11 + }, + { + color="green", + x=9, + class="static_wall", + y=11 + }, + { + color="green", + x=10, + class="static_wall", + y=11 + }, + { + color="green", + x=11, + class="static_wall", + y=11 + }, + { + color="green", + x=11, + class="static_wall", + y=10 + }, + { + color="green", + x=11, + class="static_wall", + y=8 + }, + { + color="green", + x=11, + class="static_wall", + y=7 + }, + { + color="green", + x=11, + class="static_wall", + y=6 + }, + { + color="green", + x=11, + class="static_wall", + y=3 + }, + { + color="green", + x=11, + class="static_wall", + y=2 + }, + { + color="green", + x=11, + class="static_wall", + y=3 + }, + { + color="green", + x=11, + class="static_wall", + y=4 + }, + { + color="green", + x=11, + class="static_wall", + y=5 + }, + { + color="green", + x=11, + class="static_wall", + y=4 + }, + { + color="green", + x=11, + class="static_wall", + y=3 + }, + { + color="green", + x=11, + class="static_wall", + y=2 + }, + { + color="green", + x=11, + class="static_wall", + y=1 + }, + { + color="green", + x=10, + class="static_wall", + y=1 + }, + { + color="green", + x=9, + class="static_wall", + y=1 + }, + { + color="green", + x=8, + class="static_wall", + y=1 + }, + { + color="green", + x=7, + class="static_wall", + y=1 + }, + { + color="green", + x=5, + class="static_wall", + y=1 + }, + { + color="green", + x=4, + class="static_wall", + y=1 + }, + { + color="green", + x=3, + class="static_wall", + y=1 + }, + { + color="green", + x=2, + class="static_wall", + y=1 + }, + { + color="green", + x=1, + class="static_wall", + y=1 + }, + { + color="green", + x=11, + class="door", + y=9 + }, + { + color="green", + x=2, + class="static_wall", + y=5 + }, + { + color="green", + x=2, + class="static_wall", + y=9 + }, + { + color="green", + x=6, + class="static_wall", + y=1 + }, + { + color="blue", + x=1, + class="static_wall", + y=11 + }, + { + color="blue", + x=2, + class="static_wall", + y=11 + }, + { + color="blue", + x=3, + class="static_wall", + y=11 + }, + { + color="blue", + x=4, + class="static_wall", + y=11 + }, + { + color="blue", + x=5, + class="static_wall", + y=11 + }, + { + color="blue", + x=6, + class="static_wall", + y=11 + }, + { + color="blue", + x=7, + class="static_wall", + y=11 + }, + { + color="blue", + x=8, + class="static_wall", + y=11 + }, + { + color="blue", + x=9, + class="static_wall", + y=11 + }, + { + color="blue", + x=10, + class="static_wall", + y=11 + }, + { + color="blue", + x=11, + class="static_wall", + y=11 + }, + { + color="blue", + x=11, + class="static_wall", + y=10 + }, + { + color="blue", + x=11, + class="static_wall", + y=8 + }, + { + color="blue", + x=11, + class="static_wall", + y=7 + }, + { + color="blue", + x=11, + class="static_wall", + y=6 + }, + { + color="blue", + x=11, + class="static_wall", + y=3 + }, + { + color="blue", + x=11, + class="static_wall", + y=2 + }, + { + color="blue", + x=11, + class="static_wall", + y=3 + }, + { + color="blue", + x=11, + class="static_wall", + y=4 + }, + { + color="blue", + x=11, + class="static_wall", + y=5 + }, + { + color="blue", + x=11, + class="static_wall", + y=4 + }, + { + color="blue", + x=11, + class="static_wall", + y=3 + }, + { + color="blue", + x=11, + class="static_wall", + y=2 + }, + { + color="blue", + x=11, + class="static_wall", + y=1 + }, + { + color="blue", + x=10, + class="static_wall", + y=1 + }, + { + color="blue", + x=9, + class="static_wall", + y=1 + }, + { + color="blue", + x=8, + class="static_wall", + y=1 + }, + { + color="blue", + x=7, + class="static_wall", + y=1 + }, + { + color="blue", + x=5, + class="static_wall", + y=1 + }, + { + color="blue", + x=4, + class="static_wall", + y=1 + }, + { + color="blue", + x=3, + class="static_wall", + y=1 + }, + { + color="blue", + x=2, + class="static_wall", + y=1 + }, + { + color="blue", + x=1, + class="static_wall", + y=1 + }, + { + color="blue", + x=11, + class="door", + y=9 + }, + { + color="blue", + x=2, + class="static_wall", + y=5 + }, + { + color="blue", + x=2, + class="static_wall", + y=9 + }, + { + color="blue", + x=6, + class="static_wall", + y=1 + }, + { + color="red", + x=7, + class="player_blocker", + y=5 + }, + { + color="red", + x=8, + class="player_blocker", + y=5 + }, + { + color="red", + x=9, + class="player_blocker", + y=5 + }, + { + color="red", + x=10, + class="player_blocker", + y=5 + }, + { + color="red", + x=7, + class="player_blocker", + y=2 + }, + { + color="red", + x=7, + class="player_blocker", + y=3 + }, + { + color="red", + x=7, + class="player_blocker", + y=4 + }, + { + color="green", + x=7, + class="player_blocker", + y=5 + }, + { + color="green", + x=8, + class="player_blocker", + y=5 + }, + { + color="green", + x=9, + class="player_blocker", + y=5 + }, + { + color="green", + x=10, + class="player_blocker", + y=5 + }, + { + color="green", + x=7, + class="player_blocker", + y=2 + }, + { + color="green", + x=7, + class="player_blocker", + y=3 + }, + { + color="green", + x=7, + class="player_blocker", + y=4 + }, + { + color="blue", + x=7, + class="player_blocker", + y=5 + }, + { + color="blue", + x=8, + class="player_blocker", + y=5 + }, + { + color="blue", + x=9, + class="player_blocker", + y=5 + }, + { + color="blue", + x=10, + class="player_blocker", + y=5 + }, + { + color="blue", + x=7, + class="player_blocker", + y=2 + }, + { + color="blue", + x=7, + class="player_blocker", + y=3 + }, + { + color="blue", + x=7, + class="player_blocker", + y=4 + }, + { + color="red", + x=10, + class="switch", + y=2 + }, + { + color="green", + x=10, + class="switch", + y=2 + }, + { + color="blue", + x=10, + class="switch", + y=2 + }, + { + text="right now it's possible to like...strand the sticky block\ +here if it's at the end of one of the Ls and you push it with the other l.\ +\ +\ +is this something we can address? it would require the reset\ +block but idk. the only other thing is making it so\ +there's always a sticky and one non sticky. if you have\ +mopre than one nonsticky it will always be possible to strand \ +at certain depths of playerblockers.\ +", + x=5, + class="note", + y=3 + } +}, +wires={ +} +} \ No newline at end of file diff --git a/rooms/world.sav b/rooms/world.sav index fcdf2f1..ac7fe52 100644 --- a/rooms/world.sav +++ b/rooms/world.sav @@ -1,272 +1,292 @@ { -width=18, -height=18, -lastRoom="testing_sticky", rooms={ { y=10, - x=10, - name="3" + name="3", + x=10 }, { y=10, - x=12, - name="5" + name="5", + x=12 }, { y=9, - x=12, - name="village_1" + name="village_1", + x=12 }, { y=8, - x=11, - name="village_4" + name="village_4", + x=11 }, { y=7, - x=11, - name="yellow_1" + name="yellow_1", + x=11 }, { y=6, - x=11, - name="yellow_3" + name="yellow_3", + x=11 }, { y=7, - x=12, - name="yellow_2" + name="yellow_2", + x=12 }, { y=5, - x=11, - name="yellow_4" + name="yellow_4", + x=11 }, { y=4, - x=11, - name="yellow_5" + name="yellow_5", + x=11 }, { y=5, - x=10, - name="yellow_6" + name="yellow_6", + x=10 }, { y=1, - x=1, - name="default" + name="default", + x=1 }, { y=1, - x=3, - name="old_yellow_3" + name="old_yellow_3", + x=3 }, { y=1, - x=5, - name="test_patt" + name="test_patt", + x=5 }, { y=1, - x=7, - name="test_patt_update" + name="test_patt_update", + x=7 }, { y=1, - x=9, - name="white_asymmetrical" + name="white_asymmetrical", + x=9 }, { y=1, - x=11, - name="white_ok" + name="white_ok", + x=11 }, { y=1, - x=13, - name="white_primary" + name="white_primary", + x=13 }, { y=1, - x=15, - name="yellow_arches" + name="yellow_arches", + x=15 }, { y=1, - x=17, - name="yellow_asymmetrical" + name="yellow_asymmetrical", + x=17 }, { y=3, - x=1, - name="yellow_cc_moustache" + name="yellow_cc_moustache", + x=1 }, { y=3, - x=3, - name="yellow_color_changing_levvel_1" + name="yellow_color_changing_levvel_1", + x=3 }, { y=3, - x=7, - name="yellow_smile" + name="yellow_smile", + x=7 }, { y=10, - x=9, - name="2" + name="2", + x=9 }, { y=9, - x=11, - name="room_11_09" + name="room_11_09", + x=11 }, { y=3, - x=9, - name="yellow_skull" + name="yellow_skull", + x=9 }, { y=5, - x=5, - name="jorge_room" + name="jorge_room", + x=5 }, { y=10, - x=11, - name="4" + name="4", + x=11 }, { y=5, - x=1, - name="room_01_05" + name="room_01_05", + x=1 }, { y=8, - x=2, - name="ok" + name="ok", + x=2 }, { y=18, - x=5, - name="room_05_18" + name="room_05_18", + x=5 }, { y=11, - x=9, - name="village_start" + name="village_start", + x=9 }, { y=8, - x=4, - name="spiky_test" + name="spiky_test", + x=4 }, { y=7, - x=5, - name="corner_trimino_test" + name="corner_trimino_test", + x=5 }, { y=7, - x=6, - name="tetromino_loop_t" + name="tetromino_loop_t", + x=6 }, { y=6, - x=5, - name="corner_trimino_test_copy" + name="corner_trimino_test_copy", + x=5 }, { y=7, - x=7, - name="blocker_test" + name="blocker_test", + x=7 }, { y=8, - x=5, - name="spiky_test_2" + name="spiky_test_2", + x=5 }, { y=9, - x=5, - name="spiky_test_3" + name="spiky_test_3", + x=5 }, { y=14, - x=3, - name="jorge2" + name="jorge2", + x=3 }, { y=7, - x=8, - name="room_08_07" + name="room_08_07", + x=8 }, { y=8, - x=13, - name="village_3" + name="village_3", + x=13 }, { y=8, - x=12, - name="village_2" + name="village_2", + x=12 }, { y=7, - x=14, - name="room_14_07" + name="room_14_07", + x=14 }, { y=13, - x=9, - name="room_09_13" + name="room_09_13", + x=9 }, { y=13, - x=8, - name="room_08_13" + name="room_08_13", + x=8 }, { y=15, - x=9, - name="room_10_15" + name="room_10_15", + x=9 }, { y=14, - x=14, - name="room_14_14" + name="room_14_14", + x=14 }, { y=13, - x=13, - name="room_13_13" + name="room_13_13", + x=13 }, { y=14, - x=12, - name="room_12_14" + name="room_12_14", + x=12 }, { y=14, - x=13, - name="room_13_14" + name="room_13_14", + x=13 }, { y=13, - x=5, - name="testing_sticky" + name="testing_sticky", + x=5 }, { y=13, - x=6, - name="testing_sticky_two" + name="testing_sticky_two", + x=6 }, { y=14, - x=5, - name="room_05_14" + name="room_05_14", + x=5 + }, + { + y=16, + name="testing_sticky_3", + x=5 + }, + { + y=16, + name="testing_sticky_4", + x=6 + }, + { + y=16, + name="sticky_test_5", + x=7 + }, + { + y=15, + name="room_05_15", + x=5 } -} +}, +width=18, +height=18, +lastRoom="testing_sticky_3" } \ No newline at end of file