WIKI

Mod

Scenery mods: difficulty and wave sequences

Le guide ai mod sono in inglese, come vengono distribuite con il gioco.

Enable Sample mod - Traditional path in Options → Mods, then restart Torreta. The bundled example starts disabled. It turns the pit into a classic tower defense board: the insects follow one fixed path, and the towers stand on raised mesas beside it. The sample ships no model of its own: its scene names the game's internal traditional scene (see Built-in scenes). Your own GLBs may replace it with completely different landscapes within the arena's gameplay footprint, and Sample mod - Tidal Coast, on the Steam Workshop, shows a complete arena GLB of its own.

Author a mod

Copy sample_traditional (or a subscribed Tidal Coast's workshop_<id>) to a new folder inside the Mods folder. Change its id and name in mod.json; disable the bundled sample while testing your copy. To use your own arena, replace the scene's "builtin": "traditional" with "file": "Models/YourArena.glb" and author the GLB to the contracts below.

Add scenarios.json alongside mod.json:

{
  "version": 1,
  "scenes": {
    "canyon": {"file": "Models/Canyon.glb"},
    "forest": {"file": "Models/Forest.glb"},
    "ruins": {"file": "Models/Ruins.glb"}
  },
  "difficulties": {
    "1": {
      "cycle_waves": 150,
      "stages": [
        {"from_wave": 1, "scene": "canyon"},
        {"from_wave": 51, "scene": "forest"},
        {"from_wave": 101, "scene": "ruins"}
      ]
    },
    "2": {
      "stages": [
        {"from_wave": 1, "scene": "forest"},
        {"from_wave": 51, "scene": "ruins"}
      ]
    },
    "3": {
      "stages": [{"from_wave": 1, "scene": "ruins"}]
    }
  }
}
  • Difficulty keys are "1", "2", "3". They follow the actual difficulty, independently of the time of day or multiplayer weather.
  • Stage thresholds are inclusive: 51 first appears at wave 51. Start at 1 and list unique, increasing positive integer waves. Wave 0 also uses stage 1.
  • Omit cycle_waves, or set it to 0, to keep the final stage indefinitely. With 150, the example restarts at wave 151, then changes at 201 and 251. A cycle must include the final threshold. The actual run wave never resets.
  • Omitted difficulties keep Environment/Arena from models.json, or the original game arena. A single static replacement can still use only models.json; existing mods continue to work.
  • Scene IDs must be identifiers such as red_canyon. Paths are relative to this mod, with / separators. Use self-contained GLB 2 files with embedded textures, indexed triangles and normals, up to 64 MiB per file. No scripts, external resources, baked animations, skeletons, cameras or lights.
  • Imported PBR materials retain textures, roughness, metallic, normal maps and emission. The game adds weather, cloud shadows and worm openings. Scenery materials use "material": "imported" (the default).
  • A scene may name a built-in scene instead of a file: {"builtin": "traditional"}. It cannot have a file as well.
  • "tower_fences": false leaves the scene's towers without their low fence, for a relief that already frames each tower (the traditional sample does). Omitted or true, towers keep it. Any other value rejects the scene.

Built-in scenes

The game package holds scenes that a mod can name but never receives as files. A built-in scene is a relief laid over the game's own arena: the original floor, walls, weather, wildlife and traffic wear stay, and only the relief and its GameplayTiles are new. Its models live inside the game and are not copied to the Mods folder.

builtinBoard
traditionalOne looping path from the north nest (15,1) to the south cave (15,17): 75 steps over 72 Walkable cells, crossing itself at (15,4), (10,6) and (15,12). Every other pit cell (137) is a Buildable concrete platform at height 10

The raised platforms use worn light concrete, including their low retaining faces. The road remains the arena's natural soil. This presentation applies to every mod selecting the built-in scene, including Traditional Path and Iron Kingdom, on all difficulties. It does not recolor the vanilla arena or replace materials in mod-authored GLB scenes. Tile permissions and heights are unchanged.

Source/tile_layout.json in the traditional sample lists the same cells (walkable, buildable, buildable_height) and the route's turns (route). Its tile_markers.py creates the matching GameplayTiles in a Blender scene, so an arena of your own can keep the same board under different scenery.

Geometry contract

The menu's 3D Torreta sculpture automatically takes its surface from the active scenery. The original arena keeps its sculpted sand. OceanWater supplies moving water, with the same pause-aware clock as the sea. Other landscapes use the PBR material of the ground beneath the lettering, including textures and average vertex tint. When there is no surface there, the largest upward-facing surface is the fallback. Hidden foundations and undersides do not win over the visible floor. Materials are prepared and rendered behind the startup loading screen and reused when a wave/difficulty changes the scene.

To choose a different surface, parent an existing landscape mesh under a Blender Empty named MenuLogoSurface (or give the mesh that name). This wins over the automatic ocean/ground choice; within the group, the surface with the largest projected XZ area wins. Choose a representative horizontal surface. Its largest triangle supplies the world-space UV projection, so planar terrain textures retain their scale and orientation on the lettering. Vertex-painted surfaces contribute their area-weighted average tint. The marker does not hide the source mesh or change navigation, collision, or tower placement. It works in both scheduled GLBs and a static Environment/Arena replacement, without scripts or extra JSON.

An explicit Environment/MenuSandLogo model override retains its own authored materials. This feature only affects the live 3D showcase: loading-screen and store logos remain their separate artwork, and no lettering appears in a run.

The model changes the visible environment and cockpit camera collision. Optional GameplayTiles nodes also define enemy navigation and tower placement; see below. Meshes alone remain decorative for navigation. Keep facilities, cave mouths and the visible floor aligned with the gameplay cells you mark.

Coordinates before the game's camera projection correction:

FeatureLogical mapExported GLB (Godot Y up)
PlayfieldX 448–1536, Y 208–1000X 1440–2528, Z 368–1160
GroundHeight 0Y 0
Plateau / facilitiesHeight 137Y 137
Cave center lineX 992, half-width 47X 1984, half-width 47

For a logical position (x, y) and height h, author in Blender at (x + 992, -(y + 160), h). Export using glTF Y up and scale 1. The game applies its existing Z correction (1.0977222864644) once. Do not bake this scale into your model. Keep both north and south approaches open. Place large decorations outside the playable floor; extend the plateau far enough to cover the overview and cockpit horizon. Replacing scenery never removes gameplay rubble, towers, buildings or the factory.

Walkable and buildable cells: Blender nodes

Add one Empty named GameplayTiles anywhere under the exported model. Give it two Empty children named Walkable and Buildable, and optionally a third, Route (see An ordered route). Under Walkable and Buildable, place one leaf Empty at the center of every cell you allow for that permission:

Arena
  ...visible meshes...
  GameplayTiles
    Walkable
      Entry
      Cell_9_6
      Cell_11_6
      ...
    Buildable
      Cell_9_6
      Cell_10_6
      ...
    Route            (optional)
      Route_0
      Route_1
      ...

Marker names are free; their positions choose the cells. The group names are the contract. Blender's .001 / Godot's _001 duplicate suffixes are accepted. Group/parent transforms are included when calculating marker positions. Export these empties together with the model; they never render or create colliders. No custom properties, extra JSON permissions or Godot editor import are needed.

The two lists are independent:

Cell belongs toGround insectsNew towers
Both groupsCan pass until blocked by a tower/rubbleAllowed
Walkable onlyCan passForbidden
Buildable onlyCannot pass, even after selling a towerAllowed
Neither groupCannot passForbidden

An unmarked cell is blocked for both purposes when GameplayTiles exists. Both groups are required, although Buildable can be empty. Without the entire GameplayTiles root, legacy scenery keeps the original game's layout. Removing only one group is an error, not an implicit default. Flyers retain their flight behavior; these walk permissions describe the ground.

The existing logical grid uses 64 × 64 units. For tile (column, row), use this Empty location in Blender, before any parent transforms:

X = column * 64 + 32 + 992
Y = -(row * 64 + 32 + 160)
Z = 0

For example, tile (10, 6) is Blender (1664, -576, 0), exported GLB (1664, 0, 576). Markers must be centered within 0.5 units; snap to the grid.

Heights. Walkable cells are ground at height 0: model the path's floor there. A Buildable marker's height (Blender Z, glTF Y) is the surface its tower stands on: put it on top of a raised mesa (Z = 10 in the traditional board) and the tower, its fence, rubble and the cockpit seat rise to it. Keep mesas low: shots fly straight from the barrel to the insect, and a tall wall between them reads as rounds passing through rock. Leave it at 0 for build cells on the floor. A cell in both groups is floor. Heights outside -400..400 reject the model. This raises build cells only; it does not add stacked floors, ramps or navigation meshes, and insects always walk at 0. The renderer treats marked cells as ground even outside the original pit.

Cells may override original cliffs/forbidden ground inside the existing map's TileMap cells. Author matching floor geometry there. Marker nodes do not resize the simulation grid or move the cave entrances, exit, factory or camera bounds. The existing MapCoords configuration remains the navigation authority for entrances and the destination; these markers do not relocate their visuals.

The traditional sample's Source/tile_layout.json records its cell lists, mesa height and route, and tile_markers.py creates the same empties in another Blender scene. The Python helper is for Blender authoring only; Torreta never executes it. To create another build-only tile, remove its Empty from Walkable and retain the corresponding Empty in Buildable. Move or delete empties to shape the rest of your map.

Existing installed sample folders are never overwritten. If yours predates the tile nodes, copy the updated sample from the game's bundled mods_example directory to a new mod folder, or use the helper on your own model.

An ordered route

Without a Route, ground insects take the shortest way to the exit through the Walkable cells (A*), and the player's towers shape it. A path that crosses itself would then be cut short at every crossing. The optional Route group fixes the walk instead: ground insects follow it in order, every loop included, and pass each crossing as many times as the route does.

  • Name its empties Route_<number> (Route_0, Route_1, ...). The number is the order; node order and gaps in the numbering do not matter.
  • Put one at the start, one at every turn and one at the end. Each pair of consecutive markers must share a row or a column; the cells between them are filled in. A marker on every cell works too.
  • The route must start at the nest cell (default (15,1)) and end at the exit cell ((15,17)), on Walkable cells only. Multi-entry maps cannot use it.
  • Walkable cells off the route stay walkable ground but are never walked.

Flyers still fly straight from the nest to the cave. The route preview, the insects' remaining distance and a boss's minions (which walk on from the boss's own pass) all follow the route. A tower on a route cell would close it, so the placement preview refuses one; keep route cells out of Buildable.

Validation and occupied boards

Every Walkable cell must connect to the exit through cardinal neighbors. Entry/exit anchors and their approach cells must be Walkable and never Buildable (default north (15,1), (15,2) and south (15,16), (15,17)). In multi-entry maps, the other configured entrances and central destination are checked too. Out-of-map cells, duplicate markers, malformed groups, disconnected paths and a route that turns diagonally, leaves the Walkable cells or misses the nest or exit are reported in mod warnings. An invalid scheduled stage rejects its difficulty's schedule, preserving the preceding valid schedule. An invalid standalone arena layout falls back to the stock arena.

Placement previews, mouse/controller building, route previews, insect A* (or the authored route) and natural rubble generation use these permissions. Dynamic restrictions still apply: a valid Buildable cell must be free of rubble, an existing tower or an active worm hole, and placement retains the normal cost/enemy/maze rules. Clearing rubble restores the authored permissions; it cannot unlock a NoBuild cell.

Different waves can use different layouts. The scenery and permissions change together. A change waits until a later wave if ground insects are still present, an existing tower would lose its Buildable cell, or existing rubble would seal an entrance. No tower, insect or deposit is deleted to force a transition. Use the same marker lists across stages for guaranteed scenery changes at the exact threshold. Saves preserve the scene actually accepted, including a deferred transition; the co-op host sends its accepted scene with the wave-start packet.

Animated ocean surfaces

Sample mod - Tidal Coast, on the Steam Workshop, is an alternative to the traditional path. It includes Source/TidalCoast.blend and a GLB with a beach, rocky boundaries and a forest edge, starting on wave 1 in every difficulty. Enable only the scenery mod you want, then restart.

In any scenery GLB, put water meshes below an Empty called OceanWater. Each surface must have a second UV map (glTF TEXCOORD_1). Use UV2.x for shoreline depth: 0 at shore, 1 offshore, and negative values down to -0.25 for the wash strip. UV2.y is unused. Invalid or missing depths reject the model with a mod warning. Duplicate suffixes such as .001 are accepted on the Empty.

The game assigns its built-in surf shader to these meshes: moving swells, broken foam and a moving wash edge. Subdivide the surface for swells, point its normals upward, and retain the second UV set when exporting. The shader displaces local Y by at most 2.7 units, so do not rotate the water's local vertical axis. Its material responds to the scene's lights. Insects still move on logical ground height 0; keep shallows just above that floor and use the tile groups to prohibit construction there. Water itself never changes walking/building permissions.

Ocean surfaces cast no shadows and receive no solid cockpit collider. Their offshore extents do not enlarge the board's camera pan bounds. Their clock advances with real gameplay time, freezes on pause and resets with a run. The active ocean also suppresses the desert's ambient nest glow, sand plumes and spontaneous rockfalls; combat effects and weather remain active. The same prepared water is used by the menu showcase, overview and cockpit. This feature adds no mod scripts or animations; it is a named-node contract like tower rigs.

Complete custom arenas also omit the stock desert's ambient cave glow, sand plumes and spontaneous rockfalls, including dry landscapes such as Banana Grove. These effects depend on the original cave and cliff geometry. Built-in overlays retain them because they still use that geometry; combat debris and rain remain active in every landscape.

Loading, saves and multiplayer

Restart after editing, enabling, disabling, installing or removing a scenery mod. Options already shows the restart warning; the running showcase and run continue using the configuration loaded at startup until you restart.

The existing startup loading screen prepares every referenced GLB, camera collider and initial GPU draw. A wave change attaches the prepared scenery to the existing world. It does not reload the run, interrupt the cockpit, reset the camera, despawn insects or stop the factory. There is no recurring loading screen for these prepared stages. Keep meshes and texture sizes modest: all used stages remain in memory, and adding many large landscapes increases startup time and RAM. Reuse one scene ID whenever possible.

The current difficulty and absolute wave request the scene, subject to the occupied-board checks above. Continue restores the accepted scene; new runs return to wave 1's scene. Co-op and PvP use the existing mod compatibility signature: scenarios.json and its GLBs, including their tile nodes, are included in the content hash. A built-in scene is part of the game itself, so it is the same for every player on the same game version. Players must enable the same mods: matchmaking filters by that signature, and a lobby reached by invite is refused when it differs. Each run owns its layout; this adds no network pause.

Mods follow the normal load order. The last valid schedule wins per difficulty. If a schedule references a missing/invalid scene, that entire difficulty entry is rejected and the preceding valid mod or original arena remains usable. Read the mod warnings for the rejected file; fix it and restart.