Skip to content

Commit 840dbb5

Browse files
committed
добавлено начисление после благословления ДЕДОМ
1 parent 6f212fe commit 840dbb5

4 files changed

Lines changed: 96 additions & 2 deletions

File tree

artifacts/api-server/src/adepts.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
applyActiveQuizPatch,
1212
applyPickCell,
1313
applyPlayerDonation,
14+
applyHostMounts400DedDonationDoubleReward,
1415
cloneQuizRelay,
1516
getQuizRelayOrDefault,
1617
} from "./lib/adepts-quiz-room-store";
@@ -295,6 +296,22 @@ export function setupAdepts(io: Server): void {
295296
run();
296297
return;
297298
}
299+
case "hostMounts400DedDonationBonus": {
300+
if (!host) return;
301+
const ti = Number(cmd["themeIndex"]);
302+
const qi = Number(cmd["questionIndex"]);
303+
if (!Number.isFinite(ti) || !Number.isFinite(qi)) return;
304+
const r = applyHostMounts400DedDonationDoubleReward(sessionId, ti, qi);
305+
if (!r.ok) {
306+
logger.warn(
307+
{ sessionId, socketId: socket.id, err: r.error, themeIndex: ti, questionIndex: qi },
308+
"hostMounts400DedDonationBonus rejected",
309+
);
310+
return;
311+
}
312+
run();
313+
return;
314+
}
298315
case "hostClearActiveCard": {
299316
if (!host) return;
300317
applyHostClearActiveCard(sessionId);

artifacts/api-server/src/lib/adepts-quiz-room-store.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,10 @@ export function setQuizRelayFull(sessionId: string, payload: AdeptsQuizRelayPayl
105105
delete base.themes;
106106
delete base.questions;
107107
}
108+
/** Каждый lean-relay от ведущего несёт `themes` — обновляем подписи без полного каталога. */
109+
if (Array.isArray(payload.themes) && payload.themes.length > 0) {
110+
base.themes = payload.themes.map((x) => String(x ?? "").trim().slice(0, 64));
111+
}
108112
// (lean relay, same board) → keep existing catalog intact so clients that connect later
109113
// still receive the most recently edited catalog for this board.
110114
}
@@ -315,6 +319,44 @@ export function applySeatNickRosterToQuizRelay(sessionId: string, seatNicks: str
315319
}
316320
}
317321

322+
/**
323+
* Карточка на 400 (индекс вопроса 3): клик ведущего по «деду» (dedFly) — +2× сумма пожертвования на **место**
324+
* (0–4) из журнала. Текущий игрок на месте получает очки. Название темы на сервере не проверяем (часто пусто
325+
* или другое написание). Строки без `seatIndex` игнорируются.
326+
*/
327+
export function applyHostMounts400DedDonationDoubleReward(
328+
sessionId: string,
329+
themeIndex: number,
330+
questionIndex: number,
331+
): { ok: true } | { ok: false; error: string } {
332+
const s = getQuizRelayOrDefault(sessionId);
333+
const c = s.activeQuizCard;
334+
if (!c) return { ok: false, error: "no active card" };
335+
const t = Math.floor(themeIndex);
336+
const q = Math.floor(questionIndex);
337+
if (c.themeIndex !== t || c.questionIndex !== q) return { ok: false, error: "card mismatch" };
338+
if (pointValueForQuestionIndex(q) !== 400) return { ok: false, error: "not 400" };
339+
340+
const log = s.donationLog ?? [];
341+
const bonusBySeat = new Map<number, number>();
342+
343+
for (const e of log) {
344+
const amt = Math.floor(Number(e.amount));
345+
if (!Number.isFinite(amt) || amt < 1) continue;
346+
const si = e.seatIndex;
347+
if (typeof si !== "number" || !Number.isInteger(si) || si < 0 || si > 4) continue;
348+
const seat = ((si % 5) + 5) % 5;
349+
const bonus = amt * 2;
350+
bonusBySeat.set(seat, (bonusBySeat.get(seat) ?? 0) + bonus);
351+
}
352+
353+
for (const [seat, add] of bonusBySeat) {
354+
const p = s.players[seat];
355+
if (p) p.score += add;
356+
}
357+
return { ok: true };
358+
}
359+
318360
export function applyPlayerDonation(
319361
sessionId: string,
320362
seat: number,

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

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,23 @@ import { useRole } from "@/hooks/useRole";
1111
import { ChatPanel } from "@/components/ChatPanel";
1212
import { QuizBoardPandoraLottoOverlay } from "@/components/QuizBoardPandoraLottoOverlay";
1313
import { DonationsTable } from "@/components/DonationsTable";
14+
import { getAdeptsCommandSocket } from "@/lib/adeptsCommandSocket";
1415
import { getQuizNavSocket } from "@/hooks/quizNavSocket";
1516

17+
/** Вопрос 400 = индекс 3. Бонус дед-слеша: тема «Маунты» по названию или любой dedFly в каталоге. */
18+
function shouldEmitDedFlyDonationBonus(
19+
themeName: string | undefined,
20+
questionIndex: number,
21+
splashVariant: string | undefined,
22+
): boolean {
23+
if (questionIndex !== 3) return false;
24+
if (splashVariant === "dedFly") return true;
25+
const n = String(themeName ?? "")
26+
.trim()
27+
.toLowerCase();
28+
return n.includes("маунт") || n.includes("mount");
29+
}
30+
1631
function resolveUrl(url: string): string {
1732
if (!url) return url;
1833
if (url.startsWith("http") || url.startsWith("//")) return url;
@@ -218,7 +233,26 @@ export default function Home({ boardId }: { boardId: AdeptsBoardId }) {
218233
allowRaccoonSplashSeatPass={openCard.splashSeatPassUsed !== true}
219234
splashDismissed={openCard.splashDismissed === true}
220235
splashDedFlyExitStarted={openCard.splashDedFlyExitStarted === true}
221-
onDedFlyExitStart={() => patchActiveQuizCard({ splashDedFlyExitStarted: true })}
236+
onDedFlyExitStart={() => {
237+
patchActiveQuizCard({ splashDedFlyExitStarted: true });
238+
if (!isHost || !openCard) return;
239+
const qMeta = state.questions[openCard.themeIndex]?.[openCard.questionIndex];
240+
if (
241+
shouldEmitDedFlyDonationBonus(
242+
state.themes[openCard.themeIndex],
243+
openCard.questionIndex,
244+
qMeta?.splashVariant,
245+
)
246+
) {
247+
queueMicrotask(() => {
248+
getAdeptsCommandSocket().emit("command", {
249+
type: "hostMounts400DedDonationBonus",
250+
themeIndex: openCard.themeIndex,
251+
questionIndex: openCard.questionIndex,
252+
});
253+
});
254+
}
255+
}}
222256
canFinalizeDedFlySplashDismiss={isHost}
223257
canDismissRaccoonSplash={canDismissSplash}
224258
onDismissSplash={() =>

artifacts/game-client/src/lib/adeptsQuizSocketRelay.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,10 @@ export function buildAdeptsQuizRelayPayload(
6464
};
6565
if (boardId !== undefined) out.boardId = boardId;
6666
if (slice.dataVersion !== undefined) out.dataVersion = slice.dataVersion;
67+
/** Всегда шлём подписи тем — на сервере нужны для «Маунты 400» и т.п. без тяжёлого каталога. */
68+
out.themes = slice.themes;
6769
if (includeCatalog) {
6870
out.catalogIncluded = true;
69-
out.themes = slice.themes;
7071
out.questions = slice.questions;
7172
}
7273
return out;

0 commit comments

Comments
 (0)