PageSourceSearch

https://scoremj.com/assets/ScoreGamePage-mj4GdVvv.js

js scoremj.com collected 2026-10-09 21:27:00 UTC 25,421 bytes, 657 lines download raw bytes

1import { a8 as interopRequireDefaultExports, a9 as requireCreateSvgIcon, j as jsxRuntimeExports, s as reactExports, D as useAuth, a as useQuery, u as useMutation, a1 as React, r as navigate, l as namedRoutes, K as lodashExports, a4 as Ie, B as Button, E as Box, T as Typography, ar as FormControl, as as InputLabel, S as Select, M as MenuItem, b as TextField, N as VIEW_GAME, _ as _t, at as SUBMIT_HAND_RESULT, au as COMPLETE_GAME } from "./index-C4CHA07n.js";
2import { d as default_1$2 } from "./ArrowBack-C4_OAgEz.js";
3import { M as MetaTags } from "./MetaTags-BAQyR9et.js";
4import { G as GameStatusDisplay, P as PlayerDisplayMode, a as GameHandsDisplay } from "./GameStatus-BgzBHbrA.js";
5import { N as NotFound } from "./NotFound-BeY5nixI.js";
6import { O as ORDERED_DIRECTIONS } from "./mahjong-GF7DfyT4.js";
7import { c as convertPenaltyState, f as formatUsernameWithSeat } from "./string-3k44aTru.js";
8import { D as Dialog, a as DialogContent, b as DialogActions } from "./DialogContent-WZK7CRo1.js";
9import { D as DialogTitle } from "./DialogTitle-CB7KUzON.js";
10import { D as DialogContentText } from "./DialogContentText-DW97wTcV.js";
11import { T as ToggleButtonGroup, a as ToggleButton } from "./ToggleButtonGroup-CBxZOaa3.js";
12import { G as Grid } from "./Grid-BLLzrUSJ.js";
13import "./DeleteForever-DZlkv-Jj.js";
14import "./Switch-CGdkIIZh.js";
15import "./SwitchBase-CyJ6H0eD.js";
16import "./PointStick-BDCrk6Ew.js";
17import "./Tooltip-ANTVaZKH.js";
18import "./Popper-Dd3Hvd48.js";
19import "./logo-D1jnWoFK.js";
20var Send = {};
21var _interopRequireDefault$1 = interopRequireDefaultExports;
22Object.defineProperty(Send, "__esModule", {
23  value: true
24});
25var default_1$1 = Send.default = void 0;
26var _createSvgIcon$1 = _interopRequireDefault$1(requireCreateSvgIcon());
27var _jsxRuntime$1 = jsxRuntimeExports;
28var _default$1 = (0, _createSvgIcon$1.default)(/* @__PURE__ */ (0, _jsxRuntime$1.jsx)("path", {
29  d: "M2.01 21 23 12 2.01 3 2 10l15 2-15 2z"
30}), "Send");
31default_1$1 = Send.default = _default$1;
32var StopCircle = {};
33var _interopRequireDefault = interopRequireDefaultExports;
34Object.defineProperty(StopCircle, "__esModule", {
35  value: true
36});
37var default_1 = StopCircle.default = void 0;
38var _createSvgIcon = _interopRequireDefault(requireCreateSvgIcon());
39var _jsxRuntime = jsxRuntimeExports;
40var _default = (0, _createSvgIcon.default)(/* @__PURE__ */ (0, _jsxRuntime.jsx)("path", {
41  d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm4 14H8V8h8v8z"
42}), "StopCircle");
43default_1 = StopCircle.default = _default;
44function useForceUpdate() {
45  const [_, setValue] = reactExports.useState(0);
46  return () => setValue((value) => value + 1);
47}
48const SCORE_WIN_TYPE = {
49  RON: "RON",
50  TSUMO: "TSUMO",
51  TENPAI: "TENPAI",
52  CHOMBO: "CHOMBO",
53  HU: "HU",
54  SELFDRAW: "SELF-DRAW",
55  DRAW: "DRAW"
56};
57function directionsFromRiichiToggles(state) {
58  return ORDERED_DIRECTIONS.filter((_, i) => state[i]);
59}
60function clampPenaltySeat(v) {
61  const n = Math.floor(Number(v));
62  if (!Number.isFinite(n)) {
63    return 0;
64  }
65  return Math.max(-128, Math.min(127, n));
66}
67function coercePenaltyForGraphql(state) {
68  return {
69    0: clampPenaltySeat(state[0]),
70    1: clampPenaltySeat(state[1]),
71    2: clampPenaltySeat(state[2]),
72    3: clampPenaltySeat(state[3])
73  };
74}
75function directionsFromTenpaiToggles(state) {
76  return ORDERED_DIRECTIONS.filter((_, i) => state[i]);
77}
78function tryBuildHandResultInput(draft) {
79  const {
80    winType,
81    isMCR,
82    riichiState,
83    tenpaiState,
84    winningPlayer,
85    losingPlayer,
86    han,
87    fu,
88    fan,
89    penaltyState
90  } = draft;
91  const riichiSeats = directionsFromRiichiToggles(riichiState);
92  if (winType === SCORE_WIN_TYPE.RON || winType === SCORE_WIN_TYPE.TSUMO) {
93    if (winningPlayer === null || !han || !fu) {
94      return null;
95    }
96    const h = Number(han);
97    const f = Number(fu);
98    if (!Number.isFinite(h) || !Number.isFinite(f) || h < 1 || f < 20) {
99      return null;
100    }
101  }
102  if (winType === SCORE_WIN_TYPE.HU || winType === SCORE_WIN_TYPE.SELFDRAW) {
103    if (winningPlayer === null || fan === "") {
104      return null;
105    }
106    if (!Number.isFinite(Number(fan))) {
107      return null;
108    }
109  }
110  if (winType === SCORE_WIN_TYPE.RON || winType === SCORE_WIN_TYPE.HU) {
111    if (losingPlayer === null || winningPlayer === null) {
112      return null;
113    }
114    if (winningPlayer === losingPlayer) {
115      return null;
116    }
117  }
118  if (winType === SCORE_WIN_TYPE.CHOMBO) {
119    if (winningPlayer === null) {
120      return null;
121    }
122  }
123  if (winType === SCORE_WIN_TYPE.RON) {
124    const w = winningPlayer;
125    const l = losingPlayer;
126    if (w === null || l === null) {
127      return null;
128    }
129    return {
130      ronHandResult: {
131        riichiSeats,
132        ronResults: [{
133          actor: ORDERED_DIRECTIONS[w],
134          target: ORDERED_DIRECTIONS[l],
135          han: Number(han),
136          fu: Number(fu)
137        }]
138      }
139    };
140  }
141  if (winType === SCORE_WIN_TYPE.TSUMO) {
142    const w = winningPlayer;
143    if (w === null) {
144      return null;
145    }
146    return {
147      tsumoHandResult: {
148        riichiSeats,
149        actor: ORDERED_DIRECTIONS[w],
150        han: Number(han),
151        fu: Number(fu)
152      }
153    };
154  }
155  if (winType === SCORE_WIN_TYPE.TENPAI) {
156    return {
157      exhaustiveDrawHandResult: {
158        riichiSeats,
159        tenpaiSeats: directionsFromTenpaiToggles(tenpaiState)
160      }
161    };
162  }
163  if (winType === SCORE_WIN_TYPE.CHOMBO) {
164    const w = winningPlayer;
165    if (w === null) {
166      return null;
167    }
168    return {
169      chomboHandResult: {
170        actor: ORDERED_DIRECTIONS[w]
171      }
172    };
173  }
174  if (winType === SCORE_WIN_TYPE.HU && isMCR) {
175    const w = winningPlayer;
176    const l = losingPlayer;
177    if (w === null || l === null) {
178      return null;
179    }
180    const ps = coercePenaltyForGraphql(penaltyState);
181    return {
182      ronHandResult: {
183        riichiSeats,
184        ronResults: [{
185          actor: ORDERED_DIRECTIONS[w],
186          target: ORDERED_DIRECTIONS[l],
187          han: Number(fan),
188          fu: convertPenaltyState(ps)
189        }]
190      }
191    };
192  }
193  if (winType === SCORE_WIN_TYPE.SELFDRAW && isMCR) {
194    const w = winningPlayer;
195    if (w === null) {
196      return null;
197    }
198    const ps = coercePenaltyForGraphql(penaltyState);
199    return {
200      tsumoHandResult: {
201        riichiSeats,
202        actor: ORDERED_DIRECTIONS[w],
203        han: Number(fan),
204        fu: convertPenaltyState(ps)
205      }
206    };
207  }
208  if (winType === SCORE_WIN_TYPE.DRAW && isMCR) {
209    return {
210      exhaustiveDrawHandResult: {
211        riichiSeats,
212        tenpaiSeats: directionsFromTenpaiToggles(tenpaiState)
213      }
214    };
215  }
216  return null;
217}
218var WinType = /* @__PURE__ */ ((WinType2) => {
219  WinType2["RON"] = "RON";
220  WinType2["TSUMO"] = "TSUMO";
221  WinType2["TENPAI"] = "TENPAI";
222  WinType2["CHOMBO"] = "CHOMBO";
223  return WinType2;
224})(WinType || {});
225var WinTypeMCR = /* @__PURE__ */ ((WinTypeMCR2) => {
226  WinTypeMCR2["HU"] = "HU";
227  WinTypeMCR2["SELFDRAW"] = "SELF-DRAW";
228  WinTypeMCR2["DRAW"] = "DRAW";
229  return WinTypeMCR2;
230})(WinTypeMCR || {});
231const ScoreGamePage = ({
232  gameId
233}
233) => {
234  const {
235    currentUser,
236    hasRole
237  } = useAuth();
238  const forceUpdate = useForceUpdate();
239  reactExports.useEffect(() => {
240    function handleVisibilityChange() {
241      if (document.hidden) {
242        return;
243      }
244      forceUpdate();
245    }
246    document.addEventListener("visibilitychange", handleVisibilityChange);
247    return () => {
248      document.removeEventListener("visibilitychange", handleVisibilityChange);
249    };
250  }, [forceUpdate]);
251  const {
252    data,
253    error,
254    loading
255  } = useQuery(VIEW_GAME, {
256    variables: {
257      gameId
258    },
259    pollInterval: 2e3,
260    fetchPolcy: "network-only"
261  });
262  const [submitHandResult] = useMutation(SUBMIT_HAND_RESULT, {
263    refetchQueries: ["ViewGame"],
264    onError: (error2) => {
265      _t.error(error2.message);
266    }
267  });
268  const [completeGame] = useMutation(COMPLETE_GAME, {
269    onError: (error2) => {
270      _t.error(error2.message);
271    }
272  });
273  const [endGameModalOpen, setEndGameModalOpen] = React.useState(false);
274  const handleEndGameModalOpen = () => {
275    setEndGameModalOpen(true);
276  };
277  const handleEndGameModalClose = () => {
278    setEndGameModalOpen(false);
279  };
280  const [submitting, setSubmitting] = reactExports.useState(false);
281  const [riichiState, setRiichiState] = reactExports.useState({
282    0: false,
283    1: false,
284    2: false,
285    3: false
286  });
287  const [tenpaiState, setTenpaiState] = reactExports.useState({
288    0: false,
289    1: false,
290    2: false,
291    3: false
292  });
293  const [winningPlayer, setWinningPlayer] = reactExports.useState(null);
294  const [losingPlayer, setLosingPlayer] = reactExports.useState(null);
295  const [han, setHan] = reactExports.useState("");
296  const [fu, setFu] = reactExports.useState("");
297  const [fan, setFan] = reactExports.useState(8);
298  const [penaltyState, setPenaltyState] = reactExports.useState({
299    0: 0,
300    1: 0,
301    2: 0,
302    3: 0
303  });
304  function incrementFan(amount) {
305    setFan(Math.max(0, Number(fan) + amount));
306  }
307  const [winType, setWinType] = reactExports.useState(
308    "RON"
309    /* RON */
310  );
311  if (!(data == null ? void 0 : data.game) && (error || loading)) return /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, {});
312  if (!(data == null ? void 0 : data.game)) {
313    return /* @__PURE__ */ jsxRuntimeExports.jsx(NotFound, {});
314  }
315  const {
316    game: {
317      gameRules,
318      players: rawPlayers,
319      status,
320      currentRound
321    }
322  } = data;
323  const isSanma = gameRules.gameType === "SANMA";
324  const numPlayers = isSanma ? 3 : 4;
325  if (status !== "IN_PROGRESS") {
326    navigate(namedRoutes.viewGame({
327      gameId
328    }), {
329      replace: true
330    });
331  }
332  let hanOptions = Array.from({
333    length: 13
334  }, (_, i) => i + 1).map((num) => num.toString());
335  if (gameRules.aotenjou) {
336    hanOptions = Array.from({
337      length: 52
338    }, (_, i) => i + 1).map((num) => num.toString());
339  } else if (gameRules.multiYakuman) {
340    hanOptions = Array.from({
341      length: 13
342    }, (_, i) => i + 1).map((num) => num.toString());
343    hanOptions.push("26");
344    hanOptions.push("39");
345    hanOptions.push("52");
346  }
347  const fuOptions = ["20", "25", "30", "40", "50", "60", "70", "80", "90", "100", "110", "120", "130", "140", "150", "160", "170"];
348  const players = lodashExports.sortBy(rawPlayers, (player) => ORDERED_DIRECTIONS.indexOf(player.startingDirection));
349  function computeNewMultistate(state, value) {
350    const newState = {
351      ...state
352    };
353    const newValue = Number(value);
354    newState[newValue] = !newState[newValue];
355    return newState;
356  }
357  function handleRiichiChange(_, rawValue) {
358    const newRiichiState = computeNewMultistate(riichiState, rawValue);
359    setRiichiState(newRiichiState);
360    if (winType !== "TENPAI") {
361      const newTenpaiState = computeNewMultistate(tenpaiState, rawValue);
362      setTenpaiState(newTenpaiState);
363    }
364  }
365  function handleTenpaiChange(_, rawValue) {
366    const newTenpaiState = computeNewMultistate(tenpaiState, rawValue);
367    setTenpaiState(newTenpaiState);
368  }
369  async function endGame() {
370    handleEndGameModalClose();
371    setSubmitting(true);
372    try {
373      await completeGame({
374        variables: {
375          gameId
376        }
377      });
378    } finally {
379      setSubmitting(false);
380    }
381    navigate(namedRoutes.viewGame({
382      gameId
383    }), {
384      replace: true
385    });
386    return;
387  }
388  async function submitHand() {
389    const handInput = tryBuildHandResultInput({
390      winType,
391      isMCR,
392      riichiState,
393      tenpaiState,
394      winningPlayer,
395      losingPlayer,
396      han,
397      fu,
398      fan,
399      penaltyState
400    });
401    if (!handInput) {
402      alert("Invalid values");
403      return;
404    }
405    setSubmitting(true);
406    try {
407      const {
408        errors
409      } = await submitHandResult({
410        variables: {
411          gameId,
412          input: handInput
413        }
414      });
415      if (errors) {
416        alert(errors);
417      }
418      const freshState = {
419        0: false,
420        1: false,
421        2: false,
422        3: false
423      };
424      setRiichiState(freshState);
425      setTenpaiState(freshState);
426      setWinningPlayer(null);
427      setLosingPlayer(null);
428      setHan("");
429      setFu("");
430      setFan(8);
431      setWinType(
432        "RON"
433        /* RON */
434      );
435      setPenaltyState({
436        0: 0,
437        1: 0,
438        2: 0,
439        3: 0
440      });
441    } finally {
442      setSubmitting(false);
443    }
444  }
445  const isRiichi = gameRules.gameType === "SANMA" || gameRules.gameType === "YONMA";
446  const isMCR = gameRules.gameType === "MCR";
447  const isSeated = rawPlayers.some((player) => player.user.id === (currentUser == null ? void 0 : currentUser.user.id));
448  return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
449    /* @__PURE__ */ jsxRuntimeExports.jsx(Ie, { toastOptions: {
450      className: "rw-toast",
451      duration: 5e3
452    } }),
453    /* @__PURE__ */ jsxRuntimeExports.jsx(MetaTags, { title: "Score Game" }),
454    /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { href: namedRoutes.viewGame({
455      gameId
456    }), sx: {
457      mb: -1
458    }, startIcon: /* @__PURE__ */ jsxRuntimeExports.jsx(default_1$2, {}), size: "large", children: "Back" }),
459    gameRules.gameType === "YONMA" && hasRole(["GAME_ADMIN", "SITE_ADMIN"]) && !isSeated && /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { href: namedRoutes.streamModerate({
460      gameId
461    }), variant: "outlined", sx: {
462      ml: 1,
463      mb: -1
464    }, children: "Stream Moderate" }),
465    /* @__PURE__ */ jsxRuntimeExports.jsxs(Dialog, { open: endGameModalOpen, onClose: handleEndGameModalClose, children: [
466      /* @__PURE__ */ jsxRuntimeExports.jsx(DialogTitle, { children: "Are you sure you want to end the game?" }),
467      /* @__PURE__ */ jsxRuntimeExports.jsx(DialogContent, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(DialogContentText, { children: "This will end the game and finalize the scores, you will not be able to undo this action without the help of a game administrator." }) }),
468      /* @__PURE__ */ jsxRuntimeExports.jsxs(DialogActions, { children: [
469        /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { onClick: handleEndGameModalClose, variant: "contained", children: "Cancel" }),
470        /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { onClick: endGame, disabled: submitting, variant: "contained", color: "error", endIcon: /* @__PURE__ */ jsxRuntimeExports.jsx(default_1, {}), children: "End Game" })
471      ] })
472    ] }),
473    /* @__PURE__ */ jsxRuntimeExports.jsx(GameStatusDisplay, { gameId, displayMode: PlayerDisplayMode.GAME_TABLE, currentUserId: currentUser.user.id }),
474    /* @__PURE__ */ jsxRuntimeExports.jsxs(Box, { sx: {
475      pt: 0,
476      display: "flex",
477      flexDirection: "column"
478    }, children: [
479      isRiichi && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
480        /* @__PURE__ */ jsxRuntimeExports.jsx(Typography, { sx: {
481          mb: 0
482        }, align: "center", variant: "h6", gutterBottom: true, children: "Riichi" }),
483        /* @__PURE__ */ jsxRuntimeExports.jsx(ToggleButtonGroup, { size: "small", onChange: handleRiichiChange, fullWidth: true, color: "primary", sx: {
484          marginBottom: "10px"
485        }, children: players.map((player, i) => /* @__PURE__ */ jsxRuntimeExports.jsx(ToggleButton, { value: i, selected: riichiState[i], sx: {
486          pl: 0,
487          pr: 0,
488          maxWidth: isSanma ? "fit-content(33.333%)" : "fit-content(25%)",
489          wordBreak: "break-all"
490        }, children: lodashExports.capitalize(formatUsernameWithSeat(player, currentRound, numPlayers, gameRules.gameType)) }, player.user.id)) })
491      ] }),
492      /* @__PURE__ */ jsxRuntimeExports.jsx(ToggleButtonGroup, { size: "small", onChange: (_, v) => setWinType(v), fullWidth: true, color: "primary", exclusive: true, children: Object.values(isMCR ? WinTypeMCR : WinType).map((key) => /* @__PURE__ */ jsxRuntimeExports.jsx(ToggleButton, { value: key, selected: winType === key, children: lodashExports.capitalize(key) }, key)) }),
493      winType === "TENPAI" ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
494        /* @__PURE__ */ jsxRuntimeExports.jsx(Typography, { sx: {
495          mb: 0
496        }, align: "center", variant: "h6", gutterBottom: true, children: "Players in Tenpai" }),
497        /* @__PURE__ */ jsxRuntimeExports.jsx(ToggleButtonGroup, { size: "small", onChange: handleTenpaiChange, fullWidth: true, color: "primary", sx: {
498          marginBottom: "10px"
499        }, children: players.map((player, i) => /* @__PURE__ */ jsxRuntimeExports.jsx(ToggleButton, { value: i, selected: tenpaiState[i], sx: {
500          pl: 0,
501          pr: 0,
502          maxWidth: isSanma ? "fit-content(33.333%)" : "fit-content(25%)",
503          wordBreak: "break-all"
504        }, children: lodashExports.capitalize(formatUsernameWithSeat(player, currentRound, numPlayers, gameRules.gameType)) }, player.user.id)) })
505      ] }) : winType !== "DRAW" && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
506        /* @__PURE__ */ jsxRuntimeExports.jsx(Typography, { sx: {
507          mb: 0
508        }, align: "center", variant: "h6", gutterBottom: true, children: "Winner" }),
509        /* @__PURE__ */ jsxRuntimeExports.jsx(ToggleButtonGroup, { size: "small", onChange: (_, v) => setWinningPlayer(Number(v)), fullWidth: true, color: "primary", exclusive: true, children: players.map((player, i) => /* @__PURE__ */ jsxRuntimeExports.jsx(ToggleButton, { value: i, selected: winningPlayer === Number(i), sx: {
510          pl: 0,
511          pr: 0,
512          maxWidth: isSanma ? "fit-content(33.333%)" : "fit-content(25%)",
513          wordBreak: "break-all"
514        }, children: lodashExports.capitalize(formatUsernameWithSeat(player, currentRound, numPlayers, gameRules.gameType)) }, i)) }),
515        (winType === "RON" || winType === "HU") && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
516          /* @__PURE__ */ jsxRuntimeExports.jsx(Typography, { sx: {
517            mb: 0
518          }, align: "center", variant: "h6", gutterBottom: true, children: "Loser" }),
519          /* @__PURE__ */ jsxRuntimeExports.jsx(ToggleButtonGroup, { size: "small", onChange: (_, v) => setLosingPlayer(Number(v)), fullWidth: true, color: "primary", exclusive: true, children: players.map((player, i) => /* @__PURE__ */ jsxRuntimeExports.jsx(ToggleButton, { size: "small", value: i, selected: losingPlayer === Number(i), sx: {
520            pl: 0,
521            pr: 0,
522            maxWidth: isSanma ? "fit-content(33.333%)" : "fit-content(25%)",
523            wordBreak: "break-all"
524          }, children: lodashExports.capitalize(formatUsernameWithSeat(player, currentRound, numPlayers, gameRules.gameType)) }, i)) })
525        ] }),
526        /* @__PURE__ */ jsxRuntimeExports.jsxs(Box, { sx: {
527          display: "flex",
528          flexDirection: "row",
529          justifyContent: "space-between",
530          marginTop: "10px"
531        }, children: [
532          isRiichi && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
533            /* @__PURE__ */ jsxRuntimeExports.jsxs(FormControl, { sx: {
534              flexGrow: "0.48"
535            }, children: [
536              /* @__PURE__ */ jsxRuntimeExports.jsx(InputLabel, { children: "Han" }),
537              /* @__PURE__ */ jsxRuntimeExports.jsx(Select, { label: "Han", value: `${han}`, onChange: (event) => {
538                setHan(Number(event.target.value));
539              }, children: hanOptions.map((hanValue) => /* @__PURE__ */ jsxRuntimeExports.jsx(MenuItem, { value: hanValue, children: hanValue }, hanValue)) })
540            ] }),
541            /* @__PURE__ */ jsxRuntimeExports.jsxs(FormControl, { sx: {
542              flexGrow: "0.48"
543            }, children: [
544              /* @__PURE__ */ jsxRuntimeExports.jsx(InputLabel, { children: "Fu" }),
545              /* @__PURE__ */ jsxRuntimeExports.jsx(Select, { label: "Fu", value: `${fu}`, onChange: (event) => {
546                setFu(Number(event.target.value));
547              }, children: fuOptions.map((fuValue) => /* @__PURE__ */ jsxRuntimeExports.jsx(MenuItem, { value: fuValue, children: fuValue }, fuValue)) })
548            ] })
549          ] }),
550          isMCR && /* @__PURE__ */ jsxRuntimeExports.jsxs(Grid, { container: true, display: "flex", flexWrap: "nowrap", margin: "auto", width: "100%", padding: "0", justifyContent: "center", children: [
551            /* @__PURE__ */ jsxRuntimeExports.jsxs(Box, { sx: {
552              maxWidth: "40%",
553              display: "flex",
554              flexWrap: "wrap",
555              alignItems: "center",
556              justifyContent: "flex-end"
557            }, children: [
558              /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { variant: "outlined", sx: {
559                minWidth: "20px",
560                margin: "0 2px",
561                padding: "10px"
562              }, onClick: () => incrementFan(-10), children: "-10" }),
563              /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { variant: "outlined", sx: {
564                minWidth: "20px",
565                margin: "0 2px",
566                padding: "10px"
567              }, onClick: () => incrementFan(-5), children: "-5" }),
568              /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { variant: "outlined", sx: {
569                minWidth: "20px",
570                margin: "0 2px",
571                padding: "10px"
572              }, onClick: () => incrementFan(-1), children: "-1" })
573            ] }),
574            /* @__PURE__ */ jsxRuntimeExports.jsx(FormControl, { sx: {
575              minWidth: "20px",
576              maxWidth: "20%",
577              margin: "0 2px"
578            }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(TextField, { label: "Fan", type: "number", InputProps: {
579              inputProps: {
580                min: 0,
581                max: 1e3
582              }
583            }, value: `${fan}`, onChange: (event) => {
584              setFan(event.target.value);
585            }, onBlur: () => {
586              setFan(Math.max(0, Math.floor(Number(fan))));
587            } }) }),
588            /* @__PURE__ */ jsxRuntimeExports.jsxs(Box, { sx: {
589              maxWidth: "40%",
590              display: "flex",
591              flexWrap: "wrap",
592              alignItems: "center"
593            }, children: [
594              /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { variant: "outlined", sx: {
595                minWidth: "20px",
596                margin: "0 2px",
597                padding: "10px"
598              }, onClick: () => incrementFan(1), children: "+1" }),
599              /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { variant: "outlined", sx: {
600                minWidth: "20px",
601                margin: "0 2px",
602                padding: "10px"
603              }, onClick: () => incrementFan(5), children: "+5" }),
604              /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { variant: "outlined", sx: {
605                minWidth: "20px",
606                margin: "0 2px",
607                padding: "10px"
608              }, onClick: () => incrementFan(10), children: "+10" })
609            ] })
610          ] })
611        ] })
612      ] }),
613      isMCR && winType !== "DRAW" && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
614        /* @__PURE__ */ jsxRuntimeExports.jsx(Typography, { sx: {
615          mb: 0
616        }, align: "center", variant: "h6", gutterBottom: true, children: "Penalty" }),
617        /* @__PURE__ */ jsxRuntimeExports.jsx(Box, { sx: {
618          display: "flex",
619          flexDirection: "row",
620          justifyContent: "space-between",
621          marginTop: "10px"
622        }, children: players.map((player, i) => /* @__PURE__ */ jsxRuntimeExports.jsx(FormControl, { sx: {
623          flexGrow: "0.25"
624        }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(TextField, { type: "number", InputProps: {
625          inputProps: {
626            min: -128,
627            max: 127
628          }
629        }, label: formatUsernameWithSeat(player, currentRound, numPlayers, gameRules.gameType).toUpperCase(), value: `${penaltyState[i]}`, onChange: (event) => {
630          setPenaltyState({
631            ...penaltyState,
632            [i]: event.target.value
633          });
634        }, onBlur: () => {
635          let val = Math.floor(penaltyState[i]);
636          if (val < -128) val = -128;
637          if (val > 127) val = 127;
638          setPenaltyState({
639            ...penaltyState,
640            [i]: val
641          });
642        } }) }, i)) })
643      ] }),
644      /* @__PURE__ */ jsxRuntimeExports.jsxs(Grid, { container: true, columnSpacing: 1, spacing: 0, sx: {
645        mt: "10px",
646        mb: "10px"
647      }, children: [
648        /* @__PURE__ */ jsxRuntimeExports.jsx(Grid, { item: true, xs: 8, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { onClick: submitHand, disabled: submitting, variant: "contained", fullWidth: true, endIcon: /* @__PURE__ */ jsxRuntimeExports.jsx(default_1$1, {}), children: "Submit" }) }),
649        /* @__PURE__ */ jsxRuntimeExports.jsx(Grid, { item: true, xs: 4, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Button, { onClick: handleEndGameModalOpen, disabled: submitting, variant: "contained", fullWidth: true, color: "error", endIcon: /* @__PURE__ */ jsxRuntimeExports.jsx(default_1, {}), children: "End" }) })
650      ] })
651    ] }),
652    /* @__PURE__ */ jsxRuntimeExports.jsx(GameHandsDisplay, { gameId })
653  ] });
654};
655export {
656  ScoreGamePage as default
657};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.