Skip to main content

Game Scenarios

Scenario 1: Joining Room and Starting Game

Steps:

  1. Get Room Information:

    GET /v1/rooms/room-123
    Headers: X-Player-Token: abc123
  2. WebSocket Connection:

    ws://{API_URL}/ws?room_id=room-123&name=Player1&currency=USD&launch_url_token=abc123&token=
  3. Initial Messages from Server:

    • Token message (new token and refreshToken)
    • userlist message (player list)
    • gameState message (game state)
  4. Game Start:

    • Server sends countdown messages (3, 2, 1...)
    • Server sends gameState message (actionState.type = 6 - StartGame)
    • Client emits GAME_EVENTS.START_GAME event
    • Client emits GAME_EVENTS.PLAYER_HAND_DEALT event (tiles are dealt)

Scenario 2: Normal Game Loop

Steps:

  1. Turn Start:

    • Server sends gameState message (turn = current player)
    • Server sends turn_timer_start message
    • Client emits CURRENT_PLAYER_TURN event
  2. Player Actions:

    • Draw from Middle:

      • Client: move message (moveType: 8)
      • Server: gameState message (new tile added to tileBag)
    • Draw from Discard:

      • Client: move message (moveType: 9)
      • Server: gameState message (tile added to tileBag)
    • Discard Tile:

      • Client: move message (moveType: 7, with tile object)
      • Server: gameState message (tile added to discardPile, turn changes)
    • Open Set:

      • Client: move message (moveType: 10, with tiles array)
      • Server: gameState message (openSeries updated)
    • Merge Set:

      • Client: move message (moveType: 11, with groupId, playerId, tile)
      • Server: gameState message (openSeries updated)
  3. Turn Timer:

    • Server sends turn_timer_update messages (time updates)
    • When time expires: turn_timer_expired message
    • Automatic timeout penalty applied

Scenario 3: Game End and Play Again Flow

State: Game ended, winner determined.

Step 1: Game End Message

Server sends endRound or gameState message:

{
"type": "endRound",
"gameState": {
"winnerId": "player-1",
"isTie": false,
"gamePhase": "finished",
"players": [
{
"uniqueId": "player-1",
"isWinner": true,
"currentTotalSetPoints": 0,
"remainingTilesScore": 5
},
{
"uniqueId": "player-2",
"isWinner": false,
"currentTotalSetPoints": 15,
"penaltyTotal": 10
}
]
}
}

Client:

  • GAME_EVENTS.END_GAME event is emitted
  • Game end modal is shown (scores, penalties)
  • "Play Again" button becomes active

Step 2: 30-Second Timeout Starts

Server automatically starts a 30-second timeout. During this time:

  • Players can send "Play Again" request
  • Players can click "Return to Lobby" button
  • When timeout expires, automatically return to lobby

Step 3A: A Player Sends "Play Again" Request

Player 1 (Request Sender):

  1. Client → Server:

    {
    "type": "play_again_request",
    "token": "abc123",
    "userName": "Player1",
    "content": {}
    }
  2. Server → Player 1:

    {
    "type": "playAgainRequestSent",
    "data": "Play again request sent successfully"
    }
  3. Server → Other Players (Player 2, Player 3, Player 4):

    {
    "type": "playAgainNotification",
    "from": "player-1",
    "content": {
    "requestingPlayerId": "player-1",
    "requestingPlayerName": "Player 1",
    "expiresAt": 1704067300000,
    "timeoutSeconds": 30
    }
    }
  4. Client (Other Players):

    • playAgainRequestModal is shown
    • "Accept" and "Reject" buttons become active
    • playAgainRequestingPlayer is saved to state

Step 3B: Other Players Respond

Player 2 Accepts:

  1. Client → Server:

    {
    "type": "play_again_response",
    "token": "abc123",
    "userName": "Player2",
    "content": {
    "accepted": true
    }
    }
  2. Server → All Players:

    {
    "type": "playAgainAccepted",
    "data": {
    "accepted": true
    }
    }

Player 3 Rejects:

  1. Client → Server:

    {
    "type": "play_again_response",
    "token": "abc123",
    "userName": "Player3",
    "content": {
    "accepted": false
    }
    }
  2. Server → All Players:

    {
    "type": "playAgainRejected",
    "data": {
    "accepted": false
    }
    }

Step 4: Result

State A: All Players Accepted

  1. Server → All Players:

    {
    "type": "playAgainResult",
    "data": {
    "type": "playAgainResult",
    "from": "player-2",
    "content": {
    "accepted": true,
    "respondingPlayerId": "player-2",
    "reason": ""
    }
    }
    }
  2. Client:

    • UI_EVENTS.ON_RESTART_GAME event is emitted
    • Game end modal closes
    • Play again request modal closes
    • New game starts (new gameState message arrives)

State B: A Player Rejected

  1. Server → All Players:

    {
    "type": "playAgainResult",
    "data": {
    "type": "playAgainResult",
    "from": "player-3",
    "content": {
    "accepted": false,
    "respondingPlayerId": "player-3",
    "reason": ""
    }
    }
    }
  2. Client:

    • onGameEnd() function is called
    • WebSocket connection is closed
    • window.parent.postMessage({ type: 'return_lobby' }) is sent
    • LeaveRoom action is sent
    • Players return to lobby

State C: Timeout Expired (30 Seconds)

  1. Server → All Players:

    {
    "type": "gameEndTimeout"
    }
  2. Client:

    • onGameEnd() function is called
    • WebSocket connection is closed
    • window.parent.postMessage({ type: 'return_lobby' }) is sent
    • LeaveRoom action is sent
    • Players return to lobby

Step 5: Direct Return to Lobby (Always Possible)

Any player can click the "Return to Lobby" button:

  1. Client → Server:

    {
    "type": "leave_table",
    "token": "abc123",
    "userName": "Player1",
    "content": {
    "moveType": 2,
    "timestamp": 1704067200000
    }
    }
  2. Client:

    • window.parent.postMessage({ type: 'return_lobby' }) is sent
    • WebSocket connection is closed
    • Player returns to lobby

Note: Clicking "Reject" button in the play again request modal also performs the same action.

Scenario 4: Connection Loss and Reconnection

State: WebSocket connection lost.

  1. Client:

    • SOCKET_CLOSE event is emitted
    • Disconnected modal is shown
    • Auto-reconnect starts (after 1 second)
  2. Reconnection:

    • SOCKET_RECONNECT event is emitted
    • state_recovery message is requested
    • Server sends current game state
  3. State Recovery:

    {
    "type": "state_recovery",
    "current_state": {
    // Full game state
    }
    }

Scenario 5: Timer Management

Turn Timer:

  1. Turn Start:

    • Server sends turn_timer_start message
    • Client starts timer
  2. Timer Updates:

    • Server sends turn_timer_update messages (every second)
    • Client updates timer
  3. Timer Expired:

    • Server sends turn_timer_expired message
    • Client applies automatic timeout penalty

Timer Status Request:

When client becomes visible (tab switch):

{
"type": "get_timer_status",
"token": "abc123",
"userName": "Player1",
"content": {}
}

Server sends current timer status:

{
"type": "turn_timer_status",
"data": {
"status": {
"current_turn": "player-1",
"turn_duration": "30",
"timers": { ... }
}
}
}