- 개요, 조사(BGA·한국 인기 보드게임·UI/UX), 아키텍처, 실시간 프로토콜, 안정성·보안, 계정, 로비·방, UI/UX, 데이터 모델, 게임 엔진, 테스트, 배포·운영, 로드맵(M0~M9), 사용자 결정 항목 - 게임별 규칙·엔진 설계·UI·테스트 체크리스트 26종 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
328 lines
28 KiB
Markdown
328 lines
28 KiB
Markdown
# 뱅! (`bang`)
|
|
|
|
> 마일스톤: M6 · 인원: 최소 4 ~ 최대 7명 · 예상 시간: 약 20~40분 · 난이도: 어려움
|
|
|
|
## 1. 개요
|
|
- 서부극 배경의 정체 숨기기 + 카드 전투 게임. 각자 비밀 역할(보안관/부관/무법자/배신자)을 받고, 보안관만 정체를 공개한다. "뱅!"(사격)과 "빗나감!"(회피)을 주고받으며 상대 팀을 제거한다.
|
|
- 한국에서는 보드게임 카페 정식 한글판(2000년대 후반~)으로 널리 알려진 대표 마피아류 카드 게임이다. 친구끼리 "누가 무법자냐"를 추리하는 맛이 핵심.
|
|
- 인원 근거: 원작(dV Giochi, 2002) 기본판 박스 표기 4~7인. 3인 규칙과 8인 규칙(확장 "닷지 시티")은 기본판 범위 밖이므로 이 문서에서는 다루지 않는다(12장 참고).
|
|
|
|
## 2. 모드와 옵션
|
|
| 옵션 키 | 설명 | 선택지 | 기본값 |
|
|
|---|---|---|---|
|
|
| `characterDraft` | 캐릭터 배정 방식 | `random`(1장 무작위) / `choose2`(2장 중 1장 선택) | `random` |
|
|
| `turnSeconds` | 내 턴 제한 시간(초) | 30 / 60 / 90 / 120 | 60 |
|
|
| `reactionSeconds` | 반응(빗나감!/맥주/결투 응수/잡화점 선택) 제한 시간(초) | 8 / 15 / 25 | 15 |
|
|
| `autoDefend` | 반응 시간 초과 시 가능한 방어 카드를 자동으로 사용 | on / off | on |
|
|
| `autoBarrel` | 술통/주르도네 판정을 묻지 않고 자동 실행 | on / off | on |
|
|
| `revealRoleOnDeath` | 사망 시 역할 공개(원작 규칙) | on 고정 | on |
|
|
| `showDistanceHelper` | 각 플레이어까지 거리와 사거리 내 여부 표시 | on / off | on |
|
|
| `beginnerHints` | 카드별 "지금 쓸 수 있는 이유/없는 이유" 툴팁 | on / off | on |
|
|
|
|
원작 규칙 자체를 바꾸는 하우스 룰은 7장에 따로 둔다.
|
|
|
|
## 3. 구성물
|
|
### 3.1 역할 카드
|
|
보안관 1, 부관 2, 무법자 3, 배신자 1 (총 7장, 인원에 맞게 사용).
|
|
|
|
### 3.2 캐릭터 16종
|
|
| 캐릭터(한글 표기 / 원어) | 생명 | 능력 |
|
|
|---|---|---|
|
|
| 바트 캐시디 (Bart Cassidy) | 4 | 생명을 1 잃을 때마다 덱에서 카드 1장을 뽑는다(잃은 생명 수만큼). |
|
|
| 블랙 잭 (Black Jack) | 4 | 1단계에서 두 번째로 뽑은 카드를 모두에게 공개하고, 그것이 하트 또는 다이아몬드면 1장을 더 뽑는다. |
|
|
| 캘러미티 자넷 (Calamity Janet) | 4 | 뱅!을 빗나감!으로, 빗나감!을 뱅!으로 쓸 수 있다. 빗나감!을 뱅!으로 쓰면 "턴당 뱅! 1회" 제한에 포함된다. 결투/인디언!에서도 빗나감!을 뱅!으로 낼 수 있다. |
|
|
| 엘 그링고 (El Gringo) | 3 | 다른 플레이어가 낸 카드 때문에 생명을 잃을 때마다(1점당 1회) 그 플레이어의 손패에서 무작위 1장을 가져온다. 다이너마이트 피해에는 발동하지 않는다. 상대 손패가 없으면 아무것도 없다. |
|
|
| 제시 존스 (Jesse Jones) | 4 | 1단계 첫 번째 카드를 덱 대신 원하는 플레이어의 손패에서 무작위로 가져올 수 있다. 두 번째 카드는 덱에서. |
|
|
| 주르도네 (Jourdonnais) | 4 | 항상 술통을 장착한 것으로 간주한다. 실제 술통도 있으면 판정을 두 번 할 수 있다. |
|
|
| 킷 칼슨 (Kit Carlson) | 4 | 1단계에서 덱 위 3장을 보고 2장을 고른 뒤 나머지 1장을 덱 맨 위에 덮어 둔다. |
|
|
| 럭키 듀크 (Lucky Duke) | 4 | "판정"(draw!)을 할 때마다 덱 위 2장을 공개하고 그중 1장을 결과로 고른다. 두 장 모두 버림 더미로. |
|
|
| 폴 리그레트 (Paul Regret) | 3 | 항상 머스탱을 장착한 것으로 간주(남이 볼 때 거리 +1). 실제 머스탱이 있으면 +2. |
|
|
| 페드로 라미레스 (Pedro Ramirez) | 4 | 1단계 첫 번째 카드를 버림 더미 맨 위에서 가져올 수 있다. 두 번째는 덱에서. |
|
|
| 로즈 둘란 (Rose Doolan) | 4 | 항상 조준경을 장착한 것으로 간주(내가 볼 때 거리 -1). 실제 조준경이 있으면 -2. |
|
|
| 시드 케첨 (Sid Ketchum) | 4 | 언제든(자기 턴, 반응 중, 빈사 상태 포함) 손패 2장을 버려 생명 1을 회복할 수 있다. 여러 번 가능. 최대 생명을 넘을 수 없다. 2인 남았을 때도 사용 가능. |
|
|
| 슬랩 더 킬러 (Slab the Killer) | 4 | 그가 쏜 뱅!을 막으려면 빗나감! 효과가 2번 필요하다(술통 성공 1회 = 1번). 개틀링에는 적용되지 않는다. |
|
|
| 수지 라파예트 (Suzy Lafayette) | 4 | 손패가 0장이 되는 순간 덱에서 1장을 뽑는다. |
|
|
| 벌처 샘 (Vulture Sam) | 4 | 다른 캐릭터가 제거되면 그 플레이어의 손패와 장착 카드를 모두 자기 손패로 가져온다. |
|
|
| 윌리 더 키드 (Willy the Kid) | 4 | 자기 턴에 뱅!을 몇 장이든 낼 수 있다. |
|
|
|
|
### 3.3 놀이 카드 80장 (무늬·숫자 포함, "판정"에 사용)
|
|
갈색 테두리 = 즉시 효과 후 버림. 파란 테두리 = 자기(또는 대상) 앞에 장착되어 계속 효과.
|
|
무늬 기호: ♠ 스페이드, ♥ 하트, ♦ 다이아몬드, ♣ 클럽. 숫자: 2~10, J, Q, K, A.
|
|
|
|
| 카드(한글 / 원어) | 종류 | 장수 | 각 장의 무늬·숫자 |
|
|
|---|---|---|---|
|
|
| 뱅! (BANG!) | 갈색 | 25 | A♠ / 2♦ 3♦ 4♦ 5♦ 6♦ 7♦ 8♦ 9♦ 10♦ J♦ Q♦ K♦ A♦ / 2♣ 3♣ 4♣ 5♣ 6♣ 7♣ 8♣ 9♣ / Q♥ K♥ A♥ |
|
|
| 빗나감! (Missed!) | 갈색 | 12 | 10♣ J♣ Q♣ K♣ A♣ / 2♠ 3♠ 4♠ 5♠ 6♠ 7♠ 8♠ |
|
|
| 맥주 (Beer) | 갈색 | 6 | 6♥ 7♥ 8♥ 9♥ 10♥ J♥ |
|
|
| 패닉! (Panic!) | 갈색 | 4 | J♥ Q♥ A♥ 8♦ |
|
|
| 캣 벌루 (Cat Balou) | 갈색 | 4 | K♥ 9♦ 10♦ J♦ |
|
|
| 결투 (Duel) | 갈색 | 3 | Q♦ J♠ 8♣ |
|
|
| 잡화점 (General Store) | 갈색 | 2 | 9♣ Q♠ |
|
|
| 인디언! (Indians!) | 갈색 | 2 | K♦ A♦ |
|
|
| 역마차 (Stagecoach) | 갈색 | 2 | 9♠ 9♠ |
|
|
| 개틀링 (Gatling) | 갈색 | 1 | 10♥ |
|
|
| 살롱 (Saloon) | 갈색 | 1 | 5♥ |
|
|
| 웰스 파고 (Wells Fargo) | 갈색 | 1 | 3♥ |
|
|
| 술통 (Barrel) | 파란색 | 2 | Q♠ K♠ |
|
|
| 머스탱 (Mustang) | 파란색 | 2 | 8♥ 9♥ |
|
|
| 조준경 (Scope / Appaloosa) | 파란색 | 1 | A♠ |
|
|
| 감옥 (Jail) | 파란색 | 3 | J♠ 10♠ 4♥ |
|
|
| 다이너마이트 (Dynamite) | 파란색 | 1 | 2♥ |
|
|
| 볼캐닉 (Volcanic) — 무기, 사거리 1 | 파란색 | 2 | 10♠ 10♣ |
|
|
| 스코필드 (Schofield) — 무기, 사거리 2 | 파란색 | 3 | J♣ Q♣ K♠ |
|
|
| 레밍턴 (Remington) — 무기, 사거리 3 | 파란색 | 1 | K♣ |
|
|
| 카빈 (Rev. Carabine) — 무기, 사거리 4 | 파란색 | 1 | A♣ |
|
|
| 윈체스터 (Winchester) — 무기, 사거리 5 | 파란색 | 1 | 8♠ |
|
|
|
|
합계: 갈색 63장 + 파란색 17장 = 80장. (장수 합계는 테스트로 검증한다. 10장 참고)
|
|
기본 무기 "콜트 45"(사거리 1)는 카드가 아니라 무기가 없을 때의 기본값이다.
|
|
|
|
## 4. 준비(셋업)
|
|
1. 인원별 역할 구성(무작위로 비공개 배정, 보안관만 공개):
|
|
|
|
| 인원 | 보안관 | 부관 | 무법자 | 배신자 |
|
|
|---|---|---|---|---|
|
|
| 4 | 1 | 0 | 2 | 1 |
|
|
| 5 | 1 | 1 | 2 | 1 |
|
|
| 6 | 1 | 1 | 3 | 1 |
|
|
| 7 | 1 | 2 | 3 | 1 |
|
|
|
|
2. 좌석 순서는 방 입장 순서를 RNG로 섞어서 결정한다(시계 방향 = 배열 순서).
|
|
3. 캐릭터: `random`이면 16장 중 1장씩 무작위, `choose2`면 2장씩 보여 주고 선택(제한 시간 초과 시 첫 번째).
|
|
4. 최대 생명 = 캐릭터 생명, 보안관은 +1. 현재 생명 = 최대 생명.
|
|
5. 80장 덱을 섞고 각자 현재 생명 수만큼 손패로 받는다.
|
|
6. 보안관이 첫 턴을 가진다. 진행은 시계 방향.
|
|
|
|
## 5. 진행 규칙
|
|
### 5.1 용어
|
|
- **판정(draw!)**: 덱 맨 위 1장을 공개하고 무늬/숫자를 확인한 뒤 버림 더미로 보낸다. 럭키 듀크는 2장 공개 후 선택.
|
|
- **거리**: 살아 있는 플레이어만 세어, 좌석 기준 시계 방향과 반시계 방향 중 짧은 쪽 칸 수.
|
|
- `거리(A→B) = max(1, 좌석거리 + (B의 머스탱 ? 1 : 0) + (B가 폴 리그레트 ? 1 : 0) - (A의 조준경 ? 1 : 0) - (A가 로즈 둘란 ? 1 : 0))`
|
|
- **사거리**: 장착 무기의 숫자(없으면 1). 뱅!은 `거리(A→B) <= 사거리`인 대상에게만.
|
|
- 패닉!은 무기와 무관하게 `거리(A→B) <= 1` 대상에게만. 캣 벌루·결투는 거리 무관.
|
|
|
|
예시(5인, 살아 있는 순서 A-B-C-D-E): A→C 좌석거리 = min(2, 3) = 2. C가 머스탱 장착 시 3. A가 조준경 장착 시 2. A가 레밍턴(3)이면 사격 가능, 스코필드(2)면 불가. B가 사망하면 A→C 좌석거리는 1이 된다.
|
|
|
|
### 5.2 턴 구조
|
|
턴 시작 시 순서대로:
|
|
1. **다이너마이트 판정**(장착 중일 때): 결과가 ♠2~♠9면 폭발 — 생명 3 손실, 다이너마이트 버림. 아니면 다이너마이트를 왼쪽(시계 방향 다음)의 살아 있는 플레이어 앞으로 넘긴다. 폭발로 죽으면 턴 종료.
|
|
2. **감옥 판정**(장착 중일 때): ♥면 탈출 — 감옥 버리고 정상 진행. 아니면 감옥 버리고 이번 턴 전체를 건너뛴다(카드도 뽑지 않음).
|
|
3. **1단계: 뽑기** — 덱에서 2장. 캐릭터 예외: 블랙 잭, 제시 존스, 킷 칼슨, 페드로 라미레스.
|
|
4. **2단계: 카드 내기** — 원하는 만큼, 원하는 순서로. 제한:
|
|
- 뱅!은 턴당 1장(볼캐닉 장착 또는 윌리 더 키드는 무제한).
|
|
- 같은 이름의 파란 카드는 한 사람 앞에 1장까지. 무기는 1개만(새 무기를 내면 기존 무기는 버림).
|
|
- 빗나감!은 자기 턴에 능동적으로 낼 수 없다(반응 전용). 단 캘러미티 자넷은 빗나감!을 뱅!으로 낼 수 있다.
|
|
- 맥주는 생명이 최대치이거나 살아 있는 플레이어가 2명뿐이면 효과가 없으므로 내지 못하게 막는다(사유 표시).
|
|
5. **3단계: 버리기** — 손패가 현재 생명보다 많으면 초과분을 골라 버린다. 그 후 턴 종료.
|
|
|
|
### 5.3 카드별 효과와 합법 조건
|
|
| 카드 | 대상 | 효과 / 조건 |
|
|
|---|---|---|
|
|
| 뱅! | 다른 1명, 사거리 내 | 대상은 빗나감!(슬랩 상대 시 2장)을 내거나 술통 판정 성공 시 회피, 아니면 생명 1 손실. |
|
|
| 빗나감! | 반응 전용 | 뱅!·개틀링 1발을 무효화. |
|
|
| 맥주 | 자신 | 생명 +1(최대 초과 불가). 2명 남으면 무효(사용 불가). 자기 턴 외에는 빈사(생명 0 이하) 때만 사용 가능. |
|
|
| 살롱 | 전원 | 살아 있는 모든 플레이어 생명 +1(최대 초과 불가). 2명 남아도 유효. |
|
|
| 역마차 | 자신 | 덱에서 2장. |
|
|
| 웰스 파고 | 자신 | 덱에서 3장. |
|
|
| 잡화점 | 전원 | 살아 있는 인원 수만큼 덱에서 공개. 낸 사람부터 시계 방향으로 1장씩 고른다. |
|
|
| 패닉! | 거리 1 이내 다른 1명 | 대상의 손패 무작위 1장 또는 장착 카드 지정 1장을 내 손패로. |
|
|
| 캣 벌루 | 다른 1명(거리 무관) | 대상의 손패 무작위 1장 또는 장착 카드 지정 1장을 버림. |
|
|
| 결투 | 다른 1명(거리 무관) | 대상부터 번갈아 뱅!을 1장씩 버린다. 먼저 못 내거나 안 낸 쪽이 생명 1 손실. 결투 중 뱅!은 턴당 제한에 포함 안 됨. 빗나감!/술통 불가. |
|
|
| 인디언! | 다른 모두 | 각자 뱅! 1장을 버리거나 생명 1 손실. 빗나감!/술통 불가. |
|
|
| 개틀링 | 다른 모두 | 각자에게 뱅!(거리 무관). 빗나감!/술통 가능. 턴당 뱅! 제한에 포함 안 됨. 슬랩 능력 미적용. |
|
|
| 술통 | 자신 장착 | 뱅!/개틀링 대상이 되면 판정: ♥면 빗나감! 1회 효과. |
|
|
| 머스탱 | 자신 장착 | 남이 나를 볼 때 거리 +1. |
|
|
| 조준경 | 자신 장착 | 내가 남을 볼 때 거리 -1. |
|
|
| 감옥 | 보안관 제외 다른 1명, 이미 감옥 없는 대상 | 대상의 다음 턴 시작에 판정. 감옥에 갇혀 있어도 뱅! 등의 대상이 되며 반응도 가능. |
|
|
| 다이너마이트 | 자신 장착 | 5.2의 1번. 폭발 피해는 "누가 낸 카드"가 아니므로 처치 보상/엘 그링고 없음. |
|
|
| 무기 | 자신 장착 | 사거리 변경. 볼캐닉은 사거리 1 + 뱅! 무제한. |
|
|
|
|
패닉!/캣 벌루 대상은 "다른 플레이어"로 한정한다(자기 자신 불가, 결정 사항).
|
|
|
|
### 5.4 반응 창(Reaction window)
|
|
턴 진행은 다음 반응이 모두 끝날 때까지 멈춘다. 각 반응에는 `reactionSeconds` 타이머가 있다.
|
|
- **뱅! 반응**: 대상에게 `missedNeeded`(기본 1, 슬랩의 뱅!은 2). 순서: (1) 술통 판정(실제 술통, 주르도네 능력 각각 1회, `autoBarrel`이면 자동) → 성공마다 needed -1. (2) 남은 needed만큼 빗나감!(캘러미티는 뱅!도) 제출 또는 포기. 포기/시간 초과 시 생명 1 손실.
|
|
- 슬랩 상대로 빗나감!이 1장뿐이면 내 봐야 소용없으므로 UI에서 "막을 수 없음"을 안내하되 낼 수는 있다(효과 없음 → 실제로는 막지 못함). 엔진은 needed를 모두 채울 때만 카드 제출을 받는다(부분 제출 금지, 결정 사항).
|
|
- **개틀링 / 인디언!**: 대상 전원에게 동시에 반응 창을 연다. 각자의 응답은 도착 순서대로 개별 처리된다.
|
|
- **결투**: 하나의 반응이 번갈아 넘어간다. 현재 차례만 active. 뱅! 1장 제출 시 상대에게 넘어가고, 포기/시간 초과 시 그 사람이 생명 1 손실, 결투 종료. 피해의 원인 제공자는 결투 상대(처치 보상 계산용).
|
|
- **잡화점**: 선택자가 1명씩 차례로 active.
|
|
- **빈사(dying)**: 생명이 0 이하가 되면 즉시 빈사 반응. 맥주(2명 남았으면 불가)나 시드 케첨 능력으로 생명을 1 이상으로 만들면 생존. 필요한 맥주 수 = `1 - 현재생명`. 못 하면 제거.
|
|
|
|
### 5.5 생명 손실 처리 순서(결정 사항)
|
|
1. 생명 감소 → 2. 빈사 판정/반응 → 3. 생존 시에만 바트 캐시디/엘 그링고 능력 발동 → 4. 수지 라파예트 확인(어느 시점이든 손패 0장이 되면 즉시 1장).
|
|
원작은 빈사와 능력 발동 순서를 명확히 정하지 않아, "죽은 사람은 능력을 쓰지 않는다"로 정한다. 7장의 `drawBeforeDeath` 옵션으로 반대 해석(먼저 뽑고 그 카드로 살 수 있음)을 고를 수 있게 한다.
|
|
|
|
### 5.6 제거(사망)
|
|
1. 역할 공개.
|
|
2. 보상/벌칙: 처치자가 있고 제거된 사람이 무법자면 처치자(무법자여도)가 덱에서 3장. 보안관이 부관을 처치하면 보안관은 손패와 장착 카드를 모두 버린다.
|
|
3. 제거된 사람의 손패와 장착 카드: 벌처 샘이 살아 있으면 그의 손패로, 아니면 버림 더미로.
|
|
4. 승리 조건 확인(6장). 끝났으면 즉시 종료.
|
|
5. 현재 턴의 플레이어가 죽었으면 남은 반응을 정리하고 다음 살아 있는 플레이어의 턴으로.
|
|
|
|
처치자: 뱅!/개틀링/인디언!/결투를 낸 사람(결투는 승자). 다이너마이트는 처치자 없음.
|
|
|
|
### 5.7 덱 소진
|
|
덱이 비면 버림 더미 전체를 섞어 새 덱으로 만든다. 둘 다 비었으면 뽑기는 그냥 생략한다(드묾).
|
|
|
|
## 6. 승패와 점수 계산
|
|
- 보안관 팀(보안관+부관) 승리: 무법자 전원과 배신자가 제거됨.
|
|
- 무법자 팀 승리: 보안관이 제거됨. 단 그때 살아 있는 사람이 배신자 혼자뿐이면 배신자 승리.
|
|
- 배신자 승리: 배신자가 마지막 생존자(보안관을 마지막에 처치).
|
|
- 승리는 팀 단위: 이미 죽은 같은 팀원도 승리.
|
|
- 예: 보안관·부관·배신자 생존 상태에서 배신자가 보안관을 쏴 죽이면 → 배신자 혼자가 아니므로 무법자 승리.
|
|
- 동점/무승부 없음. 연쇄 사망(개틀링 등)은 응답 도착 순서대로 처리하며, 각 사망 직후 승리 판정.
|
|
- 점수(방 내 기록용): 승리 팀 각 1점. 순위 표시는 승리자 → 패배자(사망 순서 역순).
|
|
|
|
## 7. 지역 룰 / 하우스 룰 (옵션으로 켜고 끄기)
|
|
| 옵션 키 | 내용 | 기본값 |
|
|
|---|---|---|
|
|
| `drawBeforeDeath` | 바트 캐시디/엘 그링고가 빈사 판정 전에 카드를 받아 그 카드로 살아날 수 있음 | off |
|
|
| `beerAtFullHealth` | 생명 최대치에서도 맥주를 낼 수 있음(효과 없음, 버리기 용도) | off |
|
|
| `selfTargetCatBalou` | 캣 벌루/패닉!을 자기 장착 카드에 사용 가능(예: 자기 다이너마이트 제거) | off |
|
|
| `deputyCount7` | 7인에서 부관 2 대신 부관 1 + 무법자 4 | off |
|
|
|
|
확장 "닷지 시티"(8인, 녹색 카드, 캐릭터 15종 추가)는 향후 별도 옵션으로 추가 예정. 이번 범위 아님.
|
|
|
|
## 8. 엔진 설계
|
|
### 8.1 상태(State)
|
|
```ts
|
|
type Suit = 'S' | 'H' | 'D' | 'C';
|
|
type Rank = 2|3|4|5|6|7|8|9|10|'J'|'Q'|'K'|'A';
|
|
type CardKind = 'bang'|'missed'|'beer'|'saloon'|'stagecoach'|'wellsFargo'|'generalStore'|'panic'|'catBalou'
|
|
|'duel'|'indians'|'gatling'|'barrel'|'mustang'|'scope'|'jail'|'dynamite'
|
|
|'volcanic'|'schofield'|'remington'|'carabine'|'winchester';
|
|
interface Card { id: number; kind: CardKind; suit: Suit; rank: Rank } // id 0..79 고정
|
|
type Role = 'sheriff'|'deputy'|'outlaw'|'renegade';
|
|
type CharacterId = 'bart'|'blackJack'|'calamity'|'elGringo'|'jesse'|'jourdonnais'|'kit'|'lucky'
|
|
|'paul'|'pedro'|'rose'|'sid'|'slab'|'suzy'|'vulture'|'willy';
|
|
|
|
interface PlayerState {
|
|
id: PlayerId; seat: number; role: Role; character: CharacterId;
|
|
characterOffer?: CharacterId[]; // choose2 단계
|
|
maxLife: number; life: number; alive: boolean;
|
|
hand: number[]; // 카드 id
|
|
inPlay: number[]; // 장착 카드 id (무기 포함)
|
|
}
|
|
|
|
type Reaction =
|
|
| { kind: 'bang'; target: PlayerId; source: PlayerId; via: 'bang'|'gatling'; needed: number; barrelTried: boolean; jourTried: boolean; deadline: number }
|
|
| { kind: 'indians'; target: PlayerId; source: PlayerId; deadline: number }
|
|
| { kind: 'duel'; actor: PlayerId; other: PlayerId; deadline: number }
|
|
| { kind: 'store'; picker: PlayerId; order: PlayerId[]; revealed: number[]; deadline: number }
|
|
| { kind: 'dying'; player: PlayerId; killer: PlayerId | null; deadline: number }
|
|
| { kind: 'luckyPick'; player: PlayerId; purpose: 'dynamite'|'jail'|'barrel'; options: [number, number]; deadline: number }
|
|
| { kind: 'kitKeep'; player: PlayerId; options: [number, number, number]; deadline: number }
|
|
| { kind: 'choose2'; player: PlayerId; deadline: number };
|
|
|
|
interface BangState {
|
|
options: BangOptions;
|
|
rng: RngState;
|
|
players: PlayerState[]; // 좌석 순
|
|
deck: number[]; // 맨 위 = 배열 끝
|
|
discard: number[]; // 맨 위 = 배열 끝
|
|
turn: { player: PlayerId; phase: 'setup'|'start'|'draw'|'play'|'discard'; bangsPlayed: number; deadline: number; blackJackReveal?: number };
|
|
reactions: Reaction[]; // 비어 있지 않으면 턴 진행 정지
|
|
lastCheck?: { player: PlayerId; cardIds: number[]; purpose: string; success: boolean }; // UI 표시용(공개 정보)
|
|
winner: null | 'law' | 'outlaws' | 'renegade';
|
|
deathOrder: PlayerId[];
|
|
log: PublicLogEntry[]; // 공개 로그(비밀 카드 내용 없음)
|
|
}
|
|
```
|
|
|
|
### 8.2 액션
|
|
| type | payload | 누가 / 언제 | 검증 조건 |
|
|
|---|---|---|---|
|
|
| `pickCharacter` | `{ character }` | choose2 단계, 본인 | 제안 2장 중 하나 |
|
|
| `draw` | `{ jesseFrom?: PlayerId; pedroDiscard?: boolean }` | 현재 플레이어, phase=draw | 제시는 손패 1장 이상인 다른 생존자, 페드로는 버림 더미 비어 있지 않음, 해당 캐릭터만 |
|
|
| `kitKeep` | `{ keep: [id, id] }` | 킷 칼슨, kitKeep 반응 | options 중 서로 다른 2장 |
|
|
| `luckyPick` | `{ cardId }` | 럭키 듀크, luckyPick 반응 | options 중 1장 |
|
|
| `play` | `{ cardId; as?: 'bang'|'missed'; target?: PlayerId; targetCard?: number | 'hand' }` | 현재 플레이어, phase=play, reactions 비어 있음 | 손패에 있음 / 카드별 대상·거리·사거리 / 뱅! 횟수 / 파란 카드 중복 / 감옥은 보안관 불가 / 맥주 조건 / `as`는 캘러미티만 |
|
|
| `respond` | `{ cardIds: number[] }` | 반응 대상자 | bang: 빗나감!(캘러미티는 뱅!도) 정확히 needed장 / indians: 뱅! 1장 / duel: 뱅! 1장(캘러미티는 빗나감!도) / dying: 맥주 정확히 필요한 수, 2명 남았으면 불가 |
|
|
| `useBarrel` | `{}` | 뱅! 반응 대상, autoBarrel off | 술통 또는 주르도네, 해당 판정 미사용 |
|
|
| `takeHit` | `{}` | bang/indians/duel 반응 대상 | 해당 반응의 active |
|
|
| `giveUp` | `{}` | dying 반응 대상 | 즉시 제거 |
|
|
| `storePick` | `{ cardId }` | store 반응의 picker | revealed 안에 있음 |
|
|
| `sidHeal` | `{ cardIds: [id, id] }` | 시드 케첨, 자기 턴 play 단계 또는 자신이 대상인 반응 중 | 손패 2장, 생명 < 최대 |
|
|
| `endPlay` | `{}` | 현재 플레이어, phase=play, reactions 비어 있음 | 손패 > 생명이면 phase=discard로, 아니면 턴 종료 |
|
|
| `discard` | `{ cardIds }` | 현재 플레이어, phase=discard | 개수 = 손패 - 생명 |
|
|
|
|
`play`의 세부 검증 예: 뱅!은 `target != actor && alive && distance(actor, target) <= range(actor) && (bangsPlayed < 1 || 볼캐닉 || 윌리)`. 거부 사유 예: "사거리가 닿지 않습니다(거리 3, 사거리 2)", "이번 턴에는 뱅!을 이미 썼습니다", "보안관은 감옥에 넣을 수 없습니다".
|
|
|
|
### 8.3 공개/비공개 정보 (view)
|
|
- 모두에게 공개: 좌석, 캐릭터, 생명/최대 생명, 손패 장수, 장착 카드, 보안관 정체, 사망자 역할, 덱 장수, 버림 더미 전체, 판정 결과, 잡화점 공개 카드, 블랙 잭의 공개 카드, 반응 진행 상황(누가 무엇을 기다리는지), 공개 로그.
|
|
- 본인에게만: 자기 역할, 자기 손패 내용, 킷 칼슨이 본 3장, choose2 후보.
|
|
- 비공개(누구에게도 보내지 않음): 덱 순서, 다른 사람 손패 내용, 다른 사람 역할(사망 전), RNG 상태.
|
|
- 패닉!/캣 벌루/제시/엘 그링고의 "무작위 손패" 선택은 서버 RNG로 하므로 클라이언트에 손패 순서/인덱스를 노출하지 않는다. 가져간 카드 내용은 가져간 사람과 잃은 사람에게만 보이고, 캣 벌루로 버린 카드는 버림 더미에 공개.
|
|
- 관전자(viewer=null): 모두 공개 정보만. 게임 종료 후 전체 공개.
|
|
|
|
### 8.4 랜덤 요소 (시드 RNG 사용 지점)
|
|
좌석 섞기, 역할 배정, 캐릭터 배정/후보, 덱 셔플(시작 및 버림 더미 재사용), 패닉!/캣 벌루/제시/엘 그링고의 무작위 손패 선택, 시간 초과 시 무작위 버리기.
|
|
|
|
### 8.5 타이머·시간 초과·연결 끊김 시 자동 행동
|
|
- `deadline`: 반응이 있으면 가장 이른 반응 마감, 없으면 턴 마감.
|
|
- `onTimeout(player)`:
|
|
- choose2 → 첫 후보. kitKeep → 위 2장. luckyPick → 성공하는 카드 우선(없으면 첫 장).
|
|
- draw 단계 → 기본 `draw`(능력 미사용).
|
|
- play 단계 → `endPlay`. discard 단계 → 초과분을 RNG로 골라 버림.
|
|
- bang 반응 → `autoDefend`면 술통 → 필요한 빗나감! 제출, 불가면 `takeHit`. off면 `takeHit`.
|
|
- indians/duel → `autoDefend`면 뱅! 1장, 없으면 `takeHit`.
|
|
- dying → 맥주로 살 수 있으면 자동 사용(시드는 손패 2장씩 자동 사용), 아니면 `giveUp`.
|
|
- store → revealed[0].
|
|
- 연결 끊김 120초 이상: 이후 모든 차례를 즉시 onTimeout으로 처리(봇 모드). 재접속 시 해제.
|
|
|
|
### 8.6 종료 조건과 결과(GameResult)
|
|
```ts
|
|
interface BangResult {
|
|
winnerTeam: 'law' | 'outlaws' | 'renegade';
|
|
players: { id: PlayerId; role: Role; character: CharacterId; alive: boolean; won: boolean; deathOrder: number | null }[];
|
|
ranking: PlayerId[]; // 승자(생존자 우선) → 패자(늦게 죽은 순)
|
|
summary: string; // 예: "무법자 승리! 보안관이 3라운드에 쓰러졌습니다."
|
|
}
|
|
```
|
|
|
|
## 9. UI/UX
|
|
- 모바일 세로: 상단 원형 테이블(플레이어 아바타 + 생명 탄환 아이콘 + 장착 카드 축소판 + 손패 장수), 하단 손패 가로 스크롤(카드 높이 120px 이상), 그 사이 행동 버튼(턴 종료 등 48px 이상).
|
|
- 카드를 탭하면 쓸 수 있는 대상 플레이어가 초록 테두리로 강조되고 사거리 밖은 회색 + "거리 3 / 사거리 2" 표시. 쓸 수 없는 카드는 흐리게 + 이유 툴팁.
|
|
- 반응 창: 화면 중앙 큰 모달 "뱅! 공격을 받았습니다 — [빗나감! 내기] [맞기]" + 원형 타이머. 슬랩 상대 시 "빗나감! 2장 필요" 문구.
|
|
- 판정 애니메이션: 카드 뒤집기 1초, 성공/실패 색상.
|
|
- 역할 확인: 길게 누르면 내 역할 카드가 보이는 방식(옆 사람 훔쳐보기 방지).
|
|
- "규칙 보기": 카드 도감(카드 탭 시 효과 설명), 역할별 승리 조건 요약. 초보자 힌트 on이면 "부관은 보안관을 지켜야 해요" 같은 역할 팁.
|
|
- PC: 테이블 중앙, 손패 하단, 우측 로그 패널.
|
|
|
|
## 10. 테스트 체크리스트
|
|
- [ ] 덱 생성: 80장, 카드 종류별 장수와 무늬·숫자가 3.3 표와 정확히 일치.
|
|
- [ ] 4/5/6/7인 역할 분배가 표와 일치하고 보안관 생명 +1, 시작 손패 = 생명.
|
|
- [ ] 거리: 5인에서 중간 1명 사망 후 거리 감소, 머스탱+폴 리그레트 = +2, 조준경+로즈 = -2, 최소 1.
|
|
- [ ] 뱅! 1회 제한: 두 번째 뱅! 거부. 볼캐닉/윌리는 허용. 캘러미티의 빗나감!-as-뱅!도 1회에 포함.
|
|
- [ ] 슬랩의 뱅!: 빗나감! 1장 제출 거부, 술통 성공 1 + 빗나감! 1로 회피 성공. 슬랩의 개틀링은 1장으로 회피.
|
|
- [ ] 주르도네 + 술통: 판정 2회, 럭키 듀크가 아닌 경우 각 1장씩 공개.
|
|
- [ ] 다이너마이트: ♠2~♠9 폭발(3 피해), ♠10/♥ 등은 다음 생존자로 이동. 다이너마이트 판정 후 감옥 판정 순서. 폭발로 무법자 사망 시 3장 보상 없음.
|
|
- [ ] 감옥: 보안관 대상 거부, ♥ 탈출 시 정상 턴, 실패 시 1단계 포함 턴 전체 건너뜀.
|
|
- [ ] 맥주: 2명 남았을 때 빈사에서 사용 불가 → 제거. 생명 -1 상태 빈사에서 맥주 2장 필요. 살롱은 2명에서도 회복.
|
|
- [ ] 결투 왕복: A가 B에게 결투, B 뱅! → A 뱅! → B 포기 → B 생명 1 손실, 처치자 A. A가 먼저 포기하면 A 손실, 처치자 B.
|
|
- [ ] 인디언!/개틀링 동시 반응: 3명이 서로 다른 순서로 응답, 도착 순서대로 처리, 모두 끝나기 전 현재 플레이어 `play` 거부.
|
|
- [ ] 잡화점: 생존자 수만큼 공개, 낸 사람부터 시계 방향 선택, 시간 초과 시 첫 장 자동 선택.
|
|
- [ ] 처치 보상/벌칙: 무법자 처치 시 처치자 3장(처치자가 무법자여도). 보안관이 부관 처치 시 보안관 손패·장착 전부 버림.
|
|
- [ ] 벌처 샘: 사망자 카드 전부 손패로. 보안관-부관 벌칙과 동시 발생 시 각각 정상 처리.
|
|
- [ ] 승리 판정: 보안관·부관·배신자 생존 중 보안관 사망 → 무법자 승리. 배신자 1대1에서 보안관 처치 → 배신자 승리.
|
|
- [ ] 수지 라파예트: 결투 중 마지막 뱅!을 내 손패 0 → 즉시 1장.
|
|
- [ ] 엘 그링고: 뱅!으로 1 피해 시 공격자 손패 무작위 1장, 다이너마이트 피해 시 없음, 공격자 손패 0이면 없음.
|
|
- [ ] 시간 초과: 턴 중 무응답 → endPlay → 손패 초과분 자동 버림. 반응 무응답 + autoDefend on → 빗나감! 자동.
|
|
- [ ] 연결 끊김 120초 → 봇 모드, 재접속 시 복귀, 그동안 상태 일관성 유지.
|
|
- [ ] 비공개 정보 누출 검사: 모든 플레이어/관전자 view를 직렬화해 다른 사람 손패 카드 id, 생존자 역할(보안관·본인 제외), 덱 순서, 킷 칼슨 후보가 포함되지 않는지 자동 검사.
|
|
- [ ] 같은 시드 + 같은 액션 로그 재생 시 최종 상태 동일.
|
|
|
|
## 11. 참고 자료
|
|
- dV Giochi, BANG! 공식 규칙서(영문, 4th edition) — https://www.dvgiochi.com/giochi/bang/
|
|
- 나무위키 "뱅!(보드게임)" — https://namu.wiki/w/뱅!
|
|
- BoardGameGeek, BANG! — https://boardgamegeek.com/boardgame/3955/bang
|
|
- BGG 스레드 "Card by Card Explanations for BANG!" — https://boardgamegeek.com/thread/668345/card-by-card-explanations-for-bang
|
|
- UltraBoardGames, BANG! 카드 설명 — https://www.ultraboardgames.com/bang/cards.php
|
|
- 오픈소스 구현 albertoxamin/bang (덱 무늬·숫자 및 캐릭터 생명 교차 확인) — https://github.com/albertoxamin/bang/blob/HEAD/backend/bang/cards.py
|
|
|
|
## 12. 메모 (상표·법적 주의 등)
|
|
- "BANG!"은 dV Giochi의 상표이며, 카드 일러스트·캐릭터 이름(바트 캐시디 등)도 저작물이다. 게임 규칙 자체는 보호 대상이 아니지만 이름·그림을 그대로 쓰면 안 된다.
|
|
- 표시 이름 후보(사용자 선택): "황야의 총잡이", "서부 결투", "보안관과 무법자". 캐릭터는 자체 이름과 능력 설명으로 대체(능력 로직은 그대로 두고 표시 이름만 교체하는 매핑 테이블 사용).
|
|
- 무기 이름 Winchester/Remington/Colt 등은 실존 총기 회사 상표이므로 "권총(사거리 1)", "장총(사거리 3)" 같은 일반 명칭 사용 권장.
|
|
- 아동 이용자 고려: 총기·사망 표현을 순화하는 "어린이 표현 모드"(예: 물총/탈락) 검토. 도박 요소 없음.
|