Skip to content

Add scripting functions to create new map geometry #2025

Description

@slserpent

Editor

Map editor

Description of your feature request

Add scripting functions to create new map geometry: vertices, lines, sides, and sectors. The Lua API is currently read-only - no way to build geometry from a script (issue #1135 is similar but now moot with the "Edit Objects" scaling feature).

Proposed API:

  • Map:CreateVertex(x, y) -> MapVertex
  • Map:CreateLine(v1, v2) -> MapLine
  • Map:CreateSide(line, isFront, sectorIndex) -> MapSide
  • Map:CreateSector() -> MapSector

Each constructor in minimal to merely connect the new map element to its constituent elements, other fields are already settable via the existing SetStringProperty/SetIntProperty/SetFloatProperty calls (sector.texturefloor, sector.heightfloor, side.texturemiddle, etc.). MapSector.connectedSides doesn't need to be script-settable - it can be derived from which sides reference the sector.

Use cases:

  1. Procedural/complex geometry creation (curved staircases, complex shapes or shapes with curves) - mock-up attached.
  2. Automated full map generation or import, including via LLM or conversion from another format
  3. Map cleanup at scale (e.g. merging close vertices, unused vertices) - kind of a different issue but currently disabled by MapVertex::scriptCanModifyProp()

Mock-up

-- Curved Staircase Generator (MOCK-UP - requires geometry-creation API)

local START_X, START_Y = 0, 0
local START_ANGLE = 0 -- 0 is east
local STEP_COUNT  = 12
local STEP_WIDTH  = 64
local STEP_DEPTH  = 32
local STEP_RISE   = 8
local CEIL_HEIGHT = 128
local CURVE_ANGLE = 4

local function v(x, y) return { x = x, y = y } end
local function vAdd(a, b) return v(a.x + b.x, a.y + b.y) end
local function vScale(a, s) return v(a.x * s, a.y * s) end
local function vRot(a, deg)
   local r = math.rad(deg)
   local c, s = math.cos(r), math.sin(r)
   return v(a.x * c - a.y * s, a.x * s + a.y * c)
end

-- one-sided (impassable) line: front side only, tied to sector
local function wallLine(map, v1, v2, sector)
   local line = map:CreateLine(v1, v2)
   map:CreateSide(line, true, sector.index)
   return line
end

-- two-sided line between two sectors, for step edges
local function stepLine(map, v1, v2, frontSector, backSector)
   local line = map:CreateLine(v1, v2)
   map:CreateSide(line, true, frontSector.index)
   map:CreateSide(line, false, backSector.index)
   return line
end

local map = App.MapEditor().map
local halfW = STEP_WIDTH / 2
local pos = v(START_X, START_Y)
local dir = v(math.cos(math.rad(START_ANGLE)), math.sin(math.rad(START_ANGLE)))
local perp = vRot(dir, 90)

local prevSector, prevBL, prevBR = nil, nil, nil

for i = 1, STEP_COUNT do
   local sector = map:CreateSector()
   local floorH = (i - 1) * STEP_RISE
   sector:SetIntProperty("heightfloor", floorH)
   sector:SetIntProperty("heightceiling", floorH + CEIL_HEIGHT)

   local frontC, backC = pos, vAdd(pos, vScale(dir, STEP_DEPTH))
   local flPos, frPos = vAdd(frontC, vScale(perp, -halfW)), vAdd(frontC, vScale(perp, halfW))
   local blPos, brPos = vAdd(backC, vScale(perp, -halfW)), vAdd(backC, vScale(perp, halfW))

   local fl = prevBL or map:CreateVertex(flPos.x, flPos.y)
   local fr = prevBR or map:CreateVertex(frPos.x, frPos.y)
   local bl = map:CreateVertex(blPos.x, blPos.y)
   local br = map:CreateVertex(brPos.x, brPos.y)

   if prevSector then
      stepLine(map, fl, fr, sector, prevSector)
   else
      wallLine(map, fl, fr, sector)
   end
   wallLine(map, fr, br, sector)
   wallLine(map, bl, fl, sector)
   if i == STEP_COUNT then
      wallLine(map, br, bl, sector)
   end

   prevSector, prevBL, prevBR = sector, bl, br
   pos = backC
   dir = vRot(dir, CURVE_ANGLE)
   perp = vRot(perp, CURVE_ANGLE)
end

App.LogMessage("Generated " .. STEP_COUNT .. " steps")

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions