Skip to content

Ranking & Reputation

Two parallel progression tracks:

  1. Military Rankwhat you've done. Achievement-based, never lost.
  2. Personal Reputationhow you've behaved. Alignment scale that swings with combat actions.

Plus a separate per-faction reputation (covered in factions-and-teams.md).


Military Rank

Tiers and thresholds

18 ranks across five tiers (services/ranking_service.py:RANK_DEFINITIONS).

Level Tier Rank Points required Trading bonus Combat bonus Max-turns bonus
0 Enlisted Recruit 0 0% 0 0
1 Enlisted Spacer 50 +2% +1 +5
2 Enlisted Corporal 150 +3% +2 +10
3 NCO Sergeant 300 +5% +4 +15
4 NCO Staff Sergeant 500 +6% +5 +20
5 NCO Master Sergeant 800 +7% +6 +25
6 Warrant Warrant Officer 1,200 +8% +8 +30
7 Warrant Chief Warrant Officer 1,800 +10% +10 +35
8 Officer Ensign 2,500 +12% +12 +40
9 Officer Lieutenant 3,500 +15% +14 +45
10 Officer Commander 5,000 +18% +16 +50
11 Officer Captain 7,000 +20% +18 +55
12 Officer Senior Captain 10,000 +22% +20 +60
13 Flag Commodore 14,000 +25% +22 +70
14 Flag Rear Admiral 20,000 +30% +25 +80
15 Flag Vice Admiral 28,000 +35% +28 +90
16 Flag Admiral 40,000 +40% +32 +100
17 Flag Fleet Admiral 60,000 +50% +40 +120

Achievement gates beyond points

Some ranks require minimum stat thresholds in addition to points (RANK_REQUIREMENTS):

Rank Extra requirement
Sergeant 25 trades, 50 sectors visited
Staff Sergeant 50 trades, 10 combat victories
Master Sergeant 100 trades, 25 combat victories, 100 sectors
Warrant Officer 50 combat victories, 200 trades
Ensign 100 combat victories, 1 planet owned
Lieutenant 500 trades, 200 combat victories
Commander 3 planets owned, 500 combat victories
Captain 1,000 trades, 1,000 combat victories, 5 planets owned

Earning rank points

Valid award reasons (VALID_REASONS): - combat_victory — points scaled by relative rank of attacker vs defender (RankingService.calculate_combat_points). - trading_volume — proportional to trade revenue. - exploration — first-discovery of sectors. - colony_establishment — claiming a planet. - admin_grant — manual.

The combat hook in combat_service.attack_player calls:

ranking_service.award_rank_points(winner_id, points, "combat_victory")

Ranks are permanent

Once promoted, a player stays at that rank even if their stats fluctuate. Promotion is checked on every point award.

Old-save rank-name compatibility

LEGACY_RANK_MAP translates older save data to current rank IDs: - PrivateRecruit - GeneralAdmiral - MajorCommander - ColonelCommodore

Special medals

Medals are the horizontal achievement layer that sits alongside the linear rank progression. The full catalog (combat / economic / exploration / diplomatic / special), award lifecycle, the Orange Cat Society lore, and the privacy model live in dedicated docs:

The three combat-tier medals (Bronze Cluster at 100 victories, Silver Cluster at 1,000, Quantum Cross at 10,000) are the only ones wired into code today via MedalService.check_combat_medals (services/medal_service.py). The rest of the catalog is 📐 Design-only.

