Award personal objectives through group votes

This commit is contained in:
2026-09-04 19:26:37 -07:00
parent 8fdd10f7a3
commit 2f8f67a24c
12 changed files with 279 additions and 32 deletions
+93
View File
@@ -2742,3 +2742,96 @@ def test_single_obstacle_rejects_assistance_but_allows_tax_actor(session):
assert crud.request_tax(session, challenge.id, rat.id, helper.id)[0]
assert crud.respond_tax(session, challenge.id, helper.id, True)[0]
assert crud.play_challenge_card(session, helper.id, obs.id, "KH")[0]
def test_objective_vote_majority_awards_once_and_preserves_rollback(session):
game, deep, (rat, helper) = make_scene_game(session, num_pirats=2)
rank = rat.rank
assert not crud.propose_personal_objective(session, game.id, deep.id, rat.id, 'personal_2')[0]
assert crud.propose_personal_objective(session, game.id, deep.id, rat.id, 'personal_1')[0]
proposal = json.loads(game.objective_votes)[0]
assert not rat.completed_personal_1
assert not crud.propose_personal_objective(session, game.id, helper.id, rat.id, 'personal_1')[0]
snapshot = crud.serialize_game_state(game)
assert crud.vote_personal_objective(session, game.id, helper.id, proposal['id'], True)[0]
assert rat.completed_personal_1 and rat.needs_gat_description
assert rat.rank == rank + 1
assert json.loads(game.objective_votes) == []
assert not crud.vote_personal_objective(session, game.id, helper.id, proposal['id'], True)[0]
assert rat.rank == rank + 1
rat_id = rat.id
crud.apply_game_state(session, game, snapshot)
rat = session.get(Player, rat_id)
session.refresh(game)
assert not rat.completed_personal_1
assert json.loads(game.objective_votes)[0]['id'] == proposal['id']
@pytest.mark.parametrize('captain_vote, awarded', [(True, True), (False, False), (None, False)])
def test_objective_vote_ties(session, captain_vote, awarded):
game, deep, (rat, helper, captain) = make_scene_game(session, num_pirats=3)
if captain_vote is not None:
game.captain_player_id = captain.id
session.commit()
assert crud.propose_personal_objective(session, game.id, deep.id, rat.id, 'personal_1')[0]
pid = json.loads(game.objective_votes)[0]['id']
assert crud.vote_personal_objective(session, game.id, rat.id, pid, False)[0]
assert crud.vote_personal_objective(session, game.id, helper.id, pid, not bool(captain_vote))[0]
assert crud.vote_personal_objective(session, game.id, captain.id, pid, bool(captain_vote))[0]
assert rat.completed_personal_1 == awarded
assert json.loads(game.objective_votes) == []
def test_objective_votes_reject_foreign_players_and_close_at_scene_end(session):
game, deep, (rat, helper) = make_scene_game(session, num_pirats=2)
other = crud.create_game(session)
foreign = crud.add_player(session, other.id, 'Outsider')
assert not crud.propose_personal_objective(session, game.id, foreign.id, rat.id, 'personal_1')[0]
assert crud.propose_personal_objective(session, game.id, deep.id, rat.id, 'personal_1')[0]
pid = json.loads(game.objective_votes)[0]['id']
assert not crud.vote_personal_objective(session, game.id, foreign.id, pid, True)[0]
assert crud.end_scene_and_transition(session, game.id)[0]
assert json.loads(game.objective_votes) == []
assert not crud.vote_personal_objective(session, game.id, rat.id, pid, True)[0]
def test_objective_vote_rejection_and_death_effects(session):
game, deep, (rat, helper) = make_scene_game(session, num_pirats=2)
assert crud.propose_personal_objective(session, game.id, deep.id, rat.id, 'personal_1')[0]
pid = json.loads(game.objective_votes)[0]['id']
assert crud.vote_personal_objective(session, game.id, rat.id, pid, False)[0]
assert crud.vote_personal_objective(session, game.id, helper.id, pid, False)[0]
assert not rat.completed_personal_1
rat.completed_personal_1 = rat.completed_personal_2 = True
game.captain_player_id = rat.id
session.commit()
assert crud.propose_personal_objective(session, game.id, helper.id, rat.id, 'personal_3')[0]
pid = json.loads(game.objective_votes)[0]['id']
assert crud.vote_personal_objective(session, game.id, rat.id, pid, True)[0]
assert rat.is_dead and rat.needs_rank_3_bonus
assert game.captain_player_id is None
def test_personal_objective_api_requires_vote(session):
from fastapi.testclient import TestClient
from pirats.main import app
from pirats.database import get_session
game, deep, (rat, helper) = make_scene_game(session, num_pirats=2)
def override():
yield session
app.dependency_overrides[get_session] = override
try:
client = TestClient(app)
path = f'/api/game/{game.id}/player'
response = client.post(f'{path}/{rat.id}/objective/toggle', data={'type': 'personal_1'})
assert response.status_code == 400
assert not rat.completed_personal_1
response = client.post(f'{path}/{deep.id}/objective/propose', data={'target_id': rat.id, 'type': 'personal_1'})
assert response.status_code == 200
pid = json.loads(game.objective_votes)[0]['id']
response = client.post(f'{path}/{helper.id}/objective/vote', data={'proposal_id': pid, 'approve': 'true'})
assert response.status_code == 200
session.refresh(rat)
assert rat.completed_personal_1
finally:
app.dependency_overrides.clear()