Files
drinkmarble/app/game/cell-event.ts

93 lines
2.4 KiB
TypeScript

import type { Chessman } from './chessman';
export type PlaneCell = {
id: number;
x: number;
y: number;
/** UI에 보이는 이름 */
type: string;
/** 효과가 있을 때만 설정. 없으면 착지 시 아무 일도 없음 */
eventId?: string | null;
/** 칸 이미지 (없으면 텍스트만) */
imageSrc?: string | null;
/** false면 게임 판에서 이름·이미지를 숨김 */
contentVisible?: boolean;
};
export type TurnContext = {
chessman: Chessman;
board: PlaneCell[];
roll: number;
landIndex: number;
};
export type TurnResult = {
message: string;
/** 비행기 등: 즉시 이동할 칸 */
teleportTo?: number;
};
export interface CellEvent {
readonly id: string;
apply(ctx: TurnContext): TurnResult;
}
/** 무인도: 최대 3턴 대기, 주사위 6이면 즉시 탈출 가능 */
export class IslandEvent implements CellEvent {
readonly id = 'island';
apply(ctx: TurnContext): TurnResult {
ctx.chessman.enterIsland(3, 6);
return { message: '무인도! 3턴 대기 (6이면 탈출)' };
}
}
/** 역방향: 진행 방향을 반대로 */
export class ReverseEvent implements CellEvent {
readonly id = 'reverse';
apply(ctx: TurnContext): TurnResult {
const dir = ctx.chessman.reverseDirection();
return {
message: dir === 1 ? '역방향! 다시 시계방향' : '역방향! 반시계로 진행',
};
}
}
/** 비행기: 지정한 칸으로 즉시 이동 */
export class AirplaneEvent implements CellEvent {
readonly id = 'airplane';
constructor(private readonly targetIndex: number) {}
apply(ctx: TurnContext): TurnResult {
const target =
((this.targetIndex % ctx.board.length) + ctx.board.length) % ctx.board.length;
ctx.chessman.teleport(target);
const dest = ctx.board[target];
return {
message: `비행기! → ${dest?.type ?? target}`,
teleportTo: target,
};
}
}
export const CELL_EVENTS: Record<string, CellEvent> = {
island: new IslandEvent(),
reverse: new ReverseEvent(),
// 기본 도착지는 시작(0). 판 생성 시 덮어쓸 수 있다.
airplane: new AirplaneEvent(0),
};
export function getCellEvent(eventId: string | null | undefined): CellEvent | null {
if (!eventId) return null;
return CELL_EVENTS[eventId] ?? null;
}
export function applyLandEvent(ctx: TurnContext): TurnResult | null {
const cell = ctx.board[ctx.landIndex];
const event = getCellEvent(cell?.eventId);
if (!event) return null;
return event.apply(ctx);
}