Defense towers

Usage guide of defense.towers: towers with tiers built on build spots with money, upgrades, selling, targeting modes, splash and statuses, the defense_towers and defense_spots collections, settings and defaults, service, events, hooks and verbs.

Source: module-kits:kits/defense_towers/usage/en.mdView Markdown source

Also read offline — CLI: grip-forge docs defense-towersMCP tool: gripforge_docs { "topic": "defense-towers" }

Defense towers (defense.towers) #

What it is for #

defense.towers lets the player build towers on build spots with money, upgrade them and sell them. A tower is a document with tiers: range, cadence, damage, an instant hit or a homing shot, splash around the target, a status put on what it hits (a slow, a burn), and whether it hits the air and the ground. Each tower picks a target among the enemies in range by a mode the player sets (first, last, strongest, nearest) and fires through combat.attacks, so its shots are drawn and saved like any other. An upgrade costs the price of the next tier; a sold tower gives back a share of everything it cost. Clicking or tapping a spot or a tower opens its panel. Tower defence, base defence, any game with turrets the player places.

Turn it on #

Install the kit in a project and set its settings with the tools below; gripforge kit api defense.towers lists every setting, and gripforge docs defense-towers prints this guide offline.

gripforge_gamekit_install   { project_id: "gkp_…", id: "defense.towers" }
gripforge_gamekit_configure { project_id: "gkp_…", id: "defense.towers",
                              config: { "sellRefund": 0.5, "defaultTargeting": "strongest", "rangeMarker": true } }
{ "id": "bolt", "name": "Bolt", "tiers": [
  { "cost": 50, "range": 6, "cadence": 0.5, "damage": 8 },
  { "cost": 40, "damage": 14, "name": "Bolt II", "range": 7 },
  { "cost": 60, "cadence": 0.3 } ] }
{ "id": "spot_1", "at": [4, 2] }

First example #

<!-- test: kits/game_engine/host/tests/parity.rs::rust_host_matches_the_typescript_traces (fixture defense.towers.siege) --> A bolt tower (tiers costing 50, 40 and 60) is built on a spot, upgraded and sold. Building spends the first tier price, each upgrade the next one, and selling refunds sellRefund of the total. A cannon that does not hit the air ignores flying enemies.

defense.towers.build("spot_1", "bolt")      // defense.tower.built { tower: "bolt", cost: 50 }
defense.towers.upgrade(tower)               // defense.tower.upgraded { tier: 2, cost: 40 }
defense.towers.setTargeting(tower, "nearest")
defense.towers.sell(tower)                  // defense.tower.sold { refund: sellRefund x 90, rounded down }

Settings and defaults #

SettingDefaultMeaning
teamplayercombat.health team of the towers; they shoot entities of every other team
targetTagenemy{{s_targetTag}}
flyingTagflying{{s_flyingTag}}
sellRefund0.7{{s_sellRefund}}
defaultTargetingfirst{{s_defaultTargeting}}
pickRadius2.5{{s_pickRadius}}
spotSize2.6{{s_spotSize}}
towerHealth1000{{s_towerHealth}}
rangeMarkerfalse{{s_rangeMarker}}

Services #

  • defense.towers (service): types(), spots(), towers(), stats(entity), build(spot, tower, opts?), upgrade(entity), sell(entity), refund(entity), setTargeting(entity, mode), select(entity | null), selected() and pick(point).
  • Content. defense_towers: id (lowercase letters, digits, _), name, description, air and ground (both default true), targeting, size ([width, height, depth]), and tiers (1 to 6): the built tower, then its upgrades in order; a tier keeps what it does not say from the tier before. A tier has name, cost (the build price for the first tier, the upgrade price for the next ones), range (m), cadence (seconds between shots), damage, projectileSpeed (0: an instant hit; otherwise a homing shot in m/s), splash (radius in m) with splashDamage (share of the damage the others take, default 0.5), status (a combat.core status put on the target) with statusOnSplash, style (arrow, orb, heavy) and color. defense_spots: id, at ([x, z] or [x, y, z]) and towers (only these towers can stand there). An instance with the component tower_spot { towers } is a build spot too.

Events #

  • defense.tower.built: a tower was built (entity, tower, spot, cost).
  • defense.tower.upgraded: a tower went up a tier (entity, tower, tier 1-based, cost).
  • defense.tower.sold: a tower was sold (entity, tower, refund).
  • defense.tower.refused: an action was refused (action, reason of money, taken, unknown, max, spot, allowed, or the reason of a tap).
  • defense.tower.selected: the selection changed (entity, kind of spot, tower, or empty when cleared); it listens to combat.attack.impact and combat.attack.cancelled.

Hooks and modding #

  • tower.build: a tower is about to be built on a free spot that allows it (spot, tower, cost, free), before the money is spent; cost is mutable (0 when free), and cancelling emits defense.tower.refused with the reason of the tap (refused by default) and spends nothing.
  • tower.upgrade: a tower is about to go up to tier (1-based) for cost, before the money is spent; cost is mutable, and cancelling refuses with the reason of the tap.
  • tower.sell: a tower is about to be sold for refund (sellRefund x everything it cost, rounded down); refund is mutable, and cancelling keeps the tower.
  • tower.fire: a tower whose cadence is ready picked a target and is about to shoot it for damage (the splash takes its share); damage is mutable, and cancelling makes it hold its fire and ask again on the next tick; the hit itself goes through the combat.damage hook.
{ "id": "half_price_archers", "hook": "tower.build", "match": { "tower": "archer" }, "mul": { "cost": 0.5 } }

Using it from content #

Script verbs: the action build_tower (spot: an id of defense_spots or an entity, tower, free: no money taken) and the condition towers_built (tower, count, at least 1). The input tower_select (button Mouse0) selects a spot or a tower. Variables: defense.selected, defense.towers.

{ "build_tower": { "spot": "spot_1", "tower": "bolt", "free": true } }
{ "type": "towers_built", "count": 3 }

When it does not do what you expect #

SymptomCause and fix
A build is refusedRead defense.tower.refused: money (too poor), taken (the spot is occupied), unknown (no such tower or spot), spot (not a build spot), allowed (the spot does not allow that tower), max (no tier left to upgrade).
A tower never fires at some enemiesThey lack targetTag (default enemy) or share the tower team, are out of range, or are flying (flyingTag) while the tower has air: false, or on the ground while it has ground: false.
Clicking does not select a spotThe click landed further than pickRadius from it; use the service pick(point) to test a point.

Limits #

  • It does not spawn enemies or waves, nor award money for kills: pair it with a wave kit and economy.money.
  • Towers shoot through combat.attacks; the shot look is style and color, and a model per tower comes from the defense_tower asset slot (variant = tower id).
  • The tower panel is a web display module; on other targets the service, the verbs and the events work and your game draws its own panel.

Versions #

Kit defense.towers 1.1.0 (2026-10-09: the hooks tower.build, tower.upgrade, tower.sell, tower.fire and towerHealth; 1.0.0 was the first release). It needs combat.attacks, combat.health, combat.damage, economy.money, input.actions and game.engine ^1.