Combat¶
Two layers: ship-vs-ship/port/planet combat (CombatLog, CombatStats) and the fleet/drone subsystem (Fleet*, Drone*). CombatLog lives in combat_log.py.
CombatLog¶
Source: services/gameserver/src/models/combat_log.py
Purpose: Immutable per-engagement record (ship-vs-ship, port attack, planet defense). Captures forces, damage, loot, and admin moderation state.
Fields:
| name | type | constraints | notes |
|---|---|---|---|
| id | UUID | PK | |
| attacker_id, defender_id | UUID FK players.id | nullable, SET NULL | nullable so logs survive player deletes |
| attacker_ship_id, defender_ship_id | UUID FK ships.id | nullable, SET NULL | |
| attacker_ship_name, defender_ship_name | String(100) | nullable | denormalized snapshot |
| attacker_ship_type, defender_ship_type | String(50) | nullable | denormalized |
| sector_id | Integer | nullable | human-readable |
| sector_uuid | UUID FK sectors.id | nullable, SET NULL | |
| port_id | UUID FK stations.id | nullable, SET NULL | FK targets stations |
| planet_id | UUID FK planets.id | nullable, SET NULL | |
| combat_type | String(50) | default ship_to_ship |
ship_to_ship/port_attack/planet_defense |
| outcome | String(20) | not null | attacker_win/defender_win/draw/escaped (matches CombatOutcome) |
| attacker_drones, defender_drones | Integer | default 0 | totals at start |
| attacker_attack_drones, attacker_defense_drones, defender_attack_drones, defender_defense_drones | Integer | default 0 | by class |
| attacker_damage_dealt, defender_damage_dealt | Integer | default 0 | |
| attacker_drones_lost, defender_drones_lost | Integer | default 0 | |
| credits_looted | Integer | default 0 | |
| cargo_looted | JSONB | nullable | commodity → quantity |
| experience_gained | Integer | default 0 | |
| combat_duration | Float | default 0.0 | seconds |
| rounds | Integer | default 1 | |
| combat_log | Text | nullable | textual play-by-play |
| timestamp | DateTime | server default now | primary sort |
| started_at, ended_at | DateTime | mixed | |
| admin_notes | Text | nullable | |
| admin_resolved | Boolean | default false | |
| admin_resolved_at | DateTime | nullable | |
| disputed | Boolean | default false | |
| resolved | Boolean | default true | |
| admin_reviewed | Boolean | default false |
Relationships: attacker, defender, attacker_ship, defender_ship, sector, station (via port_id), planet.
CombatStats¶
Source: services/gameserver/src/models/combat_log.py
Purpose: Daily aggregated combat statistics for admin dashboards.
Key fields: date (unique), counts (total_combats, ship_combats, port_attacks, planet_defenses), outcomes (attacker_wins, defender_wins, draws, escapes), economy (total_credits_looted, total_cargo_looted_value, average_loot_per_combat), efficiency (total_drones_lost, average_combat_duration, most_effective_ship_type), most_active_attacker_id / most_active_defender_id FK players, unique_combatants, calculated_at.
Drone¶
Source: services/gameserver/src/models/drone.py
Purpose: Individual deployable combat/scout/mining/repair unit. Drones live in sectors, fight, and accumulate stats.
Fields:
| name | type | constraints | notes |
|---|---|---|---|
| id | UUID | PK | |
| player_id | UUID FK players.id | not null, CASCADE, indexed | |
| team_id | UUID FK teams.id | nullable, SET NULL, indexed | |
| drone_type | String(50) | not null | attack/defense/scout/mining/repair (DroneType enum) |
| name | String(100) | nullable | optional custom name |
| level | Integer | default 1 | |
| health, max_health | Integer | default 100 | |
| attack_power, defense_power | Integer | default 10 | |
| speed | Float | default 1.0 | |
| status | String(50) | default deployed |
deployed/combat/returning/destroyed/damaged |
| sector_id | UUID FK sectors.id | nullable, SET NULL, indexed | |
| deployed_at, last_action | DateTime | nullable | |
| kills, damage_dealt, damage_taken, battles_fought | Integer | default 0 | lifetime stats |
| abilities | String(255) | nullable | comma-separated ability IDs |
| destroyed_at | DateTime | nullable |
Relationships: player, team, sector (back-pop deployed_drones); deployments → DroneDeployment (1:many cascade).
DroneDeployment¶
Per-deployment record. Columns: drone_id FK CASCADE, player_id FK CASCADE, sector_id UUID FK sectors.id CASCADE, deployed_at, recalled_at, is_active, deployment_type (defense/patrol/mining/…), target_id (optional UUID, no FK), enemies_destroyed, resources_collected, damage_prevented.
DroneCombat¶
Per-engagement record between two drones. Columns: attacker_drone_id / defender_drone_id FK SET NULL, sector_id UUID FK SET NULL, started_at, ended_at, rounds, winner_drone_id, attacker_damage_dealt, defender_damage_dealt, combat_log String(2000) (JSON-encoded).
Fleet¶
Source: services/gameserver/src/models/fleet.py
Purpose: Group of ships organized for large-scale battle, scoped to a team.
Fields:
| name | type | constraints | notes |
|---|---|---|---|
| id | UUID | PK | |
| team_id | UUID FK teams.id | not null, CASCADE, indexed | |
| commander_id | UUID FK players.id | nullable, SET NULL | |
| name | String(100) | not null | |
| status | String(50) | default forming |
forming/ready/in_battle/retreating/disbanded (FleetStatus) |
| formation | String(50) | default standard |
|
| sector_id | UUID FK sectors.id | nullable, SET NULL, indexed | |
| total_ships, total_firepower, total_shields, total_hull | Integer | default 0 | aggregated from members |
| average_speed | Float | default 0.0 | |
| morale | Integer | default 100 | 0-100 |
| supply_level | Integer | default 100 | 0-100 |
| disbanded_at, last_battle | DateTime | nullable |
Relationships: team, commander, sector, members → FleetMember (1:many cascade).
FleetMember¶
Columns: fleet_id FK CASCADE, ship_id FK CASCADE, player_id FK CASCADE, role (flagship/attacker/defender/support/scout), position, joined_at, ready_status.
FleetBattle¶
Inter-fleet engagement record. Key columns: attacker_fleet_id, defender_fleet_id, sector_id (all SET NULL on delete), phase (preparation/engagement/main_battle/pursuit/aftermath), started_at, ended_at, attacker_ships_initial, defender_ships_initial, winner (attacker/defender/draw), attacker_ships_destroyed, defender_ships_destroyed, attacker_ships_retreated, defender_ships_retreated, total_damage_dealt, attacker_damage_dealt, defender_damage_dealt, battle_log JSON, credits_looted, resources_looted JSON.
Relationships: attacker_fleet, defender_fleet, sector, ship_casualties → FleetBattleCasualty (1:many cascade).
FleetBattleCasualty¶
Per-ship casualty entry. Columns: battle_id FK CASCADE, ship_id (SET NULL), player_id (SET NULL), fleet_id (SET NULL), ship_name and ship_type (denormalized in case of delete), was_attacker, destroyed, retreated, damage_taken, damage_dealt, kills, casualty_time, battle_phase.
Notes¶
CombatLog.combat_typeis a free-form string mirroring the canonical valuesship_to_ship,port_attack,planet_defense,sector_defense,ship_vs_drones,planet_defense,port_defense.CombatLog.outcomeuses theCombatOutcomestring enum fromcombat_log.py(ongoing/attacker_win/defender_win/draw/escaped).CombatLog.port_idis namedport_idbut the FK targetsstations.