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 drones — combat_service.attack_sector_drones.
- Planet — combat_service.attack_planet.
- Port / station — combat_service.attack_port.
- Fleet vs fleet — fleet_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.combatshields first then overflows into hull, destruction fires on the unroundedhull <= 0, and attrition persists on both ships (flag_modified) even when nobody dies. The attack-drones+5% per 10modifier 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: thesector modifierterm (not yet read into the roll),shield_resistance/armor_rating(read with0defaults — not seeded ontoShip.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 consciousness —
winner.aria_total_interactions += 1. Thresholds: 50 → L2 (1.1× turn regen), 150 → L3 (1.2×), 400 → L4 (1.35×), 1000 → L5 (1.5×). - Medals —
MedalService.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".
- Bounty —
BountyService.collect_bountyif 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.pyread the real player-name attribute (fleet.commander.username); thefleet.commander.nameAttributeErrorthat 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
FleetBattlemodel 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'sdefensesJSONB; 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 |