WIKI

Mods

Tower models and firing points

Die Mod-Anleitungen sind auf Englisch, so wie sie dem Spiel beiliegen.

Applies to the GLB model API v1. See the modding guide for installation, materials and export settings. This guide ships as a separate file so existing installations also receive it in Options → Mods → Open Mods Folder, without overwriting edited guides.

Can a creature replace any tower?

Yes, as a visual replacement that keeps the original tower's gameplay contract. For example, a Flame dragon can breathe the existing fire from its mouth, a Laser creature can shoot from an eye, and a Cannon creature can have two firing points. The game does not recognize mouths, eyes or barrel openings from mesh geometry. You must place the required named Empty nodes at those locations in Blender.

The live board and cockpit read the same posed GLB sockets. A socket's world position supplies the visual shot origin: projectiles, muzzle flashes, Flame/ Poison plumes and Bolt lightning use this path. The Collector instead keeps its existing boom/hook behavior; giving it a mouth does not make it an attacking tower.

Names and hierarchy

Optional throwing attack

Set "attack_animation": "throw" beside file and material in a tower's models.json entry to opt into a hand throw. Add these rigid Empty nodes:

Pitch
└── ThrowArm            shoulder pivot
    └── ThrowForearm    elbow pivot
        └── ThrowHand   palm/release point
            └── ThrowPayload   held object, hidden at release

Author the arm in its release pose, pointing along local +X. Shoulder and elbow rotate around Godot +Z (Blender -Y). Keep the required Muzzle_* nodes directly under Pitch; the renderer moves them to the palm. All of a volley's sockets release from that hand. Each shot waits for a 0.09–0.24 second windup, scaled by the tower's cadence. The clock belongs to the simulation and pauses with the run, including when the model is offscreen. The real projectile captures the exact hand position and the held object's mesh/materials at release. An empty ThrowPayload retains the standard projectile appearance. Fire/Poison hold the casting arm out while the stream runs. Throwers suppress gunpowder flashes, casing ejection and whole body recoil. Other tower rigs keep their current behavior.

This is a gameplay-affecting opt-in. Every peer needs the same gameplay mods; the field is part of the existing mod content hash. Missing joints reject the override rather than silently firing through an invalid hand.

Standard sockets

Use the exact names and direct parent relationships from vanilla_reference/model_catalog.json for the asset you replace. A basic single-socket tower uses:

ModelRoot
├── FixedBody                 mesh; choose your own nonreserved name
└── Yaw                       Empty; rotates around Godot Y
    └── Pitch                 Empty; tilts around Godot Z and receives recoil
        ├── CreatureHead      mesh; choose your own nonreserved name
        └── Muzzle_0          Empty; place at the mouth/eye/barrel exit

Muzzle_0 is an exported Empty/Node3D, not the name of the visible mouth mesh. Keep it directly under Pitch, alongside the head/barrel geometry, so both follow the same pose. Do not put it under an extra Mouth or Jaw parent: the current loader validates the direct parent relationship. Preserve all other required pivots even if your replacement does not need visible geometry on each one.

Names are case-sensitive. The loader tolerates Blender numeric duplicate suffixes such as .001/_001, but use the unsuffixed names for your own exports. Reserve Yaw*, Pitch* and Muzzle* for the actual control nodes: the runtime searches those prefixes. A decorative mesh called MuzzleCover can be mistaken for a socket. Name it something else, such as MouthRim.

Preserve the source socket order as well as the names. The current renderer reads Muzzle* nodes in scene traversal order; it does not sort them by their numeric suffix. Do not reorder, duplicate or add sockets to request extra shots.

Spent ammunition cases

Gun, Cannon and MachineGun replacements may export optional Empty/Node3D markers named CasingPort_0, CasingPort_1, etc. Place each one just outside a modeled receiver outlet, under the aiming part that carries it. Local +Z in Godot points outward (Blender -Y with the normal glTF axis conversion). Cases leave this axis with a small upward and sideways variation on successful shots. A single outlet can serve all barrels; additional markers are selected by the firing socket's child index modulo the number of outlets.

