Skip to content

Combat

How fights happen — from a one-on-one dogfight to a team-scale fleet battle. Numbers below come from the implementation.

Scope and target classifications

Combat targets, in code: - Ship (PvP or vs hostile NPC) — combat_service.attack_player. - Sector dronescombat_service.attack_sector_drones. - Planetcombat_service.attack_planet. - Port / stationcombat_service.attack_port. - Fleet vs fleetfleet_service.py.

Initiating combat costs turns; defending is free. Defender-side cost is read from the defender ship type's ShipSpecification.attack_turn_cost — meaning it is intentionally expensive to attack tiny targets like an escape pod (which is set to a very high attack cost to discourage pod-killing).

Default turn costs (combat_service.py):

Action Turns
Attack player ship attack_turn_cost of defender's ship type, min 2
Attack sector drones 2
Attack planet 3
Attack port 3
Defend 0

Combat resolution model

The resolver is in services/gameserver/src/services/combat_service.py (~1940 lines; entry points _resolve_ship_combat, _resolve_drone_combat, _resolve_planet_combat, _resolve_port_combat).

Ship-vs-ship

Inputs: - Ship hull and shield values (per ship row). - Drone counts (Player.attack_drones, Player.defense_drones). - Ship type matchup multiplier (SHIP_COMBAT_MODIFIERS): - DEFENDER vs CARGO_HAULER = 1.5× - DEFENDER vs LIGHT_FREIGHTER = 1.3× - FAST_COURIER vs CARRIER = 0.7× - SCOUT vs CARRIER = 0.5× - CARRIER vs SCOUT = 1.8× - CARRIER vs FAST_COURIER = 1.5× - COLONY vs DEFENDER = 0.5× - Default weapon by ship (SHIP_DEFAULT_WEAPONS): Scout uses EMP, Defender uses Plasma, Carrier uses Missile, Warp Jumper uses Plasma, all others use Laser. Per-ship defaults are also surfaced in ./ship-roster.md#combat-sensor-stats (Combat & sensor stats table). - Weapon profile (WEAPON_TYPES):

Weapon Base damage vs Shields vs Hull Description
EMP 0.5 2.0 0.3 Electromagnetic pulse, devastating to shields
Laser 1.0 0.8 1.0 Standard energy weapon
Missile 1.5 0.6 1.5 Physical projectile, bypasses some shields
Plasma 1.2 1.2 0.9 High-energy plasma bolts

The four weapon types pair with each ship's combat archetype: - EMP excels at shield-stripping (2.0× vs shields) but tickles hull (0.3× vs hull); Scout's EMP suits the "disable, don't kill" recon role. - Laser is the balanced all-purpose weapon; civilian and utility hulls default to it. - Missile is the hull-killer (1.5× damage, 1.5× vs hull) but weaker against shields; Carrier's Missile pairs heavy ordnance with its drone bay. - Plasma is the well-rounded mid-tier (1.2× across the board, slightly weaker vs hull); Defender and Warp Jumper default to it.

