Skip to content

Commit 5b2988d

Browse files
committed
Пофикшены баги в работе карточек с енотом, добавлены каринки и анимация для передачи хода игроку. Отмена полёта енота кликом, доступна только игроку с ходом и ведущему.
1 parent 16177d2 commit 5b2988d

9 files changed

Lines changed: 209 additions & 109 deletions

File tree

artifacts/game-client/src/apps/adepts-game-2/hooks/useGameState.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ export type ActiveQuizCard = {
99
themeIndex: number;
1010
questionIndex: number;
1111
stage: "question" | "answer";
12+
/** Клик ведущего / ходящего по вылетающему еноту — синхронно всем клиентам */
13+
splashDismissed?: boolean;
14+
/** После передачи хода по еноту — один раз за открытую карточку, для всех клиентов */
15+
splashSeatPassUsed?: boolean;
1216
};
1317

1418
export type GameState = {

artifacts/game-client/src/apps/adepts-game-2/pages/Home.tsx

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import { useEffect, useMemo, useState } from "react";
1+
import { useEffect, useMemo } from "react";
22
import { useGameState } from "../hooks/useGameState";
33
import { Scoreboard } from "@/lib/adepts-scoreboard";
44
import { QuizBoard } from "@/lib/adepts-quiz-board";
5+
import { isAdeptsWheelFaceDownCell } from "@/lib/isAdeptsWheelFaceDownCell";
56
import { QuestionModal } from "@/lib/adepts-question-modal";
67
import { GamePhaseNav } from "@/components/GamePhaseArrows";
78
import { QuizBoardReloadButton } from "@/components/QuizBoardReloadButton";
@@ -52,21 +53,34 @@ export default function Home() {
5253
? active
5354
: null;
5455

55-
const [raccoonSplashSeatPassUsed, setRaccoonSplashSeatPassUsed] = useState(false);
56-
const openCardKey = openCard ? `${openCard.themeIndex}-${openCard.questionIndex}` : null;
57-
useEffect(() => {
58-
setRaccoonSplashSeatPassUsed(false);
59-
}, [openCardKey]);
60-
6156
const seatRaw = Number(localStorage.getItem("player_seat_index"));
6257
const seatIndex =
6358
Number.isInteger(seatRaw) && seatRaw >= 0 && seatRaw <= 4 ? seatRaw : -1;
6459
const canOpenCards =
6560
isHost || (!isSpectator && seatIndex === state.currentTurnSeat);
61+
const blockTurnPlayerFromPlayedOrFaceDownCells =
62+
!isHost && !isSpectator && seatIndex >= 0 && seatIndex <= 4 && seatIndex === state.currentTurnSeat;
63+
64+
const canDismissRaccoonSplash =
65+
isHost ||
66+
(!isSpectator && seatIndex >= 0 && seatIndex <= 4 && seatIndex === state.currentTurnSeat);
6667

6768
const handleQuestionClick = (themeIndex: number, questionIndex: number) => {
6869
if (!canOpenCards) return;
69-
setActiveQuizCard({ themeIndex, questionIndex, stage: "question" });
70+
const q = state.questions[themeIndex]?.[questionIndex];
71+
if (
72+
q &&
73+
blockTurnPlayerFromPlayedOrFaceDownCells &&
74+
(q.used || isAdeptsWheelFaceDownCell(q))
75+
)
76+
return;
77+
setActiveQuizCard({
78+
themeIndex,
79+
questionIndex,
80+
stage: "question",
81+
splashDismissed: false,
82+
splashSeatPassUsed: false,
83+
});
7084
};
7185

7286
const closeQuestion = () => {
@@ -109,6 +123,7 @@ export default function Home() {
109123
onUpdateTheme={updateThemeName}
110124
onQuestionClick={handleQuestionClick}
111125
readonly={!canOpenCards}
126+
blockTurnPlayerFromPlayedOrFaceDownCells={blockTurnPlayerFromPlayedOrFaceDownCells}
112127
/>
113128
</main>
114129
</div>
@@ -144,9 +159,12 @@ export default function Home() {
144159
onPassTurnNext={() => setCurrentTurnSeat((state.currentTurnSeat + 1) % 5)}
145160
currentTurnSeat={state.currentTurnSeat}
146161
viewerSeatIndex={isHost || isSpectator || seatIndex < 0 ? null : seatIndex}
147-
allowRaccoonSplashSeatPass={!raccoonSplashSeatPassUsed}
162+
allowRaccoonSplashSeatPass={openCard.splashSeatPassUsed !== true}
163+
splashDismissed={openCard.splashDismissed === true}
164+
canDismissRaccoonSplash={canDismissRaccoonSplash}
165+
onDismissSplash={() => patchActiveQuizCard({ splashDismissed: true })}
148166
onPassTurnToSeat={(target) => {
149-
setRaccoonSplashSeatPassUsed(true);
167+
patchActiveQuizCard({ splashSeatPassUsed: true });
150168
setCurrentTurnSeat(target);
151169
}}
152170
readonly={!isHost}

artifacts/game-client/src/apps/adepts-game-3/hooks/useGameState.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ export type ActiveQuizCard = {
99
themeIndex: number;
1010
questionIndex: number;
1111
stage: "question" | "answer";
12+
/** Клик ведущего / ходящего по вылетающему еноту — синхронно всем клиентам */
13+
splashDismissed?: boolean;
14+
/** После передачи хода по еноту — один раз за открытую карточку, для всех клиентов */
15+
splashSeatPassUsed?: boolean;
1216
};
1317

1418
export type GameState = {

artifacts/game-client/src/apps/adepts-game-3/pages/Home.tsx

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import { useEffect, useMemo, useState } from "react";
1+
import { useEffect, useMemo } from "react";
22
import { useGameState } from "../hooks/useGameState";
33
import { Scoreboard } from "@/lib/adepts-scoreboard";
44
import { QuizBoard } from "@/lib/adepts-quiz-board";
5+
import { isAdeptsWheelFaceDownCell } from "@/lib/isAdeptsWheelFaceDownCell";
56
import { QuestionModal } from "@/lib/adepts-question-modal";
67
import { GamePhaseNav } from "@/components/GamePhaseArrows";
78
import { QuizBoardReloadButton } from "@/components/QuizBoardReloadButton";
@@ -52,21 +53,34 @@ export default function Home() {
5253
? active
5354
: null;
5455

55-
const [raccoonSplashSeatPassUsed, setRaccoonSplashSeatPassUsed] = useState(false);
56-
const openCardKey = openCard ? `${openCard.themeIndex}-${openCard.questionIndex}` : null;
57-
useEffect(() => {
58-
setRaccoonSplashSeatPassUsed(false);
59-
}, [openCardKey]);
60-
6156
const seatRaw = Number(localStorage.getItem("player_seat_index"));
6257
const seatIndex =
6358
Number.isInteger(seatRaw) && seatRaw >= 0 && seatRaw <= 4 ? seatRaw : -1;
6459
const canOpenCards =
6560
isHost || (!isSpectator && seatIndex === state.currentTurnSeat);
61+
const blockTurnPlayerFromPlayedOrFaceDownCells =
62+
!isHost && !isSpectator && seatIndex >= 0 && seatIndex <= 4 && seatIndex === state.currentTurnSeat;
63+
64+
const canDismissRaccoonSplash =
65+
isHost ||
66+
(!isSpectator && seatIndex >= 0 && seatIndex <= 4 && seatIndex === state.currentTurnSeat);
6667

6768
const handleQuestionClick = (themeIndex: number, questionIndex: number) => {
6869
if (!canOpenCards) return;
69-
setActiveQuizCard({ themeIndex, questionIndex, stage: "question" });
70+
const q = state.questions[themeIndex]?.[questionIndex];
71+
if (
72+
q &&
73+
blockTurnPlayerFromPlayedOrFaceDownCells &&
74+
(q.used || isAdeptsWheelFaceDownCell(q))
75+
)
76+
return;
77+
setActiveQuizCard({
78+
themeIndex,
79+
questionIndex,
80+
stage: "question",
81+
splashDismissed: false,
82+
splashSeatPassUsed: false,
83+
});
7084
};
7185

7286
const closeQuestion = () => {
@@ -109,6 +123,7 @@ export default function Home() {
109123
onUpdateTheme={updateThemeName}
110124
onQuestionClick={handleQuestionClick}
111125
readonly={!canOpenCards}
126+
blockTurnPlayerFromPlayedOrFaceDownCells={blockTurnPlayerFromPlayedOrFaceDownCells}
112127
/>
113128
</main>
114129
</div>
@@ -144,9 +159,12 @@ export default function Home() {
144159
onPassTurnNext={() => setCurrentTurnSeat((state.currentTurnSeat + 1) % 5)}
145160
currentTurnSeat={state.currentTurnSeat}
146161
viewerSeatIndex={isHost || isSpectator || seatIndex < 0 ? null : seatIndex}
147-
allowRaccoonSplashSeatPass={!raccoonSplashSeatPassUsed}
162+
allowRaccoonSplashSeatPass={openCard.splashSeatPassUsed !== true}
163+
splashDismissed={openCard.splashDismissed === true}
164+
canDismissRaccoonSplash={canDismissRaccoonSplash}
165+
onDismissSplash={() => patchActiveQuizCard({ splashDismissed: true })}
148166
onPassTurnToSeat={(target) => {
149-
setRaccoonSplashSeatPassUsed(true);
167+
patchActiveQuizCard({ splashSeatPassUsed: true });
150168
setCurrentTurnSeat(target);
151169
}}
152170
readonly={!isHost}

artifacts/game-client/src/apps/adepts-game/hooks/useGameState.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ export type ActiveQuizCard = {
99
themeIndex: number;
1010
questionIndex: number;
1111
stage: "question" | "answer";
12+
/** Клик ведущего / ходящего по вылетающему еноту — синхронно всем клиентам */
13+
splashDismissed?: boolean;
14+
/** После передачи хода по еноту — один раз за открытую карточку, для всех клиентов */
15+
splashSeatPassUsed?: boolean;
1216
};
1317

1418
export type GameState = {

artifacts/game-client/src/apps/adepts-game/pages/Home.tsx

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import { useEffect, useMemo, useState } from "react";
1+
import { useEffect, useMemo } from "react";
22
import { useGameState } from "../hooks/useGameState";
33
import { Scoreboard } from "@/lib/adepts-scoreboard";
44
import { QuizBoard } from "@/lib/adepts-quiz-board";
5+
import { isAdeptsWheelFaceDownCell } from "@/lib/isAdeptsWheelFaceDownCell";
56
import { QuestionModal } from "@/lib/adepts-question-modal";
67
import { GamePhaseNav } from "@/components/GamePhaseArrows";
78
import { QuizBoardReloadButton } from "@/components/QuizBoardReloadButton";
@@ -52,21 +53,34 @@ export default function Home() {
5253
? active
5354
: null;
5455

55-
const [raccoonSplashSeatPassUsed, setRaccoonSplashSeatPassUsed] = useState(false);
56-
const openCardKey = openCard ? `${openCard.themeIndex}-${openCard.questionIndex}` : null;
57-
useEffect(() => {
58-
setRaccoonSplashSeatPassUsed(false);
59-
}, [openCardKey]);
60-
6156
const seatRaw = Number(localStorage.getItem("player_seat_index"));
6257
const seatIndex =
6358
Number.isInteger(seatRaw) && seatRaw >= 0 && seatRaw <= 4 ? seatRaw : -1;
6459
const canOpenCards =
6560
isHost || (!isSpectator && seatIndex === state.currentTurnSeat);
61+
const blockTurnPlayerFromPlayedOrFaceDownCells =
62+
!isHost && !isSpectator && seatIndex >= 0 && seatIndex <= 4 && seatIndex === state.currentTurnSeat;
63+
64+
const canDismissRaccoonSplash =
65+
isHost ||
66+
(!isSpectator && seatIndex >= 0 && seatIndex <= 4 && seatIndex === state.currentTurnSeat);
6667

6768
const handleQuestionClick = (themeIndex: number, questionIndex: number) => {
6869
if (!canOpenCards) return;
69-
setActiveQuizCard({ themeIndex, questionIndex, stage: "question" });
70+
const q = state.questions[themeIndex]?.[questionIndex];
71+
if (
72+
q &&
73+
blockTurnPlayerFromPlayedOrFaceDownCells &&
74+
(q.used || isAdeptsWheelFaceDownCell(q))
75+
)
76+
return;
77+
setActiveQuizCard({
78+
themeIndex,
79+
questionIndex,
80+
stage: "question",
81+
splashDismissed: false,
82+
splashSeatPassUsed: false,
83+
});
7084
};
7185

7286
const closeQuestion = () => {
@@ -109,6 +123,7 @@ export default function Home() {
109123
onUpdateTheme={updateThemeName}
110124
onQuestionClick={handleQuestionClick}
111125
readonly={!canOpenCards}
126+
blockTurnPlayerFromPlayedOrFaceDownCells={blockTurnPlayerFromPlayedOrFaceDownCells}
112127
/>
113128
</main>
114129
</div>
@@ -144,9 +159,12 @@ export default function Home() {
144159
onPassTurnNext={() => setCurrentTurnSeat((state.currentTurnSeat + 1) % 5)}
145160
currentTurnSeat={state.currentTurnSeat}
146161
viewerSeatIndex={isHost || isSpectator || seatIndex < 0 ? null : seatIndex}
147-
allowRaccoonSplashSeatPass={!raccoonSplashSeatPassUsed}
162+
allowRaccoonSplashSeatPass={openCard.splashSeatPassUsed !== true}
163+
splashDismissed={openCard.splashDismissed === true}
164+
canDismissRaccoonSplash={canDismissRaccoonSplash}
165+
onDismissSplash={() => patchActiveQuizCard({ splashDismissed: true })}
148166
onPassTurnToSeat={(target) => {
149-
setRaccoonSplashSeatPassUsed(true);
167+
patchActiveQuizCard({ splashSeatPassUsed: true });
150168
setCurrentTurnSeat(target);
151169
}}
152170
readonly={!isHost}

0 commit comments

Comments
 (0)