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

Earned via MedalService (services/medal_service.py). Combat medals: - Bronze Star — 100 victories. - Silver Star — 1,000. - Quantum Cross — 10,000.

🚧 Planned — economic / exploration / diplomatic / special medals (Trader's Merit, Pathfinder, Orange Cat Society…). Only combat medals are wired in medal_service.check_combat_medals.

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 modifies attack outcomes.

🐛 Bug — combat_bonus not applied. ranking_service.py:RANK_DEFINITIONS exposes a per-rank combat_bonus value (+1 at Spacer up to +40 at Fleet Admiral), but combat_service.py:attack_player does not read it during damage resolution. The bonus is documented and stored but doesn't reach the dice. Wiring this into the attack roll is the design target.

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, and the player-client ranking/ UI (RankDisplay, RankProgress, Leaderboard, MedalShowcase) renders against them. The full ranking service, REST routes, lifetime-stats table, and trading-bonus integration described above are 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
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)

Score Effect
≤ −500 +20% station price markup, bounty hunters target you
≤ −250 +10% station price markup
≥ +250 −5% station price discount
≥ +500 −10% station price 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.

🚧 Planned — auto-bounty placement at thresholds (−500 / −750 / −1000), bounty redemption-by-reform, and bounty-hunter NPC AI. Infrastructure exists (models/Bounty, BountyService); auto-placement and redemption flows are not all hooked up.

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 mission access, port pricing, and territory access for each NPC faction.

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.