Damage stack (canonical — full order-of-operations in ../../SYSTEMS/combat-resolver.md#damage-stack-order-of-operations):

1. base_damage = weapon.base_damage
                 × attack_drones_modifier        (+5% per 10 drones)
                 × ship-vs-ship matchup modifier
                 × sector modifier               (nebula, radiation, etc.)
                 × (1 + rank.combat_bonus / 100) (per-rank percent scalar)

2. shield_hit  = min(base_damage, defender.shields)
                 × (1 - defender.shield_resistance)
                 × weapon.shield_effectiveness

3. residual    = base_damage - min(base_damage, defender.shields)   (pre-resistance)
   hull_hit    = residual
                 × (1 - defender.armor_rating)
                 × weapon.hull_effectiveness
                 × (1 - defender.defense_drones_modifier)            (-5% per 10 drones)

4. critical    = (RNG < 0.05) ? hull_hit × 0.5 : 0

5. defender.shields -= shield_hit
   defender.hull    -= hull_hit + critical

Shields absorb first (capped at the shield pool), and the pre-resistance residual is what feeds hull damage — so a shield-resistance fraction never leaks across to hull when shields would have absorbed everything.

defender.shield_resistance and defender.armor_rating are Floats in [0.0, 1.0] on Ship.combat — fractions of damage absorbed. rank.combat_bonus is a per-rank percent scalar applied to base damage (Spacer +1% up to Fleet Admiral +40%, see ./ranking.md#military-rank).

Round-by-round drone attrition is rolled stochastically; outcome is one of ATTACKER_VICTORY, DEFENDER_VICTORY, DRAW. Logged to CombatLog.

Status: ✅ Shipped — round damage depletes Ship.combat shields first then overflows into hull, destruction fires on the unrounded hull <= 0, and attrition persists on both ships (flag_modified) even when nobody dies. The attack-drones +5% per 10 modifier applies in both directions, the hull-ratio escape valve is live, escape pods are rejected as targets (S-V1), and a self-attack guard holds. 📐 Still deferred: the sector modifier term (not yet read into the roll), shield_resistance / armor_rating (read with 0 defaults — not seeded onto Ship.combat), and between-battle shield regeneration (no scheduler; shields/hull restore only via repair facilities).

Sector drones

Defender drones get a +5% bonus over ship-deployed drones (SECTOR_DEFENSE). Drone-vs-drone exchanges resolve probabilistically until one side hits zero; survivor keeps remaining drones.

Planet assault

Assault is rejected if attacker is the owner, planet has no owner, or attacker is docked/landed. Resolution incorporates planet.defense_level, deployed drones, citadel-level defenses (turrets, shields, orbital platforms, rail guns — see planets/defense.md). On capture, ownership transfers atomically.

Port assault

Port defenses scale with port class — Class 1: 50 drones; Class 2: 100; Class 3: 200; Class 4: 300 + auto-turrets; Class 5: 500 + advanced grid. Successful raid temporarily disables the port (regen ~24h). 🚧 Partial — full takeover/sabotage flow is design-stage.

Escape mechanics

Players can attempt to flee. Success is a function of: - Ship type — Fast Courier and Scout get a flat boost (FAST_ESCAPE_SHIP_TYPES). - Remaining hull (lower hull = harder). - Distance to sector edge (closer = better). - Pursuer ship class (heavier ships pursue worse).

If a ship is destroyed: 1. Player is auto-ejected to escape pod. 2. Cargo lost. Credits retained. 3. If insured, payout based on InsuranceType (see ships.md). 4. Combat log records cause and salvage.

Post-combat hooks

combat_service.attack_player fires the following on resolution (best-effort; failures are logged but don't roll back the fight):

  • Ranking — winner gets rank points via RankingService.calculate_combat_points (see ranking.md).
  • ARIA consciousnesswinner.aria_total_interactions += 1. Thresholds: 50 → L2 (1.1× turn regen), 150 → L3 (1.2×), 400 → L4 (1.35×), 1000 → L5 (1.5×).
  • MedalsMedalService.check_combat_medals(winner_id, victory_count) (Bronze Cluster at 100 wins, Silver at 1k, Quantum Cross at 10k).
  • Personal reputation (PersonalReputationService):
  • Killed a defender with active bounties → +100, "defeat_bounty_target".
  • Killed an innocent (no bounty) → −100, "attack_innocent".
  • Killed a defender in an escape pod → additional −500, "kill_escape_pod".
  • Successfully defended → +50, "defend_against_attacker".
  • BountyBountyService.collect_bounty if the defender had bounties placed (see bounties.md).

Drones

Drone type Cost (cr) Notes
Attack 1,000 Offensive primary
Defense 1,200 Damage reduction

Every 10 attack drones = +5% combat effectiveness; every 10 defense drones = −5% incoming damage. Drones prefer engaging enemy drones first.

Code: services/drone_service.py, model models/drone.py.

Weapons

combat_service.py:WEAPON_TYPES covers laser/plasma/missile/emp. 🚧 Planned — fuller weapon catalog (autocannon, particle, torpedo, tractor, mining); the resolver currently consumes only the four primary types listed above.

Tractor weapon mode

📐 Design-only. The tractor weapon entry is the combat-side face of the dual-use Tractor Beam equipment slot (the tow-side use is in ./ships.md#tractor-beam-tow-operations).

Property Value
Damage 0 (no hull or shield damage)
Effect Locks target; reduces target's effective current_speed by 50% for 3 combat rounds
Flee suppression Locked target cannot succeed at flee actions while the lock holds
Counterplay Target breaks the lock by destroying the tractor-equipped ship, by being towed out of weapons range by an ally, or by waiting out the 3-round window
Stack Multiple tractor locks from different attackers stack the speed debuff additively up to a 90% floor
Mutual exclusion A ship in active tow operation cannot also fire tractor in weapon mode (the equipment can only do one thing at a time)

Tractor is intended as a tactical control weapon — denying escape, holding a flagship in place for focused fire, or pulling a Warp Jumper out of jump-cooldown range. It does no damage on its own; effectiveness depends on coordinated team fire.

Fleet battles

services/fleet_service.py (~908 lines) handles team fleets: - Roles (FleetRole): flagship, attacker, defender, support, scout. At most one flagship per fleet; flagship destruction triggers a one-shot −30 morale penalty. - Formations (single string field on the fleet, applied to all members): standard ×1.00/×1.00, aggressive (Wedge) ×1.15/×0.85, defensive ×0.85/×1.15, flanking (Offensive) ×1.10/×0.90, turtle (Scatter) ×0.60/×1.40 — values are (attack_modifier, defense_modifier). - Stats aggregated from member ships' combat JSONB via _recalculate_fleet_stats. - Status machine (FleetStatus): forming → ready → in_battle → retreating → disbanded (with reversible transitions back to ready on battle end). Ships can only be added while forming or ready; movement is blocked while in_battle.

See fleet-tactics.md for the full breakdown of role bonuses, morale and supply mechanics, coordination scaling, and battle-resolution math.

Battle records are persisted as FleetBattle + FleetBattleCasualty rows.

Status: ✅ Shipped — fleet response builders in services/gameserver/src/api/routes/fleets.py read the real player-name attribute (fleet.commander.username); the fleet.commander.name AttributeError that broke six response sites is resolved.

🚧 Planned: large-scale (100v100+) tier. Current fleet system handles team-vs-team coordinated combat at moderate scale; the items below are 📐 Design-only — captured here as launch-direction intent without committed timing.

📐 Design-only — large-scale combat ambitions:

  • Multi-team battles — up to 3–8 teams in a single engagement (current FleetBattle model is two-fleet only; needs a multi-side battle model).
  • Battle scale taxonomy — named tiers for grouping engagement size (e.g. SKIRMISH 2–5 players / 10–50 units; ENGAGEMENT 6–15 / 51–200; CAMPAIGN 16–30 / 201–1,000; MASSIVE_WAR 31–75 / 1,001–5,000; LEGENDARY 76+ / 5,000+). Drives matchmaking, resource budget, performance targets.
  • Hot-join / late-arrival — players warp in at rally points after a battle starts, with an escalating join cost the longer the battle has been running.
  • Reinforcement waves — SOS broadcast triggers staggered re-entry (e.g. every 5 minutes) for team-mates not initially engaged; escalation spiral as more reinforcements arrive.
  • Adaptive UI by chaos level — interface complexity scales with sector occupancy: cleaner views at low player counts (1–10), aggregated readouts at medium (11–25), command-only views at high (26–50), AI-assisted summaries at extreme (51+).
  • Team home-base infrastructure — team-owned forward bases that produce drones on a timer (e.g. 50 drones/hour), construct ships, host garrisons, and run automated supply convoys to active battle sectors.
  • Spectator viewing modes — beyond the basic combat:{combat_id} topic stream, richer modes including god view, commander cam, individual unit tracking, and cinematic mode.
  • Battle chronicles — long-term lore-persistence layer above CombatLog: hall of fame for participants, decisive-moment highlight reels, sector monuments commemorating major battles, ship naming for heroes, AI-generated battle narratives.
  • Tournament / event system — scheduled player tournaments, role-play wars, charity battles, and developer challenges with bracket structure, rewards, and broadcast hooks.
  • Behavioral cheat detection — automated analytics for impossible actions (e.g. simultaneous moves), statistical anomalies in win rates, multi-account coordination patterns, and timing-based bot detection. Distinct from the existing rate-limiting and server-side validation layer.
  • Combat performance SLOs — explicit turn-resolution targets per battle size (e.g. 100v100 in <3s, 500v500 in <8s), concurrent-battle capacity per gameserver, and degradation behavior under load. Drives infrastructure scaling decisions.

These items are captured as design intent for future ADRs; none commit to timing or implementation approach.

Sector control & deployable assets

  • Deployed drones can be left in a sector to defend it (one player per sector). Deployed drones get +5% effectiveness vs ship-based.
  • Mines damage hostile entrants. ✅ Armored mines shipped 2026-06-14 (5,000 cr): bought at any mine_dealer/spacedock armory, laid in open space (POST /armory/deploy) into the sector's defenses JSONB; a hostile ship entering takes 200 hull from one mine (consumed per entry), floored at 1 hull (cripple, not destroy) — see ADR-0083. Same-team fields are friendly; a sector holds one commander's field at a time. 📐 Limpet mines (2,000 cr, tracking/surveillance) remain design-only — their mechanic is not built, so they are not yet purchasable.
  • Rented NPC defenders — design only, not implemented in code.

See galaxy/sectors.md.

Player-facing affordances

  • Combat HUD shows hull/shield/cargo, weapon list, target, action buttons (Attack / Defend / Evade / Flee).
  • Turn cost preview before initiating.
  • Combat log (models/combat_log.py) is queryable per player and shows full history.

Source map

Topic Path
Player-vs-player resolver services/gameserver/src/services/combat_service.py
Drone combat helpers services/gameserver/src/services/combat_service.py:_resolve_drone_combat
Player combat orchestration services/gameserver/src/services/player_combat_service.py
Fleet battles services/gameserver/src/services/fleet_service.py
Combat models services/gameserver/src/models/combat.py, combat_log.py
Drones services/gameserver/src/models/drone.py, services/drone_service.py
Combat REST routes services/gameserver/src/api/routes/combat.py, player_combat.py
Admin combat tools services/gameserver/src/api/routes/admin_combat.py
Ranking hook services/gameserver/src/services/ranking_service.py
Reputation hook services/gameserver/src/services/personal_reputation_service.py
Bounty hook services/gameserver/src/services/bounty_service.py
Medal hook services/gameserver/src/services/medal_service.py