Replacement models without markers emit no cases and receive no vanilla ejection housing. These optional nodes do not change the required Muzzle* hierarchy, damage, ammunition supply or firing cadence. The three stock calibers use hollow spent brass, shared across levels; cases remain for 12–18 seconds and fade during their final two seconds. Physics is cosmetic, pauses with gameplay, and is bounded per arena by the graphics preset. Cases are not salvage or building obstacles.

Level indicators

Level one has no indicator. The game adds two or three small, non-emissive metal chips to the stationary base at levels two and three (fusions retain three). They follow the scene lighting and stay subdued at night. Custom models keep their own materials and aiming rig. For a custom mounting point, export an optional Empty/Node3D named LevelChipsAnchor directly under the model root. Its transform places and scales the row: local X runs along the chips, local Y is up, and its origin is the bottom of the housing. Without an anchor the game fits the stationary plinth; low creature perches use a ground-mounted row in front. Leave room for the full three-chip module (14.5 × 1.0 × 4.7 Godot units). Do not model a second set of chips yourself. These markers also appear in generated mod icons.

Flame, Frost, Bolt, Laser and Poison can export optional Empty/Node3D markers named LinkSocket_0, LinkSocket_1, and so on. Place each marker just inside a modeled connector's opening. Supply opposite ports on the base: each linked pair uses one inlet and a separate outlet, on opposite sides of its centerline. Four cardinal sockets support links along either grid axis, including multiple neighbors. Outgoing and returning flows occupy different sides of the pair. Their broad arcs leave the bores along the outward radial direction, keeping both streams visible. These are cosmetic connections; combo eligibility, range, damage and recipes stay unchanged.

Prefer stationary sockets under the model root so the connection remains seated while the weapon aims. The markers use their full model hierarchy transform; custom scale, rotation and elevated scenery are respected. Without these optional nodes, existing mods retain the previous visual endpoint. The game does not attach stock metal fittings to a custom creature or other replacement. Stock elementals use four foundation fittings with a separate material that shares tower wetness, construction and location-dependent wear.

Required sockets by tower

This table describes the GLB rig, not the number of shots per trigger. For two sockets, retain Muzzle_0 and Muzzle_1; for three, also Muzzle_2; for four, also Muzzle_3.

TowerLevel 1Level 2Level 3Fused level 3Additional required pivots
Gun1221—
Cannon222unsupported—
MachineGun333unsupported—
Missile234unsupportedRocketPod under Pitch
Flame1111—
Poison1111SprayNozzle under Pitch
Bolt1111—
Frost1111—
Laser1111—
Collect111unsupportedBoom and Hook under Pitch; Cable under Hook

All rows also require Yaw, Pitch under Yaw, and every Muzzle_n directly under Pitch. Check the catalog when a future game update changes an asset. An invalid replacement is rejected and logged; the game retains an earlier valid override or the vanilla model. A mesh merely named Mouth does not satisfy the rig.

Position, direction and damage are different contracts

  • Position: moving Muzzle_0 moves the live visual origin. Put it just outside the visible opening so the first part of the effect is not hidden in the mesh.
  • Direction: rotating the Empty alone does not redirect the weapon. The renderer uses its position; tower aim, target selection and projectile behavior determine the direction. Preserve the source model's axes and resting pose. Ordinary tower art faces +X in Godot, with Y up. Missile/Poison have authored launcher inclinations; retain those reference poses. Bolt stays omnidirectional.
  • Gameplay: replacing a GLB does not change range, damage, firing cadence, target eligibility, build footprint, projectile type or the number of streams. Flame and Poison still use their existing ground-only damage cone. Missile still launches upward before following its target.
  • Alignment limits: the underlying 2D simulation still has type/level-specific muzzle offsets and collision rules. It does not rebuild them from a custom GLB. Keep mouth/barrel position, height and length compatible with the original rig. Moving a socket far away can separate the visible effect from damage coverage; naming the socket correctly alone does not make arbitrary geometry accurate.
  • Animation: the API supports the game's rigid named-part animation, including the optional creature joints below. It does not accept armatures, skins or exported animation clips. Shape the creature around the supported pivots.

Stock firing mechanisms and mod compatibility

