aboutsummaryrefslogtreecommitdiffstats
path: root/data
diff options
context:
space:
mode:
authorEmil A. Overbeck <emil.a.overbeck@gmail.com>2026-07-19 04:19:48 +0200
committerEmil A. Overbeck <emil.a.overbeck@gmail.com>2026-07-19 04:19:48 +0200
commit521b5da83485a956811fc510cba9f139acad8b26 (patch)
tree29b210263300479e9a565af568812c5e707d23f7 /data
parentff85499d5567c36ce63e2d7903d5f872fd9aef1d (diff)
downloadforts_clone-521b5da83485a956811fc510cba9f139acad8b26.tar.gz
forts_clone-521b5da83485a956811fc510cba9f139acad8b26.zip
New maps and map selectormain
Diffstat (limited to 'data')
-rw-r--r--data/map.lua13
-rw-r--r--data/maps.lua198
-rw-r--r--data/mods/enemy-fort/map.lua3
-rw-r--r--data/mods/enemy-fort/maps.lua21
-rw-r--r--data/mods/enemy-fort/mod.lua3
-rw-r--r--data/mods/enemy-fort/structures.lua19
-rw-r--r--data/structures.lua5
7 files changed, 221 insertions, 41 deletions
diff --git a/data/map.lua b/data/map.lua
deleted file mode 100644
index 13f9c94..0000000
--- a/data/map.lua
+++ /dev/null
@@ -1,13 +0,0 @@
--- Base scenario map: metal deposits and pre-placed devices. Mods append (the
--- enemy-fort mod adds the enemy reactor). Coordinates are world units; y ~ 1 is
--- the ground surface.
-Deposits = Deposits or {}
-MapDevices = MapDevices or {}
-
--- Metal deposits (mines must sit on these). Player side (left) + enemy side (right).
-for _, x in ipairs({ -24, -11, 23, 31 }) do
- table.insert(Deposits, { x, 1.0 })
-end
-
--- Player reactor on the left.
-table.insert(MapDevices, { type = "reactor", x = -22, y = 2.0, team = 0 })
diff --git a/data/maps.lua b/data/maps.lua
new file mode 100644
index 0000000..d49d9e6
--- /dev/null
+++ b/data/maps.lua
@@ -0,0 +1,198 @@
+-- Selectable scenarios. The engine loads every entry of the global `Maps` array
+-- and the Dev panel ("Map" section) switches between them at runtime; switching
+-- tears the world down and rebuilds it from the chosen entry. Maps[1] is the
+-- one the game starts on.
+--
+-- Each map is self-contained:
+-- name, description shown in the Dev panel
+-- ground_level height of the ground plane. Terrain is still a flat
+-- half-plane, so this moves the ground up/down but cannot
+-- change its SHAPE (real terrain is M6).
+-- deposits { {x, y}, ... } mines only produce while on one
+-- devices { {type=, x=, y=, team=}, ... } team 0 = player
+-- weapons { {type=, x=, y=}, ... } the player's starting guns
+-- structures { {name=, beams={ {x1,y1,x2,y2,material}, ... }}, ... }
+--
+-- Building rules the beams must respect (see data/materials.lua):
+-- * a beam should be <= 3 units (wood/armour/bg-brace max_length); prebuilt
+-- beams are welded raw and are NOT auto-subdivided
+-- * TRIANGULATE. An un-triangulated strut snaps once it rotates ~30 degrees,
+-- so every bay wants a diagonal or the fort folds up on the first hit
+-- * an endpoint at y == ground_level becomes a pinned foundation; keep other
+-- nodes clear of the ground+0.3 band so they don't pin by accident
+
+Maps = Maps or {}
+
+-- 1. Open ground, a wide firing lane, and a boxy enemy fort with an armour face
+-- turned towards you. The balanced default.
+table.insert(Maps, {
+ name = "Proving Ground",
+ description = "Open lane, boxy enemy fort with an armoured front.",
+ ground_level = 1.0,
+ deposits = { {-24, 1}, {-11, 1}, {23, 1}, {31, 1} },
+ devices = {
+ { type = "reactor", x = -22, y = 2.0, team = 0 },
+ { type = "reactor", x = 27, y = 3.0, team = 1 },
+ },
+ weapons = {
+ { type = "cannon", x = -18, y = 2.6 },
+ { type = "laser", x = -14, y = 2.6 },
+ },
+ structures = {
+ {
+ name = "player deck", -- gun platform; gives recoil something to shove
+ beams = {
+ {-20,1,-20,2,"wood"}, {-18,1,-18,2,"wood"}, {-16,1,-16,2,"wood"},
+ {-14,1,-14,2,"wood"}, {-12,1,-12,2,"wood"},
+ {-20,2,-18,2,"wood"}, {-18,2,-16,2,"wood"},
+ {-16,2,-14,2,"wood"}, {-14,2,-12,2,"wood"},
+ {-20,1,-18,2,"wood"}, {-18,1,-16,2,"wood"},
+ {-16,1,-14,2,"wood"}, {-14,1,-12,2,"wood"},
+ },
+ },
+ {
+ name = "enemy fort",
+ beams = {
+ -- front column facing the player is armour, the rest is wood
+ {25,1,25,3,"armour"}, {25,3,25,5,"armour"},
+ {27,1,27,3,"wood"}, {27,3,27,5,"wood"},
+ {29,1,29,3,"wood"}, {29,3,29,5,"wood"},
+ {25,1,27,1,"wood"}, {27,1,29,1,"wood"},
+ {25,3,27,3,"wood"}, {27,3,29,3,"wood"},
+ {25,5,27,5,"wood"}, {27,5,29,5,"wood"},
+ {25,1,27,3,"wood"}, {27,1,29,3,"wood"},
+ {25,3,27,5,"wood"}, {27,3,29,5,"wood"},
+ },
+ },
+ },
+})
+
+-- 2. A tall armoured tower braced internally with background bracing: shells
+-- pass straight through the bracing, so you have to chew the armour or burn
+-- the bracing out from under it. Vertical fight.
+table.insert(Maps, {
+ name = "Iron Bastion",
+ description = "A two-storey gun emplacement against a walled keep: armoured "
+ .. "outer wall, a bridge back to the tower, bg-brace interior.",
+ ground_level = 1.0,
+ deposits = { {-28, 1}, {-13, 1}, {19, 1}, {34, 1} },
+ devices = {
+ { type = "reactor", x = -26, y = 2.0, team = 0 },
+ { type = "reactor", x = 28, y = 3.0, team = 1 },
+ },
+ weapons = {
+ { type = "cannon", x = -21, y = 5.6 }, -- upper deck
+ { type = "laser", x = -17, y = 3.6 }, -- lower deck
+ },
+ structures = {
+ {
+ name = "player emplacement",
+ beams = {
+ -- lower storey; armour on the RIGHT column, the face the enemy
+ -- actually shoots at
+ {-24,1,-24,3,"wood"}, {-22,1,-22,3,"wood"}, {-20,1,-20,3,"wood"},
+ {-18,1,-18,3,"wood"}, {-16,1,-16,3,"armour"},
+ {-24,3,-22,3,"wood"}, {-22,3,-20,3,"wood"},
+ {-20,3,-18,3,"wood"}, {-18,3,-16,3,"wood"},
+ {-24,1,-22,3,"wood"}, {-22,1,-20,3,"wood"},
+ {-20,1,-18,3,"wood"}, {-18,1,-16,3,"wood"},
+ -- upper storey over the middle bays
+ {-22,3,-22,5,"wood"}, {-20,3,-20,5,"wood"}, {-18,3,-18,5,"wood"},
+ {-22,5,-20,5,"wood"}, {-20,5,-18,5,"wood"},
+ {-22,3,-20,5,"wood"}, {-20,3,-18,5,"wood"},
+ },
+ },
+ {
+ name = "outer wall", -- fully armoured, soaks the first volleys
+ beams = {
+ {22,1,22,3,"armour"}, {22,3,22,5,"armour"},
+ {24,1,24,3,"armour"}, {24,3,24,5,"armour"},
+ {22,1,24,1,"wood"}, {22,3,24,3,"wood"}, {22,5,24,5,"wood"},
+ {22,1,24,3,"wood"}, {22,3,24,5,"wood"},
+ },
+ },
+ {
+ name = "curtain bridge", -- cut this and the wall fights alone
+ beams = {
+ {24,3,26,3,"wood"}, {24,5,26,5,"wood"}, {24,3,26,5,"wood"},
+ },
+ },
+ {
+ name = "the keep",
+ beams = {
+ -- armoured outer face, full height
+ {26,1,26,3,"armour"}, {26,3,26,5,"armour"},
+ {26,5,26,7,"armour"}, {26,7,26,9,"armour"},
+ {28,1,28,3,"wood"}, {28,3,28,5,"wood"},
+ {28,5,28,7,"wood"}, {28,7,28,9,"wood"},
+ {30,1,30,3,"wood"}, {30,3,30,5,"wood"},
+ {30,5,30,7,"wood"}, {30,7,30,9,"wood"},
+ -- floors
+ {26,1,28,1,"wood"}, {28,1,30,1,"wood"},
+ {26,3,28,3,"wood"}, {28,3,30,3,"wood"},
+ {26,5,28,5,"wood"}, {28,5,30,5,"wood"},
+ {26,7,28,7,"wood"}, {28,7,30,7,"wood"},
+ {26,9,28,9,"wood"}, {28,9,30,9,"wood"},
+ -- internal bracing: shells pass through it, fire eats it fast
+ {26,1,28,3,"bgbrace"}, {28,1,30,3,"bgbrace"},
+ {26,3,28,5,"bgbrace"}, {28,3,30,5,"bgbrace"},
+ {26,5,28,7,"bgbrace"}, {28,5,30,7,"bgbrace"},
+ {26,7,28,9,"bgbrace"}, {28,7,30,9,"bgbrace"},
+ },
+ },
+ },
+})
+
+-- 3. Raised ground and forts almost in each other's faces: short flight times,
+-- both sides armoured on the facing wall. A brawl rather than a siege.
+table.insert(Maps, {
+ name = "The Narrows",
+ description = "Raised ground, two three-storey redoubts almost muzzle to "
+ .. "muzzle, armour facing armour. Reactors sit inside the forts.",
+ ground_level = 2.0,
+ deposits = { {-18, 2}, {-4, 2}, {4, 2}, {18, 2} },
+ devices = {
+ { type = "reactor", x = -13, y = 3.0, team = 0 },
+ { type = "reactor", x = 11, y = 3.0, team = 1 },
+ },
+ weapons = {
+ { type = "cannon", x = -12, y = 6.6 }, -- on the roof
+ { type = "laser", x = -10, y = 6.6 },
+ },
+ structures = {
+ {
+ name = "player redoubt", -- armour on the inward (enemy-facing) column
+ beams = {
+ {-14,2,-14,4,"wood"}, {-12,2,-12,4,"wood"},
+ {-10,2,-10,4,"wood"}, {-8,2,-8,4,"armour"},
+ {-14,4,-14,6,"wood"}, {-12,4,-12,6,"wood"},
+ {-10,4,-10,6,"wood"}, {-8,4,-8,6,"armour"},
+ {-14,4,-12,4,"wood"}, {-12,4,-10,4,"wood"}, {-10,4,-8,4,"wood"},
+ {-14,6,-12,6,"wood"}, {-12,6,-10,6,"wood"}, {-10,6,-8,6,"wood"},
+ {-14,2,-12,4,"wood"}, {-12,2,-10,4,"wood"}, {-10,2,-8,4,"wood"},
+ {-14,4,-12,6,"wood"}, {-12,4,-10,6,"wood"}, {-10,4,-8,6,"wood"},
+ },
+ },
+ {
+ name = "enemy redoubt",
+ beams = {
+ {8,2,8,4,"armour"}, {10,2,10,4,"wood"},
+ {12,2,12,4,"wood"}, {14,2,14,4,"wood"},
+ {8,4,8,6,"armour"}, {10,4,10,6,"wood"},
+ {12,4,12,6,"wood"}, {14,4,14,6,"wood"},
+ {8,4,10,4,"wood"}, {10,4,12,4,"wood"}, {12,4,14,4,"wood"},
+ {8,6,10,6,"wood"}, {10,6,12,6,"wood"}, {12,6,14,6,"wood"},
+ {8,2,10,4,"wood"}, {10,2,12,4,"wood"}, {12,2,14,4,"wood"},
+ {8,4,10,6,"wood"}, {10,4,12,6,"wood"}, {12,4,14,6,"wood"},
+ },
+ },
+ },
+})
+
+function IndexOfMap(name)
+ for i, m in ipairs(Maps) do if m.name == name then return i end end
+ return nil
+end
+function FindMap(name)
+ local i = IndexOfMap(name); if i then return Maps[i] end; return nil
+end
diff --git a/data/mods/enemy-fort/map.lua b/data/mods/enemy-fort/map.lua
deleted file mode 100644
index 443b74b..0000000
--- a/data/mods/enemy-fort/map.lua
+++ /dev/null
@@ -1,3 +0,0 @@
--- The enemy fort's reactor (team 1). Sits inside the fort (columns x=25..29).
--- Destroy it to win.
-table.insert(MapDevices, { type = "reactor", x = 27, y = 3.0, team = 1 })
diff --git a/data/mods/enemy-fort/maps.lua b/data/mods/enemy-fort/maps.lua
new file mode 100644
index 0000000..4f748ae
--- /dev/null
+++ b/data/mods/enemy-fort/maps.lua
@@ -0,0 +1,21 @@
+-- Layered-modding demo: this runs AFTER data/maps.lua, so it can reach into a
+-- map the base game defined and change it. Here we bolt an extra armour skin
+-- onto the Proving Ground enemy fort, making it a tougher target.
+--
+-- A mod could equally `table.insert(Maps, { ... })` to ship a whole new map;
+-- see data/maps.lua for the shape of an entry.
+
+local m = FindMap("Proving Ground")
+if m then
+ table.insert(m.structures, {
+ name = "enemy outer plating",
+ beams = {
+ -- a second armoured skin one unit in front of the fort's face,
+ -- tied back to it so the whole thing stays triangulated
+ {24,1,24,3,"armour"}, {24,3,24,5,"armour"},
+ {24,1,25,1,"wood"}, {24,3,25,3,"wood"}, {24,5,25,5,"wood"},
+ {24,1,25,3,"wood"}, {24,3,25,5,"wood"},
+ },
+ })
+ m.description = m.description .. " (+ enemy-fort mod plating)"
+end
diff --git a/data/mods/enemy-fort/mod.lua b/data/mods/enemy-fort/mod.lua
index b2bc990..01a6b42 100644
--- a/data/mods/enemy-fort/mod.lua
+++ b/data/mods/enemy-fort/mod.lua
@@ -1,4 +1,5 @@
--- Scenario mod: a prebuilt enemy fort on the right for the player to shoot at.
+-- Scenario mod: reinforces the Proving Ground enemy fort with extra armour
+-- plating. Doubles as the worked example of layered map modding (maps.lua).
Selectable = true
Priority = 5
Category = "Scenario"
diff --git a/data/mods/enemy-fort/structures.lua b/data/mods/enemy-fort/structures.lua
deleted file mode 100644
index ce6bdd0..0000000
--- a/data/mods/enemy-fort/structures.lua
+++ /dev/null
@@ -1,19 +0,0 @@
--- A triangulated wooden fort on the right side (columns at x=25,27,29; rows at
--- y=1,3,5). Foundations sit on the ground (y=1). All beams <= 3 units so they
--- obey the material length limits. Shoot it apart with the cannon.
-table.insert(Structures, {
- name = "enemy fort",
- beams = {
- -- verticals
- {25,1,25,3,"wood"}, {25,3,25,5,"wood"},
- {27,1,27,3,"wood"}, {27,3,27,5,"wood"},
- {29,1,29,3,"wood"}, {29,3,29,5,"wood"},
- -- horizontals
- {25,1,27,1,"wood"}, {27,1,29,1,"wood"},
- {25,3,27,3,"wood"}, {27,3,29,3,"wood"},
- {25,5,27,5,"wood"}, {27,5,29,5,"wood"},
- -- diagonals (triangulation, so it's rigid)
- {25,1,27,3,"wood"}, {27,1,29,3,"wood"},
- {25,3,27,5,"wood"}, {27,3,29,5,"wood"},
- },
-})
diff --git a/data/structures.lua b/data/structures.lua
deleted file mode 100644
index f7d88f2..0000000
--- a/data/structures.lua
+++ /dev/null
@@ -1,5 +0,0 @@
--- Base scenario structures. Empty by default; mods under data/mods/ append to
--- the global `Structures` list. Each structure is:
--- { name = "...", beams = { {x1,y1,x2,y2,material}, ... } }
--- The loader creates/merges nodes at the endpoints and welds the beams.
-Structures = Structures or {}