Player-facing display

  • Insignia next to player name in chat, leaderboards, team rosters.
  • Trading bonus is applied at port transactions.
  • max_turns_bonus raises the player's turn cap (and the natural turn-pool ceiling).
  • combat_bonus is a percent scalar applied to base damage in the canonical damage stack (base_damage × (1 + combat_bonus / 100), per ../../SYSTEMS/combat-resolver.md#damage-stack-order-of-operations). Values run +1% at Spacer up to +40% at Fleet Admiral.

✅ Shipped — combat_bonus applied. combat_service.attack_player reads RankingService.get_rank_bonuses(attacker.military_rank) and applies the per-rank combat_damage_bonus_percent as attacker_damage_mult = 1 + percent/100 in the damage-roll step, per ADR-0061 S-D2.

Mid-combat rank promotion deferral (per ADR-0061 S-I4): when rank_points crosses a rank threshold during an active combat, the promotion is queued and fires at combat end. The combat_bonus value used throughout the fight is the pre-combat rank's bonus (snapshot at combat init). No mid-combat stat changes; combat math stays internally consistent round-to-round; ARIA narrates the rank-up after the fight resolves.

Source map

Topic Path
Rank tables, promotion logic services/gameserver/src/services/ranking_service.py
Player rank fields services/gameserver/src/models/player.py (military_rank, rank_points)
Ranking REST routes services/gameserver/src/api/routes/ranking.py
Medal awards services/gameserver/src/services/medal_service.py
Awarding hook services/gameserver/src/services/combat_service.py

Status: 🚧 Partial — Player.military_rank and Player.rank_points columns exist, the player-client ranking/ UI (RankDisplay, RankProgress, Leaderboard, MedalShowcase) renders against them, ranking_service.py is live behind routes/ranking.py (rank / leaderboard / progress / medals / reputation / bounties), and trading.py awards rank points on buy and sell. The lifetime-stats table described above is the remaining gap, not yet plumbed end-to-end.


Personal Reputation

Tracks moral alignment — separate from faction standing. Eight tiers across the −1000 to +1000 range. Used to drive name color, bounty system, and station-pricing modifiers.

Tiers (personal_reputation_service.py:REPUTATION_TIERS)

Score range Tier Name color (hex)
−1000 to −750 Villain #FF0000
−749 to −500 Criminal #FF4400
−499 to −250 Outlaw #FF8800
−249 to −1 Suspicious #FFCC00
0 Neutral #FFFFFF
+1 to +249 Lawful #88FF88
+250 to +499 Heroic #00FF00
+500 to +1000 Legendary #00FFFF

Triggers (REPUTATION_TRIGGERS)

Action Δ Reason key
Attack a player with no bounty −100 attack_innocent
Kill a player in an escape pod −500 kill_escape_pod
Salvage another player's Cargo Wreck during the 1-hour grace window (non-team-member) −25 early_salvage (📐)
Pilot a ship reported stolen, per real-time day −100 pilot_stolen_ship (📐)
Caught at port docking with a stolen ship −100 stolen_ship_impound (📐)
Successfully defend against an attacker +50 defend_against_attacker
Defeat a player with active bounty +100 defeat_bounty_target
Complete legitimate trade +1 complete_trade
Destroy hostile sector drones +10 destroy_pirate_drones

Adjustments are clamped to [−1000, +1000]. The service writes both the new score and the cached reputation_tier / name_color columns on Player.

Gameplay effects (get_reputation_info)

Mirrors the per-tier bracket table in ../../SYSTEMS/bounty-and-reputation.md#reputation-tier-table. Bracket boundaries match the tier table above:

Score range Tier Effect
[−1000, −750] Villain +20% station markup, bounty hunters target
[−749, −500] Criminal +20% station markup
[−499, −250] Outlaw +10% station markup
[−249, −1] Suspicious (no station effect)
[0, 0] Neutral (no station effect)
[+1, +249] Lawful −5% station discount
[+250, +499] Heroic −5% station discount, +5% faction standing bonus
[+500, +1000] Legendary −10% station discount, +5% faction standing bonus

Decay

apply_weekly_decay pulls extreme values back toward 0 by 5 points per week (positive scores decrement, negative scores increment). Once a player hits Neutral, decay stops.

Bounty interaction

When an attacker wins combat, BountyService.collect_bounty(attacker_id, defender_id) runs. If bounties exist, attacker collects the pool (minus a system fee) and gains reputation; if not, the attacker is treated as having attacked an innocent and loses reputation. See bounties.md for the full bounty system.

Suspect status (temporary flag)

Distinct from the persistent personal_reputation integer above, Suspect Status is a temporary boolean flag on Player that fires from specific actions and auto-clears on a timer. Currently the only trigger is early-window Cargo Wreck salvage (see ships.md → Cargo Wreck).

When Player.suspect_status = True:

  • Name color shifts to gray/yellow across all UI surfaces (overrides the personal_reputation tier color for the duration of the flag).
  • Federation-zone immunity is suspended — anyone may attack the flagged player in fed-space without the normal policing penalties; the flagged player fights back without fed-space combat-cost penalties.
  • Flag auto-clears at Player.suspect_until.

Stacking rules: - Each suspect-triggering event sets suspect_until = max(suspect_until, now + 1h) — i.e., extends the timer to 1 hour from now if that's later than the current expiry. - Maximum cumulative duration: 4 hours from the first triggering event. Even chronic offenders cap at 4 hours of flag. - After clear, future events restart the cycle.

📐 Design-only — Player.suspect_status and Player.suspect_until columns are launch-target additions; not in code today.

Wanted status

A stronger flag than Suspect, fired by piloting a ship the registered owner has reported stolen (see ../../SYSTEMS/ship-registry.md). While Player.wanted_status = True:

  • Name color renders red in all UI surfaces (overrides personal-reputation tier color and Suspect Status if both are active).
  • Federation-zone immunity is suspended — anyone may attack a Wanted player in fed-space without normal policing penalties.
  • NPC patrols actively hunt the player (📐 design-only — patrol AI hooks).
  • An automatic bounty equal to 50% of the ship's appraised value is auto-placed on the Wanted player by the registry. See bounties.md.
  • Daily personal-reputation drain−100 / day while still piloting the stolen ship.
  • Port-docking impound — at any port, attempting to dock with a stolen ship results in:
  • Ship impounded; returned to registered owner (held at port for collection).
  • Pilot fined 25% of credits (capped at 100k cr).
  • Pilot personal-reputation hit −100 (separate from the daily drain).
  • Pilot ejected to escape pod.

Wanted Status auto-clears the moment the pilot is no longer in the stolen ship — eject voluntarily, ship destroyed, ship impounded, or registered owner retracts the stolen report.

📐 Design-only — Player.wanted_status boolean is a launch-target addition; not in code today.

Shipped — system bounty auto-placement at thresholds (−500 / −750 / −1000) is live: bounty_service.SYSTEM_BOUNTY_TIERS + _get_system_bounties emit virtual bounties consumed by get_bounties_on_player and collect_bounty. 🚧 Planned — bounty-hunter NPC AI to actively hunt flagged players.

Source map

Topic Path
Tier table, adjustment logic services/gameserver/src/services/personal_reputation_service.py
Player columns services/gameserver/src/models/player.py (personal_reputation, reputation_tier, name_color)
Bounty service services/gameserver/src/services/bounty_service.py
Combat hook services/gameserver/src/services/combat_service.py

How rank, personal reputation, and faction standing interact

These three are independent:

  • Military Rank can rise even while you're a Villain (the Admiral Darkstar pattern).
  • Personal Reputation sets your name color and bounty status — visible to everyone in any sector.
  • Faction Standing (per-faction, see factions-and-teams.md) determines port pricing, patrol response, and territory access for each NPC faction. Movement is purely emergent — see ./factions-and-teams.md#reputation-triggers.

A player with high rank, low personal reputation, and Allied Federation standing is possible — they're feared by other players but still the Federation's top mercenary.