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.
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 #
| Setting | Default | Meaning |
|---|---|---|
team | player | combat.health team of the towers; they shoot entities of every other team |
targetTag | enemy | {{s_targetTag}} |
flyingTag | flying | {{s_flyingTag}} |
sellRefund | 0.7 | {{s_sellRefund}} |
defaultTargeting | first | {{s_defaultTargeting}} |
pickRadius | 2.5 | {{s_pickRadius}} |
spotSize | 2.6 | {{s_spotSize}} |
towerHealth | 1000 | {{s_towerHealth}} |
rangeMarker | false | {{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()andpick(point).- Content.
defense_towers:id(lowercase letters, digits,_),name,description,airandground(both defaulttrue),targeting,size([width, height, depth]), andtiers(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 hasname,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) withsplashDamage(share of the damage the others take, default 0.5),status(acombat.corestatus put on the target) withstatusOnSplash,style(arrow,orb,heavy) andcolor.defense_spots:id,at([x, z]or[x, y, z]) andtowers(only these towers can stand there). An instance with the componenttower_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,tier1-based,cost).defense.tower.sold: a tower was sold (entity,tower,refund).defense.tower.refused: an action was refused (action,reasonofmoney,taken,unknown,max,spot,allowed, or the reason of a tap).defense.tower.selected: the selection changed (entity,kindofspot,tower, or empty when cleared); it listens tocombat.attack.impactandcombat.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;costis mutable (0 when free), and cancelling emitsdefense.tower.refusedwith the reason of the tap (refusedby default) and spends nothing.tower.upgrade: a tower is about to go up totier(1-based) forcost, before the money is spent;costis mutable, and cancelling refuses with the reason of the tap.tower.sell: a tower is about to be sold forrefund(sellRefundx everything it cost, rounded down);refundis mutable, and cancelling keeps the tower.tower.fire: a tower whose cadence is ready picked a target and is about to shoot it fordamage(the splash takes its share);damageis mutable, and cancelling makes it hold its fire and ask again on the next tick; the hit itself goes through thecombat.damagehook.
{ "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 #
| Symptom | Cause and fix |
|---|---|
| A build is refused | Read 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 enemies | They 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 spot | The 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 isstyleandcolor, and a model per tower comes from thedefense_towerasset 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.