From 53c9fe4c0c52a244c64ded78930a3ae33b7d713c Mon Sep 17 00:00:00 2001 From: Axel Meyer Date: Thu, 21 May 2026 15:50:59 +0200 Subject: [PATCH] Add v2 gameplay queries: walkable / blocks_walk / blocks_sight Replace the v1 is_walkable stub with a v2-aware version that requires surface tile present and no blocking wall layer cell. Add blocks_walk (wall-layer OOB-safe check) and blocks_sight (wall + upper_wall with per-tile blocks_sight override). v1 path unchanged via schema_version branch. Co-Authored-By: Claude Opus 4.7 (1M context) --- init.lua | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/init.lua b/init.lua index 5e48247..e4fc4ba 100644 --- a/init.lua +++ b/init.lua @@ -385,10 +385,61 @@ function M.tile_at(a, b, c) return m.tilemap.tiles[palette_id] end +-- v2 walkability: surface non-empty AND no blocking wall function M.is_walkable(a, b, c) - local t = M.tile_at(a, b, c) - if t == nil then return false end - return t.walkable == true + local map_id, tx, ty + if c == nil then + map_id, tx, ty = current_map_id, a, b + else + map_id, tx, ty = a, b, c + if map_id == nil then map_id = current_map_id end + end + if not map_id then + error("maps.is_walkable: no current map") + end + local m = map_registry[map_id] + if m.schema_version ~= 2 then + -- v1 fallback: surface-only walkability via legacy tile_at + local t = M.tile_at(map_id, tx, ty) + if t == nil then return false end + return t.walkable == true + end + -- v2: needs surface tile present AND lower_wall/wall absent + local surface = M.tile_at_layer("surface", tx, ty, map_id) + if surface == nil then return false end + if M.cell_gid("lower_wall", tx, ty, map_id) ~= 0 then return false end + if M.cell_gid("wall", tx, ty, map_id) ~= 0 then return false end + return surface.walkable == true +end + +function M.blocks_walk(x, y, map_id) + local id = map_id or current_map_id + if not id then error("maps.blocks_walk: no current map") end + local m = map_registry[id] + if x < 0 or x >= m.size.w or y < 0 or y >= m.size.h then return false end + if M.cell_gid("lower_wall", x, y, id) ~= 0 then return true end + if M.cell_gid("wall", x, y, id) ~= 0 then return true end + return false +end + +function M.blocks_sight(x, y, map_id) + local id = map_id or current_map_id + if not id then error("maps.blocks_sight: no current map") end + local m = map_registry[id] + if x < 0 or x >= m.size.w or y < 0 or y >= m.size.h then return false end + if M.cell_gid("wall", x, y, id) ~= 0 then return true end + -- upper_wall: per-tile blocks_sight flag in atlas metadata; default true for walls + local up_gid = M.cell_gid("upper_wall", x, y, id) + if up_gid ~= 0 then + local atlas_idx, tile_id, _rot = decode_gid(up_gid) + local atlas = m.atlases[atlas_idx + 1] + local tile = atlas and atlas.tiles[tile_id] + if tile and tile.blocks_sight == false then + return false + end + return true + end + return false end function M.tilemap_id(map_id)