Collapse the spiky/sticky/skewer box-variant assets into a single per-
instance `adhesion` property on any moveable block, chosen in the editor
via a dropdown next to the colour picker and stored in the .sav alongside
the class.
- spiky -> sticky: soft grab on every true edge (goopy shader)
- skewer -> gluey: rigid weld on every true edge (spiked outline)
- old trailing-face sticky is removed; its saves fold into new sticky
Move the spike geometry + drawGlueySprite into shaders.lua, fold drawing
and the adhesion flag into GenericMoveable, and delete the three
Generic{Sticky,Spiky,Skewer} classes and box_variants.lua. Room:createEntity
normalises legacy spiky_/skewer_/sticky_ class prefixes so old saves load,
and serialization emits `adhesion`. World/map previews and the movement
proxy follow the rename.
Backfill rooms/*.sav to the new format via tools/backfill_adhesion.lua
(41 objects across 8 files). Update tests to the two-mode model; the two
tests asserting the removed lateral-shear limitation are dropped and a
legacy-load migration test added. 27/27 pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
79 lines
3.1 KiB
Lua
79 lines
3.1 KiB
Lua
require "libs/TSerial"
|
|
|
|
local targetFolder = "art"
|
|
local reanalyzeCells = true
|
|
|
|
function getAllAssets()
|
|
local objectnames = {}
|
|
local topFolder = "art"
|
|
local files = love.filesystem.getDirectoryItems(topFolder)
|
|
for _, folder in pairs(files) do
|
|
if string.sub(folder, 1, 1) ~= "_" then
|
|
-- we ignore directories which are prepended w/ an underscore
|
|
if not string.find(folder, "%.") then
|
|
objectnames[folder] = {}
|
|
-- love.filesystem.createDirectory("art/" .. folder)
|
|
-- this is a folder, probably
|
|
local newFiles = love.filesystem.getDirectoryItems(topFolder .. "/" .. folder)
|
|
for _, fileToAnalyze in pairs(newFiles) do
|
|
if fileToAnalyze:find("_r.png") or fileToAnalyze:find("_g.png") or fileToAnalyze:find("_b.png")then
|
|
local color
|
|
if fileToAnalyze:find("_r.png") then color = "red"
|
|
elseif fileToAnalyze:find("_g.png") then color = "green"
|
|
elseif fileToAnalyze:find("_b.png") then color = "blue" end
|
|
|
|
local name = fileToAnalyze:sub(1, fileToAnalyze:len() - 6)
|
|
|
|
if not globalAssetProperties[name] then
|
|
globalAssetProperties[name] = {}
|
|
globalAssetProperties[name].directory = folder
|
|
globalAssetProperties[name].sprites = {}
|
|
globalAssetProperties[name].preload = false
|
|
end
|
|
|
|
-- class comes from a <name>.meta sitting next to the art
|
|
-- (authoritative); default to immoveable if none exists
|
|
local metaPath = topFolder .. "/" .. folder .. "/" .. name .. ".meta"
|
|
if love.filesystem.getInfo(metaPath, "file") then
|
|
globalAssetProperties[name].class = TSerial.unpack(love.filesystem.read(metaPath)).class
|
|
elseif not globalAssetProperties[name].class then
|
|
globalAssetProperties[name].class = "immoveable"
|
|
end
|
|
|
|
local sprite = topFolder .. "/" .. folder .. "/" .. fileToAnalyze
|
|
globalAssetProperties[name].sprites[color] = sprite
|
|
|
|
-- Precompute the occupied-cell shape once per asset/colour and
|
|
-- cache it here; entities share this table by reference so
|
|
-- collision never rescans pixels at runtime. Keyed per colour
|
|
-- (each channel leaves its own gaps) rather than reset per file.
|
|
globalAssetProperties[name].cells = globalAssetProperties[name].cells or {}
|
|
if not globalAssetProperties[name].cells[color] or reanalyzeCells then
|
|
globalAssetProperties[name].cells[color] = getCellsFromSprite(sprite)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Wired devices intentionally reuse the familiar switch/door artwork. Their
|
|
-- white terminal marker is drawn by the entity class, while these synthetic
|
|
-- asset records make them available to the ordinary palette and brush.
|
|
local function synthetic(name, source, behavior)
|
|
local original = globalAssetProperties[source]
|
|
if not original then return end
|
|
globalAssetProperties[name] = {
|
|
directory = original.directory,
|
|
sprites = original.sprites,
|
|
cells = original.cells,
|
|
class = behavior,
|
|
preload = false,
|
|
synthetic = true,
|
|
}
|
|
end
|
|
synthetic("wired_switch", "switch", "wired_switch")
|
|
synthetic("wired_door", "door", "wired_door")
|
|
|
|
return globalAssetProperties
|
|
end
|