Combat Mechanics

Purpose: AI-readable reference for Structs combat. Consolidates formulas, requirements, outcomes, and edge cases.


Combat Actions

Action Message Description
Attack struct-attack Direct struct-to-struct combat
Defend struct-defense-set Set struct to defense mode (blocking)
Raid planet-raid-complete Planet assault; steals unrefined ore

Ambit Targeting

Combat in Structs revolves around four ambits. Each struct operates in one ambit, and each weapon can only target specific ambits. This creates a strategic mesh where fleet composition and positioning determine what you can hit and what can hit you.

Ambit Bit Value
Water 2
Land 4
Air 8
Space 16

Weapon Target Matrix

Which ambits each struct’s primary weapon can hit:

Struct Lives In Targets (Primary) Targets (Secondary)
Command Ship Any (movable) Local only (flag 32 = current ambit)
Battleship Space Space, Land, Water
Starfighter Space Space Space
Frigate Space Space, Air
Pursuit Fighter Air Air
Stealth Bomber Air Land, Water
High Altitude Interceptor Air Space, Air
Mobile Artillery Land Land, Water
Tank Land Land
SAM Launcher Land Space, Air
Cruiser Water Land, Water Air
Destroyer Water Air, Water
Submersible Water Space, Water

Threatened-By Matrix

Which structs can attack into each ambit:

Target Ambit Threatened By
Space Battleship, Starfighter, Frigate, High Altitude Interceptor, SAM Launcher, Submersible
Air Frigate, Pursuit Fighter, High Altitude Interceptor, SAM Launcher, Cruiser (secondary), Destroyer
Land Battleship, Stealth Bomber, Mobile Artillery, Tank, Cruiser
Water Battleship, Stealth Bomber, Mobile Artillery, Cruiser, Destroyer, Submersible

The Command Ship can attack into any ambit but must first move there (see below).

Command Ship Ambit Mobility

The Command Ship is the only struct that can change ambits. All other structs are fixed in their operating ambit.


Health Points

Each struct has a Max HP that determines how much damage it can absorb before destruction.

Struct Max HP
Command Ship 6
All other structs 3

Damage Formulas

Multi-Shot Damage

damage = sum(successful_shots) - damageReduction
if damage >= health then health = 0
else health = health - damage
Variable Description
weaponShots Number of shots per attack
weaponShotSuccessRate Per-shot success (Numerator/Denominator)
weaponDamage Damage per successful shot
damageReduction Defense reduction
health Target current health

Algorithm: For each shot, IsSuccessful(weaponShotSuccessRate); if true, add weaponDamage. Apply damageReduction to total. Minimum damage after reduction is 1. Cap at target health.

Attack results: Attack events include health results (remaining health after attack) in addition to damage amounts.

Evasion

if weaponControl == guided then successRate = guidedDefensiveSuccessRate
else successRate = unguidedDefensiveSuccessRate
canEvade = IsSuccessful(successRate) if successRate.Numerator != 0

Weapon Control vs Defense Type

The interaction between a weapon’s control type (guided/unguided) and the target’s defense type is the core of combat tactics. This matrix determines whether shots can be evaded:

Target Defense vs Guided vs Unguided
Signal Jamming (Battleship, Pursuit Fighter, Cruiser) 66% miss Full hit
Defensive Maneuver (High Alt Interceptor) Full hit 66% miss
Armour (Tank) Full hit, -1 damage Full hit, -1 damage
Stealth Mode (Stealth Bomber, Submersible) Same-ambit only Same-ambit only
Indirect Combat Module (Mobile Artillery) Full hit Full hit
None Full hit Full hit

Tactical takeaways: Use unguided weapons against Signal Jamming targets (Battleship, Pursuit Fighter, Cruiser). Use guided weapons against Defensive Maneuver targets (High Alt Interceptor). Armour always reduces damage by 1 regardless of weapon control.

Stealth

Stealthed structs (Stealth Bomber, Submersible) are not invisible – they can still be targeted by structs in the same ambit. Stealth blocks cross-ambit targeting only. A stealthed Submersible (water) can be attacked by other water structs, but air/land/space structs cannot target it.

Recoil Damage

Attacker takes damage after firing: health = health - weaponRecoilDamage. Recoil only applies if the attacker survives the entire shot sequence (including counter-attacks).

Post-Destruction Damage

If health == 0 and postDestructionDamage > 0, damage applies to surrounding structs.

