Replace box variants with a moveable adhesion property
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>
This commit is contained in:
parent
c348b81a93
commit
7d84f595e4
25 changed files with 4010 additions and 3797 deletions
28
movement.lua
28
movement.lua
|
|
@ -1,6 +1,7 @@
|
|||
-- 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.
|
||||
-- pushing), is softly grabbed by a sticky block, or is rigidly welded to a
|
||||
-- gluey block.
|
||||
local Movement = {}
|
||||
|
||||
local adjacentDirections = {
|
||||
|
|
@ -18,15 +19,11 @@ local function isPassable(entity)
|
|||
return entity.canPassOver and entity:canPassOver()
|
||||
end
|
||||
|
||||
local function isSkewer(entity)
|
||||
return entity.isSkewer and entity:isSkewer()
|
||||
local function isGluey(entity)
|
||||
return entity.isGluey and entity:isGluey()
|
||||
end
|
||||
|
||||
local function isSpiky(entity)
|
||||
return entity.isSpiky and entity:isSpiky()
|
||||
end
|
||||
|
||||
-- Build one rigid component: ordinary pushes are required, and skewers join
|
||||
-- Build one rigid component: ordinary pushes are required, and gluey blocks weld
|
||||
-- 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)
|
||||
|
|
@ -59,7 +56,7 @@ local function findRigidGroup(startCells, direction, entityAt, isInBounds, alrea
|
|||
table.insert(pendingCells, projectedCell)
|
||||
end
|
||||
|
||||
-- Skewers make every edge contact part of this rigid component.
|
||||
-- Gluey blocks make every edge contact part of this rigid component.
|
||||
for _, occupiedCell in ipairs(entity:getOccupiedCells()) do
|
||||
for _, adjacentDirection in ipairs(adjacentDirections) do
|
||||
local adjacentCell = {
|
||||
|
|
@ -69,7 +66,7 @@ local function findRigidGroup(startCells, direction, entityAt, isInBounds, alrea
|
|||
if isInBounds(adjacentCell) then
|
||||
local adjacentEntity = entityAt(adjacentCell)
|
||||
local attached = adjacentEntity and (
|
||||
isSkewer(entity) or isSkewer(adjacentEntity)
|
||||
isGluey(entity) or isGluey(adjacentEntity)
|
||||
)
|
||||
if attached and adjacentEntity ~= entity and adjacentEntity:canMove() and
|
||||
not (alreadyMoving and alreadyMoving[adjacentEntity]) then
|
||||
|
|
@ -99,9 +96,9 @@ function Movement.findMovableGroup(startCells, direction, entityAt, isInBounds)
|
|||
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.
|
||||
-- Sticky contact is soft on every face: it tries to drag each neighbour
|
||||
-- along, but 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 = {
|
||||
|
|
@ -110,11 +107,8 @@ function Movement.findMovableGroup(startCells, direction, entityAt, isInBounds)
|
|||
}
|
||||
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)))
|
||||
isSticky(entity) or isSticky(adjacentEntity)
|
||||
)
|
||||
if softContact and adjacentEntity ~= entity and
|
||||
not entities[adjacentEntity] and not attemptedPulls[adjacentEntity] and
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue