# Property Tycoon GameActions.py
# Contains the classes for the game actions, such as the play turn, the handle buy decision, and the start auction.
import pygame
import sys
import random
from src.Cards import CardType
from src.Sound_Manager import sound_manager
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GRAY = (128, 128, 128)
LIGHT_GRAY = (200, 200, 200)
UI_BG = (18, 18, 18)
DARK_RED = (139, 0, 0)
DARK_GREEN = (0, 100, 0)
DARK_BLUE = (0, 0, 139)
GOLD = (218, 165, 32)
CREAM = (255, 253, 208)
BURGUNDY = (128, 0, 32)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
ACCENT_COLOR = BURGUNDY
BUTTON_HOVER = (160, 20, 40)
ERROR_COLOR = (220, 53, 69)
SUCCESS_COLOR = DARK_GREEN
MODE_COLOR = DARK_BLUE
TIME_COLOR = (255, 180, 100)
HUMAN_COLOR = DARK_GREEN
AI_COLOR = DARK_RED
[docs]
class GameActions:
def __init__(self, game):
self.game = game
[docs]
def play_turn(self):
if self.game.game_over:
return False
if self.game.dice_animation:
return False
if any(player.is_moving for player in self.game.players):
return False
current_player = self.game.logic.players[self.game.logic.current_player_index]
if not current_player:
self.game.board.add_message("Error: No current player found")
return False
player_obj = next(
(p for p in self.game.players if p.name == current_player["name"]), None
)
is_ai_player = player_obj and player_obj.is_ai
if self.game.development_mode and not is_ai_player:
return False
self.game.update_current_player()
if not player_obj:
print(f"Warning: Could not find player object for {current_player['name']}")
return False
if player_obj.in_jail != current_player.get("in_jail", False):
print(f"Synchronizing jail status for {player_obj.name}")
player_obj.in_jail = current_player.get("in_jail", False)
current_player["in_jail"] = player_obj.in_jail
player_obj.jail_turns = current_player.get("jail_turns", 0)
current_player["jail_turns"] = player_obj.jail_turns
if player_obj.in_jail and player_obj.stay_in_jail:
print(
f"Player {current_player['name']} chose to stay in jail - skipping turn"
)
self.game.board.add_message(
f"{current_player['name']} is staying in jail - skipping turn"
)
self.game.handle_turn_end()
return True
if player_obj.in_jail and current_player.get("in_jail", False):
print(f"Player {current_player['name']} is in jail - showing jail options")
jail_result = self.handle_jail_turn(current_player)
if not jail_result:
self.game.board.add_message(f"{current_player['name']} stays in jail")
self.game.handle_turn_end()
return True
old_position = current_player["position"]
self.game.lap_count[current_player["name"]] += 1
print(
f"Lap count for {current_player['name']}: {self.game.lap_count[current_player['name']]}"
)
if self.game.state == "ROLL":
self.game.dice_animation = True
self.game.animation_start = pygame.time.get_ticks()
sound_manager.play_sound("dice_roll")
dice1, dice2 = self.game.logic.play_turn()
if dice1 is None:
self.game.dice_animation = False
return True
while self.game.logic.message_queue:
message = self.game.logic.message_queue.pop(0)
print(f"Processing message: {message}")
self.game.board.add_message(message)
if "left jail" in message:
print(f"Jail exit notification: {message}")
sound_manager.play_sound("jail")
self.game.dice_values = (dice1, dice2)
for player in self.game.players:
if player.name == current_player["name"]:
if player.position != old_position:
print(
f"Correcting position mismatch for {player.name}: Player object: {player.position}, Game logic: {old_position}"
)
player.position = old_position
spaces_to_move = (current_player["position"] - old_position) % 40
if (
spaces_to_move == 0
and current_player["position"] != old_position
):
spaces_to_move = 40
self.game.move_player(player, spaces_to_move)
print(
f"Starting animation for {player.name} to move {spaces_to_move} spaces from {old_position} to {current_player['position']}"
)
self.game.wait_for_animations()
self.game.board.update_board_positions()
if current_player["position"] < old_position:
self.game.rounds_completed[current_player["name"]] += 1
self.game.board.add_message("*** PASSED GO! ***")
self.game.board.add_message(f"{current_player['name']} collected £200")
sound_manager.play_sound("collect_money")
self.game.board.add_message(f"{current_player['name']} rolled {dice1 + dice2}")
if dice1 == dice2:
self.game.board.add_message("Doubles! Roll again!")
self.game.renderer.draw()
pygame.display.flip()
if self.game.check_game_over():
return True
return False
[docs]
def handle_buy_decision(self, wants_to_buy):
current_player = self.game.logic.players[self.game.logic.current_player_index]
property_data = self.game.current_property
print("\n=== Property Purchase Debug ===")
print(f"Current state: {self.game.state}")
print(f"Player: {current_player['name']}")
print(f"Player money: £{current_player['money']}")
print(f"Property: {property_data['name']}")
print(f"Property price: £{property_data['price']}")
print(f"Wants to buy: {wants_to_buy}")
print(f"Is AI: {self.game.current_player_is_ai}")
print(
f"Completed circuits: {self.game.logic.completed_circuits.get(current_player['name'], 0)}"
)
print(
f"Current lap count: {self.game.lap_count.get(current_player['name'], 0)}"
)
print(f"Property owner before: {property_data.get('owner', 'None')}")
if wants_to_buy:
if current_player["money"] >= property_data["price"]:
print("\nAttempting purchase...")
current_player["money"] -= property_data["price"]
property_data["owner"] = current_player["name"]
print(f"Property owner set to: {property_data['owner']}")
print(f"Property data position: {property_data['position']}")
print(
f"Property in self.game.logic.properties: {property_data['position'] in self.game.logic.properties}"
)
if str(property_data["position"]) in self.game.logic.properties:
print(
f"Global property owner: {self.game.logic.properties[str(property_data['position'])].get('owner', 'None')}"
)
self.game.logic.properties[str(property_data["position"])][
"owner"
] = current_player["name"]
print(
f"Updated global property owner: {self.game.logic.properties[str(property_data['position'])].get('owner', 'None')}"
)
self.game.board.add_message(
f"{current_player['name']} bought {property_data['name']} for £{property_data['price']}"
)
print("Purchase successful")
sound_manager.play_sound("buy_property")
if self.game.current_player_is_ai:
pygame.event.post(
pygame.event.Event(
pygame.USEREVENT, {"action": "ai_buy_action_complete"}
)
)
if (
not hasattr(self.game.logic, "current_auction")
or not self.game.logic.current_auction
):
print("State changed to ROLL")
self.game.state = "ROLL"
else:
print("Auction in progress - maintaining AUCTION state")
print("\nPlayer properties after purchase:")
owned_count = 0
for prop_pos, prop in self.game.logic.properties.items():
if prop.get("owner") == current_player["name"]:
owned_count += 1
print(
f" - {prop['name']} (Position: {prop_pos}, Group: {prop.get('group', 'None')})"
)
print(f"Total properties owned: {owned_count}")
self.game.board.update_ownership(self.game.logic.properties)
self.game.renderer.draw()
pygame.display.flip()
else:
print("\nNot enough money for purchase")
self.game.board.add_message(
f"{current_player['name']} doesn't have enough money to buy {property_data['name']}"
)
print("Starting auction due to insufficient funds")
self.start_auction(property_data)
else:
print("\nPlayer passed on purchase")
self.start_auction(property_data)
print("\nFinal state:")
print(f"Property owner: {property_data['owner']}")
print(f"Player money: £{current_player['money']}")
if (
not hasattr(self.game.logic, "current_auction")
or not self.game.logic.current_auction
):
print(f"Final state: {self.game.state}")
if self.game.state == "ROLL":
self.game.update_current_player()
else:
print(f"Auction in progress - state is {self.game.state}")
self.game.renderer.draw()
pygame.display.flip()
[docs]
def start_auction(self, property_data):
print(f"\n=== Starting Auction for {property_data['name']} ===")
any_eligible = False
for player in self.game.logic.players:
if self.game.logic.completed_circuits.get(player["name"], 0) >= 1:
any_eligible = True
break
if not any_eligible:
print("No players have completed a circuit - skipping auction")
message = "No players have completed a circuit - property remains unsold"
self.game.board.add_message(message)
self.game.state = "ROLL"
self.game.renderer.draw()
pygame.display.flip()
self.game.update_current_player()
return
any_moving = any(player.is_moving for player in self.game.players)
if any_moving:
print("Animations in progress - delaying auction start")
self.game.pending_auction_property = property_data
self.game.waiting_for_animation = True
return
active_players = [
p["name"]
for p in self.game.logic.players
if not p.get("bankrupt", False) and not p.get("exited", False)
]
if len(active_players) == 1:
print(f"Only one active player ({active_players[0]}) - skipping auction")
self.game.state = "ROLL"
self.game.renderer.draw()
pygame.display.flip()
self.game.update_current_player()
return
result = self.game.logic.auction_property(property_data["position"])
if result == "auction_in_progress":
self.game.state = "AUCTION"
self.game.auction_bid_amount = ""
print(f"State changed to {self.game.state}")
self.game.auction_just_started = True
self.game.board.add_message(f"Auction for {property_data['name']} started!")
self.game.renderer.draw()
pygame.display.flip()
else:
print(f"Failed to start auction: {result}")
self.game.state = "ROLL"
print(f"State changed to {self.game.state}")
self.game.renderer.draw()
pygame.display.flip()
self.game.update_current_player()
print(f"Final state: {self.game.state}")
print("=== End Auction ===\n")
[docs]
def handle_jail_turn(self, player):
print(f"\n=== Jail Turn Handler for {player['name']} ===")
print(f"In jail: {player['in_jail']}")
print(f"Jail turns: {player.get('jail_turns', 0)}")
print(f"Money: £{player['money']}")
print(
f"Has jail free cards: {self.game.logic.jail_free_cards.get(player['name'], 0)}"
)
if not player["in_jail"]:
print("Player not in jail - exiting jail handler")
return False
player_obj = next(
(p for p in self.game.players if p.name == player["name"]), None
)
if not player_obj:
print(f"Warning: Could not find player object for {player['name']}")
return False
if not player_obj.in_jail:
print(f"Synchronizing jail state for {player['name']}")
player_obj.in_jail = True
player_obj.jail_turns = player["jail_turns"]
if player_obj.is_ai:
print(f"AI player {player['name']} deciding how to handle jail")
if self.game.logic.jail_free_cards.get(player["name"], 0) > 0:
print(f"AI using 'Get Out of Jail Free' card")
card_type = player_obj.use_jail_card()
if card_type == CardType.POT_LUCK:
self.game.pot_luck_deck.return_jail_card(card_type)
print("Returned Pot Luck jail card to deck")
else:
self.game.opportunity_deck.return_jail_card(card_type)
print("Returned Opportunity Knocks jail card to deck")
player["in_jail"] = False
player["jail_turns"] = 0
player_obj.in_jail = False
player_obj.jail_turns = 0
player_obj.stay_in_jail = False
self.game.board.add_message(
f"{player['name']} used Get Out of Jail Free card and left jail!"
)
print(f"AI player {player['name']} successfully left jail using card")
return True
elif player["money"] >= 50 and random.random() < 0.5:
print(
f"AI player {player['name']} paying £50 to leave jail (randomly decided)"
)
player["money"] -= 50
self.game.logic.free_parking_fund += 50
self.game.synchronize_free_parking_pot()
player["in_jail"] = False
player["jail_turns"] = 0
player_obj.in_jail = False
player_obj.jail_turns = 0
player_obj.stay_in_jail = False
self.game.board.add_message(f"{player['name']} paid £50 and left jail!")
print(
f"AI player {player['name']} successfully left jail by paying £50"
)
return True
else:
print(f"AI player {player['name']} will try to roll doubles")
else:
print(f"Human player {player['name']} choosing jail option")
self.game.renderer.draw()
pygame.display.flip()
choice = self.game.get_jail_choice(player)
print(f"Human player selected option: {choice}")
if (
choice == "card"
and self.game.logic.jail_free_cards.get(player["name"], 0) > 0
):
print(f"Using 'Get Out of Jail Free' card")
card_type = player_obj.use_jail_card()
if card_type == CardType.POT_LUCK:
self.game.pot_luck_deck.return_jail_card(card_type)
else:
self.game.opportunity_deck.return_jail_card(card_type)
player["in_jail"] = False
player["jail_turns"] = 0
player_obj.in_jail = False
player_obj.jail_turns = 0
player_obj.stay_in_jail = False
self.game.board.add_message(
f"{player['name']} used Get Out of Jail Free card and left jail!"
)
print(f"Player {player['name']} successfully left jail using card")
return True
elif choice == "pay" and player["money"] >= 50:
print(f"Paying £50 to leave jail")
player["money"] -= 50
self.game.logic.free_parking_fund += 50
self.game.synchronize_free_parking_pot()
player["in_jail"] = False
player["jail_turns"] = 0
player_obj.in_jail = False
player_obj.jail_turns = 0
player_obj.stay_in_jail = False
self.game.board.add_message(f"{player['name']} paid £50 and left jail!")
try:
self.game.board.add_message(
f"{player['name']} paid £50 and left jail!"
)
except AttributeError:
print("Error: board.add_message call failed")
print(f"Player {player['name']} successfully left jail by paying £50")
return True
elif choice == "stay":
print(f"Player {player['name']} chose to stay in jail")
player_obj.stay_in_jail = True
player["jail_turns"] = player.get("jail_turns", 0) + 1
player_obj.jail_turns = player["jail_turns"]
self.game.board.add_message(f"{player['name']} chose to stay in jail!")
return False
elif choice == "roll":
print(f"Player {player['name']} will try to roll doubles")
return True
player["jail_turns"] = player.get("jail_turns", 0) + 1
player_obj.jail_turns = player["jail_turns"]
print(f"Jail turn count increased to {player['jail_turns']}")
if player["jail_turns"] >= 3:
print(f"Player {player['name']} has been in jail for 3 turns")
if player["money"] >= 50:
print("Forcing payment after 3 turns")
player["money"] -= 50
self.game.logic.free_parking_fund += 50
self.game.synchronize_free_parking_pot()
player["in_jail"] = False
player["jail_turns"] = 0
player_obj.in_jail = False
player_obj.jail_turns = 0
player_obj.stay_in_jail = False
self.game.board.add_message(
f"{player['name']} paid £50 after 3 turns and left jail!"
)
print(
f"Player {player['name']} successfully left jail after 3 turns by paying £50"
)
return True
else:
print(
f"Player {player['name']} can't pay jail fine - leaving jail bankrupt"
)
player["in_jail"] = False
player["jail_turns"] = 0
player_obj.in_jail = False
player_obj.jail_turns = 0
player_obj.stay_in_jail = False
self.game.board.add_message(
f"{player['name']} couldn't pay jail fine and left jail bankrupt!"
)
self.handle_bankruptcy(player)
return True
print(f"Player {player['name']} remains in jail - jail turn handled\n")
return False
[docs]
def handle_voluntary_exit(self, player_name, final_assets):
print(f"\n=== Voluntary Exit Debug ===")
print(f"Player {player_name} is exiting the game")
logic_player = next(
(p for p in self.game.logic.players if p["name"] == player_name), None
)
if logic_player:
actual_final_assets = self.calculate_player_assets(logic_player)
print(f"Final assets calculated from game logic: {actual_final_assets}")
else:
actual_final_assets = final_assets
print(f"Using provided final assets: {final_assets}")
print(f"Current number of players: {len(self.game.logic.players)}")
print(
f"Current player index before exit: {self.game.logic.current_player_index}"
)
self.game.board.add_message(f"{player_name} exits game")
player_obj = next((p for p in self.game.players if p.name == player_name), None)
if not player_obj:
print(f"Error: Could not find player object for {player_name}")
return False
print(f"Found player object: {player_obj.name}")
player_properties = [
p
for p in self.game.logic.properties.values()
if p.get("owner") == player_name
]
print(
f"Player has {len(player_properties)} properties that will be returned to bank"
)
if hasattr(player_obj, "handle_voluntary_exit"):
print(f"Setting voluntary_exit flag for {player_name}")
player_obj.final_assets = actual_final_assets
player_obj.handle_voluntary_exit()
result = self.game.logic.remove_player(player_name, voluntary=True)
print(f"Game logic marked player as exited: {result}")
if result:
exited_player = next(
(p for p in self.game.logic.players if p["name"] == player_name), None
)
if exited_player and exited_player.get("exited", False):
print(f"Player {player_name} successfully marked as exited")
else:
print(f"Warning: Player {player_name} not properly marked as exited")
self.game.board.update_ownership(self.game.logic.properties)
active_players = [
p for p in self.game.logic.players if not p.get("exited", False)
]
print(f"Active players after exit: {[p['name'] for p in active_players]}")
next_player_found = False
original_index = self.game.logic.current_player_index
while not next_player_found and active_players:
self.game.logic.current_player_index = (
self.game.logic.current_player_index + 1
) % len(self.game.logic.players)
if self.game.logic.current_player_index == original_index:
break
current_player = self.game.logic.players[
self.game.logic.current_player_index
]
if not current_player.get("exited", False):
next_player_found = True
print(
f"Next active player: {current_player['name']} (index: {self.game.logic.current_player_index})"
)
print(
f"Current player index after exit: {self.game.logic.current_player_index}"
)
if len(active_players) <= 1:
print(
f"Only {len(active_players)} active player(s) left - game should end soon"
)
if self.game.check_one_player_remains():
print("Game ending due to only one player remaining")
game_over_data = self.end_full_game()
return game_over_data
self.game.state = "ROLL"
print("Checking if next player is an AI...")
self.game.check_and_trigger_ai_turn()
return True
else:
print("Failed to mark player as exited in game logic")
return False
[docs]
def calculate_player_assets(self, player):
try:
if not player or not isinstance(player, dict):
print(
f"Warning: Invalid player object in calculate_player_assets: {player}"
)
return 0
total = player.get("money", 0)
if (
not hasattr(self.game.logic, "properties")
or not self.game.logic.properties
):
print("Warning: No properties found in game logic")
return total
for prop_id, prop in self.game.logic.properties.items():
if not isinstance(prop, dict):
continue
if prop.get("owner") == player.get("name"):
total += prop.get("price", 0)
if "houses" in prop and prop["houses"] > 0:
house_costs = prop.get("house_costs", [])
if isinstance(house_costs, list) and house_costs:
houses_count = min(prop["houses"], len(house_costs))
for i in range(houses_count):
total += house_costs[i]
elif isinstance(house_costs, (int, float)):
total += house_costs * prop["houses"]
return total
except Exception as e:
print(f"Error in calculate_player_assets: {e}")
return player.get("money", 0)
[docs]
def handle_ai_turn(self, ai_player):
MAX_ITERATIONS = 100
iteration_count = 0
try:
player_obj = next(
(
player
for player in self.game.players
if player.name == ai_player["name"]
),
None,
)
if not player_obj:
return None
if not player_obj.is_ai:
return None
player_pos_valid = (
isinstance(player_obj.position, int) and 1 <= player_obj.position <= 40
)
logic_pos_valid = (
isinstance(ai_player.get("position"), int)
and 1 <= ai_player.get("position", 0) <= 40
)
if not player_pos_valid and logic_pos_valid:
player_obj.position = ai_player["position"]
elif player_pos_valid and not logic_pos_valid:
ai_player["position"] = player_obj.position
elif not player_pos_valid and not logic_pos_valid:
player_obj.position = 1
ai_player["position"] = 1
elif player_obj.position != ai_player["position"]:
player_obj.position = ai_player["position"]
except Exception as e:
return None
if self.game.state == "ROLL":
self.play_turn()
start_time = pygame.time.get_ticks()
while self.game.state == "BUY" and self.game.current_property:
current_time = pygame.time.get_ticks()
if current_time - start_time > 5000:
print(
f"Timeout reached for AI {ai_player['name']} in BUY state - forcing decision"
)
self.handle_buy_decision(False)
break
iteration_count += 1
if iteration_count > MAX_ITERATIONS:
print(
f"Maximum iterations reached for AI {ai_player['name']} in BUY state - forcing decision"
)
self.handle_buy_decision(False)
break
print(f"\n=== AI Purchase Decision ===")
print(f"AI Player: {ai_player['name']}")
print(f"Property: {self.game.current_property['name']}")
print(f"Price: £{self.game.current_property['price']}")
print(f"AI Money: £{ai_player['money']}")
try:
should_buy = self.game.logic.ai_player.should_buy_property(
self.game.current_property,
ai_player["money"],
[
p
for p in self.game.logic.properties.values()
if p.get("owner") == ai_player["name"]
],
)
if should_buy:
print("AI Decision: Buy")
self.handle_buy_decision(True)
else:
print("AI Decision: Pass")
self.handle_buy_decision(False)
except Exception as e:
print(f"Error in AI purchase decision: {e}")
self.handle_buy_decision(False)
break
elif self.game.state == "AUCTION" and hasattr(
self.game.logic, "current_auction"
):
auction_data = self.game.logic.current_auction
if auction_data is None:
print("Warning: Auction data is None in handle_ai_turn")
return None
start_time = pygame.time.get_ticks()
while (
auction_data["active_players"][auction_data["current_bidder_index"]][
"name"
]
== ai_player["name"]
):
current_time = pygame.time.get_ticks()
if current_time - start_time > 5000:
print(
f"Timeout reached for AI {ai_player['name']} in AUCTION state - forcing pass"
)
success, message = self.game.logic.process_auction_pass(ai_player)
if message:
self.game.board.add_message(message)
break
iteration_count += 1
if iteration_count > MAX_ITERATIONS:
print(
f"Maximum iterations reached for AI {ai_player['name']} in AUCTION state - forcing pass"
)
success, message = self.game.logic.process_auction_pass(ai_player)
if message:
self.game.board.add_message(message)
break
print(f"\n=== AI Auction Turn ===")
print(f"AI Player: {ai_player['name']}")
print(f"Property: {auction_data['property']['name']}")
print(f"Current bid: £{auction_data['current_bid']}")
print(f"Minimum bid: £{auction_data['minimum_bid']}")
if ai_player["name"] in auction_data.get("passed_players", set()):
print(f"AI {ai_player['name']} has already passed")
break
try:
bid_amount = self.game.logic.get_ai_auction_bid(
ai_player, auction_data["property"], auction_data["current_bid"]
)
if bid_amount and bid_amount >= auction_data["minimum_bid"]:
print(f"AI Decision: Bid £{bid_amount}")
success, message = self.game.logic.process_auction_bid(
ai_player, bid_amount
)
if message:
self.game.board.add_message(message)
else:
print("AI Decision: Pass")
success, message = self.game.logic.process_auction_pass(
ai_player
)
if message:
self.game.board.add_message(message)
except Exception as e:
print(f"Error in AI auction decision: {e}")
success, message = self.game.logic.process_auction_pass(ai_player)
if message:
self.game.board.add_message(message)
result_message = self.game.logic.check_auction_end()
if result_message:
self.game.board.add_message(result_message)
self.game.state = "ROLL"
self.game.board.update_ownership(self.game.logic.properties)
break
return None
[docs]
def handle_bankruptcy(self, player):
for ui_player in self.game.players:
if ui_player.name == player["name"]:
ui_player.bankrupt = True
print(f"Marking player {ui_player.name} as bankrupt in UI")
break
if self.game.logic.remove_player(player["name"]):
self.game.board.add_message(f"{player['name']} bankrupt!")
sound_manager.play_sound("bankruptcy")
self.game.board.update_ownership(self.game.logic.properties)
if self.game.check_one_player_remains():
print("Only one player remains after bankruptcy - ending game")
if (
hasattr(self.game, "game_settings")
and self.game.game_settings.get("mode") == "full"
):
self.end_full_game()
else:
self.end_abridged_game()
return True
return False
[docs]
def add_to_free_parking(self, amount):
self.game.free_parking_pot += amount
self.game.board.add_message(
f"£{amount} added to Free Parking pot (Total: £{self.game.free_parking_pot})"
)
[docs]
def collect_free_parking(self, player):
if self.game.free_parking_pot > 0:
amount = self.game.free_parking_pot
player["money"] += amount
self.game.free_parking_pot = 0
self.game.logic.free_parking_fund = 0
self.game.board.add_message(
f"{player['name']} collected £{amount} from Free Parking!"
)
self.game.show_card = True
self.game.current_card = {
"type": "Free Parking",
"message": f"You collected £{amount:,} from the Free Parking pot!",
}
self.game.current_card_player = player
self.game.card_display_time = pygame.time.get_ticks()
pygame.event.clear()
waiting = True
while waiting:
self.game.renderer.draw()
pygame.display.flip()
for event in pygame.event.get():
if event.type in [pygame.MOUSEBUTTONDOWN, pygame.KEYDOWN]:
waiting = False
self.game.show_card = False
self.game.current_card = None
self.game.current_card_player = None
elif event.type == pygame.QUIT:
pygame.quit()
sys.exit()
pygame.time.wait(30)
return True
return False
[docs]
def handle_fine_payment(self, player, amount, reason="fine"):
if player["money"] >= amount:
player["money"] -= amount
self.add_to_free_parking(amount)
self.game.board.add_message(f"{player['name']} paid £{amount} {reason}")
return True
else:
self.game.board.add_message(
f"{player['name']} cannot pay £{amount} {reason}"
)
return False
[docs]
def show_time_stats(self):
if self.game.game_mode == "abridged" and self.game.time_limit:
current_time = pygame.time.get_ticks()
elapsed = (current_time - self.game.start_time) // 1000
remaining = max(0, self.game.time_limit - elapsed)
minutes = remaining // 60
seconds = remaining % 60
self.game.board.add_message(f"Time: {minutes:02d}:{seconds:02d}")
min_rounds = min(self.game.rounds_completed.values())
max_rounds = max(self.game.rounds_completed.values())
if min_rounds != max_rounds:
self.game.board.add_message(f"Rounds: {min_rounds}-{max_rounds}")
[docs]
def show_exit_confirmation(self):
return self.game.show_exit_confirmation()
[docs]
def check_one_player_remains(self):
return self.game.check_one_player_remains()
[docs]
def check_game_over(self):
return self.game.check_game_over()
[docs]
def check_and_trigger_ai_turn(self):
return self.game.check_and_trigger_ai_turn()
[docs]
def end_full_game(self):
return self.game.end_full_game()
[docs]
def end_abridged_game(self):
return self.game.end_abridged_game()