From 7198eb0181eaef5d6f975fa7a73ecd44fc66ca9f Mon Sep 17 00:00:00 2001 From: Yuto Nishida Date: Sun, 7 Dec 2025 22:54:32 -0800 Subject: [PATCH] [2nub] Display role and handle 50/50 cop --- .../2nub/src/client/components/Onub.tsx | 8 ++++++ .../client/components/OnubRoleAssignment.tsx | 26 +++++++++++++++++++ experimental/2nub/src/server/gameState.ts | 11 ++++++++ experimental/2nub/src/types.ts | 4 +-- 4 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 experimental/2nub/src/client/components/OnubRoleAssignment.tsx diff --git a/experimental/2nub/src/client/components/Onub.tsx b/experimental/2nub/src/client/components/Onub.tsx index ef9a901..9662cb3 100644 --- a/experimental/2nub/src/client/components/Onub.tsx +++ b/experimental/2nub/src/client/components/Onub.tsx @@ -1,6 +1,9 @@ import React, { useState } from 'react'; import { GameStateClient } from '../../types'; import { OnubLobby } from './OnubLobby'; +import { OnubRoleAssignment } from './OnubRoleAssignment'; +import { OnubNight } from './OnubNight'; +import '../styles/main.scss'; interface OnubProps { game: GameStateClient; @@ -26,8 +29,13 @@ export const Onub: React.FC = ({ game, currentPlayerId }) => { switch (game.state.state) { case 'lobby': content = ; + break; + case 'roleAssignment': + content = ; + break; case 'night': content = ; + break; default: //throw new Error(`Onub component: Unsupported game state "${game.state.state}"`); } diff --git a/experimental/2nub/src/client/components/OnubRoleAssignment.tsx b/experimental/2nub/src/client/components/OnubRoleAssignment.tsx new file mode 100644 index 0000000..62c2238 --- /dev/null +++ b/experimental/2nub/src/client/components/OnubRoleAssignment.tsx @@ -0,0 +1,26 @@ +import React, { useState } from 'react'; +import { GameStateClient, StateNight, StateRoleAssignment } from '../../types'; +import '../styles/main.scss'; + +/** + * Remove parentheses and their contents from a string. + * @param input String containing parentheses + * @returns String without any parentheses and their contents + */ +function removeParenthesesNaively(input: string): string { + return input.replace(/\s*\([^)]*\)/g, ''); +} + +interface OnubRoleAssignmentProps { + stateRoleAssignment: StateRoleAssignment; + currentPlayerId: string; +} + +export const OnubRoleAssignment: React.FC = ({ stateRoleAssignment, currentPlayerId }) => { + const roleWithParentheses = stateRoleAssignment.playerData[currentPlayerId].originalRoleId; + const role = removeParenthesesNaively(roleWithParentheses); + return
+

Role Assignment

+

Your role is: {role}

+
; +} \ No newline at end of file diff --git a/experimental/2nub/src/server/gameState.ts b/experimental/2nub/src/server/gameState.ts index 9b13b52..131ba64 100644 --- a/experimental/2nub/src/server/gameState.ts +++ b/experimental/2nub/src/server/gameState.ts @@ -263,6 +263,17 @@ class GameStateManager { const count5050DuoCop = game.state.ruleset.roleOrder.filter(roleId => roleId === '50/50 duo cop').length; if (count5050DuoCop !== 0 && count5050DuoCop !== 2) return null; + // Transform cops into sane/insane variants if present + if (count5050DuoCop === 2) { + const firstIsSane = flip(0.5); + game.state.ruleset.roleOrder = game.state.ruleset.roleOrder.map(roleId => { + if (roleId === '50/50 duo cop') { + return firstIsSane ? '50/50 duo cop(sane)' : '50/50 duo cop(insane)'; + } + return roleId; + }); + } + await standardDelay(); // Transition to in-game state diff --git a/experimental/2nub/src/types.ts b/experimental/2nub/src/types.ts index 7570284..c2cb1d8 100644 --- a/experimental/2nub/src/types.ts +++ b/experimental/2nub/src/types.ts @@ -12,8 +12,8 @@ export const ROLES = [ "mason", "insomniac", "50/50 duo cop", - "cop(sane)", - "cop(insane)", + "50/50 duo cop(sane)", + "50/50 duo cop(insane)", ] as const; export type RoleId = typeof ROLES[number]; -- 2.51.2