Add multiplayer state sync model, concrete stats, movement model, monster AI, lobby/disconnect handling, economy, and chat system. Fix room probabilities, combat action naming, and AoE interactions. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
280 lines
12 KiB
Markdown
280 lines
12 KiB
Markdown
# Catacombs — Design Spec
|
||
|
||
SSH 멀티플레이어 협동 로그라이크 터미널 게임
|
||
|
||
## Overview
|
||
|
||
Go + Charm 스택 기반의 SSH 접속 멀티플레이어 협동 로그라이크. 2~4인 파티가 절차적 생성 던전을 탐험하며, 반실시간 턴제 전투와 클래스 기반 역할 분담으로 20층 던전을 클리어하는 게임.
|
||
|
||
- **접속:** SSH 메인 (`ssh catacombs.tolelom.xyz`), 웹 터미널 추후 추가
|
||
- **한 판:** 30~45분, 고정 20층
|
||
- **인원:** 2~4인 협동
|
||
- **시각:** 박스 드로잉 + ANSI 컬러
|
||
|
||
## Architecture
|
||
|
||
단일 Go 바이너리 모놀리스, Docker 컨테이너 하나로 배포.
|
||
|
||
```
|
||
┌─────────────────────────────────────────┐
|
||
│ Docker Container │
|
||
│ │
|
||
│ ┌─────────────┐ ┌────────────────┐ │
|
||
│ │ Wish SSH │──▶│ Bubble Tea │ │
|
||
│ │ Server │ │ TUI Engine │ │
|
||
│ │ :2222 │ └───────┬────────┘ │
|
||
│ └─────────────┘ │ │
|
||
│ ┌───────▼────────┐ │
|
||
│ │ Game Engine │ │
|
||
│ │ - Lobby │ │
|
||
│ │ - Dungeon │ │
|
||
│ │ - Combat │ │
|
||
│ │ - Turn Timer │ │
|
||
│ └───────┬────────┘ │
|
||
│ ┌───────▼────────┐ │
|
||
│ │ BoltDB │ │
|
||
│ │ (랭킹, 통계) │ │
|
||
│ └────────────────┘ │
|
||
└─────────────────────────────────────────┘
|
||
```
|
||
|
||
### Dependencies
|
||
|
||
- `charmbracelet/wish` — SSH 서버
|
||
- `charmbracelet/bubbletea` — TUI 프레임워크
|
||
- `charmbracelet/lipgloss` — 스타일링 (색상, 박스 드로잉)
|
||
- `go.etcd.io/bbolt` — 경량 임베디드 DB (랭킹/통계)
|
||
|
||
### Multiplayer State Sync
|
||
|
||
각 게임 세션(파티)마다 하나의 `GameSession` goroutine이 중앙 게임 루프를 돌린다.
|
||
|
||
```
|
||
┌──────────────┐
|
||
Player A (SSH) ──▶ │ │ ──▶ tea.Msg to A
|
||
Player B (SSH) ──▶ │ GameSession │ ──▶ tea.Msg to B
|
||
Player C (SSH) ──▶ │ goroutine │ ──▶ tea.Msg to C
|
||
└──────────────┘
|
||
```
|
||
|
||
- 각 플레이어의 Bubble Tea 프로그램은 입력을 `GameSession`의 채널로 전송
|
||
- `GameSession`은 턴 타이머 관리, 입력 수집, 게임 상태 갱신을 담당
|
||
- 상태 갱신 후 각 플레이어의 `tea.Program.Send()`로 `StateUpdateMsg` 브로드캐스트
|
||
- 게임 상태는 `GameSession`이 단독 소유 (lock-free, 채널 기반)
|
||
- 플레이어의 TUI 모델은 수신한 `StateUpdateMsg`를 렌더링만 함 (읽기 전용 뷰)
|
||
|
||
### Deployment
|
||
|
||
- Docker 이미지 빌드, Mac Mini에서 `docker compose up`
|
||
- SSH 포트(2222)는 Docker에서 직접 호스트 포트로 노출 (Caddy 불필요 — SSH는 TCP라 L7 프록시 대상 아님)
|
||
- `ssh -p 2222 tolelom.xyz`
|
||
- 플레이어 식별: SSH 공개키 fingerprint 기반. 최초 접속 시 닉네임 설정, BoltDB에 저장
|
||
|
||
## Game Flow
|
||
|
||
```
|
||
SSH 접속 → 타이틀 → 로비 (방 생성/참가) → 클래스 선택 → 던전 탐험
|
||
→ 이벤트 (전투/상점/보물) → 다음 층 or 사망 → 결과 화면 → 랭킹
|
||
```
|
||
|
||
### Movement Model
|
||
|
||
- **파티 단위 이동**: 파티는 하나의 유닛으로 방-to-방(room-to-room) 이동
|
||
- 탐험 중에는 자유 이동 (턴 타이머 없음), 아무 파티원이 방향 선택 가능
|
||
- 전투방 진입 시 자동으로 턴 모드 전환
|
||
- 전투 중 이동은 턴 액션 소모 (이동 OR 공격, 둘 다는 불가)
|
||
- 전투 중 이동은 도주 판정 (50% 확률 성공, 실패 시 턴 낭비)
|
||
|
||
### Turn System (반실시간)
|
||
|
||
전투 중에만 활성화. 탐험 중에는 자유 이동.
|
||
|
||
1. 서버가 "행동 입력 대기" 상태 시작, 5초 타이머
|
||
2. 각 플레이어가 공격/스킬/아이템/도주/대기 중 선택
|
||
3. 타이머 종료 시 미입력 플레이어는 대기(방어 자세)
|
||
4. 모든 입력 수집 → 동시 실행 → 결과 렌더링
|
||
5. 적 턴 자동 실행 → 다음 턴
|
||
|
||
## Classes
|
||
|
||
| 클래스 | HP | ATK | DEF | 역할 | 특수 스킬 |
|
||
|--------|-----|-----|-----|------|-----------|
|
||
| 전사 | 120 | 12 | 8 | 탱커 | 도발 (적 어그로 2턴 집중) |
|
||
| 마법사 | 70 | 20 | 3 | 딜러 | 화염구 (전체 적 0.8x 데미지) |
|
||
| 힐러 | 90 | 8 | 5 | 서포터 | 치유 (아군 1명 HP 30 회복) |
|
||
| 도적 | 85 | 15 | 4 | 유틸 | 정찰 (다음 방 미리보기) |
|
||
|
||
## Combat System
|
||
|
||
- 파티 vs 몬스터 그룹 (1~5마리)
|
||
- 행동 선택: `[공격] [스킬] [아이템] [도주] [대기]`
|
||
- 타겟 지정: 방향키/번호로 적 선택
|
||
- 데미지 계산: `max(1, ATK × 스킬배율 - DEF) × 랜덤(0.85~1.15)`
|
||
- 협동 보너스: 같은 적을 2명 이상 단일 대상 공격 시, 2번째 이후 공격자에게 10% 추가 데미지 (DEF 감산 후 적용). AoE 스킬은 협동 보너스 트리거/대상에서 제외
|
||
|
||
### Monster Stats (기준)
|
||
|
||
| 몬스터 | HP | ATK | DEF | 등장 층 |
|
||
|--------|-----|-----|-----|---------|
|
||
| 슬라임 | 20 | 5 | 1 | 1~5 |
|
||
| 스켈레톤 | 35 | 10 | 4 | 3~10 |
|
||
| 오크 | 55 | 14 | 6 | 6~14 |
|
||
| 다크나이트 | 80 | 18 | 10 | 12~20 |
|
||
| 보스 (5층) | 150 | 15 | 8 | 5 |
|
||
| 보스 (10층) | 250 | 22 | 12 | 10 |
|
||
| 보스 (15층) | 400 | 30 | 16 | 15 |
|
||
| 최종 보스 | 600 | 40 | 20 | 20 |
|
||
|
||
일반 몬스터는 층마다 HP/ATK +15% 스케일링 (기준값 × 1.15^(현재층-등장시작층)).
|
||
|
||
### Monster AI
|
||
|
||
- 기본: 가장 가까운 플레이어 공격
|
||
- 도발 상태의 전사가 있으면 전사에게 집중 (2턴)
|
||
- HP 가장 낮은 아군이 있으면 30% 확률로 타겟 변경
|
||
- 보스: 매 3턴마다 전체 공격 (0.5x 데미지). 도발은 단일 대상 공격만 유도, AoE는 도발 무시
|
||
|
||
### Economy
|
||
|
||
| 항목 | 가격 |
|
||
|------|------|
|
||
| 몬스터 처치 골드 | 5~15 (층에 비례) |
|
||
| 소모품 (HP 포션) | 20 |
|
||
| 무기 (ATK+3~8) | 40~80 |
|
||
| 방어구 (DEF+2~5) | 30~60 |
|
||
| 유물 | 100~150 |
|
||
|
||
### Progression
|
||
|
||
- 레벨업 없음 (로그라이크)
|
||
- 성장은 아이템 의존 — 무기, 방어구, 소모품, 특수 유물
|
||
- 층마다 상점 등장 확률 30%, 골드로 아이템 구매
|
||
- 유물은 패시브 효과 (예: "적 처치 시 HP 5 회복")
|
||
|
||
## Dungeon Generation
|
||
|
||
- BSP(Binary Space Partitioning)로 층마다 맵 생성
|
||
- 한 층: 5~8개 방 + 복도로 연결
|
||
- 맵 크기: 약 60×30 타일
|
||
|
||
### Room Types
|
||
|
||
| 타입 | 확률 | 내용 |
|
||
|------|------|------|
|
||
| 일반 전투 | 45% | 몬스터 조우 |
|
||
| 보물방 | 15% | 아이템 획득 |
|
||
| 상점 | 10% | 골드로 아이템 구매 |
|
||
| 이벤트 | 15% | 랜덤 이벤트 (함정, 축복 등) |
|
||
| 빈 방 | 15% | 안전지대 |
|
||
|
||
보스방은 확률과 별개로 매 층 1개 고정 배치. 나머지 4~7개 방에 위 확률 적용.
|
||
|
||
### Field of View
|
||
|
||
- 전장의 안개(Fog of War) — 파티 주변만 보임
|
||
- 도적의 정찰 스킬로 시야 확장 가능
|
||
- 방문한 방은 희미하게 표시
|
||
|
||
## Rendering
|
||
|
||
```
|
||
┌─ Catacombs B3 ──────────── Party: 4/4 ─┐
|
||
│ │
|
||
│ ┌─────┐ ┌─────┐ │
|
||
│ │.....│───│..$..│ │
|
||
│ │..@..│ │.....│ ░░░░░ │
|
||
│ │..♦..│ └─────┘ ░░░░░ │
|
||
│ └──┬──┘ ░░░░░ │
|
||
│ │ │
|
||
│ ┌──┴──┐ ┌─────┐ │
|
||
│ │..D..│───│.....│ │
|
||
│ │.....│ │..?..│ │
|
||
│ └─────┘ └─────┘ │
|
||
│ │
|
||
├─────────────────────────────────────────┤
|
||
│ HP ██████░░ 65/100 │ 골드: 120 │
|
||
│ [1]이동 [2]공격 [3]스킬 [4]아이템 │
|
||
│ ⏱ 4.2s │
|
||
└─────────────────────────────────────────┘
|
||
```
|
||
|
||
`@` 플레이어 `♦` 아군 `D` 몬스터 `$` 아이템 `?` 이벤트 `░` 미탐사
|
||
|
||
최소 터미널 크기: 80×24. UI는 고정 너비 (80컬럼). 터미널이 작으면 접속 시 경고 표시.
|
||
|
||
## Difficulty & Balance
|
||
|
||
### Floor Scaling
|
||
|
||
- 몬스터 HP/ATK가 층마다 ~15% 증가
|
||
- 5층, 10층, 15층, 20층에 보스 등장
|
||
- 보스 처치 시 유물 확정 드랍
|
||
|
||
### Difficulty Curve
|
||
|
||
| 구간 | 층 | 특징 |
|
||
|------|-----|------|
|
||
| 초반 | 1~5 | 튜토리얼 느낌, 쉬운 적, 기본 아이템 수급 |
|
||
| 중반 | 6~12 | 역할 분담 중요해짐, 자원 관리 시작 |
|
||
| 후반 | 13~18 | 강적 등장, 유물 시너지로 승부 |
|
||
| 최종 | 19~20 | 최종 보스, 파티 연계 필수 |
|
||
|
||
### Death
|
||
|
||
- 개인 사망 → 해당 층에서는 관전 모드 (맵/채팅 가능, 행동 불가). 다음 층 시작 시 HP 30%로 부활
|
||
- 전멸 → 게임 오버, 결과 화면
|
||
- 세이브 없음 (로그라이크)
|
||
|
||
### Gold & Communication
|
||
|
||
- 골드는 개인 소유. 몬스터 처치 시 파티원 전원에게 동일 골드 지급
|
||
- 간이 채팅: 턴 입력 중 `/` 키로 한 줄 메시지 전송 (파티 전체에 표시)
|
||
|
||
### Disconnect Handling
|
||
|
||
- 접속 끊김 시 해당 플레이어는 자동 대기 모드 (매 턴 방어 자세)
|
||
- 60초 내 재접속 시 SSH 공개키로 식별하여 세션 복귀
|
||
- 60초 초과 시 파티에서 제거, 남은 인원으로 계속 진행
|
||
|
||
### Lobby
|
||
|
||
- 방 목록 표시 (방 이름, 현재 인원, 상태)
|
||
- 방 생성 시 4자리 코드 부여 (예: `ABCD`)
|
||
- 코드 입력으로 참가 또는 목록에서 선택
|
||
- 최소 1인으로 시작 가능. 솔로 시 몬스터 HP 50%로 감소 (의도적 하드모드는 아님)
|
||
- 동시 게임 세션 제한 없음 (서버 리소스 한도 내)
|
||
|
||
## Project Structure
|
||
|
||
```
|
||
catacombs/
|
||
├── main.go # 진입점, SSH 서버 시작
|
||
├── server/
|
||
│ └── ssh.go # Wish SSH 설정, 세션 관리
|
||
├── game/
|
||
│ ├── lobby.go # 로비, 방 생성/참가
|
||
│ ├── session.go # 게임 세션 (파티 상태 관리)
|
||
│ ├── turn.go # 턴 타이머, 입력 수집, 실행
|
||
│ └── event.go # 이벤트 처리 (전투, 상점, 보물 등)
|
||
├── dungeon/
|
||
│ ├── generator.go # BSP 던전 생성
|
||
│ ├── room.go # 방 타입, 내용물 배치
|
||
│ └── fov.go # 시야 계산
|
||
├── entity/
|
||
│ ├── player.go # 플레이어, 클래스, 인벤토리
|
||
│ ├── monster.go # 몬스터 정의, AI
|
||
│ └── item.go # 아이템, 유물
|
||
├── combat/
|
||
│ └── combat.go # 데미지 계산, 전투 로직
|
||
├── ui/
|
||
│ ├── model.go # Bubble Tea 메인 모델
|
||
│ ├── title.go # 타이틀 화면
|
||
│ ├── lobby_view.go # 로비 뷰
|
||
│ ├── game_view.go # 던전/전투 뷰
|
||
│ └── result_view.go # 결과 화면
|
||
├── store/
|
||
│ └── db.go # BoltDB 랭킹/통계
|
||
├── Dockerfile
|
||
└── docker-compose.yml
|
||
```
|