Actions

Game class

Game

Bases: Model

Represents the core state and data of a single "Magnate" game session.

Attributes:

Name Type Description
datetime DateTimeField

The timestamp of when the game was created or started.

positions JSONField

Maps a player's user ID (str/int) to their current square's custom ID (int).

money JSONField

Maps a player's user ID (str/int) to their current money balance (int).

active_phase_player ForeignKey

The user who must take action in the current micro-phase (e.g., the user who needs to respond to a trade, which might differ from the active_turn_player).

active_turn_player ForeignKey

The user whose actual turn it is on the board.

phase CharField

The current GamePhase of the game state machine.

players ManyToManyField

The pool of users actively participating in this game.

ordered_players JSONField

A list of player primary keys [pk1, pk2, pk3, ...] representing the strict turn order of the game.

streak IntegerField

Tracks consecutive identical dice rolls (e.g., rolling doubles). Usually triggers jail time if it hits 3.

possible_destinations JSONField

Maps a target square_id (str) to the dice_combination (int) required to get there. Used when a player has multiple routing options (e.g., taking a tram).

parking_money PositiveIntegerField

The accumulated jackpot for landing on the "Free Parking" equivalent.

jail_remaining_turns JSONField

Maps a player's user ID (str/int) to the number of turns (int) they have left to serve in jail.

proposal ForeignKey

A reference to an active trade proposal (ActionTradeProposal) currently blocking the game state awaiting a response.

fantasy_event ForeignKey

A reference to an active chance/community chest style event (FantasyEvent) currently being resolved.

current_auction ForeignKey

A reference to an active property auction (Auction) taking place.

finished BooleanField

Flag indicating if the game has concluded.

bonus_response ForeignKey

Reference to a specific bonus or penalty modifier (ResponseBonus) applied to the current state.

kick_out_task_id CharField

The ID of the scheduled Celery task responsible for kicking a player if they fail to act within the time limit.

next_phase_task_id CharField

The ID of the scheduled Celery task responsible for auto-advancing the game to the next phase if a timeout occurs.

current_turn PositiveIntegerField

The global counter for the number of turns that have elapsed.

