Discard completed obstacles automatically and verify scene refresh rules

This commit is contained in:
2026-09-04 19:21:35 -07:00
parent 1837bf04e6
commit 749bef6ff1
5 changed files with 51 additions and 3 deletions
+1 -1
View File
@@ -19,7 +19,7 @@
## Rules
- [ ] Check against rules on correct quantity of of obstacles and obstacle refresh rules
- [x] Check against rules on correct quantity of of obstacles and obstacle refresh rules
- [ ] Check against the rules on pi-rat hand size and conditions for drawing more cards
- [ ] Assisting other pi-rats should only be available if there are multiple obstacles in the current challenge
- [ ] Checking off personal objectives (gat/name/death) should be handled by group vote rather than adjudication by the deep
+2 -1
View File
@@ -6,10 +6,11 @@
// - Add a CHANGELOG entry only when a commit changes something players can
// see. Skip refactors, tests, and tooling. Keep wording player-facing.
export const VERSION = 31;
export const VERSION = 32;
// Newest first. Each entry: { version, date: 'YYYY-MM-DD', changes: [string, ...] }.
export const CHANGELOG = [
{ version: 32, date: '2026-09-04', changes: ['Obstacles are automatically discarded with their columns once they reach one success per player. Unfinished obstacles carry over between scenes.'] },
{ version: 31, date: '2026-09-04', changes: ['Change your rank-up vote until everyone has voted. The final vote now reveals the result and advances automatically, without a Ready button.', 'The vote result stays visible through upkeep and next-scene setup.'] },
{ version: 30, date: '2026-09-04', changes: ['The crew roster shows voting progress with icons.', 'Your submitted vote now shows the crewmate you nominated.'] },
{ version: 29, date: '2026-09-04', changes: ['Removed the remaining deck count from the table.'] },
+5
View File
@@ -167,6 +167,11 @@ def play_challenge_card(
role_note = "" if player.id == challenge.acting_player_id else " (assist)"
add_game_event(db, game.id, f"{player.name} played {cards.parse_card(card_code)['display']} on '{obstacle.title}'{role_note}. {result['details']}", kind="card")
if obstacle.success_count >= len(game.players):
add_game_event(db, game.id, f"'{obstacle.title}' is complete and discarded with its column.", kind="obstacle")
db.delete(obstacle)
db.commit()
result["drew_card"] = drew_card
result["is_joker"] = False
return True, "Card played successfully.", result
+2 -1
View File
@@ -405,7 +405,8 @@ def grant_story_bonus_rank(db: Session, game: Game, granter: Player, target):
def clear_completed_obstacle(db: Session, game_id: str, obstacle_id: str):
obstacle = db.get(Obstacle, obstacle_id)
if obstacle:
game = get_game(db, game_id)
if obstacle and game and obstacle.game_id == game_id and obstacle.success_count >= len(game.players):
add_game_event(db, game_id, f"The Deep cleared the completed obstacle '{obstacle.title}'.", kind="obstacle")
db.delete(obstacle)
db.commit()
+41
View File
@@ -2651,3 +2651,44 @@ def test_kick_last_pending_voter_completes_voting(session):
assert crud.kick_player(session, game, b)[0]
assert game.phase == "deep_upkeep"
assert game.last_rank_up_player_id == a.id
def test_completed_obstacle_discards_without_replacement(session):
game, deep, (rat,) = make_scene_game(session)
obs = game.obstacles[0]
oid = obs.id
obs.played_cards = json.dumps([{"card": "KC", "success": True}])
rat.hand_cards = json.dumps(["QD"])
session.add(obs)
session.add(rat)
session.commit()
assert crud.create_challenge(session, game.id, deep.id, rat.id, [oid])[0]
assert crud.play_challenge_card(session, rat.id, oid, "QD")[0]
assert session.get(Obstacle, oid) is None
session.refresh(game)
assert len(game.obstacles) == 1
def test_cannot_clear_unfinished_obstacle(session):
game, deep, (rat,) = make_scene_game(session)
oid = game.obstacles[0].id
crud.clear_completed_obstacle(session, game.id, oid)
assert session.get(Obstacle, oid) is not None
def test_setup_joker_only_increases_following_scene(session, monkeypatch):
game, deep, (rat,) = make_scene_game(session)
for obs in list(game.obstacles):
session.delete(obs)
game.current_scene_number = 2
deep.previous_role = "pirat"
rat.previous_role = "deep"
session.commit()
monkeypatch.setattr('pirats.crud_scene.reshuffle_discard_pile', lambda db, game: None)
game.deck_cards = json.dumps(["Joker1", "2H", "3H", "4H"])
session.commit()
assert crud.confirm_scene_setup(session, game.id)[0]
session.refresh(game)
assert len(game.obstacles) == 2
assert game.extra_obstacles == 1
assert crud.get_game_deck(game) == ["4H"]