Stop auto-assigning the Captain when a ship is stolen
Completing Crew Objective 1 (Steal a Ship) no longer anoints the highest-ranked Pi-Rat as Captain (nor vacates the seat when the ship is lost). Captaincy is now earned: the crew chooses one via the Captaincy UI / set_captain and Crew Objective 2. Decoupled captaincy from crew_1 in toggle_objective, dropped the now-unused random import, and updated test_captaincy_and_hand_sizes accordingly. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2
TODO.md
2
TODO.md
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
- [x] When Deep issues a challenge, stakes should be two fields, success and failure
|
- [x] When Deep issues a challenge, stakes should be two fields, success and failure
|
||||||
|
|
||||||
- [ ] Captain should not be autoassigned. That's something the crew has to earn.
|
- [x] Captain should not be autoassigned. That's something the crew has to earn.
|
||||||
|
|
||||||
- [ ] The back button on the admin page should go back to the active game, not the join screen
|
- [ ] The back button on the admin page should go back to the active game, not the join screen
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import json
|
import json
|
||||||
import random
|
|
||||||
from typing import Tuple, Dict, Any
|
from typing import Tuple, Dict, Any
|
||||||
from sqlmodel import Session
|
from sqlmodel import Session
|
||||||
from .models import Game, Player, Obstacle
|
from .models import Game, Player, Obstacle
|
||||||
@@ -310,19 +309,11 @@ def toggle_objective(db: Session, game_id: str, target_id: str, obj_type: str, s
|
|||||||
if not game:
|
if not game:
|
||||||
return
|
return
|
||||||
if obj_type == "crew_1":
|
if obj_type == "crew_1":
|
||||||
|
# Stealing a ship no longer auto-anoints a Captain — the crew has to
|
||||||
|
# earn and choose one themselves (Crew Objective 2 + the Captaincy UI).
|
||||||
game.completed_crew_1 = status
|
game.completed_crew_1 = status
|
||||||
db.add(game)
|
db.add(game)
|
||||||
db.commit()
|
db.commit()
|
||||||
if status and not game.captain_player_id:
|
|
||||||
# "Once the crew controls a ship, the highest-Ranked Pi-Rat becomes the de facto Captain."
|
|
||||||
pi_rats = [p for p in game.players if p.role != "deep" and not p.is_dead and not p.is_ghost]
|
|
||||||
if pi_rats:
|
|
||||||
max_rank = max(p.rank for p in pi_rats)
|
|
||||||
candidates = [p for p in pi_rats if p.rank == max_rank]
|
|
||||||
set_captain(db, game, random.choice(candidates).id, "Highest-ranked Pi-Rat aboard the stolen ship")
|
|
||||||
elif not status and game.captain_player_id:
|
|
||||||
# The ship is lost: the Captain's position goes with it.
|
|
||||||
set_captain(db, game, None, "The ship was lost")
|
|
||||||
elif obj_type == "crew_2":
|
elif obj_type == "crew_2":
|
||||||
game.completed_crew_2 = status
|
game.completed_crew_2 = status
|
||||||
db.add(game)
|
db.add(game)
|
||||||
|
|||||||
@@ -357,20 +357,20 @@ def test_captaincy_and_hand_sizes(session):
|
|||||||
session.commit()
|
session.commit()
|
||||||
assert crud.calculate_max_hand_size(p3, game.players, game.captain_player_id) == 4
|
assert crud.calculate_max_hand_size(p3, game.players, game.captain_player_id) == 4
|
||||||
|
|
||||||
# Completing Crew Objective 1 (Steal a Ship) makes the highest-ranked Pi-Rat the Captain
|
# Stealing a ship does NOT auto-assign a Captain — the crew must earn and
|
||||||
|
# choose one. Completing Crew Objective 1 leaves the captaincy vacant.
|
||||||
crud.toggle_objective(session, game.id, p1.id, "crew_1", True)
|
crud.toggle_objective(session, game.id, p1.id, "crew_1", True)
|
||||||
session.refresh(game)
|
session.refresh(game)
|
||||||
assert game.captain_player_id in (p2.id, p3.id)
|
|
||||||
captain = crud.get_player(session, game.captain_player_id)
|
|
||||||
assert crud.is_player_captain(captain, game)
|
|
||||||
# Captain privilege: +1 hand size
|
|
||||||
assert crud.calculate_max_hand_size(captain, game.players, game.captain_player_id) == 5
|
|
||||||
|
|
||||||
# Losing the ship vacates the Captaincy
|
|
||||||
crud.toggle_objective(session, game.id, p1.id, "crew_1", False)
|
|
||||||
session.refresh(game)
|
|
||||||
assert game.captain_player_id is None
|
assert game.captain_player_id is None
|
||||||
|
|
||||||
|
# The crew chooses a Captain explicitly (via the Captaincy UI / set_captain).
|
||||||
|
crud.set_captain(session, game, p2.id)
|
||||||
|
session.refresh(game)
|
||||||
|
assert game.captain_player_id == p2.id
|
||||||
|
assert crud.is_player_captain(p2, game)
|
||||||
|
# Captain privilege: +1 hand size
|
||||||
|
assert crud.calculate_max_hand_size(p2, game.players, game.captain_player_id) == 5
|
||||||
|
|
||||||
def test_captain_tax_on_failed_challenge(session):
|
def test_captain_tax_on_failed_challenge(session):
|
||||||
game, deep, (p2, p3) = make_scene_game(session, num_pirats=2)
|
game, deep, (p2, p3) = make_scene_game(session, num_pirats=2)
|
||||||
# p3 (rank 2) becomes captain
|
# p3 (rank 2) becomes captain
|
||||||
|
|||||||
Reference in New Issue
Block a user