Source code in magnate/models.py
class Game(models.Model):
    """
    Represents the core state and data of a single "Magnate" game session.

    Attributes:
        datetime (DateTimeField): The timestamp of when the game was created or started.
        positions (JSONField): Maps a player's user ID (str/int) to their current square's custom ID (int).
        money (JSONField): Maps a player's user ID (str/int) to their current money balance (int).
        active_phase_player (ForeignKey): The user who must take action in the current micro-phase 
            (e.g., the user who needs to respond to a trade, which might differ from the active_turn_player).
        active_turn_player (ForeignKey): The user whose actual turn it is on the board.
        phase (CharField): The current `GamePhase` of the game state machine.
        players (ManyToManyField): The pool of users actively participating in this game.
        ordered_players (JSONField): A list of player primary keys `[pk1, pk2, pk3, ...]` 
            representing the strict turn order of the game.
        streak (IntegerField): Tracks consecutive identical dice rolls (e.g., rolling doubles). 
            Usually triggers jail time if it hits 3.
        possible_destinations (JSONField): Maps a target `square_id` (str) to the `dice_combination` (int) 
            required to get there. Used when a player has multiple routing options (e.g., taking a tram).
        parking_money (PositiveIntegerField): The accumulated jackpot for landing on the "Free Parking" equivalent.
        jail_remaining_turns (JSONField): Maps a player's user ID (str/int) to the number of turns (int) 
            they have left to serve in jail.
        proposal (ForeignKey): A reference to an active trade proposal (`ActionTradeProposal`) currently 
            blocking the game state awaiting a response.
        fantasy_event (ForeignKey): A reference to an active chance/community chest style event 
            (`FantasyEvent`) currently being resolved.
        current_auction (ForeignKey): A reference to an active property auction (`Auction`) taking place.
        finished (BooleanField): Flag indicating if the game has concluded.
        bonus_response (ForeignKey): Reference to a specific bonus or penalty modifier (`ResponseBonus`) 
            applied to the current state.
        kick_out_task_id (CharField): The ID of the scheduled Celery task responsible for kicking 
            a player if they fail to act within the time limit.
        next_phase_task_id (CharField): The ID of the scheduled Celery task responsible for auto-advancing 
            the game to the next phase if a timeout occurs.
        current_turn (PositiveIntegerField): The global counter for the number of turns that have elapsed.
    """
    datetime = models.DateTimeField()
    # Maps user_id -> square_custom_id
    positions = models.JSONField(default=dict, blank=True)
    # Maps user_id -> amount
    money = models.JSONField(default=dict, blank=True)
    active_phase_player = models.ForeignKey('CustomUser', on_delete=models.SET_NULL, null=True, related_name='phase_to_play')
    active_turn_player = models.ForeignKey('CustomUser', on_delete=models.SET_NULL, null=True, related_name='turns_to_play')

    class GamePhase(models.TextChoices):
        """
        Enumeration of the possible states (phases) within a game's turn cycle.

        Attributes:
            roll_the_dices: The initial phase of a turn. The `active_turn_player` 
                must throw the dice to determine movement.
            choose_square: Triggered when a player's movement path presents a fork 
                or routing option (e.g., deciding whether to take a tram/subway line). 
                The player must select their specific destination square.
            choose_fantasy: Triggered when a player lands on a dynamic event square 
                The player must acknowledge and resolve the active `fantasy_event`.
            management: Triggered when a player lands on an unowned property. The 
                player must choose to either purchase the property at its list price 
                or decline the purchase (which typically immediately triggers an `auction`).
            business: A versatile phase usually occurring at the end of a turn 
                or before a roll. The player can build/demolish houses, mortgage/unmortgage 
                properties, or finalize their board state before passing the turn.
            liquidation: An emergency phase triggered when a player owes a debt 
                (to the bank or another player) that exceeds their current liquid cash. 
                They are forced to sell assets or mortgage properties to cover the debt, 
                or face bankruptcy.
            auction: A competitive, multi-player phase triggered when a property 
                is declined in the `management` phase. The standard turn loop pauses, and 
                players take turns placing bids until a winner is determined.
            proposal_acceptance: An interruptive phase triggered when one player 
                sends a trade request to another. The game loop pauses, the 
                `active_phase_player` switches to the recipient, and they must either 
                accept or decline the pending `proposal`.
            end_game: A terminal state indicating the match has concluded, usually 
                because all other players have gone bankrupt. No further actions can 
                be taken.
        """
        roll_the_dices = 'roll_the_dices'
        choose_square = 'choose_square'
        choose_fantasy = 'choose_fantasy'
        management = 'management'
        liquidation = 'liquidation'
        business = 'business'
        auction = 'auction'
        proposal_acceptance = 'proposal_acceptance'
        end_game = 'end_game'


    phase = models.CharField(choices=GamePhase, max_length=20, default='roll_the_dices')
    players = models.ManyToManyField('CustomUser', related_name='active_playing')
    # ordered_player = [pk1, pk2, pk3, ...]
    ordered_players = models.JSONField(default=list)
    streak = models.IntegerField(default=0)
    #dict[string,int], key=square_id, value=dice_combination to get there
    possible_destinations = models.JSONField(default=dict, blank=True)
    parking_money = models.PositiveIntegerField(default=0)
    # Maps user_id -> uint
    jail_remaining_turns = models.JSONField(default=dict, blank=True)
    proposal = models.ForeignKey('ActionTradeProposal', on_delete=models.SET_NULL, null=True, blank=True, related_name='trade_proposal')

    fantasy_event = models.ForeignKey('FantasyEvent', on_delete=models.SET_NULL, null=True, blank=True, related_name='fantasy_event')

    current_auction = models.ForeignKey('Auction', on_delete=models.SET_NULL, null=True, blank=True, related_name='active_game')

    finished = models.BooleanField(default=False)
    bonus_response = models.ForeignKey('ResponseBonus', on_delete=models.SET_NULL, null=True, blank=True, related_name='bonus_response')

    kick_out_task_id = models.CharField(max_length=255, null=True, blank=True)
    next_phase_task_id = models.CharField(max_length=255, null=True, blank=True)

    current_turn = models.PositiveIntegerField(default=1)

GamePhase

Bases: TextChoices

Enumeration of the possible states (phases) within a game's turn cycle.

Attributes:

Name Type Description
roll_the_dices

The initial phase of a turn. The active_turn_player must throw the dice to determine movement.

choose_square

Triggered when a player's movement path presents a fork or routing option (e.g., deciding whether to take a tram/subway line). The player must select their specific destination square.

choose_fantasy

Triggered when a player lands on a dynamic event square The player must acknowledge and resolve the active fantasy_event.

management

Triggered when a player lands on an unowned property. The player must choose to either purchase the property at its list price or decline the purchase (which typically immediately triggers an auction).

