diff --git a/TODO.md b/TODO.md index 43cf658..6515312 100644 --- a/TODO.md +++ b/TODO.md @@ -10,7 +10,7 @@ - [x] Visual feedback confirming hand refresh in Deep Upkeep -- [ ] On the screen after pirat rank up voting, it should display the winner +- [x] On the screen after pirat rank up voting, it should display the winner - [ ] When Deep issues a challenge, stakes should be two fields, success and failure diff --git a/frontend/src/components/UpkeepPhase.svelte b/frontend/src/components/UpkeepPhase.svelte index 513c7d7..3bef644 100644 --- a/frontend/src/components/UpkeepPhase.svelte +++ b/frontend/src/components/UpkeepPhase.svelte @@ -13,6 +13,10 @@ // Helpers $: hand = state.player.hand_cards ? JSON.parse(state.player.hand_cards) : []; + // Winner of the rank-up vote, surfaced on the post-voting (deep_upkeep) screen. + $: rankUpWinner = state.game.last_rank_up_player_id + ? state.players.find(p => p.id === state.game.last_rank_up_player_id) + : null; // A nominee must be another living, in-play Pi-Rat: not the voter, not a // previous-scene Deep, and not dead / awaiting-recruit (they'd reset to @@ -202,7 +206,11 @@ {#if state.game.phase === 'deep_upkeep'}
-

✔️ Voting complete! Results tallied.

+ {#if rankUpWinner} +

🏆 {displayName(rankUpWinner)} won the vote and ranked up to Rank {rankUpWinner.rank}!

+ {:else} +

✔️ Voting complete! No one ranked up this time.

+ {/if}
{:else if hasVoted}
diff --git a/src/pirats/crud_upkeep.py b/src/pirats/crud_upkeep.py index b67b01b..1a87b70 100644 --- a/src/pirats/crud_upkeep.py +++ b/src/pirats/crud_upkeep.py @@ -83,24 +83,30 @@ def process_between_scenes_votes(db: Session, game: Game): Then sets players who were Deep to discard and redraw. """ votes = game.votes + # Reset the previous scene's winner before tallying this one. + game.last_rank_up_player_id = None + db.add(game) if not votes: + db.commit() return - + # Count votes counts = {} for v in votes: counts[v.nominated_player_id] = counts.get(v.nominated_player_id, 0) + 1 - + if counts: max_votes = max(counts.values()) winners = [pid for pid, val in counts.items() if val == max_votes] - + # If there is a clear winner (or random in case of tie) if winners: winner_id = random.choice(winners) winner = get_player(db, winner_id) if winner: change_player_rank(db, game, winner, 1) + game.last_rank_up_player_id = winner.id + db.add(game) add_game_event(db, game.id, f"{winner.name} was voted to rank up! They are now Rank {winner.rank}.", kind="rank") # Clear all votes @@ -112,6 +118,7 @@ def begin_next_scene_setup(db: Session, game: Game): """Advances to the next scene's setup: bump the scene counter and clear roles.""" game.current_scene_number += 1 game.phase = "scene_setup" + game.last_rank_up_player_id = None # Stale once we leave the post-voting screen for p in game.players: p.role = None p.is_ready = False diff --git a/src/pirats/migrations/versions/3bbf6812c261_add_last_rank_up_player_id_to_game.py b/src/pirats/migrations/versions/3bbf6812c261_add_last_rank_up_player_id_to_game.py new file mode 100644 index 0000000..6fc34a5 --- /dev/null +++ b/src/pirats/migrations/versions/3bbf6812c261_add_last_rank_up_player_id_to_game.py @@ -0,0 +1,32 @@ +"""add last_rank_up_player_id to game + +Revision ID: 3bbf6812c261 +Revises: 19ee9ae5ca0e +Create Date: 2026-06-14 09:21:11.037751 + +""" +from alembic import op +import sqlalchemy as sa +import sqlmodel + + +revision = '3bbf6812c261' +down_revision = '19ee9ae5ca0e' +branch_labels = None +depends_on = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('game', schema=None) as batch_op: + batch_op.add_column(sa.Column('last_rank_up_player_id', sqlmodel.sql.sqltypes.AutoString(), nullable=True)) + + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('game', schema=None) as batch_op: + batch_op.drop_column('last_rank_up_player_id') + + # ### end Alembic commands ### diff --git a/src/pirats/models.py b/src/pirats/models.py index 71a05fb..8f818dd 100644 --- a/src/pirats/models.py +++ b/src/pirats/models.py @@ -19,6 +19,7 @@ class Game(SQLModel, table=True): completed_crew_3: bool = Field(default=False) # Commit Piracy captain_player_id: Optional[str] = Field(default=None) # Persistent captaincy; set once the crew controls a ship teaching_deep_player_id: Optional[str] = Field(default=None) # Teaching mode: an admin who seeds themselves as the forced Rank-3 Deep for the first scene (set in the lobby, honored when starting ranks are rolled) + last_rank_up_player_id: Optional[str] = Field(default=None) # Winner of the most recent rank-up vote, shown on the post-voting upkeep screen; cleared when the next scene begins players: List["Player"] = Relationship(back_populates="game", cascade_delete=True) obstacles: List["Obstacle"] = Relationship(back_populates="game", cascade_delete=True)