위협 가이드를 관리자 전용 옵션으로(기본 꺼짐) + 최고관리자 추가 + 계정 메뉴에 관리자 메뉴
- 엔진: GameDefinition.adminOnlyOptions — 방은 항상 관리자 값 사용(잠금처럼 강제, 잠금 안내는 안 띄움) - 오목·체스·장기 threatHints, 바둑 atariWarning: 기본 false, 대기실 설정에서 뺌, 관리자 화면 게임 기본 규칙에서만 켬 - 체스·장기 hints는 off / moves만 남김 - 최고관리자 기본값에 1352267557213573160 추가(.env.example·문서 포함) - 상단 계정 메뉴: 관리자·최고관리자면 [🛠 관리자 메뉴] → /admin - 테스트: admin.test(관리자 전용 옵션 강제, 두 번째 최고관리자), admin.e2e(계정 메뉴, 위협 가이드 켜기 저장) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -17,6 +17,7 @@ import {
|
||||
placeArrangement,
|
||||
positionKey,
|
||||
pseudoMoves,
|
||||
attacks,
|
||||
sqOf,
|
||||
type Arrangement,
|
||||
type Board,
|
||||
@@ -73,6 +74,7 @@ export const janggiOptionsSchema = z.object({
|
||||
.enum(['off', 'moves'])
|
||||
.default('moves')
|
||||
.meta({ title: '도움 표시', labels: { off: '끄기', moves: '갈 수 있는 곳' } }),
|
||||
threatHints: z.boolean().default(false).meta({ title: '위협 가이드(관리자 전용): 잡힐 위험이 있는 내 기물 표시' }),
|
||||
});
|
||||
export type JanggiOptions = z.infer<typeof janggiOptionsSchema>;
|
||||
|
||||
@@ -178,6 +180,7 @@ export interface JanggiView {
|
||||
/** Only for the player to move. */
|
||||
legalMoves: JanggiLegalMove[] | null;
|
||||
canPass: boolean;
|
||||
threatened: Sq[];
|
||||
rules: Pick<JanggiOptions, 'scoring' | 'bikjang' | 'repetition' | 'allowPass' | 'moveLimit' | 'hints' | 'timeControl' | 'idleLimitSec' | 'setupTimeSec'>;
|
||||
clock: JanggiState['clock'];
|
||||
undo: { allowed: boolean; remaining: Record<Side, number | null>; pending: { by: Side; plies: number } | null };
|
||||
@@ -443,6 +446,7 @@ export const janggi: GameDefinition<JanggiState, JanggiAction, JanggiView, Jangg
|
||||
stateVersion: 1,
|
||||
defaultOptions: janggiOptionsSchema.parse({}),
|
||||
optionsSchema: janggiOptionsSchema,
|
||||
adminOnlyOptions: ['threatHints'],
|
||||
actionSchema: janggiActionSchema as z.ZodType<JanggiAction>,
|
||||
|
||||
setup({ players, options, rng, now, gameNo }) {
|
||||
@@ -651,6 +655,14 @@ export const janggi: GameDefinition<JanggiState, JanggiAction, JanggiView, Jangg
|
||||
const myTurn = playing && mySide === s.turn;
|
||||
const captured: Record<Side, PieceKind[]> = { cho: [], han: [] };
|
||||
for (const m of s.moves) if (m.kind === 'move' && m.captured) captured[m.side].push(m.captured);
|
||||
let threatened: Sq[] = [];
|
||||
if (myTurn && s.options.threatHints) {
|
||||
const opp = other(s.turn);
|
||||
threatened = [];
|
||||
s.board.forEach((p, i) => {
|
||||
if (p && p.side === s.turn && p.kind !== 'king' && attacks(s.board, opp, i)) threatened.push(sqOf(i));
|
||||
});
|
||||
}
|
||||
const last = [...s.moves].reverse().find((m) => m.kind === 'move');
|
||||
const limit = undoLimit(s.options);
|
||||
const o = s.options;
|
||||
@@ -676,6 +688,7 @@ export const janggi: GameDefinition<JanggiState, JanggiAction, JanggiView, Jangg
|
||||
repeatWarning: mo?.warn ?? false,
|
||||
legalMoves: myTurn && mo ? mo.moves.map(legalToView) : null,
|
||||
canPass: myTurn && !!mo?.pass,
|
||||
threatened,
|
||||
rules: {
|
||||
scoring: o.scoring,
|
||||
bikjang: o.bikjang,
|
||||
|
||||
Reference in New Issue
Block a user