Blocking

if !evaded and defender exists and defender.operatingAmbit == target.operatingAmbit then
  if weapon.blockable and defender.ReadinessCheck() then
    canBlock = IsSuccessful(defender.blockingSuccessRate)

Requirements (all must be true):

  1. The shot was NOT evaded – block does not fire on evaded shots
  2. Weapon must be blockable (GetWeaponBlockable returns true)
  3. Defender must pass ReadinessCheck – struct online AND owner online
  4. Defender must be in the same ambit as the target being defended (not the attacker)

A struct cannot block for a friendly in a different ambit. Blocking is strictly same-ambit defense. Unlike counter-attacks, block is attempted on every shot (not limited to once per attack).

Counter-Attack

Each struct can counter-attack at most once per struct-attack invocation. Counter-spent state is tracked per struct per attack command (not per target, not per shot). For a 3-shot Attack Run: the defender counters on the first shot only, but can attempt to block all 3 shots. The target counters once after all shots resolve.

Counter-attacks are ambit-independent from the defended target. A space-based defender can counter-attack a space-based attacker even while defending a land-based struct.

Scenario Damage
Same ambit as attacker counterAttackDamage (full)
Different ambit from attacker counterAttackDamage / 2

Requirements (all must be true):

  1. Weapon must be counterable (GetWeaponCounterable returns true)
  2. Neither counter-attacker nor attacker is destroyed
  3. Defender’s weapons must be able to target the attacker’s ambit (via CanCounterTargetAmbit)
  4. Location reachability to the attacker:

Two types of counter-attack:

Both the defender and the target can counter-attack – an attacker may take damage from two sources per target.

Planetary Defense Cannon

damage = planetaryShieldBase + sum(defenseCannon.damage for each cannon on planet)

Attack Resolution Sequence

When struct-attack is executed, the following steps occur in order per target:

  1. Validation – Verify weapon ambits can reach target ambit. Stealthed targets are only targetable from the same ambit. Verify target struct exists.
  2. Stealth break – If the attacker has stealth active, it is instantly deactivated (attacking reveals position).
  3. Evasion check (per-target, not per-shot) – Evaluate weapon control (guided/unguided) vs target defense type. If evaded, ALL shots against this target miss but counters still fire.
  4. Per-shot loop (inside ResolveDefenders) – For each projectile:
  5. Target counter-attack (once per struct-attack invocation) – fires after all shots resolve. Destroyed targets cannot counter.
  6. Early termination – If the attacker is destroyed mid-sequence, remaining targets do not process.

After all targets are resolved:

  1. Recoil damage – Applied to attacker if it survived all shots
  2. Planetary Defense Cannon auto-fire – If any target was a planetary struct, PDCs fire against the attacker

Per-Projectile Events

Each projectile gets its own EventAttackShotDetail row. For a 3-shot Attack Run, the attack event contains 3 separate shot detail entries with per-projectile hit/miss breakdowns. targetPlayerId is on EventAttackShotDetail (not EventAttackDetail).

Key implications:


Requirements

Requirement Attack Raid
Player online
Sufficient power
Sufficient charge
Fleet away
Command Ship online
Proof-of-work

Outcomes

Outcome Description
victory Attacker/raider wins
defeat Defender wins
attackerRetreated Attacker withdrew

Raid status: Raid status includes seizedOre – the amount of ore stolen during the raid. This is tracked on the planet_raid record and simplifies victory handling. See schemas/entities/planet.md for the planet_raid table schema.


Edge Cases


Struct Destruction

When a struct reaches 0 HP, it is destroyed and removed from the game. The destroyed instance is gone forever and cannot be repaired. However, you can build a new struct of the same type as a replacement — full build PoW required.

Consequence Detail
Destroyed struct Instance gone forever; build a replacement (full PoW)
Lost defenders Each destroyed defender must be individually rebuilt
Rebuild cost Full PoW + power draw, same as original build

FAQ: Can I rebuild a destroyed Command Ship?

YES. A destroyed Command Ship cannot be repaired, but you can build a brand new Command Ship (type 1) to replace it. The new Command Ship gets a new struct ID and requires full build PoW (~17 min at D=3). You choose the starting ambit at build time.

Until the replacement is online, the fleet cannot move, raid, or build in space. This downtime is the real cost of losing a Command Ship. Always assign defenders to protect it via struct-defense-set before engaging in offensive operations.


See Also