Vanilla towers now articulate individual barrels, feed drums, pump pistons and cooling/charging parts. Their compact GLBs reserve UV0 for internal rigid-piece roles; this is not a requirement or an animation API for mod models. Both material: imported and material: game overrides keep their ordinary UVs and existing named-pivot behavior. Imported PBR is preserved. Do not copy vanilla UV role numbers onto a textured replacement expecting custom animation clips.

The Yaw → Pitch → Muzzle_n contract above is unchanged. Vanilla barrel sockets follow the new mechanical stroke, while custom models retain the supported whole-Pitch recoil. These visual mechanisms cannot add shots or modify damage.

Optional creature wings and jaw

Tower replacements may include this complete trio of Empty nodes:

Yaw
├── CreatureWingL             wing geometry; local +X flap
├── CreatureWingR             wing geometry; local -X flap
└── Pitch
    ├── CreatureJaw           lower jaw geometry; local -Z opens in Godot
    ├── UpperHead             mesh
    └── Muzzle_0              socket beside the head, never inside the jaw pivot

Place each joint at its anatomical hinge and parent its mesh underneath it. The Blender jaw axis is +Y, which exports to Godot -Z. Wings use +X on the left (positive Blender Y) and -X on the right. Rest orientation is retained. All three joints are required if any is present; wrong direct parents reject the model. Ordinary tower mods without these names continue to work unchanged.

Wings breathe at 0.65 cycles/second, ±12° while idle, and approach 1.8 cycles/second, ±26° during fire. The jaw opens 14° and settles after the attack. Flame/Poison use their actual visible cone lifetime; projectile towers use recent shot events. The motion pauses with gameplay, advances once per rendered frame, and resets for construction. No scripts, imported animation clips or gameplay changes are needed in a mod. Leave clearance throughout these rotations.

Example: Flame as a dragon

Sample mod - Flame as A dragon, on the Steam Workshop, has four original GLBs and an editable Blender sculpture. Subscribe to it and restart. Its wings beat and its jaw opens while the existing fire plume leaves the mouth in both views.

Each upgrade/fusion is a separate asset key. Replacing only level 1 leaves higher levels vanilla. In your mod's models.json, map all variants you want to replace:

{
  "version": 1,
  "models": {
    "Towers/Flame_1": {"file": "Models/Dragon_1.glb", "material": "imported"},
    "Towers/Flame_2": {"file": "Models/Dragon_2.glb", "material": "imported"},
    "Towers/Flame_3": {"file": "Models/Dragon_3.glb", "material": "imported"},
    "Towers/Flame_3_Fused": {"file": "Models/Dragon_3_Fused.glb", "material": "imported"}
  }
}

These files and mod.json are supplied in example_flame_dragon. The same approach applies to another tower using its catalog key and required rig. Adding a second mouth to Flame does not create a second independently damaging stream. That would require gameplay support beyond a model replacement.

Check your replacement in game

  1. Restart with the mod enabled and check the log for rejected files/pivots.
  2. Check every replaced level and fusion from the board and cockpit.
  3. Rotate and aim through the supported limits: the mouth and effect must stay together, without entering the body or clipping the base.
  4. Fire at close enemies and near the range boundary. Check the effect's origin, contact point and damage; test ground/flying targets only where supported.
  5. Test construction, upgrades, nighttime lighting and generated tower icons.

Implementation references for contributors: mesh_art.gd (pose, muzzle), cockpit_mesh_art.gd (muzzle, sync_projectiles, sync_jets), first_person_view.gd (_update_bolts), mod_model_library.gd (_validate) and Scenes/Turrets/turrets.gd (rm_bocas_de, sync_muzzles). The first four files are under Scenes/SupportScenes/.

Optional arena finish

An imported tower, building or ally can add an empty EnvironmentFinish node anywhere below its authored root. This opts the model into the arena's reflected ground light and rain film while preserving its PBR textures and emissive lamps. The Iron Kingdom bays and mechs demonstrate it. The marker has no geometry or animation contract and does not replace any mandatory aiming/ally pivots.

Without the marker, imported surfaces retain their authored lighting response. Each marked live instance owns its rain/light parameters, so different radar views and multiplayer boards cannot change each other's weather. Texture data remains shared. Authored glTF UV0 occlusion maps are preserved for imported materials whether or not this optional marker is present.