business

A versatile phase usually occurring at the end of a turn or before a roll. The player can build/demolish houses, mortgage/unmortgage properties, or finalize their board state before passing the turn.

liquidation

An emergency phase triggered when a player owes a debt (to the bank or another player) that exceeds their current liquid cash. They are forced to sell assets or mortgage properties to cover the debt, or face bankruptcy.

auction

A competitive, multi-player phase triggered when a property is declined in the management phase. The standard turn loop pauses, and players take turns placing bids until a winner is determined.

proposal_acceptance

An interruptive phase triggered when one player sends a trade request to another. The game loop pauses, the active_phase_player switches to the recipient, and they must either accept or decline the pending proposal.

end_game

A terminal state indicating the match has concluded, usually because all other players have gone bankrupt. No further actions can be taken.

Source code in magnate/models.py
class GamePhase(models.TextChoices):
    """
    Enumeration of the possible states (phases) within a game's turn cycle.

    Attributes:
        roll_the_dices: The initial phase of a turn. The `active_turn_player` 
            must throw the dice to determine movement.
        choose_square: Triggered when a player's movement path presents a fork 
            or routing option (e.g., deciding whether to take a tram/subway line). 
            The player must select their specific destination square.
        choose_fantasy: Triggered when a player lands on a dynamic event square 
            The player must acknowledge and resolve the active `fantasy_event`.
        management: Triggered when a player lands on an unowned property. The 
            player must choose to either purchase the property at its list price 
            or decline the purchase (which typically immediately triggers an `auction`).
        business: A versatile phase usually occurring at the end of a turn 
            or before a roll. The player can build/demolish houses, mortgage/unmortgage 
            properties, or finalize their board state before passing the turn.
        liquidation: An emergency phase triggered when a player owes a debt 
            (to the bank or another player) that exceeds their current liquid cash. 
            They are forced to sell assets or mortgage properties to cover the debt, 
            or face bankruptcy.
        auction: A competitive, multi-player phase triggered when a property 
            is declined in the `management` phase. The standard turn loop pauses, and 
            players take turns placing bids until a winner is determined.
        proposal_acceptance: An interruptive phase triggered when one player 
            sends a trade request to another. The game loop pauses, the 
            `active_phase_player` switches to the recipient, and they must either 
            accept or decline the pending `proposal`.
        end_game: A terminal state indicating the match has concluded, usually 
            because all other players have gone bankrupt. No further actions can 
            be taken.
    """
    roll_the_dices = 'roll_the_dices'
    choose_square = 'choose_square'
    choose_fantasy = 'choose_fantasy'
    management = 'management'
    liquidation = 'liquidation'
    business = 'business'
    auction = 'auction'
    proposal_acceptance = 'proposal_acceptance'
    end_game = 'end_game'

GameStatusSerializer

Bases: ModelSerializer

Example

A standard serialized response during the 'roll_the_dices' phase:

{
    "id": 1,
    "datetime": "2026-04-06T18:30:00Z",
    "positions": {"42": 0, "85": 12},
    "money": {"42": 1500, "85": 1350},
    "active_phase_player": 42,
    "active_turn_player": 42,
    "phase": "roll_the_dices",
    "players": [42, 85],
    "ordered_players": [42, 85],
    "streak": 0,
    "possible_destinations": {},
    "parking_money": 200,
    "jail_remaining_turns": {},
    "proposal": null,
    "fantasy_event": null,
    "current_auction": null,
    "finished": false,
    "bonus_response": null,
    "current_turn": 5
}
Source code in magnate/serializers.py
class GameStatusSerializer(serializers.ModelSerializer):
    """
    Example:
        A standard serialized response during the 'roll_the_dices' phase:
        ```json
        {
            "id": 1,
            "datetime": "2026-04-06T18:30:00Z",
            "positions": {"42": 0, "85": 12},
            "money": {"42": 1500, "85": 1350},
            "active_phase_player": 42,
            "active_turn_player": 42,
            "phase": "roll_the_dices",
            "players": [42, 85],
            "ordered_players": [42, 85],
            "streak": 0,
            "possible_destinations": {},
            "parking_money": 200,
            "jail_remaining_turns": {},
            "proposal": null,
            "fantasy_event": null,
            "current_auction": null,
            "finished": false,
            "bonus_response": null,
            "current_turn": 5
        }
        ```
    """
    class Meta:
        model = Game
        exclude = ['kick_out_task_id', 'next_phase_task_id']