From cbfd2510b1916836215332e2bbc88a5c1cd5eb87 Mon Sep 17 00:00:00 2001 From: Logan Davidson Date: Mon, 18 Mar 2024 20:39:55 +0000 Subject: [PATCH 1/3] Make senators generate personal revenue Make aligned senators generate personal revenue immediately after the mortality phase is resolved. No additional action is required from players and there is no revenue phase (yet). --- .../functions/mortality_phase_helper.py | 12 +++-- .../rorapp/functions/revenue_phase_helper.py | 54 +++++++++++++++++++ frontend/components/ActionLog.tsx | 22 ++++---- frontend/components/SenatorListItem.tsx | 1 + .../actionLogs/ActionLog_PersonalRevenue.tsx | 29 ++++++++++ 5 files changed, 103 insertions(+), 15 deletions(-) create mode 100644 backend/rorapp/functions/revenue_phase_helper.py create mode 100644 frontend/components/actionLogs/ActionLog_PersonalRevenue.tsx diff --git a/backend/rorapp/functions/mortality_phase_helper.py b/backend/rorapp/functions/mortality_phase_helper.py index e2ed7321..e4f8ed86 100644 --- a/backend/rorapp/functions/mortality_phase_helper.py +++ b/backend/rorapp/functions/mortality_phase_helper.py @@ -1,12 +1,13 @@ import os import json -from typing import List +from typing import List, Tuple from django.conf import settings from rest_framework.response import Response from rorapp.functions.forum_phase_starter import start_forum_phase from rorapp.functions.mortality_chit_helper import draw_mortality_chits from rorapp.functions.progress_helper import get_latest_step from rorapp.functions.rank_helper import rank_senators_and_factions +from rorapp.functions.revenue_phase_helper import generate_personal_revenue from rorapp.functions.websocket_message_helper import ( create_websocket_message, destroy_websocket_message, @@ -29,7 +30,7 @@ def face_mortality( action_id: int, chit_codes: List[int] | None = None -) -> (Response, dict): +) -> Tuple[Response, dict]: """ Ready up for facing mortality. @@ -85,9 +86,7 @@ def resolve_mortality(game_id: int, chit_codes: List[int] | None = None) -> dict messages_to_send = [] killed_senator_count = 0 for code in drawn_codes: - senators = Senator.objects.filter( - game=game_id, alive=True, code=code - ) + senators = Senator.objects.filter(game=game_id, alive=True, code=code) if senators.exists(): senator = senators.first() senators_former_faction = senator.faction @@ -216,6 +215,9 @@ def resolve_mortality(game_id: int, chit_codes: List[int] | None = None) -> dict # Update senator ranks messages_to_send.extend(rank_senators_and_factions(game_id)) + # Generate personal revenue + messages_to_send.extend(generate_personal_revenue(game_id)) + # Proceed to the forum phase messages_to_send.extend(start_forum_phase(game_id)) diff --git a/backend/rorapp/functions/revenue_phase_helper.py b/backend/rorapp/functions/revenue_phase_helper.py new file mode 100644 index 00000000..0907452e --- /dev/null +++ b/backend/rorapp/functions/revenue_phase_helper.py @@ -0,0 +1,54 @@ +from rorapp.functions.progress_helper import get_latest_step +from rorapp.functions.websocket_message_helper import create_websocket_message +from rorapp.models import ActionLog, Game, Senator, Title +from rorapp.serializers import ActionLogSerializer, SenatorSerializer + + +def generate_personal_revenue(game_id: Game) -> dict: + """ + Generate personal revenue for all aligned senators. + + Args: + game_id (int): The game ID. + + Returns: + dict: The WebSocket messages to send. + """ + + messages_to_send = [] + + aligned_senators = Senator.objects.filter( + game=game_id, alive=True, faction__isnull=False + ) + faction_leader_titles = Title.objects.filter( + senator__game=game_id, name="Faction Leader", end_step__isnull=True + ) + faction_leader_senator_ids = [title.senator.id for title in faction_leader_titles] + + # Generate personal revenue for all aligned senators + for senator in aligned_senators: + if senator.id in faction_leader_senator_ids: + senator.talents += 3 + else: + senator.talents += 1 + senator.save() + messages_to_send.append( + create_websocket_message("senator", SenatorSerializer(senator).data) + ) + + # Create action log + latest_step = get_latest_step(game_id) + latest_action_log = ( + ActionLog.objects.filter(step=latest_step).order_by("index").last() + ) + action_log = ActionLog( + index=latest_action_log.index, + step=latest_step, + type="personal_revenue", + ) + action_log.save() + messages_to_send.append( + create_websocket_message("action_log", ActionLogSerializer(action_log).data) + ) + + return messages_to_send diff --git a/frontend/components/ActionLog.tsx b/frontend/components/ActionLog.tsx index fe488cfe..6390667a 100644 --- a/frontend/components/ActionLog.tsx +++ b/frontend/components/ActionLog.tsx @@ -1,14 +1,15 @@ import ActionLog from "@/classes/ActionLog" -import SelectFactionLeaderActionLog from "./actionLogs/ActionLog_SelectFactionLeader" -import FaceMortalityActionLog from "./actionLogs/ActionLog_FaceMortality" -import TemporaryRomeConsulActionLog from "./actionLogs/ActionLog_TemporaryRomeConsul" -import NewTurnActionLog from "./actionLogs/ActionLog_NewTurn" -import NewFamilyActionLog from "./actionLogs/ActionLog_NewFamily" -import NewWarActionLog from "./actionLogs/ActionLog_NewWar" -import MatchedWarActionLog from "./actionLogs/ActionLog_MatchedWar" -import NewEnemyLeaderActionLog from "./actionLogs/ActionLog_NewEnemyLeader" -import MatchedEnemyLeaderActionLog from "./actionLogs/ActionLog_MatchedEnemyLeader" -import NewSecretActionLog from "./actionLogs/ActionLog_NewSecret" +import SelectFactionLeaderActionLog from "@/components/actionLogs/ActionLog_SelectFactionLeader" +import FaceMortalityActionLog from "@/components/actionLogs/ActionLog_FaceMortality" +import TemporaryRomeConsulActionLog from "@/components/actionLogs/ActionLog_TemporaryRomeConsul" +import NewTurnActionLog from "@/components/actionLogs/ActionLog_NewTurn" +import NewFamilyActionLog from "@/components/actionLogs/ActionLog_NewFamily" +import NewWarActionLog from "@/components/actionLogs/ActionLog_NewWar" +import MatchedWarActionLog from "@/components/actionLogs/ActionLog_MatchedWar" +import NewEnemyLeaderActionLog from "@/components/actionLogs/ActionLog_NewEnemyLeader" +import MatchedEnemyLeaderActionLog from "@/components/actionLogs/ActionLog_MatchedEnemyLeader" +import NewSecretActionLog from "@/components/actionLogs/ActionLog_NewSecret" +import PersonalRevenueActionLog from "@/components/actionLogs/ActionLog_PersonalRevenue" interface ActionLogItemProps { notification: ActionLog @@ -24,6 +25,7 @@ const notifications: { [key: string]: React.ComponentType } = { new_secret: NewSecretActionLog, new_turn: NewTurnActionLog, new_war: NewWarActionLog, + personal_revenue: PersonalRevenueActionLog, select_faction_leader: SelectFactionLeaderActionLog, temporary_rome_consul: TemporaryRomeConsulActionLog, } diff --git a/frontend/components/SenatorListItem.tsx b/frontend/components/SenatorListItem.tsx index 24e50528..826b95cc 100644 --- a/frontend/components/SenatorListItem.tsx +++ b/frontend/components/SenatorListItem.tsx @@ -128,6 +128,7 @@ const SenatorListItem = ({ senator, ...props }: SenatorListItemProps) => { size={80} selectable={props.selectable} blurryPlaceholder + summary />
diff --git a/frontend/components/actionLogs/ActionLog_PersonalRevenue.tsx b/frontend/components/actionLogs/ActionLog_PersonalRevenue.tsx new file mode 100644 index 00000000..b213ce8d --- /dev/null +++ b/frontend/components/actionLogs/ActionLog_PersonalRevenue.tsx @@ -0,0 +1,29 @@ +import Image from "next/image" +import TalentsIcon from "@/images/icons/talents.svg" +import ActionLog from "@/classes/ActionLog" +import ActionLogLayout from "@/components/ActionLogLayout" + +interface ActionLogProps { + notification: ActionLog +} + +// ActionLog for when a senator dies during the mortality phase +const PersonalRevenueActionLog = ({ notification }: ActionLogProps) => { + const getIcon = () => ( +
+ Talents icon +
+ ) + + return ( + +

Aligned Senators have earned Personal Revenue.

+
+ ) +} + +export default PersonalRevenueActionLog From dd65da5e0c3effae9276794a2d95fd66010882ac Mon Sep 17 00:00:00 2001 From: Logan Davidson Date: Mon, 18 Mar 2024 20:45:44 +0000 Subject: [PATCH 2/3] Rename the faction list item "talents" attribute --- frontend/components/FactionListItem.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/components/FactionListItem.tsx b/frontend/components/FactionListItem.tsx index 4dea6eb4..f6488e7e 100644 --- a/frontend/components/FactionListItem.tsx +++ b/frontend/components/FactionListItem.tsx @@ -48,13 +48,13 @@ const FactionListItem = (props: FactionListItemProps) => { // Attribute data const attributeItems: Attribute[] = [ { - name: "influence", + name: "Influence", value: totalInfluence, icon: InfluenceIcon, }, - { name: "talents", value: totalTalents, icon: TalentsIcon }, - { name: "votes", value: totalVotes, icon: VotesIcon }, - { name: "secrets", value: secrets.length, icon: SecretsIcon }, + { name: "Personal Talents", value: totalTalents, icon: TalentsIcon }, + { name: "Votes", value: totalVotes, icon: VotesIcon }, + { name: "Secrets", value: secrets.length, icon: SecretsIcon }, ] if (!player?.user || senators.allIds.length === 0) return null From 133d6b9dba558c61851bac62c685e02ed5a7d6e2 Mon Sep 17 00:00:00 2001 From: Logan Davidson Date: Mon, 18 Mar 2024 20:58:28 +0000 Subject: [PATCH 3/3] Update test assertions --- backend/rorapp/tests/mortality_phase_tests.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/backend/rorapp/tests/mortality_phase_tests.py b/backend/rorapp/tests/mortality_phase_tests.py index 4ce6cc47..9d4e0d9c 100644 --- a/backend/rorapp/tests/mortality_phase_tests.py +++ b/backend/rorapp/tests/mortality_phase_tests.py @@ -81,9 +81,9 @@ def select_faction_leaders(self, game_id: int) -> None: def check_action_log(self, game_id: int) -> None: previous_step = get_latest_step(game_id, 1) action_log = ActionLog.objects.filter(step=previous_step) - # It's possible to have more than 1 action log in the event if more than one senator dies, + # It's possible to have more than 2 action logs in the event that more than one senator dies, # but in this deterministic test no more than one senator should die - self.assertEqual(action_log.count(), 1) + self.assertEqual(action_log.count(), 2) self.assertEqual(action_log[0].type, "face_mortality") def kill_hrao(self, game_id: int) -> None: @@ -97,7 +97,7 @@ def kill_hrao(self, game_id: int) -> None: action_logs, messages = self.kill_senators( game_id, [highest_ranking_senator.id] ) - self.assertEqual(len(messages), 18) + self.assertEqual(len(messages), 27) latest_action_log = action_logs[0] self.assertIsNone(latest_action_log.data["heir_senator"]) @@ -124,7 +124,7 @@ def kill_faction_leader(self, game_id: int) -> None: faction_leader_title = Title.objects.get(senator=faction_leader) action_logs, messages = self.kill_senators(game_id, [faction_leader.id]) - self.assertEqual(len(messages), 11) + self.assertEqual(len(messages), 20) latest_action_log = action_logs[0] heir_id = latest_action_log.data["heir_senator"] @@ -150,7 +150,7 @@ def kill_regular_senator(self, game_id: int) -> None: regular_senator = self.get_senators_with_title(game_id, None)[0] action_logs, messages = self.kill_senators(game_id, [regular_senator.id]) - self.assertEqual(len(messages), 8) + self.assertEqual(len(messages), 16) latest_action_log = action_logs[0] self.assertIsNone(latest_action_log.data["heir_senator"]) @@ -167,7 +167,7 @@ def kill_two_senators(self, game_id: int) -> None: two_regular_senators = self.get_senators_with_title(game_id, None)[0:2] senator_ids = [senator.id for senator in two_regular_senators] _, messages = self.kill_senators(game_id, senator_ids) - self.assertEqual(len(messages), 14) + self.assertEqual(len(messages), 20) post_death_living_senator_count = Senator.objects.filter( game=game_id, alive=True ).count()