From 35664f089af93287a5769201c3b9d5d0c873e6b3 Mon Sep 17 00:00:00 2001 From: swrring Date: Mon, 12 Oct 2026 11:19:13 +0900 Subject: [PATCH] =?UTF-8?q?=EB=A1=9C=EC=BB=AC=20PC=20=EC=9D=B4=EA=B4=80=20?= =?UTF-8?q?=E2=80=94=20=EB=AF=B8=EC=BB=A4=EB=B0=8B=20=EC=9E=91=EC=97=85?= =?UTF-8?q?=EB=AC=BC=20=EC=A0=84=EC=B2=B4=20=EB=8F=99=EA=B8=B0=ED=99=94=20?= =?UTF-8?q?(PD=20=EC=A7=80=EC=8B=9C)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- 공유/PD_지시_트래킹/기획팀_PD_지시_로그.md | 2 + 프로젝트/EerieVillage/기획/_build_docx.js | 962 +++++++ .../EerieVillage/기획/_build_skill_pptx.py | 2292 +++++++++++++++++ .../기획/기묘한고을_초기기획서_v1.docx | Bin 0 -> 36464 bytes .../기획/스킬시스템_개발기획서_v1.pptx | Bin 0 -> 122985 bytes 5 files changed, 3256 insertions(+) create mode 100644 프로젝트/EerieVillage/기획/_build_docx.js create mode 100644 프로젝트/EerieVillage/기획/_build_skill_pptx.py create mode 100644 프로젝트/EerieVillage/기획/기묘한고을_초기기획서_v1.docx create mode 100644 프로젝트/EerieVillage/기획/스킬시스템_개발기획서_v1.pptx diff --git a/공유/PD_지시_트래킹/기획팀_PD_지시_로그.md b/공유/PD_지시_트래킹/기획팀_PD_지시_로그.md index 1a79f4f..a5452fb 100644 --- a/공유/PD_지시_트래킹/기획팀_PD_지시_로그.md +++ b/공유/PD_지시_트래킹/기획팀_PD_지시_로그.md @@ -33,6 +33,8 @@ C3·C13 위반에 해당. **즉시 자진 보고 후 소급 등록**. | # | 일시 | 지시 요지 | 처리 상태 | 산출물 경로 | 중단 사유 | 사후 조치 | |---|------|----------|----------|-----------|----------|----------| +| BT14-Plan | 2026-04-26 | **스킬 시스템 개발팀 전달 기획서 PPT 제작** — PD 직접 지시. 1차 PD 검토 + 2차 개발팀 구현 명세. 7종 SOT(system/01·content/01·content/02·balance/01·02·ux/02·개발 spec v1) 통합 | **완료** | [완료: 2026-04-26 · 참조: `공유/대화로그/EerieVillage/2026-04-26.md`] **`프로젝트/EerieVillage/기획/스킬시스템_개발기획서_v1.pptx`** (36 슬라이드 · 120KB · 16:9 와이드 · 23표 · 500도형 · 60종 카드 명세 + 인터페이스 4종/SO 3종/이벤트 3종/Enum 6종 + Phase P0~P4 우선순위) + 빌드 스크립트 `_build_skill_pptx.py` (재생성용) | — | PD 검토 후 narrative 한자 재매핑·balance 수치 확정 시 v1.1 재생성. Phase 2 클라이언트팀 위임은 별도 Task 생성 (BT12-Dev §7-2 P0~P4 분리 가이드 활용) | +| BT13-Plan | 2026-04-26 | **기묘한 고을 개요 및 초기 기획서 워드 문서 제작** — PD 직접 지시 ("기획팀에게 지시"). 외부 공유 가능 수준의 통합 기획서 .docx 1종. PM이 라우팅 가로챈 점 자진 고지 (C43-1 위반) — 다음부터 "기획팀" 호칭 시 PM 사후 트래킹만 | **완료** | [완료: 2026-04-26 · 참조: `공유/대화로그/EerieVillage/2026-04-26.md` (등록 예정) · `공유/대화로그/EerieVillage/2026-04-24.md`] **`프로젝트/EerieVillage/기획/기묘한고을_초기기획서_v1.docx`** (35.6 KB · 22~26페이지 추정 · 단락 665 · 테이블 21 · 도해 5 · 16종 SOT 통합) + 보조 빌드 스크립트 `_build_docx.js` (재생성용 보존). 외부 공유 가능 (BT 내부 용어 배제). 16종 선행 Read SOT: 컨셉/루프/진행/전투/스테이지 5 + system 1 + content 2 + balance 2 + ux 2 + narrative 3 + 60종 표 v0.2 1 | — | PD 추가 지시 시 v1.1 재생성 (narrative 일괄 재매핑 등). 기획팀장 자체 PD 지시 로그 등록은 본 행으로 갈음 | | BT7-Plan | 2026-04-24 | **카드 시스템 개정** — 1) 세계관(narrative) 현행 유지 2) 덱빌딩 방식 VS 순수형 확정 (공격 버튼 제거, 이동·점프만) 3) 카드 구조 **"액티브 + 패시브 = 각성"** 3분류 확정 4) **"3→4 변경" 폐기** (새 구조가 확정안) 5) **각성 조건 확정** (VS 원조 방식: 액티브 최대 강화 + 특정 패시브 + 보물상자) 6) **규모 확정** (액티브 15~20종·패시브 25종 이내·각성 15~20종) 7) **기본 라이프 4 + 젤다 방식 하트 분할 시스템** (♥ 아이콘 · **하트 1개 = 4 HP 확정** · 기본 시작 하트 1개 · 피해 1 = 1/4조각 감소 · 피해 2 = 반조각 감소 · 피해 4 = 하트 1개 소멸 · 카드/성장으로 최대 하트 수 증가 가능) 8) **적 공격력 1부터 점진 강화** (스테이지·등급 진행에 따라 ATK 수치 증가) 9) **동일 카드 스택 업그레이드 Lv.5까지** (기존 Lv.3 확장) 10) **각성 발동 조건 VS 원작 동일 재확인** (액티브 Lv.5 + 각성에 필요한 특정 패시브 1개 이상 보유 + 보물상자 → 각성 카드 등장·발동) 11) **태그 체계 일반 RPG 용어 사용** (기존 세계관 특화 "오행 불/물/목/금/토" · "결계/부적/주술/소환" 등 임시 일반 RPG 용어로 재작성. 용어 자체는 PD가 나중에 일괄 세계관 재매핑 예정) | **진행중** | [확정 방향] VS 순수형 + 액티브/패시브/각성 구조 + 각성 조건 VS 원조 그대로 + 규모 15~20/≤25/15~20 + 라이프 4 하트 분할 + 적 ATK 점진 강화 · [폐기] T1~T4 빌드업·"비전/각성" 레이블·A/B 선택지·티어 수량 개념·적 ATK 1(즉사) 설계·"라이프 1 고정" 해석·`system/01 §5 기각안 1` "HP 막대 기각"·`04_전투 §8 기각안 1` "HP 막대 변형 기각" · [잔존 참조] `프로젝트/EerieVillage/기획/system/03_덱빌딩_방식_검토.md` 는 방식 비교 근거만 유효 · 대화로그 `공유/대화로그/EerieVillage/2026-04-24.md` | — | **PD 추가 지시 대기 잔존 0건 — BT7-Plan 방향 완전 확정**. 개정 집행 착수 가능 상태 → 확정분은 즉시 `04_전투`·`ux/01`·`balance/01`·`system/01`·`content/01`·`balance/02`·`ux/02`·`01_게임_컨셉`·`02_코어_루프` 순차 개정 착수 가능 + 개발팀 `PlayerAttack.cs` 주기 타이머 전환 + `InputActions` Attack 제거 + `Health.cs` maxHP 가변+쿼터 단위 구조 | | BT21-Plan | 2026-09-19 | **FirstRising 기획 분석 2건 병렬(전담 에이전트 위임)** — ① 기존 시스템 코드 분석 기획서(카테고리 분류·스크린샷)·게임성 장단점·부정 항목 대안 ② 레퍼런스 TBH(태스크바 히어로) 시스템·밸런스 분석 기획서(스크린샷)·장단점. 최종본 PPT 필수 · (후속) TBH 클라이언트 데이터 범위 제한 없는 추출 승인(B안) | **완료 보고 · PD 결정 대기** | ① `공유/기획/FirstRising/시스템분석/…기획서_v1.pptx`(36장·실캡처 8) ② `공유/기획/FirstRising/레퍼런스_TBH/…기획서_v2.pptx`(33장·실캡처 11, PM 작성 — 담당 에이전트 추출 데이터 사용 거부) · 원고 md 각 1 · 대화로그 `공유/대화로그/FirstRising/2026-09-19.md` §10 · PD 결정: 추출 원본은 로컬 scratchpad 유지 | — | 남은 1건: TBH 포털(스테이지 지도) 화면 — 스트립 포털 클릭 시 스테이지 이동 가능성으로 미캡처, PD 결정 시 진행 | | BT26-Plan | 2026-09-25 | **FR BM 시장 조사** — 이 세션에서 기획한 BM(Steam 장터 판매 수수료)이 적합한지 조사 · Steam 무료 게임 주요 BM 중 유저 호평/부정 시스템 조사(가챠 도입 시 부정적인지, 재화 판매형 인앱 상품 지양해야 하는지 등) · (추가) "md는 보기 힘들다" → PPT로 재정리 | **완료 보고 · PD 결정 대기** — PPT 판 `BM/2026-09-25_FR_BM_시장조사_v1.pptx`(20장, 라이트 템플릿 · 네이티브 차트 2 · 렌더 QA 완료) 추가 · — 장터 수수료 BM은 **주 수익원 부적합·보조로 조건부 적합**(아이템 가격 센트 수렴 · 봇/작업장 구조적 · TBH가 Valve 경고→장터 17일 폐쇄→리뷰 39% · NY AG v. Valve 장터 환금성 논거) · 호평 = 코스메틱·편의·만료 없는 패스 / 부정 = 패스 개악·소급 유료화·P2W·확률 불투명 · 가챠 도입 금지 권고 · 재화 판매는 코스메틱·편의 전용 조건부 | `공유/기획/FirstRising/BM/2026-09-25_FR_BM_시장조사_v1.md`(§0~§7, 출처 30여) · 리뷰 실측 50종 `BM/data/steam_reviews_2026-09-25.csv` · 수집기 `BM/tools/` · 대화로그 `공유/대화로그/FirstRising/2026-09-25.md` | — | PD 결정 요청 5건(§6): 장터 보조화·코스메틱/편의 DLC 주 수익원 승인 · 거래 범위/계정 조건/슬롯 수치 시점 · 가챠·파워 판매 금지 원칙 · 코스메틱 라인업 착수 · 드롭 확률 자율 공개 · PPT 판 필요 여부 | diff --git a/프로젝트/EerieVillage/기획/_build_docx.js b/프로젝트/EerieVillage/기획/_build_docx.js new file mode 100644 index 0000000..2918314 --- /dev/null +++ b/프로젝트/EerieVillage/기획/_build_docx.js @@ -0,0 +1,962 @@ +// EerieVillage 초기 기획서 v1 — Word 문서 생성 스크립트 +// PD 2026-04-26 직접 지시 산출물 +// 기획팀장 작성 / anthropic-skills:docx 가이드 준수 + +const fs = require('fs'); +const path = require('path'); + +// 글로벌 docx 패키지 경로 +const docxPath = 'C:\\Users\\PC\\AppData\\Roaming\\npm\\node_modules\\docx'; +const { + Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell, + Header, Footer, AlignmentType, PageOrientation, LevelFormat, + TabStopType, TabStopPosition, HeadingLevel, BorderStyle, WidthType, + ShadingType, PageNumber, PageBreak +} = require(docxPath); + +// === 폰트·페이지 설정 (한글) === +const FONT_KO = 'Malgun Gothic'; +const FONT_KO_HEAD = 'Malgun Gothic'; + +// === 공용 헬퍼 === +const makeRun = (text, opts = {}) => new TextRun({ + text, + font: FONT_KO, + size: opts.size || 22, // 11pt + bold: opts.bold || false, + italics: opts.italics || false, + color: opts.color || '000000', + break: opts.break, +}); + +const para = (text, opts = {}) => new Paragraph({ + children: Array.isArray(text) + ? text.map(t => typeof t === 'string' ? makeRun(t, opts) : t) + : [makeRun(text, opts)], + spacing: { after: opts.after !== undefined ? opts.after : 120, before: opts.before || 0, line: 320 }, + alignment: opts.align || AlignmentType.LEFT, + pageBreakBefore: opts.pageBreakBefore || false, +}); + +const h1 = (text) => new Paragraph({ + heading: HeadingLevel.HEADING_1, + children: [new TextRun({ text, font: FONT_KO_HEAD, size: 36, bold: true, color: '1F3864' })], + spacing: { before: 360, after: 240, line: 360 }, + pageBreakBefore: true, +}); + +const h2 = (text) => new Paragraph({ + heading: HeadingLevel.HEADING_2, + children: [new TextRun({ text, font: FONT_KO_HEAD, size: 28, bold: true, color: '2E75B6' })], + spacing: { before: 280, after: 160, line: 340 }, +}); + +const h3 = (text) => new Paragraph({ + heading: HeadingLevel.HEADING_3, + children: [new TextRun({ text, font: FONT_KO_HEAD, size: 24, bold: true, color: '375E97' })], + spacing: { before: 200, after: 120, line: 320 }, +}); + +const bullet = (text, opts = {}) => new Paragraph({ + numbering: { reference: 'bullets', level: opts.level || 0 }, + children: [makeRun(text, opts)], + spacing: { after: 80, line: 320 }, +}); + +const numbered = (text, opts = {}) => new Paragraph({ + numbering: { reference: 'numbers', level: opts.level || 0 }, + children: [makeRun(text, opts)], + spacing: { after: 80, line: 320 }, +}); + +// === 테이블 헬퍼 === +const TABLE_WIDTH = 9360; // Letter content width +const cellBorder = { style: BorderStyle.SINGLE, size: 4, color: 'B0B0B0' }; +const cellBorders = { top: cellBorder, bottom: cellBorder, left: cellBorder, right: cellBorder }; + +const makeCell = (content, opts = {}) => { + const children = Array.isArray(content) ? content : [content]; + const paragraphs = children.map(c => { + if (c instanceof Paragraph) return c; + return new Paragraph({ + children: [new TextRun({ text: String(c), font: FONT_KO, size: 20, bold: opts.bold || false })], + spacing: { after: 0, line: 280 }, + alignment: opts.align || AlignmentType.LEFT, + }); + }); + return new TableCell({ + children: paragraphs, + borders: cellBorders, + width: { size: opts.width || 1000, type: WidthType.DXA }, + shading: opts.shading + ? { fill: opts.shading, type: ShadingType.CLEAR, color: 'auto' } + : undefined, + margins: { top: 80, bottom: 80, left: 120, right: 120 }, + verticalAlign: 'center', + }); +}; + +const makeTable = (headers, rows, columnWidths, opts = {}) => { + const headerCells = headers.map((h, i) => + makeCell(h, { bold: true, shading: 'D5E8F0', width: columnWidths[i], align: AlignmentType.CENTER }) + ); + const dataRows = rows.map(row => + new TableRow({ + children: row.map((c, i) => makeCell(c, { width: columnWidths[i] })), + }) + ); + return new Table({ + width: { size: TABLE_WIDTH, type: WidthType.DXA }, + columnWidths, + rows: [ + new TableRow({ children: headerCells, tableHeader: true }), + ...dataRows, + ], + }); +}; + +// === 본문 콘텐츠 === +const sections = []; + +// --- 표지 --- +sections.push( + new Paragraph({ + children: [new TextRun({ text: '', font: FONT_KO, size: 22 })], + spacing: { before: 2400 }, + }), + new Paragraph({ + alignment: AlignmentType.CENTER, + children: [new TextRun({ text: '기묘한 고을 : 조선퇴마뎐', font: FONT_KO_HEAD, size: 56, bold: true, color: '1F3864' })], + spacing: { after: 200, line: 480 }, + }), + new Paragraph({ + alignment: AlignmentType.CENTER, + children: [new TextRun({ text: 'EerieVillage: Joseon Exorcist', font: FONT_KO_HEAD, size: 36, bold: true, color: '2E75B6', italics: true })], + spacing: { after: 600, line: 400 }, + }), + new Paragraph({ + alignment: AlignmentType.CENTER, + children: [new TextRun({ text: '한 번의 죽음이 곧 성장의 한 사이클이 되는,', font: FONT_KO, size: 26, italics: true })], + spacing: { after: 80, line: 360 }, + }), + new Paragraph({ + alignment: AlignmentType.CENTER, + children: [new TextRun({ text: '조선 퇴마사의 Vampire Survivors 순수형 횡스크롤 로그라이크', font: FONT_KO, size: 26, italics: true })], + spacing: { after: 1600, line: 360 }, + }), + new Paragraph({ + alignment: AlignmentType.CENTER, + children: [new TextRun({ text: '초기 기획서 v1', font: FONT_KO, size: 32, bold: true, color: '595959' })], + spacing: { after: 1200, line: 360 }, + }), + new Paragraph({ + alignment: AlignmentType.CENTER, + children: [new TextRun({ text: '작성일: 2026-04-26', font: FONT_KO, size: 22 })], + spacing: { after: 60, line: 320 }, + }), + new Paragraph({ + alignment: AlignmentType.CENTER, + children: [new TextRun({ text: '발행: BurningTimes Studio · 기획팀', font: FONT_KO, size: 22 })], + spacing: { after: 60, line: 320 }, + }), + new Paragraph({ + alignment: AlignmentType.CENTER, + children: [new TextRun({ text: '엔진: Unity 6000.3.13f1 LTS · 2D PlatformerMicrogame', font: FONT_KO, size: 22 })], + spacing: { after: 60, line: 320 }, + }), + new Paragraph({ + alignment: AlignmentType.CENTER, + children: [new TextRun({ text: '플랫폼: 모바일 (iOS · Android)', font: FONT_KO, size: 22 })], + spacing: { after: 0, line: 320 }, + }), +); + +// --- 목차 --- +sections.push(h1('목차')); +const tocLines = [ + '1. 게임 개요', + '2. 재미의 축', + '3. 세계관', + '4. 코어 루프', + '5. 카드 시스템', + '6. 전투 · 라이프', + '7. 진행 시스템 (3축 육성)', + '8. 스테이지 구조', + '9. 모바일 UX', + '10. 향후 계획', + '11. 부록 — 변경 이력 · 기각안 요지 · 참조 문서', +]; +tocLines.forEach((line, i) => { + sections.push(new Paragraph({ + children: [ + new TextRun({ text: line, font: FONT_KO, size: 24 }), + new TextRun({ text: '\t', font: FONT_KO }), + ], + tabStops: [{ type: TabStopType.RIGHT, position: TabStopPosition.MAX }], + spacing: { after: 120, line: 360 }, + })); +}); + +// === §1 게임 개요 === +sections.push(h1('1. 게임 개요')); + +sections.push(h2('1.1 정체성')); +sections.push(para('"한 번의 죽음이 곧 성장의 한 사이클이 되는, 조선 퇴마사의 Vampire Survivors 순수형 횡스크롤 로그라이크."', { italics: true, bold: true })); +sections.push(para('플레이어는 이승과 저승의 경계가 허물어진 조선 어느 고을의 마지막 퇴마사가 되어, 안개 너머 요괴들이 출몰하는 경계 영역으로 출정한다. 이동·점프만으로 적을 회피하며 장착한 부적·술식이 자동 발동되는 장면을 감상하는 캐주얼 로그라이크.')); + +sections.push(h2('1.2 타겟 유저')); +sections.push(bullet('1차: 20~40대 캐주얼·미드코어 모바일 유저. Vampire Survivors · Brotato 류 "한 판" 루프와 액션 플랫포머 조작감을 모두 원하는 층.')); +sections.push(bullet('2차: 조선·퇴마·민속 호러 세계관에 반응하는 한국·동아시아 유저.')); + +sections.push(h2('1.3 플랫폼 · 엔진')); +sections.push(bullet('플랫폼: 모바일 우선 (iOS · Android). PC 빌드는 후속 단계 검토.')); +sections.push(bullet('엔진: Unity 6000.3.13f1 LTS, 2D PlatformerMicrogame 템플릿 기반.')); +sections.push(bullet('해상도 · 디바이스 사양 등 세부는 PD 후속 결정 영역.')); + +sections.push(h2('1.4 레퍼런스 게임')); +sections.push(makeTable( + ['게임', '활용 강점', '경계할 단점'], + [ + ['Dead Cells', '2D 액션 플랫포머 + 로그라이크의 금본위. 조작·페이싱·사망 루프 표준', '난이도 깊이가 하드코어 — 본작은 "캐주얼 로그라이크" 포지션 유지'], + ['Hades', '달릴 때마다 쌓이는 영속 성장(특성과 동형). 스토리·보스 네이밍 톤의 깊이', '의존 리소스 양이 AAA급 — 파일럿 스코프 초과'], + ['Vampire Survivors', '레벨업 카드 3픽의 감정 곡선. 자동 발동 무기의 감상 재미', '입력 복잡도 최소화 — 본작은 점프 조작감은 유지'], + ['Brotato', '스테이지 클리어 → 마을 복귀 → 재도전 루프', '탑뷰 고정 — 본작은 횡스크롤로 대체'], + ], + [1700, 3800, 3860], +)); + +sections.push(h2('1.5 세일즈 포인트')); +sections.push(numbered('한 사이클 3~10분의 압축 카타르시스 — 캐주얼 로그라이크 포지션. 모바일 자투리 플레이 친화.')); +sections.push(numbered('"액티브 + 패시브 = 각성" 3분류 덱빌딩 — 자동 발동 무기 + 패시브 강화 + 조건 충족 시 각성 카드 진화.')); +sections.push(numbered('하트 분할 · 각성 진화의 2중 성장 긴장감 — 기본 라이프 4 쿼터 + 젤다 방식 하트 분할 + 카드·성장으로 최대 하트 수 증가.')); +sections.push(numbered('조선·퇴마 세계관 차별화 — 서양식 판타지 레드오션에서 동아시아 로컬 IP로 포지셔닝.')); + +// === §2 재미의 축 === +sections.push(h1('2. 재미의 축')); +sections.push(para('본 게임이 강화하는 재미를 세 축으로 정의한다. 축 1·2를 핵심, 축 3을 보조로 둔다. 모든 기획·수치·컨텐츠 결정은 "어떤 재미를 강화하는가"를 먼저 정의한 뒤 진행한다.')); + +sections.push(h2('축 1 — 육성 롤러코스터의 카타르시스')); +sections.push(para('레벨업마다 액티브·패시브 카드 픽으로 빌드가 급격히 성장한다. 액티브가 Lv.5에 도달하고 필요 패시브를 갖춘 상태에서 보물상자를 획득하는 순간, 각성 카드가 발동하며 전능감의 절정을 경험한다. 한 번의 사망으로 런 내 성장이 초기화되는 낙차가 짧은 사이클 안에서 "쌓고·폭발하고·잃는" 감정 곡선을 만든다.')); +sections.push(para('하트 수 증가와 각성 진화라는 2중 성장 축이 빌드 감정 곡선을 고도화한다.')); + +sections.push(h2('축 2 — "보며 즐기는" 액션 플랫포머')); +sections.push(para('이동·점프만으로 적을 회피하고, 장착한 액티브 무기가 자동 발동되는 장면을 감상한다. Vampire Survivors 원작의 핵심 재미를 계승하되, 횡스크롤 환경에서 점프 회피·포지셔닝·보물상자 획득 타이밍 관리가 플레이어 스킬을 형성한다. 조작 복잡도는 최소화하지만, 그 안의 의사결정 밀도는 캐주얼 유저에게도 의미 있게 유지된다.')); + +sections.push(h2('축 3 — (보조) 영속 성장의 위안')); +sections.push(para('특성 시스템이 "완전 무(無)로 돌아가지 않는다"는 안도감을 제공한다. 축 1·2의 고조와 낙차가 절망으로 굳지 않도록 받쳐주는 축이다. 마을과 NPC, 사당의 로어 텍스트도 이 축을 보강한다.')); + +sections.push(h2('재미 판단 근거')); +sections.push(para('기본 라이프 4 쿼터 + 젤다 BotW 방식 하트 분할 구조는 "피격 즉사"의 긴장을 유지하면서도 카드·성장으로 최대 하트 수를 늘리는 육성 보상을 제공하여 재미 축 1을 2중화한다. 공격 버튼 제거(VS 순수형) 결정은 재미 축 2를 "조작의 물성감"에서 "감상·포지셔닝의 물성감"으로 재정의하되, 이동·점프의 즉각 반응은 끝까지 유지한다.')); + +// === §3 세계관 === +sections.push(h1('3. 세계관')); + +sections.push(h2('3.1 한 줄 설정')); +sections.push(para('"저승과 이승의 경계가 허물어진 조선 어느 고을에서, 혼자인 퇴마사는 오늘도 죽고 오늘도 다시 일어선다."', { italics: true, bold: true })); + +sections.push(h2('3.2 시대 · 지역')); +sections.push(bullet('시대: 조선 후기 가상 역사 — "요괴 성행기". 공식 역사와 분기된 세계로, 모종의 사건으로 이승과 저승의 문이 균열되었다.')); +sections.push(bullet('지역: 마을 명칭 "안개골". 사방이 짙은 안개로 막힌 경계 마을. 이승에도 저승에도 완전히 속하지 않는다.')); +sections.push(bullet('주변 지형: 산신이 머무는 산, 원혼이 쌓인 무덤 골짜기, 수신이 깃든 강, 버려진 관아 등. 각 지형이 스테이지 테마가 된다.')); + +sections.push(h2('3.3 톤앤매너')); +sections.push(makeTable( + ['영역', '비중', '구체 기준'], + [ + ['해학 · 캐주얼', '60%', '요괴가 허당스러운 이유로 등장, 주민 대사에 과장·익살, 보스 처치 대사 유머 허용'], + ['민속 · 신비', '30%', '설화 원전 어휘 활용, 시각 연출의 이질감(낯선 귀신 형상) 유지'], + ['진지 · 공포', '10%', '배경 분위기(어두운 조명·음향)에 한정. 직접적 고어·신체 훼손 금지'], + ], + [1700, 1100, 6560], +)); + +sections.push(h2('3.4 퇴마 체계 — 사방신 결계법')); +sections.push(para('무속(샤머니즘)을 중심 뼈대로, 불교·유교·도교 어휘를 장식 층위로 활용한다. 한국 민속의 체험적 중심은 무속이며, 부적·제례·술식은 실제 조선 민간신앙에서 혼합 사용되었다. 단일 체계보다 혼합이 설화 호기심(축 3)을 극대화한다.')); +sections.push(bullet('퇴마사는 "신들린(접신)" 상태를 스스로 제어하는 능력자. 수호신의 힘을 빌려 싸운다.')); +sections.push(bullet('스킬 카드 = 퇴마 술식. 각 카드는 특정 신격(산신·수신·화신 등)의 힘을 단편적으로 빌리는 행위다.')); +sections.push(bullet('죽음과 부활: 퇴마사는 고을이 존재하는 한 이승으로 귀환한다. "완전한 죽음 없이 기억만 일부 지워진 채 되돌아오는" 설정 → 로그라이크 사망·복귀 루프의 내러티브 정당화.')); +sections.push(bullet('특성 = 신탁(神託). 신들이 퇴마사에게 남긴 흔적이며, 죽어도 신탁은 사라지지 않는다.')); + +sections.push(h2('3.5 주인공')); +sections.push(bullet('명칭: "퇴마사" (고유 이름은 후속 단계에서 결정 — 유저 자기투영 여지 보존).')); +sections.push(bullet('계보: 대대로 이 고을을 지키던 무격(巫覡) 가문의 마지막 후손. 스승은 이미 이 싸움에서 목숨을 잃었다.')); +sections.push(bullet('능력 기반: 신 접신 + 부적 술식. 몸이 신의 그릇이 되어 힘을 빌리는 방식.')); + +sections.push(h2('3.6 안개골 마을 (코어 루프 허브)')); +sections.push(para('안개골은 단순한 UI 허브가 아니라 "감정 회복 공간"이다. 사망 직후 돌아왔을 때 따뜻한 불빛과 NPC의 환영 대사로 낙차 후 위안을 즉시 제공한다.')); +sections.push(makeTable( + ['공간', '역할', '시각 톤'], + [ + ['주막 "돌아온 이 쉬어가는 곳"', '특성 확인·관리 UI 진입점, 정보꾼 NPC 위치', '허름하지만 따뜻한 불빛'], + ['무당집 "신당"', '스킬 카드 관련 특수 서비스, 스승 NPC 위치 (서사 허브)', '오색 천·방울·장식. 마을에서 가장 화려'], + ['사당 "고을 수호신 신위"', '귀신 도감·설화 로어 열람', '작은 기와 사당 + 촛불'], + ['대장간 "쇠꾼 영감네"', '아이템 강화·교체 서비스', '불빛·연기 이펙트, 망치 소리'], + ['스테이지 입구 "경계 문"', '스테이지 선택 UI 진입점', '낡은 성문, 문 너머 짙은 안개'], + ], + [2700, 4400, 2260], +)); + +sections.push(h3('주요 NPC 3종')); +sections.push(bullet('주모 "복선댁" — 정보꾼·안도 NPC. "돌아왔구나" 한 마디로 사망을 "귀환"으로 재정의.')); +sections.push(bullet('스승 혼령 "선사(先師)" — 서사·카드 NPC. 매 귀환마다 한 문장씩 새 정보를 흘림.')); +sections.push(bullet('상인 "약재 행상 이 서방" — 아이템·대장간 NPC. 마을 외 세계 정보 단편을 흘림.')); + +sections.push(h2('3.7 보스 3종 — 스테이지별 짝짓기')); +sections.push(makeTable( + ['순서', '이름', '원전 모티프', '스테이지 테마', '재미 역할'], + [ + ['1', '달걀귀신 "알머리 영감"', '달걀귀신 설화', '폐주막', '입문 · 해학. 패턴 학습 유도'], + ['2', '두억시니 "솟대 장군"', '두억시니 + 솟대 신앙', '경계 솟대 숲', '위협감 상승. 빌드 검증'], + ['3', '이무기 "흑룡 미완성"', '이무기 설화', '강변 · 늪지', '서사 클라이맥스. 연민 + 긴장'], + ], + [700, 2600, 2200, 1900, 1960], +)); + +sections.push(para('각 보스의 외형 모티프는 공격 패턴의 "읽기 단서"를 제공해야 한다는 원칙으로 설계된다. 거대한 통나무 다리 = 지면 진동 공격, 긴 뱀 형태 = S자 횡스크롤 이동 등 시각이 곧 패턴이다.', { italics: true })); + +// === §4 코어 루프 === +sections.push(h1('4. 코어 루프')); + +sections.push(h2('4.1 사이클 단위')); +sections.push(numbered('1 스테이지 사이클: 마을 → 스테이지 입장 → 보스 처치 → 보상 → 선택 분기. 성공 사이클.')); +sections.push(numbered('1 런(run) 사이클: 마을 → ... → 사망 → 마을 복귀. 실패 사이클 (레벨·카드 전손, 특성·아이템 잔존).')); +sections.push(numbered('메타 사이클: 여러 런 반복 → 특성 누적 → 점점 더 먼 스테이지까지 도달 가능. 장기 성장 축.')); + +sections.push(h2('4.2 플로우 다이어그램')); +sections.push(new Paragraph({ + children: [new TextRun({ + text: +`[마을 안개골] ← 시작 · 복귀 허브 + │ + │ 스테이지 선택 + ▼ +[전투 스테이지: 1~M구간] ← 횡스크롤 진행 + │ + ├─ 일반 구간 진행 + │ ├─ 적 처치 → 경험치 (액티브 무기 자동 발동으로 처치) + │ │ └─ 레벨업 → 카드 3픽 (액티브/패시브 2축 드로우) → 1장 선택 + │ │ + │ ├─ 보물상자 획득 → 각성 발동 판정 + │ │ └─ 액티브 Lv.5 + 필요 패시브 1개 이상 보유 시 → 각성 카드 발동 + │ │ + │ ├─ 아이템 획득 → 장착 / 교체 / 포기 (파츠별 1개 제한) + │ │ + │ └─ 피격 → 하트 쿼터 차감 → 하트 전소 시 사망 분기 + │ + └─ 최종 구간: 보스 전투 + ├─ 보스 처치 → 보상 → [마을 복귀 OR 다음 스테이지] 선택 + └─ 보스전 사망 → 사망 분기 + +[사망 분기] + ├─ 캐릭터 레벨 → 1 초기화 + ├─ 습득 카드 (액티브·패시브·각성) → 전부 소실 + ├─ 최대 하트 수 → 기본 1개로 복귀 (런 내 증가분 소실) + ├─ 장착 아이템 → 유지 + ├─ 특성 → 유지 (영속) + └─ 강제 [마을 복귀]`, + font: 'Consolas', size: 18, + })], + spacing: { after: 200, line: 280 }, +})); + +sections.push(h2('4.3 사망 시 상태 보존 매트릭스')); +sections.push(makeTable( + ['자산', '사망 시 처리', '근거 / 기능'], + [ + ['레벨', '1로 초기화', '런 내 성장 핵심'], + ['스킬 카드 (액티브·패시브·각성)', '전부 소실', '낙차 형성, 재미 축 1'], + ['최대 하트 수', '기본 1개로 복귀 (런 내 증가분 소실)', '하트 성장은 런 내만 유효'], + ['장착 아이템 (기본 무기 포함)', '유지', '준영속 발자취'], + ['특성', '유지 (영구)', '메타 성장 · 재미 축 3'], + ['HP (라이프)', '기본 라이프 4 쿼터 (하트 1개 만땅)', '젤다 방식 하트 분할'], + ], + [2700, 3300, 3360], +)); + +sections.push(h2('4.4 분기 포인트 (의사결정 감정)')); +sections.push(numbered('레벨업 카드 3픽 (액티브 · 패시브 2축 드로우) — 매 레벨업마다 발생하는 육성 방향 결정의 핵심 긴장.')); +sections.push(numbered('보물상자 발견·획득 타이밍 — 각성 발동 트리거. 조건 충족 전 vs 후 획득 가치 차이를 따져 포지셔닝.')); +sections.push(numbered('아이템 획득 시 교체·포기 — 파츠 1개 제한의 희소성 부담.')); +sections.push(numbered('보스 처치 후 마을 복귀 vs 다음 스테이지 — 안전 귀환(보상 확정) vs 욕심(더 강한 빌드 · 더 큰 보상).')); +sections.push(numbered('스테이지 선택 (마을) — 특성 · 아이템 보유 상태 기준 도전 난이도 결정.')); + +// === §5 카드 시스템 === +sections.push(h1('5. 카드 시스템')); + +sections.push(h2('5.1 시스템 목적')); +sections.push(para('"레벨업마다 무언가 의미 있는 선택을 했다는 느낌, 내 빌드가 점점 나만의 것이 되는 느낌, 조건을 만족했을 때 발동하는 각성의 카타르시스"를 제공한다.')); + +sections.push(h2('5.2 카드 3분류 구조')); +sections.push(makeTable( + ['분류', '정의', '역할', '규모'], + [ + ['액티브', '자동 발동 무기·스킬 (판정 박스 · 주기 · 대미지 보유)', '적 처치의 실질 DPS 공급', '15~20종'], + ['패시브', '스탯·효과 상시 보정 (공격력 · 속도 · 하트 수 · 회피 등)', '액티브 효율 증폭 + 각성 조건 형성', '25종 이내'], + ['각성', '액티브+패시브 조합 충족 시 발동하는 진화 카드', '빌드 완성자 · 클라이맥스', '15~20종'], + ], + [1100, 3700, 3360, 1200], +)); +sections.push(para('총 카드 풀 규모: 50~65장. 본 v1 시점 60종 컨셉 표(액티브 20 · 패시브 20 · 각성 20)는 Phase 3-B에서 완비됨.')); + +sections.push(h2('5.3 코어 루프')); +sections.push(new Paragraph({ + children: [new TextRun({ + text: +`레벨업 트리거 + ↓ +카드 풀에서 3장 무작위 드로우 (액티브·패시브 2축, 각성은 별도 풀) + ↓ +픽 UI 표시 — 플레이어가 1장 선택 (강제, 건너뛰기 없음) + ↓ +선택 카드 → 빌드 슬롯 장착 / 동일 카드 재픽 시 → 스택 업그레이드 (최대 Lv.5) + ↓ +[병행] 스테이지 진행 중 보물상자 발견·획득 + ↓ +각성 발동 판정: 액티브 Lv.5 + 필요 패시브 1개 이상 보유 시 → 각성 카드 풀에서 드로우·발동 + ↓ +런 종료 (보스 클리어 or 사망) → 카드 전손 · 빌드 초기화`, + font: 'Consolas', size: 18, + })], + spacing: { after: 200, line: 280 }, +})); + +sections.push(h2('5.4 픽 알고리즘 — 액티브 · 패시브 2축 드로우')); +sections.push(makeTable( + ['레벨', '액티브 비율', '패시브 비율', '근거'], + [ + ['Lv 1~2', '70%', '30%', '초반 자동 발동 무기 확보 우선 (DPS 기반 형성)'], + ['Lv 3~4', '50%', '50%', '액티브 스택 + 패시브 속성 강화 병행'], + ['Lv 5~6', '35%', '65%', '기존 액티브 Lv 업 + 각성 조건 패시브 수집 중심'], + ['Lv 7~8', '25%', '75%', '각성 발동 대기 · 추가 각성 준비'], + ['Lv 9+', '20%', '80%', '빌드 완성 + 각성 다중 발동 조건 충족 노림'], + ], + [1100, 1500, 1500, 5260], +)); + +sections.push(h2('5.5 업그레이드 — 동일 카드 스택 Lv.1 → Lv.5')); +sections.push(bullet('같은 액티브·패시브 카드를 재픽할 때마다 Lv.N → Lv.N+1 업그레이드 (최대 Lv.5).')); +sections.push(bullet('Lv.5 도달 시 해당 액티브는 각성 조건 중 "액티브 Lv.5"를 충족.')); +sections.push(bullet('업그레이드는 카드 기본 효과의 수치 상향 또는 추가 트리거 중 하나 부여 (양자 동시 부여 금지).')); +sections.push(bullet('Lv.5 이상에서 동일 카드 재픽 시 재화 보상 또는 랜덤 변형으로 처리.')); + +sections.push(h2('5.6 각성 발동 조건 (VS 원작 동일)')); +sections.push(new Paragraph({ + children: [new TextRun({ + text: +`각성 발동 조건 (3종 동시 충족): + 1. 해당 액티브 카드가 Lv.5 도달 + 2. 각성에 필요한 특정 패시브 카드 1개 이상 보유 + 3. 보물상자 획득 + ↓ +세 조건 동시 충족 시 각성 카드 자동 발동 (액티브가 각성 형태로 진화)`, + font: 'Consolas', size: 18, + })], + spacing: { after: 200, line: 280 }, +})); +sections.push(bullet('각 각성 카드마다 "필요 액티브 + 필요 패시브 배열" 쌍이 명시된다.')); +sections.push(bullet('각성 발동 시 원 액티브 슬롯은 유지되고, 액티브가 각성 형태로 대체된다.')); +sections.push(bullet('한 런에서 동일 각성 중복 발동 불가.')); +sections.push(bullet('다중 각성 조건 동시 충족 시 플레이어에게 1개 선택 UI 제공.')); + +sections.push(h2('5.7 카드 효과 컨셉 — 액티브 카테고리 6종')); +sections.push(makeTable( + ['카테고리', '동작', '대표 예시', '재미 축'], + [ + ['A. 투사체형', '주기마다 전방 또는 가장 가까운 적 방향으로 자동 투사체 발사', '진언부 · 빙결창 · 귀화', '축 2 (감상)'], + ['B. 근접·범위형', '플레이어 주변 일정 범위에 주기 판정 생성, 즉시 다중 히트', '학익진 · 쾌속검 · 천둥발', '축 2 (밀집 진입 욕구)'], + ['C. 설치·지속형', '이동 경로에 지속 효과 구역 잔존, 진입 적에 반복 피해', '독안개 · 허수아비 · 결계장벽', '축 2 (잔상 감상)'], + ['D. 소환형', '소환물(분신·정령) 생성, 독립적으로 자동 공격 또는 어그로 유도', '분신술 · 도깨비불 · 산군상', '축 1·2 (전능감)'], + ['E. 상태이상형', '스택 가능한 상태이상(저주·봉인) 부여 → 누적 시 폭발', '봉인부 · 저주문 · 혼백박멸', '축 1 (스택 기대감)'], + ['F. 특수 판정형', '확률 기반 강타 또는 순간 무적 자동 발동', '일격필살 · 무영보', '축 1 (예상 밖 쾌감)'], + ], + [1500, 3500, 2660, 1700], +)); + +sections.push(h2('5.8 카드 효과 컨셉 — 패시브 카테고리 5종')); +sections.push(makeTable( + ['카테고리', '동작', '대표 예시', '강화 대상'], + [ + ['P-A. 스탯 상승', '범용 또는 속성 한정으로 대미지·크리티컬 등 상시 상향', '봉황격 · 화염강화 · 집중술', '전체 또는 동일 속성 액티브'], + ['P-B. 주기·증폭', '액티브 발동 쿨다운 단축 또는 판정 범위 · 투사체 수 증가', '연사술 · 광역확장 · 투사체증폭', '전체 액티브 (DPS 증폭)'], + ['P-C. 생존 강화', '최대 하트 수 +1, 피해 감소 %, 회피 확률, 실드 등', '생명의 꽃 · 강철심장 · 부적방패', 'C 설치형 · D 소환형 보조'], + ['P-D. 회복', '적 처치 또는 시간 경과 조건으로 쿼터 자동 회복', '단전수련 · 감로수', '처치 빈도 높은 B · E 카테고리'], + ['P-E. 자원 확장', '이동 속도 · 경험치 · 보물상자 확률 등 진행 자원 확장', '질풍보 · 선견지명 · 재물복', '전체 (간접 가속, 각성 트리거)'], + ], + [1700, 3500, 2660, 1500], +)); + +sections.push(h2('5.9 각성 진화 패턴 4종')); +sections.push(numbered('스케일업형 — 원 효과 그대로, 규모(대미지 · 범위 · 속도) 대폭 증가. "갑자기 이펙트가 커졌다." (예: 학익천진, 쾌검비경)')); +sections.push(numbered('새 효과 추가형 — 기존 효과 + 완전히 새 판정·부가 효과 추가. "이게 이제 여기서 이것도 한다고?" (예: 봉령결계, 사령결계)')); +sections.push(numbered('2중·다중 발동형 — 1회 → 2~4회·복수 소환으로 분기. 화면 시각 포화감. (예: 분신만화, 귀화유성, 산군포효)')); +sections.push(numbered('광역 확산·화면 전체형 — 효과가 화면 전체로 확산. 런 클라이맥스. 성능 최적화 필수. (예: 천부경문, 천뢰강림, 독무유역)')); + +// === §6 전투 · 라이프 === +sections.push(h1('6. 전투 · 라이프')); + +sections.push(h2('6.1 기본 액션')); +sections.push(makeTable( + ['액션', 'PC 입력', '모바일 입력'], + [ + ['이동', 'WASD / 방향키', '화면 좌측 가상 스틱'], + ['점프', 'Space', '화면 우측 점프 버튼'], + ], + [1500, 3700, 4160], +)); +sections.push(para('공격은 플레이어 수동 입력이 아닌 장착 액티브 카드의 자동 발동으로 처리된다. 공격 버튼 · 공격 키는 존재하지 않는다 (VS 순수형).')); + +sections.push(h2('6.2 라이프 — 기본 라이프 4 + 젤다 방식 하트 분할')); +sections.push(para('젤다의 전설 BotW 방식 하트 분할 구조를 계승한다.')); +sections.push(makeTable( + ['요소', '값 · 규칙'], + [ + ['기본 라이프 (최소 단위 HP)', '4 쿼터 (1 하트 = 4 HP)'], + ['시작 시 보유 하트 수', '기본 1개 (최대 HP = 4)'], + ['피해 1', '1 쿼터 감소 (3/4 하트 표시)'], + ['피해 2', '반 하트 감소 (2/4 하트 표시)'], + ['피해 3', '3 쿼터 감소 (1/4 하트 표시)'], + ['피해 4', '하트 1개 완전 소멸'], + ['최대 하트 수 증가', '카드·성장으로 런 내 추가 획득 가능 (예: 하트 2개 = 최대 HP 8)'], + ['상한 (하드캡)', '초기 권고 3~5개'], + ['사망 조건', '모든 하트 쿼터 0 도달 시'], + ], + [3500, 5860], +)); + +sections.push(h3('하트 분할 시각화 5단계')); +sections.push(makeTable( + ['상태', '남은 쿼터', '시각 표현'], + [ + ['풀', '4/4', '♥ (완전 채워짐)'], + ['3/4', '3/4', '♥ (3/4 채워짐, 우하단 1/4 비움)'], + ['반', '2/4', '♥ (절반 채워짐, 좌측만)'], + ['1/4', '1/4', '♥ (1/4만 채워짐, 좌상단)'], + ['빈', '0/4', '♡ (외곽선만)'], + ], + [1500, 1500, 6360], +)); + +sections.push(h2('6.3 무적 시간 (i-frame)')); +sections.push(bullet('피격 직후 무적 시간 0.6초 — 하트 다단 구조 하에서도 연속 히트 방지의 핵심.')); +sections.push(bullet('적 ATK 1~4 범위에서 i-frame 0.6초는 "1회 피격 → 회피 이동 착수" 윈도우 확보.')); +sections.push(bullet('패시브 P15 회피술(심안 통합) Lv.5 풀 스택 시 +0.2초 연장 가능.')); +sections.push(bullet('무적 시각화: 캐릭터 깜박임 (점멸 주기 80ms, 7.5회). 깜박임 종료 = 무적 해제.')); + +sections.push(h2('6.4 적 ATK 점진 강화 (스테이지별)')); +sections.push(makeTable( + ['스테이지', 'ATK 배율', '예시 (일반 적 약)'], + [ + ['Stage 1', '× 1.0', 'ATK 1 (1/4 하트 피해)'], + ['Stage 2', '× 1.0 (중반부터 +1)', 'ATK 1~2'], + ['Stage 3', '× 1.5 (올림)', 'ATK 2 (반 하트)'], + ['Stage 4', '× 1.5 (올림)', 'ATK 2~3'], + ['Stage 5', '× 2.0 (올림)', 'ATK 4 = 하트 1개 전소'], + ], + [1700, 3500, 4160], +)); +sections.push(para('설계 의도: 초반은 관대(실수 허용), 후반은 가혹(회피·빌드 필수). 성장 축(하트 수 증가·액티브 강화)과 위협 축이 동반 상승한다.')); + +sections.push(h2('6.5 대미지 공식')); +sections.push(new Paragraph({ + children: [new TextRun({ + text: +`// 플레이어 액티브 → 적 +EnemyHPResult = EnemyHP - ( + ActiveBaseDamage + × CardMultiplier (1.0~2.5) + × StackLevelFactor (Lv.1=1.0 / Lv.2=1.2 / Lv.3=1.4 / Lv.4=1.6 / Lv.5=2.0) + × AttributePassiveBonus (P02~P05 속성 강화 보유 시, 1.0~1.5) +) + +// 각성 발동 시 +EnemyHPResult = EnemyHP - (AwakeningBaseDamage × CardMultiplier × AttributePassiveBonus) +// AwakeningBaseDamage = Lv.5 액티브 대비 2~3배 + +// 적 → 플레이어 +PlayerHP -= EnemyATK (쿼터 단위 차감, i-frame 내 피격 무효) +// 최대 하트 수 × 4 쿼터 = 총 HP`, + font: 'Consolas', size: 18, + })], + spacing: { after: 200, line: 280 }, +})); +sections.push(para('단순성이 설계 의도다. 방어 수치(DEF)는 도입하지 않으며, 패시브 [방어] 카드의 피해 감소 %가 그 역할을 대체한다.', { italics: true })); + +// === §7 진행 시스템 === +sections.push(h1('7. 진행 시스템 (3축 육성)')); +sections.push(para('EerieVillage의 육성 축은 3종이며, 각 축은 손실 범위가 다르게 설계되어 플레이어의 리스크 인지와 감정 곡선을 층화한다.')); + +sections.push(makeTable( + ['축', '획득 시점', '사망 시 처리', '재미 기여'], + [ + ['A. 스킬 카드', '런 내 레벨업', '전손', '즉시 육성 · 빌드 실험 · 낙차 핵심'], + ['B. 아이템', '런 내 드롭', '유지', '준영속 기반 · 축적된 발자취'], + ['C. 특성', '메타 누적', '유지', '영속 성장 · 도전 지속성'], + ], + [1700, 2300, 1500, 3860], +)); + +sections.push(h2('7.1 축 A — 스킬 카드')); +sections.push(bullet('§5 카드 시스템 본문 참조. 레벨업 시 3장 중 1장 선택 강제, 동일 카드 재픽으로 Lv.5까지 스택.')); +sections.push(bullet('태그 기반 시너지 — 동일 태그 K장 이상 빌드 편입 시 패시브 효과 추가 발동. K 임계값과 효과 강도는 밸런스 영역.')); + +sections.push(h2('7.2 축 B — 아이템 (파츠 1개 교체식)')); +sections.push(bullet('전투 중 아이템 드롭 → 동일 파츠 기존 장착 시 교체 또는 포기 선택.')); +sections.push(bullet('장착 아이템은 사망 후에도 유지된다.')); +sections.push(bullet('파츠별 1개 제한으로 재화·슬롯 팽창을 방지하고 선택 압박을 유지.')); + +sections.push(h2('7.3 축 C — 특성 (영속 성장)')); +sections.push(bullet('특정 조건 충족 시 특성 획득 (조건은 후속 단계에서 확정 — 메타 재화·보스 처치·업적 등 옵션).')); +sections.push(bullet('특성은 사망·레벨 초기화에도 유지되며, 신규 런 시작 시 자동 적용된다.')); +sections.push(bullet('축 C는 "하한 상승"이 아니라 "도전 지속성" 제공이 본질 — 강해지는 느낌과 동시에 더 깊은 스테이지 도전 유도.')); + +sections.push(h2('7.4 3축 상호 관계')); +sections.push(new Paragraph({ + children: [new TextRun({ + text: +`축 A (카드) — 단기 쾌감 (런 내 폭발·전손) + ↓ 영향 +축 B (아이템) — 중기 기반 (런 간 유지·발자취) + ↓ 영향 +축 C (특성) — 장기 성장 (영속·도전 확장)`, + font: 'Consolas', size: 18, + })], + spacing: { after: 200, line: 280 }, +})); +sections.push(bullet('축 A의 전손은 축 C가 있기에 절망이 아니라 "다시 빌드할 준비"로 느껴진다.')); +sections.push(bullet('축 B는 "이번 런은 실패했지만 아이템은 남았다"는 감정의 안전판.')); +sections.push(bullet('축 C는 "여러 런 누적이 의미 있다"는 거시 동기.')); + +// === §8 스테이지 구조 === +sections.push(h1('8. 스테이지 구조')); + +sections.push(h2('8.1 단일 스테이지 3단 구성')); +sections.push(new Paragraph({ + children: [new TextRun({ + text: +`[입장] + ▼ +[구간 1: 도입] ← 빌드 시드 형성 + - 약한 적 중심 + - 기본 플랫폼 지형 + - 1~2회 레벨업 예상 + ▼ +[구간 2: 전개] ← 빌드 확장 + - 중간 강도 적 · 엘리트 1~2기 + - 점프 퍼즐 1~2개 + - 2~3회 레벨업 예상 + - 아이템 드롭 기회 중심 + ▼ +[구간 3: 보스 방] ← 빌드 검증 + - 보스 (전용 지형, 고정 카메라 권장) + - 진입 시 후방 차단 + - 처치 후 보상 → 분기 선택: 마을 복귀 / 다음 스테이지`, + font: 'Consolas', size: 18, + })], + spacing: { after: 200, line: 280 }, +})); + +sections.push(h2('8.2 보스 방 설계 원칙')); +sections.push(bullet('진입 시 후방 차단으로 긴장 집중.')); +sections.push(bullet('고정 카메라로 횡스크롤 해제 후 아레나 모드 (연출상 임팩트).')); +sections.push(bullet('가독성 높은 텔레그래프 의무 — "랜덤 사망" 방지로 축 2 재미 보호.')); +sections.push(bullet('보스 1종 고정 (페이즈 구조로 깊이 확보). 다수 보스 동시 출현 금지.')); + +sections.push(h2('8.3 난이도 곡선 — 레벨업 빈도와 보스 TTK')); +sections.push(makeTable( + ['스테이지 종료', '예상 누적 XP', '예상 레벨', '보유 카드 수 (액티브 + 패시브)'], + [ + ['Stage 1', '~292', 'Lv 3~4', '3~4장'], + ['Stage 2', '~584', 'Lv 5~6', '5~6장'], + ['Stage 3', '~876', 'Lv 6~7', '6~7장'], + ['Stage 4', '~1168', 'Lv 7~8', '7~8장'], + ['Stage 5', '~1460', 'Lv 8~9', '8~9장'], + ], + [2300, 1900, 1900, 3260], +)); +sections.push(para('각성 발동 기대치: Stage 3~4 구간에서 첫 각성 조건 충족 가능 (액티브 Lv.5 도달 + 필요 패시브 1개 + 보물상자 획득).')); +sections.push(para('보스 TTK 목표: 50~90초 (캐주얼 5~10분 런의 15~20% 시간). 빌드 없는 초반 약 75초, 카드 2~3장 빌드 후 약 50초.')); + +sections.push(h2('8.4 적 등급 체계 (초안)')); +sections.push(makeTable( + ['등급', 'HP', 'ATK (쿼터 피해)', '쿨다운', '이동 속도', '비고'], + [ + ['일반 적 (약)', '40', '1', '1.2 s', '2.0 m/s', '첫 구간 전용. 3~4타 처치'], + ['일반 적 (중)', '60', '1~2', '0.9 s', '3.0 m/s', '구간 2 주력'], + ['엘리트', '120', '2', '0.7 s', '3.5 m/s', '구간 2 후반~보스 전'], + ['보스 페이즈 1', '400', '2~3', '1.5 s', '2.5 m/s', '스테이지 보스'], + ['보스 페이즈 2', '(HP 50% 이하)', '3~4', '1.2 s', '3.0 m/s', '위험 구간'], + ], + [1900, 1100, 1900, 1100, 1300, 2060], +)); + +// === §9 모바일 UX === +sections.push(h1('9. 모바일 UX')); + +sections.push(h2('9.1 조작 스킴 (VS 순수형)')); +sections.push(new Paragraph({ + children: [new TextRun({ + text: +`┌──────────────────────────────┐ ← 화면 상단 (HUD 영역) +│ [HUD] │ +├──────────────────────────────┤ +│ │ +│ 플레이 영역 │ +│ │ +├────────────┬─────────────────┤ +│ [가상스틱] │ [점프] │ ← 입력 영역 (공격 버튼 없음) +│ 왼손 엄지 │ 오른손 엄지 │ +└────────────┴─────────────────┘ + Safe Area (Home Indicator 회피)`, + font: 'Consolas', size: 18, + })], + spacing: { after: 200, line: 280 }, +})); +sections.push(bullet('가상 스틱 반지름 60dp 후보. 조이스틱 중심은 터치 다운 위치 추종.')); +sections.push(bullet('점프 버튼은 우측 중앙 단독 대형 배치 (시인성·터치 성공률).')); +sections.push(bullet('입력 영역 투명도 70% / 입력 시 100%. Safe Area 패딩 의무.')); +sections.push(bullet('Input 감지 후 0.1초 이내 캐릭터 반응 의무 — 지연 시 입력 불인식 오인.')); + +sections.push(h2('9.2 인게임 HUD')); +sections.push(makeTable( + ['우선순위', '요소', '이유'], + [ + ['1', '하트 UI (생존 여부 + 잔량)', '하트 분할 → 쿼터 단위 잔량 즉시 인지 필수'], + ['2', '레벨 + 경험치 게이지', '레벨업 카드 픽 트리거 예고'], + ['3', '액티브 슬롯 (장착 무기 + Lv 표기)', '자동 발동 감상 재미의 기준 정보'], + ['4', '패시브 슬롯 (장착 패시브 + Lv 표기)', '빌드 확인용. 전투 흐름 방해 금지'], + ['5', '각성 조건 진행도', '액티브 Lv.5 도달 시 "각성 대기" 표시'], + ], + [1300, 3700, 4360], +)); + +sections.push(h3('HUD 와이어프레임')); +sections.push(new Paragraph({ + children: [new TextRun({ + text: +`┌──────────────────────────────┐ +│ [Lv.3 ████████░░] [♥ ♥] │ ← 좌상단: 레벨·경험치 + 하트 분할 UI +│ [⚙] │ ← 우상단: 일시정지 +├──────────────────────────────┤ +│ 플레이 영역 │ +├────────────┬─────────────────┤ +│ 액티브: │ 패시브: │ ← 하단: 카드 슬롯 분리 (반투명) +│ [A1][A2] │ [P1][P2][P3] │ +│ [A3][★★] │ [P4][P5][P6] │ ← ★ = 각성 대기 +└────────────┴─────────────────┘`, + font: 'Consolas', size: 18, + })], + spacing: { after: 200, line: 280 }, +})); + +sections.push(h2('9.3 레벨업 카드 픽 UI')); +sections.push(bullet('트리거: 경험치 만렙 → Time.timeScale = 0 일시정지 → 카드 픽 화면 진입.')); +sections.push(bullet('Canvas: CardPickCanvas.prefab (Additive Load), Unscaled Time 사용으로 timeScale 0에서도 정상 동작.')); +sections.push(bullet('각 카드 상단에 액티브·패시브 분류 아이콘 명시 (색상·기호) — "어떤 슬롯으로 들어갈 카드인가" 즉시 인지.')); +sections.push(bullet('이미 장착한 카드는 "Lv.N → Lv.N+1" 표기, 미장착은 "신규" 표기.')); + +sections.push(h2('9.4 피드백 — 피해량별 차등')); +sections.push(makeTable( + ['피해량', '진동 (모바일)', '시각 피드백'], + [ + ['1 (1 쿼터)', '짧은 진동 40ms', '테두리 연한 섬광'], + ['2 (반 하트)', '중간 진동 80ms', '테두리 중간 섬광'], + ['3 (3/4 하트)', '긴 진동 120ms', '테두리 강한 섬광'], + ['4 (하트 전소)', '강한 진동 160ms', '테두리 최대 섬광 + 화면 살짝 흔들림'], + ], + [2300, 3300, 3760], +)); + +// === §10 향후 계획 === +sections.push(h1('10. 향후 계획')); + +sections.push(h2('10.1 PD 후속 검토 영역')); +sections.push(numbered('BM · 과금 구조 — 인앱 결제 모델, 광고 도입 여부, 유료 재화 설계.')); +sections.push(numbered('아트 톤 · UI 톤 — 일러스트 방향성, UI 컬러 팔레트, 폰트, 마을·스테이지 배경 비주얼 가이드.')); +sections.push(numbered('퇴마사 고유 이름 확정 — 현재는 "유저 자기투영" 보존을 위해 미정. 시나리오 대본 단계에서 결정.')); +sections.push(numbered('태그 세계관 재매핑 — 일반 RPG 용어 11종(물리/화염/냉기/번개/암흑/근접/원거리/범위/지속/회복/방어)을 조선 퇴마 특화 용어로 일괄 재매핑 (시나리오 영역).')); +sections.push(numbered('출시 일정 · 빌드 마일스톤 — 현 시점 미정.')); + +sections.push(h2('10.2 코어 프레임워크 (BT.Framework)')); +sections.push(para('BurningTimes 조직의 자산인 BT.Framework Tier 1 16종이 본 프로젝트에서 1순위 도입 검토 대상이다.')); +sections.push(bullet('Tier 1 즉시 활용: SafeAreaBorder, Log, ValidationEx, FormatEx, EnumEx, MathEx 등.')); +sections.push(bullet('Tier 2 신규 구현 후보: UITouchHandler (가상 스틱 멀티터치), BackKeyDispatcher (Android 뒤로가기 통합).')); +sections.push(bullet('Tier 3 (전투·네트워크·UI 고급)은 본작 기획 확정 후 재평가.')); + +sections.push(h2('10.3 검증 시나리오 (밸런스)')); +sections.push(makeTable( + ['ID', '시나리오', '기대 결과'], + [ + ['V-1', '일반 적(약) 1vs1 교전', '액티브 자동 발동 3~4타 처치, 피격 시 1/4 하트 감소'], + ['V-2', '피격 직후 연속 히트', 'i-frame 0.6초 내 2번째 적 공격 무효'], + ['V-3', '하트 분할 시각화', 'ATK 1 피격 시 풀 하트 → 3/4 하트 전환 표시'], + ['V-4', '최대 하트 수 증가', 'P15 생명의 꽃 Lv.1 획득 시 최대 HP 4 → 8 쿼터 변환'], + ['V-6', '보스 TTK 상한', '카드 0장 기준 보스 HP 400 → DPS 기준 75~100초'], + ['V-7', '각성 발동 조건', '액티브 Lv.5 + 필요 패시브 1개 + 보물상자 획득 → 각성 발동'], + ['V-8', '적 ATK 점진 강화', 'Stage 5 진입 시 일반 적 ATK 2 (반 하트) 확인'], + ], + [800, 3500, 5060], +)); + +// === §11 부록 === +sections.push(h1('11. 부록')); + +sections.push(h2('11.1 변경 이력')); +sections.push(makeTable( + ['일시', '단계', '주요 변경'], + [ + ['2026-04-23', 'v0.1 — 파일럿 초기 골격', '핵심 게임 룰 9개 기반 5종 골격 문서 작성 (게임 컨셉·코어 루프·진행 시스템·전투 스펙·스테이지 구조)'], + ['2026-04-24', 'v0.2 — BT7-Plan 개정', 'PD 직접 지시 11건 반영. VS 순수형 (공격 버튼 제거), 액티브/패시브/각성 3분류, 하트 분할, 카드 50~65장 확장, Lv.5 스택, 보물상자 각성 트리거'], + ['2026-04-24', 'v0.2 — BT11-Plan 60종 확장', '액티브 20 · 패시브 20 · 각성 20 컨셉 표 완비'], + ['2026-04-26', 'v1 — 초기 기획서 통합', '본 문서. 16종 기획 SOT 통합 정리'], + ], + [1300, 2700, 5360], +)); + +sections.push(h2('11.2 주요 기각안 요지')); +sections.push(para('본 절은 설계 과정에서 검토 후 기각된 안의 요지를 모아 둔다. 차후 같은 안건이 재논의될 때 "왜 이 방향을 선택하지 않았는지"를 빠르게 확인하기 위함이다.')); +sections.push(makeTable( + ['영역', '기각안', '기각 사유'], + [ + ['게임 컨셉', '하드코어 로그라이크 포지션', '캐주얼 로그라이크 포지션 고수. 하드코어는 타겟 유저 확장 포기 의미'], + ['게임 컨셉', '탑뷰 로그라이크 변형', '횡스크롤 플랫포머 확정. 템플릿(2D PlatformerMicrogame)과 정합'], + ['전투', '수동 공격 유지 (액티브 + 수동 병행)', 'VS 순수형 명시. 수동 공격 병행은 복잡도 증가 + 자동 발동 감상 재미 저해'], + ['전투', '4티어 레어리티 (Common/Uncommon/Rare/Epic)', '"액티브+패시브=각성" 3분류로 통일. 레어리티 체계 폐기'], + ['전투', '적 ATK = 1 (즉사) 단일 설계', '하트 분할 + 점진 강화로 전환. 초반 관대·후반 가혹의 곡선 형성'], + ['전투', 'i-frame 1.0초 / 0.3초', '1.0초는 보스 공격 대부분 무효화, 0.3초는 ATK 4 연타 위험. 0.6초 유지'], + ['전투', 'DEF 스탯 도입', '패시브 [방어] % 감소로 역할 대체. 복잡도만 증가'], + ['카드', '카드 합성 시스템 (2장 합쳐 상위 카드)', '동일 카드 스택 Lv.5가 합성의 재미를 단순 구조로 대체'], + ['카드', '카드도 사망 후 일부 유지', '축 A 낙차가 없으면 재미 축 1 성립 불가. 카드 전손 고수'], + ['카드', '각성을 레벨업 드로우 풀에 포함', '조건 미충족 각성 카드가 무의미 카드로 등장하여 픽 UX 저해. 별도 풀 + 보물상자 트리거'], + ['진행', '카드 3픽이 아닌 2픽', '3이 선택 긴장·변동성·시너지 탐색의 최소 임계'], + ['진행', '특성이 런 내에서도 증가', '축 C는 메타 영역. 런 내 증가 시 축 A와 역할 충돌'], + ['스테이지', '완전 랜덤 프로시저럴 맵', '캐주얼 로그라이크에서 학습 곡선·제작 비용 과다. 부분 랜덤 중심 고정 맵'], + ['스테이지', '보스 스킵 옵션', '"스테이지 마지막은 항상 보스" 고수. 보스가 빌드 검증·보상 분기의 핵심'], + ['스테이지', '보스 여러 마리 동시 출현', '가독성 낮은 보스전은 축 2 붕괴 위험. 보스 1종 고정 (페이즈 구조로 깊이)'], + ['세계관', '조선 고증형 리얼 세계관', '역사 오류 리스크 높고 고증 의무가 창작 자유 제한. 가상 역사 "요괴 성행기"'], + ['세계관', '불교 중심 단일 퇴마 체계', '시각 언어가 절 배경으로 쏠림. 무속 중심 혼합 체계가 다양성 우위'], + ['마을', '대규모 탐험형 마을', '마을 자체가 별도 게임 루프가 되어 재미 축 1·2를 분산. 선형 단층 마을 유지'], + ], + [1500, 3500, 4360], +)); + +sections.push(h2('11.3 참조 문서 (내부 SOT)')); +sections.push(para('본 기획서는 다음 16종 SOT를 통합 정리한 것이다. 각 항목별 상세는 해당 원본 문서 참조.')); +sections.push(bullet('프로젝트/EerieVillage/기획/01_게임_컨셉.md (v0.2)')); +sections.push(bullet('프로젝트/EerieVillage/기획/02_코어_루프.md (v0.2)')); +sections.push(bullet('프로젝트/EerieVillage/기획/03_진행_시스템_초안.md (v0.1)')); +sections.push(bullet('프로젝트/EerieVillage/기획/04_전투_기본_스펙.md (v0.2)')); +sections.push(bullet('프로젝트/EerieVillage/기획/05_스테이지_구조_초안.md (v0.1)')); +sections.push(bullet('프로젝트/EerieVillage/기획/system/01_카드_시스템.md (v0.2)')); +sections.push(bullet('프로젝트/EerieVillage/기획/content/01_카드_풀.md (v0.2)')); +sections.push(bullet('프로젝트/EerieVillage/기획/content/02_스킬_효과_컨셉.md (v0.2)')); +sections.push(bullet('프로젝트/EerieVillage/기획/balance/01_전투_수치.md (v0.2)')); +sections.push(bullet('프로젝트/EerieVillage/기획/balance/02_레벨업_곡선.md (v0.2)')); +sections.push(bullet('프로젝트/EerieVillage/기획/ux/01_모바일_터치_UX.md (v0.2)')); +sections.push(bullet('프로젝트/EerieVillage/기획/ux/02_HUD_설계.md (v0.2)')); +sections.push(bullet('프로젝트/EerieVillage/기획/narrative/01_세계관_SOT.md (v0.1)')); +sections.push(bullet('프로젝트/EerieVillage/기획/narrative/02_보스_네이밍.md (v0.1)')); +sections.push(bullet('프로젝트/EerieVillage/기획/narrative/03_마을_컨셉.md (v0.1)')); + +sections.push(h2('11.4 작성 정보')); +sections.push(bullet('작성: BurningTimes Studio 기획팀장')); +sections.push(bullet('작성일: 2026-04-26')); +sections.push(bullet('대상: 프로듀서·디렉터(PD), 외부 공유 가능')); +sections.push(bullet('단계: Phase 3-A·B 통합 정리. Phase 3-C(BM·아트 톤·세부 대본)는 후속 단계 이관.')); + +// === Document === +const doc = new Document({ + creator: 'BurningTimes Studio · 기획팀', + title: '기묘한 고을 : 조선퇴마뎐 — 초기 기획서 v1', + description: 'EerieVillage: Joseon Exorcist — Initial Design Document v1', + styles: { + default: { + document: { run: { font: FONT_KO, size: 22 } }, + }, + paragraphStyles: [ + { + id: 'Heading1', name: 'Heading 1', basedOn: 'Normal', next: 'Normal', quickFormat: true, + run: { size: 36, bold: true, font: FONT_KO_HEAD, color: '1F3864' }, + paragraph: { spacing: { before: 360, after: 240 }, outlineLevel: 0 }, + }, + { + id: 'Heading2', name: 'Heading 2', basedOn: 'Normal', next: 'Normal', quickFormat: true, + run: { size: 28, bold: true, font: FONT_KO_HEAD, color: '2E75B6' }, + paragraph: { spacing: { before: 280, after: 160 }, outlineLevel: 1 }, + }, + { + id: 'Heading3', name: 'Heading 3', basedOn: 'Normal', next: 'Normal', quickFormat: true, + run: { size: 24, bold: true, font: FONT_KO_HEAD, color: '375E97' }, + paragraph: { spacing: { before: 200, after: 120 }, outlineLevel: 2 }, + }, + ], + }, + numbering: { + config: [ + { + reference: 'bullets', + levels: [ + { + level: 0, format: LevelFormat.BULLET, text: '•', alignment: AlignmentType.LEFT, + style: { paragraph: { indent: { left: 540, hanging: 270 } } }, + }, + { + level: 1, format: LevelFormat.BULLET, text: '◦', alignment: AlignmentType.LEFT, + style: { paragraph: { indent: { left: 1080, hanging: 270 } } }, + }, + ], + }, + { + reference: 'numbers', + levels: [ + { + level: 0, format: LevelFormat.DECIMAL, text: '%1.', alignment: AlignmentType.LEFT, + style: { paragraph: { indent: { left: 540, hanging: 270 } } }, + }, + ], + }, + ], + }, + sections: [ + { + properties: { + page: { + size: { width: 12240, height: 15840 }, // US Letter + margin: { top: 1440, right: 1440, bottom: 1440, left: 1440 }, + }, + }, + headers: { + default: new Header({ + children: [new Paragraph({ + alignment: AlignmentType.RIGHT, + children: [new TextRun({ text: '기묘한 고을 : 조선퇴마뎐 — 초기 기획서 v1', font: FONT_KO, size: 18, color: '808080' })], + })], + }), + }, + footers: { + default: new Footer({ + children: [new Paragraph({ + alignment: AlignmentType.CENTER, + children: [ + new TextRun({ text: 'BurningTimes Studio · 기획팀 | ', font: FONT_KO, size: 18, color: '808080' }), + new TextRun({ text: '', font: FONT_KO, size: 18, color: '808080', children: [PageNumber.CURRENT] }), + new TextRun({ text: ' / ', font: FONT_KO, size: 18, color: '808080' }), + new TextRun({ text: '', font: FONT_KO, size: 18, color: '808080', children: [PageNumber.TOTAL_PAGES] }), + ], + })], + }), + }, + children: sections, + }, + ], +}); + +const outPath = path.join(__dirname, '기묘한고을_초기기획서_v1.docx'); +Packer.toBuffer(doc).then(buffer => { + fs.writeFileSync(outPath, buffer); + const stats = fs.statSync(outPath); + console.log('OK ' + outPath); + console.log('Size: ' + (stats.size / 1024).toFixed(1) + ' KB'); +}).catch(err => { + console.error('FAIL', err); + process.exit(1); +}); diff --git a/프로젝트/EerieVillage/기획/_build_skill_pptx.py b/프로젝트/EerieVillage/기획/_build_skill_pptx.py new file mode 100644 index 0000000..b8aa094 --- /dev/null +++ b/프로젝트/EerieVillage/기획/_build_skill_pptx.py @@ -0,0 +1,2292 @@ +# -*- coding: utf-8 -*- +""" +EerieVillage 스킬 시스템 개발 기획서 PPT 빌더 +- 산출물: 스킬시스템_개발기획서_v1.pptx +- 대상: PD 검토 + 개발팀 구현 참고 +- 통합 SOT: BT7-Plan + BT11-Plan + BT12-Dev v1 (7종 문서) +""" +from pptx import Presentation +from pptx.util import Inches, Pt, Emu +from pptx.dml.color import RGBColor +from pptx.enum.shapes import MSO_SHAPE +from pptx.enum.text import PP_ALIGN, MSO_ANCHOR +from pptx.oxml.ns import qn +from copy import deepcopy +from lxml import etree + +# ============================================================ +# 색상 팔레트 (Midnight Executive — 조선 퇴마 톤 정합) +# ============================================================ +NAVY = RGBColor(0x1E, 0x27, 0x61) # 주: 야밤 네이비 +ICE = RGBColor(0xCA, 0xDC, 0xFC) # 보조: 얼음 푸름 +ACCENT = RGBColor(0xE8, 0xB4, 0x3C) # 액센트: 황금 부적색 +WHITE = RGBColor(0xFF, 0xFF, 0xFF) +DARK_TEXT = RGBColor(0x21, 0x29, 0x5C) # 본문 텍스트 +GRAY = RGBColor(0x66, 0x66, 0x66) # 캡션 +LIGHT_BG = RGBColor(0xF8, 0xF9, 0xFB) # 컨텐츠 배경 +RED_HL = RGBColor(0xC0, 0x39, 0x2B) # 강조 (PD 결정 영역) +GREEN_OK = RGBColor(0x3D, 0x8B, 0x5A) # 완료·확정 +PURPLE = RGBColor(0x6D, 0x2E, 0x46) # 각성·진화 + +# 폰트 +HEADER_FONT = "맑은 고딕" +BODY_FONT = "맑은 고딕" +CODE_FONT = "Consolas" + +# 슬라이드 크기 (16:9 와이드) +SLIDE_W = Inches(13.333) +SLIDE_H = Inches(7.5) + +# ============================================================ +# 헬퍼 함수 +# ============================================================ +def add_solid_bg(slide, color): + bg = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, 0, 0, SLIDE_W, SLIDE_H) + bg.fill.solid() + bg.fill.fore_color.rgb = color + bg.line.fill.background() + bg.shadow.inherit = False + # 맨 뒤로 보내기 + spTree = bg._element.getparent() + spTree.remove(bg._element) + spTree.insert(2, bg._element) + return bg + +def add_text_box(slide, left, top, width, height, text, font_size=14, + bold=False, color=DARK_TEXT, align=PP_ALIGN.LEFT, + anchor=MSO_ANCHOR.TOP, font_name=BODY_FONT): + tb = slide.shapes.add_textbox(left, top, width, height) + tf = tb.text_frame + tf.word_wrap = True + tf.margin_left = Inches(0.05) + tf.margin_right = Inches(0.05) + tf.margin_top = Inches(0.02) + tf.margin_bottom = Inches(0.02) + tf.vertical_anchor = anchor + p = tf.paragraphs[0] + p.alignment = align + run = p.add_run() + run.text = text + run.font.name = font_name + run.font.size = Pt(font_size) + run.font.bold = bold + run.font.color.rgb = color + return tb + +def add_multiline_text(slide, left, top, width, height, lines, font_size=12, + color=DARK_TEXT, font_name=BODY_FONT, line_spacing=1.15): + """lines: list of dict {text, bold, color, size, bullet}""" + tb = slide.shapes.add_textbox(left, top, width, height) + tf = tb.text_frame + tf.word_wrap = True + tf.margin_left = Inches(0.05) + tf.margin_right = Inches(0.05) + for i, line in enumerate(lines): + p = tf.paragraphs[0] if i == 0 else tf.add_paragraph() + p.alignment = line.get("align", PP_ALIGN.LEFT) + p.line_spacing = line_spacing + text = line["text"] + if line.get("bullet"): + text = "• " + text + run = p.add_run() + run.text = text + run.font.name = font_name + run.font.size = Pt(line.get("size", font_size)) + run.font.bold = line.get("bold", False) + run.font.color.rgb = line.get("color", color) + return tb + +def add_shape(slide, shape_type, left, top, width, height, + fill=None, line=None, text=None, font_size=12, + text_color=WHITE, bold=False, font_name=BODY_FONT): + s = slide.shapes.add_shape(shape_type, left, top, width, height) + if fill is not None: + s.fill.solid() + s.fill.fore_color.rgb = fill + else: + s.fill.background() + if line is not None: + s.line.color.rgb = line + s.line.width = Pt(0.75) + else: + s.line.fill.background() + s.shadow.inherit = False + if text: + tf = s.text_frame + tf.word_wrap = True + tf.margin_left = Inches(0.06) + tf.margin_right = Inches(0.06) + tf.margin_top = Inches(0.04) + tf.margin_bottom = Inches(0.04) + tf.vertical_anchor = MSO_ANCHOR.MIDDLE + p = tf.paragraphs[0] + p.alignment = PP_ALIGN.CENTER + run = p.add_run() + run.text = text + run.font.name = font_name + run.font.size = Pt(font_size) + run.font.bold = bold + run.font.color.rgb = text_color + return s + +def add_table(slide, left, top, width, height, data, header=True, + header_fill=NAVY, header_color=WHITE, body_size=10, header_size=11, + col_widths=None): + rows = len(data) + cols = len(data[0]) + tbl_shape = slide.shapes.add_table(rows, cols, left, top, width, height) + tbl = tbl_shape.table + if col_widths: + total = sum(col_widths) + for i, w in enumerate(col_widths): + tbl.columns[i].width = Emu(int(width * (w / total))) + for r in range(rows): + for c in range(cols): + cell = tbl.cell(r, c) + cell.margin_left = Inches(0.05) + cell.margin_right = Inches(0.05) + cell.margin_top = Inches(0.02) + cell.margin_bottom = Inches(0.02) + tf = cell.text_frame + tf.word_wrap = True + tf.clear() + p = tf.paragraphs[0] + p.alignment = PP_ALIGN.CENTER if (r == 0 and header) else PP_ALIGN.LEFT + run = p.add_run() + txt = str(data[r][c]) + run.text = txt + run.font.name = BODY_FONT + if r == 0 and header: + run.font.size = Pt(header_size) + run.font.bold = True + run.font.color.rgb = header_color + cell.fill.solid() + cell.fill.fore_color.rgb = header_fill + else: + run.font.size = Pt(body_size) + run.font.color.rgb = DARK_TEXT + # 홀짝 행 색 + if r % 2 == 0: + cell.fill.solid() + cell.fill.fore_color.rgb = LIGHT_BG + else: + cell.fill.solid() + cell.fill.fore_color.rgb = WHITE + return tbl_shape + +def add_slide_header(slide, title, slide_no, total, section=""): + """모든 본문 슬라이드 공통 헤더""" + # 좌상단 제목 + add_text_box(slide, Inches(0.5), Inches(0.25), Inches(10), Inches(0.55), + title, font_size=24, bold=True, color=NAVY, font_name=HEADER_FONT) + # 우상단 슬라이드 번호 + 부 표기 + add_text_box(slide, Inches(11.3), Inches(0.3), Inches(2), Inches(0.4), + f"{section} | {slide_no}/{total}", font_size=10, + color=GRAY, align=PP_ALIGN.RIGHT) + # 헤더 하단 액센트 라인 (얇은 황금색) + line = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, + Inches(0.5), Inches(0.85), + Inches(12.3), Pt(2)) + line.fill.solid() + line.fill.fore_color.rgb = ACCENT + line.line.fill.background() + line.shadow.inherit = False + +def add_footer(slide, slide_no, total): + add_text_box(slide, Inches(0.5), Inches(7.15), Inches(8), Inches(0.3), + "EerieVillage: Joseon Exorcist | 스킬 시스템 개발 기획서 v1", + font_size=8, color=GRAY) + add_text_box(slide, Inches(11.3), Inches(7.15), Inches(2), Inches(0.3), + f"BurningTimes 기획팀 | {slide_no}/{total}", + font_size=8, color=GRAY, align=PP_ALIGN.RIGHT) + +# ============================================================ +# 빌드 시작 +# ============================================================ +prs = Presentation() +prs.slide_width = SLIDE_W +prs.slide_height = SLIDE_H + +BLANK = prs.slide_layouts[6] +TOTAL_SLIDES = 36 + +# ============================================================ +# 슬라이드 1 — 표지 +# ============================================================ +s = prs.slides.add_slide(BLANK) +add_solid_bg(s, NAVY) + +# 액센트 도형 (좌측 황금 띠) +band = s.shapes.add_shape(MSO_SHAPE.RECTANGLE, + 0, Inches(2.5), Inches(0.4), Inches(2.5)) +band.fill.solid() +band.fill.fore_color.rgb = ACCENT +band.line.fill.background() +band.shadow.inherit = False + +add_text_box(s, Inches(1.0), Inches(2.0), Inches(11), Inches(0.7), + "기묘한 고을 : 조선퇴마뎐", font_size=22, + color=ICE, font_name=HEADER_FONT) +add_text_box(s, Inches(1.0), Inches(2.6), Inches(11), Inches(1.2), + "스킬 시스템 개발 기획서", font_size=46, bold=True, + color=WHITE, font_name=HEADER_FONT) +add_text_box(s, Inches(1.0), Inches(3.9), Inches(11), Inches(0.5), + "EerieVillage: Joseon Exorcist — Skill System Spec v1", + font_size=16, color=ICE, font_name=BODY_FONT) +# 메타 정보 +add_multiline_text(s, Inches(1.0), Inches(5.2), Inches(11), Inches(1.5), + [ + {"text": "조직: BurningTimes 게임 개발 스튜디오 / 기획팀", + "size": 13, "color": ICE}, + {"text": "대상: PD 직접 검토 + 개발팀(클라이언트·서버·QA) 구현 참고", + "size": 13, "color": ICE}, + {"text": "통합 SOT: BT7-Plan(시스템·콘텐츠) + BT11-Plan(60종 명세) + BT12-Dev v1(개발 설계)", + "size": 13, "color": ICE}, + {"text": "작성일: 2026-04-26 / 버전: v1.0", + "size": 13, "color": ICE}, + ]) + +# ============================================================ +# 1부 — 개요 (슬라이드 2~7) +# ============================================================ + +# 슬라이드 2 — 시스템 정체성 +s = prs.slides.add_slide(BLANK) +add_solid_bg(s, WHITE) +add_slide_header(s, "시스템 정체성", 2, TOTAL_SLIDES, "1부 개요") + +add_text_box(s, Inches(0.5), Inches(1.1), Inches(12), Inches(0.6), + "한 줄 요약", font_size=16, bold=True, color=NAVY) +quote = s.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, + Inches(0.5), Inches(1.7), Inches(12), Inches(1.2)) +quote.fill.solid() +quote.fill.fore_color.rgb = ICE +quote.line.fill.background() +quote.shadow.inherit = False +qtf = quote.text_frame +qtf.margin_left = Inches(0.3) +qtf.margin_right = Inches(0.3) +qtf.vertical_anchor = MSO_ANCHOR.MIDDLE +qp = qtf.paragraphs[0] +qp.alignment = PP_ALIGN.CENTER +qr = qp.add_run() +qr.text = "레벨업 픽으로 빌드를 쌓고, 조건 충족 시 발동하는 각성으로 카타르시스를 제공하는\n자동 발동형(VS 순수형) 스킬·진화 시스템" +qr.font.name = HEADER_FONT +qr.font.size = Pt(18) +qr.font.bold = True +qr.font.color.rgb = NAVY + +add_text_box(s, Inches(0.5), Inches(3.2), Inches(12), Inches(0.5), + "VS 순수형 채택 근거 (BT7-Plan 확정 방향 2)", + font_size=15, bold=True, color=NAVY) +add_multiline_text(s, Inches(0.7), Inches(3.7), Inches(12), Inches(3.5), + [ + {"text": "공격 버튼 자체 제거 — 플레이어 입력은 이동·점프만", "bullet": True, "size": 13}, + {"text": "장착한 액티브가 고유 주기·판정·대미지로 자동 발동 (Vampire Survivors 패턴)", "bullet": True, "size": 13}, + {"text": "캐주얼 모바일 환경 정합 — 가상 스틱 1개로 5~10분 런 완결", "bullet": True, "size": 13}, + {"text": "손맛은 \"타격 순간의 히트스탑·이펙트·사운드\"로 보장 (i-frame 0.6s 유지)", "bullet": True, "size": 13}, + {"text": "조작 부담 경감 → 회피·포지셔닝·빌드 설계에 인지 자원 집중", "bullet": True, "size": 13}, + ]) + +add_footer(s, 2, TOTAL_SLIDES) + +# 슬라이드 3 — 재미 축 3종 연결 +s = prs.slides.add_slide(BLANK) +add_solid_bg(s, WHITE) +add_slide_header(s, "재미 축 3종과의 연결 (P30 재미 우선 원칙)", 3, TOTAL_SLIDES, "1부 개요") + +# 3개 컬럼 카드 +cards = [ + ("축 1", "육성 롤러코스터의\n카타르시스", + "쌓기 → 폭발 → 낙차 리듬\n각성 발동 = 절정 포인트\n빌드 완성 순간의 전능감", + PURPLE), + ("축 2", "자동 발동 감상\n(VS 순수형)", + "이동·점프만으로 포지셔닝\n장착 액티브가 화면을 채움\n\"내가 만든 군대\" 감각", + NAVY), + ("축 3", "영속 성장의 위안\n(보조)", + "패시브 스탯 누적\n최대 하트 +1 패시브로\n런 내 안도감 형성", + GREEN_OK), +] +col_w = Inches(3.9) +gap = Inches(0.2) +start_x = Inches(0.5) +for i, (axis, title, body, color) in enumerate(cards): + x = start_x + (col_w + gap) * i + # 헤더 박스 + head = s.shapes.add_shape(MSO_SHAPE.RECTANGLE, x, Inches(1.2), col_w, Inches(0.7)) + head.fill.solid() + head.fill.fore_color.rgb = color + head.line.fill.background() + head.shadow.inherit = False + htf = head.text_frame + htf.vertical_anchor = MSO_ANCHOR.MIDDLE + hp = htf.paragraphs[0] + hp.alignment = PP_ALIGN.CENTER + hr = hp.add_run() + hr.text = axis + hr.font.name = HEADER_FONT + hr.font.size = Pt(20) + hr.font.bold = True + hr.font.color.rgb = WHITE + # 본문 박스 + body_box = s.shapes.add_shape(MSO_SHAPE.RECTANGLE, x, Inches(1.9), col_w, Inches(4.3)) + body_box.fill.solid() + body_box.fill.fore_color.rgb = LIGHT_BG + body_box.line.color.rgb = color + body_box.line.width = Pt(1.5) + body_box.shadow.inherit = False + btf = body_box.text_frame + btf.margin_left = Inches(0.2) + btf.margin_right = Inches(0.2) + btf.margin_top = Inches(0.2) + bp = btf.paragraphs[0] + bp.alignment = PP_ALIGN.CENTER + br = bp.add_run() + br.text = title + br.font.name = HEADER_FONT + br.font.size = Pt(15) + br.font.bold = True + br.font.color.rgb = NAVY + bp2 = btf.add_paragraph() + bp2.alignment = PP_ALIGN.CENTER + bp2.line_spacing = 1.5 + br2 = bp2.add_run() + br2.text = "\n" + body + br2.font.name = BODY_FONT + br2.font.size = Pt(12) + br2.font.color.rgb = DARK_TEXT + +add_text_box(s, Inches(0.5), Inches(6.4), Inches(12.3), Inches(0.5), + "스킬 시스템은 3축 모두에 기여 — 액티브(축 2) + 패시브(축 3) + 각성 발동(축 1) 통합 구조", + font_size=12, color=GRAY, align=PP_ALIGN.CENTER) +add_footer(s, 3, TOTAL_SLIDES) + +# 슬라이드 4 — 핵심 KPI / 성공 지표 +s = prs.slides.add_slide(BLANK) +add_solid_bg(s, WHITE) +add_slide_header(s, "핵심 KPI / 성공 지표", 4, TOTAL_SLIDES, "1부 개요") + +add_text_box(s, Inches(0.5), Inches(1.1), Inches(12), Inches(0.5), + "스킬 시스템 성공 판정 4축", + font_size=14, bold=True, color=NAVY) + +kpi_data = [ + ["판정 축", "지표", "목표", "측정 방식"], + ["다양성", "런당 빌드 분기 수", "8종 이상 시너지 빌드", "내부 플레이테스트·시너지 카드 그래프"], + ["성장 체감", "1 스테이지 내 레벨업 횟수", "4~6회 (50~90초/회)", "balance/02 §3 곡선 검증"], + ["각성 카타르시스", "런당 각성 발동 횟수", "1~2회 (Stage 3~4 첫 발동)", "보물상자·조건 충족 빈도 로그"], + ["조작 부담", "1런 내 입력 채널", "이동·점프 2채널 한정", "InputSystem 액션 카탈로그 검증"], + ["성능", "60 fps 유지율", "모바일 95%+ (광역 각성 시)", "Profiler·Frame Debugger 실측"], + ["몰입 시간", "평균 런 길이", "5~10분 (캐주얼 정합)", "Stage 클리어·사망 timestamp"], +] +add_table(s, Inches(0.5), Inches(1.7), Inches(12.3), Inches(4.0), + kpi_data, body_size=11, header_size=12, + col_widths=[2, 3, 3.5, 3.8]) + +add_text_box(s, Inches(0.5), Inches(5.9), Inches(12), Inches(0.5), + "핵심 재미 가설", + font_size=14, bold=True, color=NAVY) +add_multiline_text(s, Inches(0.7), Inches(6.4), Inches(12), Inches(0.8), + [ + {"text": "각성 발동은 \"기다림이 보상받는\" 순간 — Lv.5 도달까지 동일 카드 5회 픽 투자가 각성 발동 시 카타르시스로 전환된다", + "bullet": True, "size": 12, "color": DARK_TEXT}, + ]) +add_footer(s, 4, TOTAL_SLIDES) + +# 슬라이드 5 — 본 문서 범위·비범위 +s = prs.slides.add_slide(BLANK) +add_solid_bg(s, WHITE) +add_slide_header(s, "본 문서 범위 (Scope) · 비범위 (Out of Scope)", 5, TOTAL_SLIDES, "1부 개요") + +# 좌측 — 범위 (포함) +left_box = s.shapes.add_shape(MSO_SHAPE.RECTANGLE, + Inches(0.5), Inches(1.2), Inches(6), Inches(5.5)) +left_box.fill.solid() +left_box.fill.fore_color.rgb = LIGHT_BG +left_box.line.color.rgb = GREEN_OK +left_box.line.width = Pt(2) +left_box.shadow.inherit = False +add_text_box(s, Inches(0.7), Inches(1.35), Inches(5.5), Inches(0.5), + "본 문서가 다루는 범위", font_size=15, bold=True, color=GREEN_OK) +add_multiline_text(s, Inches(0.9), Inches(1.95), Inches(5.5), Inches(4.7), + [ + {"text": "스킬 3분류(액티브·패시브·각성) 시스템 구조", "bullet": True, "size": 12}, + {"text": "60종 카드 카탈로그 (액티브 20·패시브 20·각성 20)", "bullet": True, "size": 12}, + {"text": "픽 알고리즘·스택 업그레이드(Lv.1~5) 메커니즘", "bullet": True, "size": 12}, + {"text": "각성 발동 3조건 동시 충족 판정 로직", "bullet": True, "size": 12}, + {"text": "보물상자 체계·시너지 발동·하트 증가 메커니즘", "bullet": True, "size": 12}, + {"text": "Unity C# 클래스·인터페이스·이벤트 구조", "bullet": True, "size": 12}, + {"text": "BT.Framework Tier 1·2 활용 영역", "bullet": True, "size": 12}, + {"text": "BT7-Dev 자산(PlayerAttack·Health 등) 통합 영역", "bullet": True, "size": 12}, + {"text": "EditMode·PlayMode 검증 시나리오·어뷰징 가드", "bullet": True, "size": 12}, + {"text": "Phase 분리 우선순위 (P0~P4)", "bullet": True, "size": 12}, + ]) + +# 우측 — 비범위 (제외) +right_box = s.shapes.add_shape(MSO_SHAPE.RECTANGLE, + Inches(6.8), Inches(1.2), Inches(6), Inches(5.5)) +right_box.fill.solid() +right_box.fill.fore_color.rgb = LIGHT_BG +right_box.line.color.rgb = RED_HL +right_box.line.width = Pt(2) +right_box.shadow.inherit = False +add_text_box(s, Inches(7.0), Inches(1.35), Inches(5.5), Inches(0.5), + "본 문서가 다루지 않는 범위", font_size=15, bold=True, color=RED_HL) +add_multiline_text(s, Inches(7.2), Inches(1.95), Inches(5.5), Inches(4.7), + [ + {"text": "구체 수치(대미지·확률·쿨다운) — balance-designer 이관", "bullet": True, "size": 12}, + {"text": "narrative 한자 카드명 재매핑 — 현행 유지 (PD 후속)", "bullet": True, "size": 12}, + {"text": "BM·과금 구조 — Phase 3-C 별도 설계", "bullet": True, "size": 12}, + {"text": "스테이지·맵·적 배치 — level-designer 영역", "bullet": True, "size": 12}, + {"text": "사운드·이펙트 아트 리소스 — 외부 아티스트 영역", "bullet": True, "size": 12}, + {"text": "특성(Trait) 시스템 상세 — system/02 별도 문서", "bullet": True, "size": 12}, + {"text": "보스 패턴·페이즈 설계 — content/03 별도", "bullet": True, "size": 12}, + {"text": "다국어·로컬라이제이션 — 출시 단계 별도", "bullet": True, "size": 12}, + ]) + +add_footer(s, 5, TOTAL_SLIDES) + +# 슬라이드 6 — 의존 시스템·문서 SOT +s = prs.slides.add_slide(BLANK) +add_solid_bg(s, WHITE) +add_slide_header(s, "의존 시스템 · 문서 SOT 인벤토리", 6, TOTAL_SLIDES, "1부 개요") + +add_text_box(s, Inches(0.5), Inches(1.1), Inches(12), Inches(0.4), + "본 기획서가 통합한 7종 SOT 문서", + font_size=14, bold=True, color=NAVY) + +sot_data = [ + ["문서", "버전", "역할", "기획서 반영 부"], + ["system/01_카드_시스템.md", "v0.2 (BT7-Plan)", "3분류 구조·픽 알고리즘·각성 조건·하트 증가", "2부 구조 / 4부 메커니즘"], + ["content/01_카드_풀.md", "v0.2 (BT7-Plan)", "3분류 카드 풀 규모·태그 체계·시너지 빌드 예시", "3부 카테고리 / 5부 60종"], + ["content/02_스킬_효과_컨셉.md", "v0.2 (BT11-Plan)", "60종 카드 단위 동작 컨셉·카테고리 분배", "3부 / 5부"], + ["balance/01_전투_수치.md", "v0.2 (BT7-Plan)", "대미지 공식·BaseCooldown·BaseDamage·StackLevelFactor", "4부 메커니즘 / 6부 구현"], + ["balance/02_레벨업_곡선.md", "v0.2 (BT7-Plan)", "경험치·레벨업 주기·픽 알고리즘 가중치", "4부 메커니즘"], + ["ux/02_HUD_설계.md", "v0.2 (BT7-Plan)", "픽 UI·각성 발동 연출·HUD 슬롯", "4부 / 6부 UI 가이드"], + ["개발/spec/스킬_시스템_설계_v1.md", "v1.0 (BT12-Dev)", "Unity C# 4계층 아키텍처·인터페이스 정의", "6부 구현 가이드 (전수)"], +] +add_table(s, Inches(0.5), Inches(1.6), Inches(12.3), Inches(4.5), + sot_data, body_size=10, header_size=11, + col_widths=[3.2, 2, 4.5, 2.6]) + +add_text_box(s, Inches(0.5), Inches(6.3), Inches(12), Inches(0.8), + "📌 본 기획서는 BT7-Plan(시스템·콘텐츠) + BT11-Plan(60종 명세) + BT12-Dev v1(개발 설계) 3종 통합 산출물로,\n" + " 각 SOT의 단일 진실 원천(SSOT)을 유지하며 본 문서는 통합 인덱스 역할을 한다.", + font_size=11, color=GRAY) +add_footer(s, 6, TOTAL_SLIDES) + +# 슬라이드 7 — 1부 요약·전환 +s = prs.slides.add_slide(BLANK) +add_solid_bg(s, NAVY) +add_text_box(s, Inches(0.5), Inches(2.5), Inches(12.3), Inches(0.7), + "2부 — 시스템 구조", font_size=42, bold=True, color=ICE, + align=PP_ALIGN.CENTER, font_name=HEADER_FONT) +add_text_box(s, Inches(0.5), Inches(3.4), Inches(12.3), Inches(0.5), + "3분류 카드 구조 · 코어 루프 · 데이터 모델 · 태그 체계 · 빌드 슬롯", + font_size=18, color=ICE, align=PP_ALIGN.CENTER) +# 좌측 황금띠 +band = s.shapes.add_shape(MSO_SHAPE.RECTANGLE, 0, Inches(2.0), Inches(0.4), Inches(2.5)) +band.fill.solid() +band.fill.fore_color.rgb = ACCENT +band.line.fill.background() +band.shadow.inherit = False +add_text_box(s, Inches(0.5), Inches(6.8), Inches(12.3), Inches(0.4), + "Slide 7 / 36", font_size=10, color=ICE, align=PP_ALIGN.CENTER) + +# ============================================================ +# 2부 — 시스템 구조 (슬라이드 8~14) +# ============================================================ + +# 슬라이드 8 — 3분류 구조 다이어그램 +s = prs.slides.add_slide(BLANK) +add_solid_bg(s, WHITE) +add_slide_header(s, "카드 3분류 구조 — 액티브 + 패시브 = 각성", 8, TOTAL_SLIDES, "2부 구조") + +# 액티브 박스 +active_box = s.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, + Inches(0.7), Inches(1.5), Inches(3.5), Inches(2.0)) +active_box.fill.solid() +active_box.fill.fore_color.rgb = NAVY +active_box.line.fill.background() +active_box.shadow.inherit = False +atf = active_box.text_frame +atf.vertical_anchor = MSO_ANCHOR.MIDDLE +atf.margin_left = Inches(0.2) +atf.margin_right = Inches(0.2) +ap = atf.paragraphs[0] +ap.alignment = PP_ALIGN.CENTER +ar = ap.add_run() +ar.text = "액티브" +ar.font.name = HEADER_FONT +ar.font.size = Pt(24) +ar.font.bold = True +ar.font.color.rgb = WHITE +ap2 = atf.add_paragraph() +ap2.alignment = PP_ALIGN.CENTER +ar2 = ap2.add_run() +ar2.text = "\n자동 발동 무기·스킬\n주기·판정·대미지\n20종 (Lv.1~Lv.5)" +ar2.font.name = BODY_FONT +ar2.font.size = Pt(13) +ar2.font.color.rgb = ICE + +# 더하기 기호 +plus = s.shapes.add_shape(MSO_SHAPE.OVAL, Inches(4.5), Inches(2.2), Inches(0.6), Inches(0.6)) +plus.fill.solid() +plus.fill.fore_color.rgb = ACCENT +plus.line.fill.background() +ptf = plus.text_frame +ptf.vertical_anchor = MSO_ANCHOR.MIDDLE +pp = ptf.paragraphs[0] +pp.alignment = PP_ALIGN.CENTER +pr = pp.add_run() +pr.text = "+" +pr.font.size = Pt(24) +pr.font.bold = True +pr.font.color.rgb = NAVY + +# 패시브 박스 +passive_box = s.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, + Inches(5.4), Inches(1.5), Inches(3.5), Inches(2.0)) +passive_box.fill.solid() +passive_box.fill.fore_color.rgb = GREEN_OK +passive_box.line.fill.background() +passive_box.shadow.inherit = False +ptf2 = passive_box.text_frame +ptf2.vertical_anchor = MSO_ANCHOR.MIDDLE +ptf2.margin_left = Inches(0.2) +pp_p = ptf2.paragraphs[0] +pp_p.alignment = PP_ALIGN.CENTER +pp_r = pp_p.add_run() +pp_r.text = "패시브" +pp_r.font.name = HEADER_FONT +pp_r.font.size = Pt(24) +pp_r.font.bold = True +pp_r.font.color.rgb = WHITE +pp_p2 = ptf2.add_paragraph() +pp_p2.alignment = PP_ALIGN.CENTER +pp_r2 = pp_p2.add_run() +pp_r2.text = "\n상시 스탯·효과 보정\n액티브 효율 증폭\n20종 (Lv.1~Lv.5)" +pp_r2.font.name = BODY_FONT +pp_r2.font.size = Pt(13) +pp_r2.font.color.rgb = WHITE + +# 화살표 (조건 충족) +arrow = s.shapes.add_shape(MSO_SHAPE.RIGHT_ARROW, + Inches(9.2), Inches(2.3), Inches(0.8), Inches(0.4)) +arrow.fill.solid() +arrow.fill.fore_color.rgb = ACCENT +arrow.line.fill.background() +arrow.shadow.inherit = False +add_text_box(s, Inches(9.05), Inches(1.85), Inches(1.2), Inches(0.4), + "조건 충족", font_size=10, color=GRAY, align=PP_ALIGN.CENTER) + +# 각성 박스 +awaken_box = s.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, + Inches(10.2), Inches(1.5), Inches(2.7), Inches(2.0)) +awaken_box.fill.solid() +awaken_box.fill.fore_color.rgb = PURPLE +awaken_box.line.fill.background() +awaken_box.shadow.inherit = False +awtf = awaken_box.text_frame +awtf.vertical_anchor = MSO_ANCHOR.MIDDLE +awp = awtf.paragraphs[0] +awp.alignment = PP_ALIGN.CENTER +awr = awp.add_run() +awr.text = "각성" +awr.font.name = HEADER_FONT +awr.font.size = Pt(24) +awr.font.bold = True +awr.font.color.rgb = WHITE +awp2 = awtf.add_paragraph() +awp2.alignment = PP_ALIGN.CENTER +awr2 = awp2.add_run() +awr2.text = "\n진화 카드\n(별도 풀)\n20종" +awr2.font.name = BODY_FONT +awr2.font.size = Pt(13) +awr2.font.color.rgb = WHITE + +# 발동 조건 (하단) +add_text_box(s, Inches(0.5), Inches(4.0), Inches(12.3), Inches(0.5), + "각성 발동 3조건 동시 충족 (VS 원작 동일)", + font_size=15, bold=True, color=NAVY, align=PP_ALIGN.CENTER) + +cond_data = [ + ["조건 1", "조건 2", "조건 3"], + ["해당 액티브 카드 Lv.5 도달", "각성에 필요한 패시브 1+ 보유", "보물상자 획득"], +] +add_table(s, Inches(1.0), Inches(4.6), Inches(11.3), Inches(1.3), + cond_data, header_fill=PURPLE, body_size=12, header_size=13, + col_widths=[1, 1, 1]) + +add_text_box(s, Inches(0.5), Inches(6.2), Inches(12.3), Inches(0.7), + "총 카드 풀 규모: 60종 (20+20+20)\n" + "구 4티어 레어리티(Common/Uncommon/Rare/Epic) 폐기 -> VS 원작 계승 3분류 구조", + font_size=11, color=GRAY, align=PP_ALIGN.CENTER) + +add_footer(s, 8, TOTAL_SLIDES) + +# 슬라이드 9 — 코어 루프 +s = prs.slides.add_slide(BLANK) +add_solid_bg(s, WHITE) +add_slide_header(s, "코어 루프 — 픽 -> 스택 -> 각성 -> 클라이맥스", 9, TOTAL_SLIDES, "2부 구조") + +# 7단계 플로우차트 +loop_steps = [ + ("1", "레벨업 트리거", "경험치 만렙 도달", NAVY), + ("2", "3장 무작위 드로우", "액티브·패시브 2축\n빌드 태그 가중", NAVY), + ("3", "픽 UI 표시", "1장 선택 (강제)\n건너뛰기 없음", NAVY), + ("4", "장착 / 스택 업그레이드", "신규 장착 또는\n동일 카드 Lv.N->N+1", NAVY), + ("5", "보물상자 획득 (병행)", "스테이지 진행 중\n조건부 스폰", ACCENT), + ("6", "각성 발동 판정", "3조건 동시 충족\n각성 풀에서 발동", PURPLE), + ("7", "런 종료", "보스 클리어 / 사망\n카드 전손·빌드 초기화", RED_HL), +] + +box_w = Inches(1.7) +box_h = Inches(2.3) +gap = Inches(0.05) +start_x = Inches(0.4) +top = Inches(1.5) + +for i, (num, title, desc, color) in enumerate(loop_steps): + x = start_x + (box_w + gap) * i + box = s.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, x, top, box_w, box_h) + box.fill.solid() + box.fill.fore_color.rgb = color + box.line.fill.background() + box.shadow.inherit = False + btf = box.text_frame + btf.margin_left = Inches(0.08) + btf.margin_right = Inches(0.08) + btf.margin_top = Inches(0.1) + btf.vertical_anchor = MSO_ANCHOR.TOP + bp = btf.paragraphs[0] + bp.alignment = PP_ALIGN.CENTER + br = bp.add_run() + br.text = num + br.font.name = HEADER_FONT + br.font.size = Pt(20) + br.font.bold = True + br.font.color.rgb = WHITE + bp2 = btf.add_paragraph() + bp2.alignment = PP_ALIGN.CENTER + bp2.line_spacing = 1.2 + br2 = bp2.add_run() + br2.text = "\n" + title + br2.font.name = HEADER_FONT + br2.font.size = Pt(11) + br2.font.bold = True + br2.font.color.rgb = WHITE + bp3 = btf.add_paragraph() + bp3.alignment = PP_ALIGN.CENTER + bp3.line_spacing = 1.15 + br3 = bp3.add_run() + br3.text = "\n" + desc + br3.font.name = BODY_FONT + br3.font.size = Pt(9) + br3.font.color.rgb = WHITE + +add_text_box(s, Inches(0.5), Inches(4.2), Inches(12), Inches(0.5), + "주요 분기점·강조 사항", + font_size=14, bold=True, color=NAVY) +add_multiline_text(s, Inches(0.7), Inches(4.7), Inches(12.3), Inches(2.3), + [ + {"text": "픽 단계(3) — \"건너뛰기\" 옵션 미제공. 3장 모두 나쁜 경우는 \"빌드 위기\"로 설계 (긴장 요소)", + "bullet": True, "size": 12}, + {"text": "스택 단계(4) — Lv.5 도달 시 각성 조건 1번 \"액티브 Lv.5\" 충족 (자동 마킹)", + "bullet": True, "size": 12}, + {"text": "보물상자(5) — 스테이지 진행 병행 트리거. 각성 게이팅 조건이며 무관 시 대체 보상 (재화·회복·경험치)", + "bullet": True, "size": 12, "color": ACCENT}, + {"text": "각성(6) — VS 원작 정합. 단순 자동 발동 아님 = \"기다림이 보상받는\" 카타르시스의 구조적 기반", + "bullet": True, "size": 12, "color": PURPLE}, + {"text": "런 종료(7) — 모든 카드·빌드 전손. 메타 진행은 별도 시스템(특성·해금) 영역", + "bullet": True, "size": 12, "color": RED_HL}, + ]) +add_footer(s, 9, TOTAL_SLIDES) + +# 슬라이드 10 — 데이터 모델 +s = prs.slides.add_slide(BLANK) +add_solid_bg(s, WHITE) +add_slide_header(s, "데이터 모델 — ScriptableObject 3종 스키마", 10, TOTAL_SLIDES, "2부 구조") + +add_text_box(s, Inches(0.5), Inches(1.05), Inches(12), Inches(0.4), + "공통 베이스 + 3종 파생 클래스 (Unity ScriptableObject)", + font_size=13, bold=True, color=NAVY) + +base = s.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, + Inches(0.5), Inches(1.5), Inches(12.3), Inches(1.4)) +base.fill.solid() +base.fill.fore_color.rgb = LIGHT_BG +base.line.color.rgb = NAVY +base.line.width = Pt(1.5) +base.shadow.inherit = False +add_text_box(s, Inches(0.7), Inches(1.55), Inches(12), Inches(0.4), + "abstract class SkillDataAsset : ScriptableObject (공통 베이스)", + font_size=12, bold=True, color=NAVY, font_name=CODE_FONT) +add_multiline_text(s, Inches(0.7), Inches(1.95), Inches(12), Inches(0.95), + [ + {"text": "string CardId | string DisplayName / EnglishName / Description | Sprite Icon", + "size": 10, "color": DARK_TEXT}, + {"text": "AttributeTag[] AttributeTags ([Flags] enum: Physical·Fire·Frost·Lightning·Dark)", + "size": 10, "color": DARK_TEXT}, + {"text": "TypeTag[] TypeTags ([Flags] enum: Melee·Ranged·Area·Persistent·Recovery·Defense)", + "size": 10, "color": DARK_TEXT}, + ], font_name=CODE_FONT) + +derives = [ + ("ActiveSkillData", NAVY, [ + "ActiveCategory Category (A·B·C·D·E·F)", + "ActiveTrigger Trigger (OnTime·OnHit·OnKill)", + "float BaseCooldown = 1.5f", + "int BaseDamage = 10", + "Vector2 HitboxSize", + "ProjectileTrajectory Trajectory", + "GameObject MinionPrefab", + "int DebuffStackLimit", + "float FireProbability (0~1, F전용)", + ]), + ("PassiveSkillData", GREEN_OK, [ + "PassiveCategory Category (P-A~P-E)", + "bool IsAlwaysOn", + "StatType TargetStat", + "float BaseModifierValue", + "PassiveTriggerKind TriggerKind", + " - OnPlayerDamaged", + " - OnEnemyKilled", + " - OnTimer", + ]), + ("AwakeningSkillData", PURPLE, [ + "AwakeningPattern Pattern", + " (ScaleUp·AddEffect·", + " MultiFire·GlobalSpread)", + "ActiveSkillData OriginalActive", + "PassiveSkillData[] RequiredPassives", + "int AwakeningBaseDamage = 25", + "int MultiFireCount = 3", + "GameObject AwakeningEffectPrefab", + ]), +] + +col_w = Inches(4.0) +gap = Inches(0.1) +start_x = Inches(0.5) +top = Inches(3.1) + +for i, (name, color, fields) in enumerate(derives): + x = start_x + (col_w + gap) * i + box = s.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, x, top, col_w, Inches(3.6)) + box.fill.solid() + box.fill.fore_color.rgb = WHITE + box.line.color.rgb = color + box.line.width = Pt(2) + box.shadow.inherit = False + hd = s.shapes.add_shape(MSO_SHAPE.RECTANGLE, x, top, col_w, Inches(0.5)) + hd.fill.solid() + hd.fill.fore_color.rgb = color + hd.line.fill.background() + hd.shadow.inherit = False + htf = hd.text_frame + htf.vertical_anchor = MSO_ANCHOR.MIDDLE + hp = htf.paragraphs[0] + hp.alignment = PP_ALIGN.CENTER + hr = hp.add_run() + hr.text = name + hr.font.name = CODE_FONT + hr.font.size = Pt(13) + hr.font.bold = True + hr.font.color.rgb = WHITE + + body_lines = [{"text": f, "size": 9, "color": DARK_TEXT, "font_name": CODE_FONT} + for f in fields] + add_multiline_text(s, x + Inches(0.15), top + Inches(0.6), + col_w - Inches(0.3), Inches(3.0), + body_lines, font_name=CODE_FONT) + +add_footer(s, 10, TOTAL_SLIDES) + +# 슬라이드 11 — 태그 체계 +s = prs.slides.add_slide(BLANK) +add_solid_bg(s, WHITE) +add_slide_header(s, "태그 체계 — 속성 5종 + 유형 6종 = 11종 (임시 일반 RPG 용어)", 11, TOTAL_SLIDES, "2부 구조") + +add_text_box(s, Inches(0.5), Inches(1.05), Inches(6.0), Inches(0.5), + "속성 태그 (후보 5종)", font_size=14, bold=True, color=NAVY) +attr_data = [ + ["태그", "의미", "대표 카드"], + ["[물리]", "순수 타격·관통", "A01·A05·A10·A12·A16"], + ["[화염]", "지속 대미지·점화", "A02·A15 / P02"], + ["[냉기]", "둔화·빙결", "A14·A19 / P03"], + ["[번개]", "연쇄·즉발", "A04·A13 / P04"], + ["[암흑]", "저주·DoT·약화", "A03·A06·A07·A08·A11 / P05"], +] +add_table(s, Inches(0.5), Inches(1.5), Inches(6.0), Inches(2.7), + attr_data, body_size=10, header_size=11, + col_widths=[1.5, 2.5, 3]) + +add_text_box(s, Inches(6.8), Inches(1.05), Inches(6.0), Inches(0.5), + "유형 태그 (후보 6종)", font_size=14, bold=True, color=NAVY) +type_data = [ + ["태그", "의미", "대표 카드"], + ["[근접]", "플레이어 주변 판정", "A05·A10·A12·A16·A18·A20"], + ["[원거리]", "투사체·원격", "A01·A02·A03·A14·A15"], + ["[범위]", "AoE·다중 타격", "A04·A05·A07·A13·A19"], + ["[지속]", "설치·오라·DoT", "A06·A09·A11·A17·A20"], + ["[회복]", "쿼터 회복·실드", "P11·P16·P17"], + ["[방어]", "피해 감소·회피·하트+1", "P12·P13·P14·P15·A09·A17"], +] +add_table(s, Inches(6.8), Inches(1.5), Inches(6.0), Inches(3.2), + type_data, body_size=10, header_size=11, + col_widths=[1.5, 2.5, 3]) + +syn_box = s.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, + Inches(0.5), Inches(5.0), Inches(12.3), Inches(1.7)) +syn_box.fill.solid() +syn_box.fill.fore_color.rgb = LIGHT_BG +syn_box.line.color.rgb = ACCENT +syn_box.line.width = Pt(1.5) +syn_box.shadow.inherit = False +add_text_box(s, Inches(0.7), Inches(5.1), Inches(11.5), Inches(0.4), + "시너지 발동 조건 — 태그 2축 설계", + font_size=13, bold=True, color=NAVY) +add_multiline_text(s, Inches(0.7), Inches(5.5), Inches(11.5), Inches(1.2), + [ + {"text": "동일 태그 카드 K장 이상 빌드 편입 시 패시브 효과 추가 발동 (K 수치는 balance-designer 영역)", + "bullet": True, "size": 11}, + {"text": "속성 빌드(예: 화염 6장) + 유형 빌드(예: 원거리 5장) 동시 추구 = 교차 빌드 (제3의 방향)", + "bullet": True, "size": 11}, + {"text": "각 카드는 1~2개 태그 보유. 2태그 카드는 두 시너지에 동시 기여 가능", + "bullet": True, "size": 11}, + ]) + +add_text_box(s, Inches(0.5), Inches(6.85), Inches(12.3), Inches(0.4), + "narrative-designer 후속: 한자·조선 퇴마 톤 일괄 재매핑 대기 (PD 직접 검토)", + font_size=10, color=RED_HL, align=PP_ALIGN.CENTER) +add_footer(s, 11, TOTAL_SLIDES) + +# 슬라이드 12 — 카드 풀 규모 +s = prs.slides.add_slide(BLANK) +add_solid_bg(s, WHITE) +add_slide_header(s, "카드 풀 규모 — 총 60종 (액티브 20 · 패시브 20 · 각성 20)", 12, TOTAL_SLIDES, "2부 구조") + +add_text_box(s, Inches(0.5), Inches(1.1), Inches(4.0), Inches(0.5), + "액티브 20종 — 6 카테고리", font_size=13, bold=True, color=NAVY) +active_cat = [ + ["카테고리", "종수"], + ["A. 투사체", "6"], + ["B. 근접·범위", "5"], + ["C. 설치·지속", "3"], + ["D. 소환", "3"], + ["E. 상태이상", "1"], + ["F. 특수 판정", "2"], +] +add_table(s, Inches(0.5), Inches(1.6), Inches(4.0), Inches(3.5), + active_cat, body_size=11, header_size=12, col_widths=[3, 1]) + +add_text_box(s, Inches(4.7), Inches(1.1), Inches(4.0), Inches(0.5), + "패시브 20종 — 5 카테고리", font_size=13, bold=True, color=GREEN_OK) +passive_cat = [ + ["카테고리", "종수"], + ["P-A. 스탯 상승", "7"], + ["P-B. 주기·증폭", "3"], + ["P-C. 생존 강화", "5"], + ["P-D. 회복", "2"], + ["P-E. 자원 확장", "3"], +] +add_table(s, Inches(4.7), Inches(1.6), Inches(4.0), Inches(3.0), + passive_cat, header_fill=GREEN_OK, body_size=11, header_size=12, col_widths=[3, 1]) + +add_text_box(s, Inches(8.9), Inches(1.1), Inches(4.0), Inches(0.5), + "각성 20종 — 4 진화 패턴", font_size=13, bold=True, color=PURPLE) +awaken_cat = [ + ["진화 패턴", "종수"], + ["1. 스케일업", "6"], + ["2. 새 효과 추가", "6"], + ["3. 다중 발동", "4"], + ["4. 광역 확산", "4"], +] +add_table(s, Inches(8.9), Inches(1.6), Inches(4.0), Inches(2.6), + awaken_cat, header_fill=PURPLE, body_size=11, header_size=12, col_widths=[3, 1]) + +add_text_box(s, Inches(0.5), Inches(5.3), Inches(12), Inches(0.4), + "분배 근거 (재미 축 + 구현 부담 균형)", + font_size=13, bold=True, color=NAVY) +add_multiline_text(s, Inches(0.7), Inches(5.7), Inches(12.3), Inches(1.5), + [ + {"text": "투사체(6) — VS 원작 핵심. 가장 직관적 \"자동 발동 감상\" 체감", + "bullet": True, "size": 11}, + {"text": "근접·범위(5) — 밀집 구간 연출 + 포지셔닝 유도. 냉기·번개·물리 속성 분산", + "bullet": True, "size": 11}, + {"text": "P-A 스탯(7) — 범용 1 + 속성 4 + 크리티컬 2. 가장 직관적 강화", + "bullet": True, "size": 11}, + {"text": "P-C 생존(5) — 실드·하트+1 2종·피해 감소·회피. 생존 빌드 풀 다양성", + "bullet": True, "size": 11}, + {"text": "각성 4 패턴 = 원작 정합. \"같은 게 세짐 / 새 효과 / 2배 발동 / 화면 전체\" 4종 카타르시스", + "bullet": True, "size": 11, "color": PURPLE}, + ]) +add_footer(s, 12, TOTAL_SLIDES) + +# 슬라이드 13 — 빌드 슬롯 구조 +s = prs.slides.add_slide(BLANK) +add_solid_bg(s, WHITE) +add_slide_header(s, "빌드 슬롯 구조 — 액티브 6 / 패시브 6 (VS 원작 참조)", 13, TOTAL_SLIDES, "2부 구조") + +add_text_box(s, Inches(0.5), Inches(1.1), Inches(6.0), Inches(0.5), + "PlayerSkillInventory 장착 슬롯", + font_size=13, bold=True, color=NAVY) + +add_text_box(s, Inches(0.5), Inches(1.7), Inches(2), Inches(0.4), + "액티브 슬롯 (최대 6)", font_size=11, bold=True, color=NAVY) +for i in range(6): + x = Inches(0.5 + i * 0.95) + slot = s.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, + x, Inches(2.15), Inches(0.85), Inches(0.85)) + slot.fill.solid() + slot.fill.fore_color.rgb = NAVY if i < 4 else WHITE + slot.line.color.rgb = NAVY + slot.line.width = Pt(1.5) + slot.shadow.inherit = False + if i < 4: + slot.text_frame.text = f"A{i+1}" + for p_ in slot.text_frame.paragraphs: + p_.alignment = PP_ALIGN.CENTER + for r_ in p_.runs: + r_.font.size = Pt(12) + r_.font.bold = True + r_.font.color.rgb = WHITE + +add_text_box(s, Inches(0.5), Inches(3.2), Inches(2), Inches(0.4), + "패시브 슬롯 (최대 6)", font_size=11, bold=True, color=GREEN_OK) +for i in range(6): + x = Inches(0.5 + i * 0.95) + slot = s.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, + x, Inches(3.65), Inches(0.85), Inches(0.85)) + slot.fill.solid() + slot.fill.fore_color.rgb = GREEN_OK if i < 5 else WHITE + slot.line.color.rgb = GREEN_OK + slot.line.width = Pt(1.5) + slot.shadow.inherit = False + if i < 5: + slot.text_frame.text = f"P{i+1}" + for p_ in slot.text_frame.paragraphs: + p_.alignment = PP_ALIGN.CENTER + for r_ in p_.runs: + r_.font.size = Pt(12) + r_.font.bold = True + r_.font.color.rgb = WHITE + +add_text_box(s, Inches(0.5), Inches(4.7), Inches(6), Inches(0.4), + "각 슬롯 우하단에 Lv.1~5 표기 (UI)", + font_size=10, color=GRAY) + +add_text_box(s, Inches(7.0), Inches(1.1), Inches(5.7), Inches(0.5), + "슬롯 운용 규칙", + font_size=13, bold=True, color=NAVY) +add_multiline_text(s, Inches(7.0), Inches(1.65), Inches(5.7), Inches(5.0), + [ + {"text": "액티브·패시브 슬롯 분리 (BT7-Plan 정합)", "bullet": True, "size": 11, "bold": True}, + {"text": "슬롯 가득 차도 동일 카드 재픽으로 Lv 업 가능", "bullet": True, "size": 11}, + {"text": "신규 카드 픽 시 빈 슬롯 우선 편입", "bullet": True, "size": 11}, + {"text": "각성 발동 시 원 액티브 슬롯 점유 유지 (대체)", "bullet": True, "size": 11, "color": PURPLE}, + {"text": "런 종료 시 모든 슬롯 초기화 (전손)", "bullet": True, "size": 11, "color": RED_HL}, + {"text": "", "size": 11}, + {"text": "픽 알고리즘 처리:", "bullet": True, "size": 11, "bold": True}, + {"text": " - 액티브·패시브 풀에서 가중 무작위 3장 드로우", + "size": 10, "color": DARK_TEXT}, + {"text": " - 빌드 주력 태그 2개 가중치 보너스", + "size": 10, "color": DARK_TEXT}, + {"text": " - 빌드 편입 카드는 후보 제외 (Lv.5 미만 업그레이드는 재등장)", + "size": 10, "color": DARK_TEXT}, + {"text": " - 3장 액티브·패시브 혼합 필터 우선 (풀 고갈 시 해제)", + "size": 10, "color": DARK_TEXT}, + {"text": "", "size": 11}, + {"text": "각성 슬롯은 별도 풀 — 레벨업 드로우 풀에 미포함", + "bullet": True, "size": 11, "color": PURPLE}, + ]) +add_footer(s, 13, TOTAL_SLIDES) + +# 슬라이드 14 — 2부 종결 / 3부 전환 +s = prs.slides.add_slide(BLANK) +add_solid_bg(s, NAVY) +band = s.shapes.add_shape(MSO_SHAPE.RECTANGLE, 0, Inches(2.0), Inches(0.4), Inches(2.5)) +band.fill.solid() +band.fill.fore_color.rgb = ACCENT +band.line.fill.background() +band.shadow.inherit = False +add_text_box(s, Inches(0.5), Inches(2.5), Inches(12.3), Inches(0.7), + "3부 — 카드 카테고리 명세", font_size=42, bold=True, color=ICE, + align=PP_ALIGN.CENTER, font_name=HEADER_FONT) +add_text_box(s, Inches(0.5), Inches(3.4), Inches(12.3), Inches(0.5), + "액티브 6 카테고리 · 패시브 5 카테고리 · 각성 4 패턴", + font_size=18, color=ICE, align=PP_ALIGN.CENTER) +add_text_box(s, Inches(0.5), Inches(6.8), Inches(12.3), Inches(0.4), + "Slide 14 / 36", font_size=10, color=ICE, align=PP_ALIGN.CENTER) + +# ============================================================ +# 3부 — 카드 카테고리 명세 (슬라이드 15~20) +# ============================================================ + +# 슬라이드 15 — 액티브 6 카테고리 +s = prs.slides.add_slide(BLANK) +add_solid_bg(s, WHITE) +add_slide_header(s, "액티브 6 카테고리 — 동작 방식·구현 복잡도", 15, TOTAL_SLIDES, "3부 카테고리") + +active_data = [ + ["#", "카테고리", "동작 방식", "구현 복잡도", "대표 카드"], + ["A", "투사체형", "주기마다 전방·유도 투사체 자동 발사, 단발 DPS", "낮음 (BT.Framework 풀링 활용)", "A01·A14·A15"], + ["B", "근접·범위형", "플레이어 주변 즉시 판정 (원형/부채꼴)", "중간 (OverlapBox 다중)", "A05·A12·A13"], + ["C", "설치·지속형", "이동 경로/위치에 지속 효과 구역 잔존", "중간~높음 (풀 + Trigger)", "A06·A09·A17"], + ["D", "소환형", "독립 행동 소환물 생성, 자동 공격/어그로", "높음 (AI + 타이머 + 풀)", "A10·A11·A20"], + ["E", "상태이상형", "스택 가능 디버프(저주·봉인·독) 부여", "중간 (적별 카운터)", "A03·A07·A08"], + ["F", "특수 판정형", "확률 자동 발동 회심 / 무적 i-frame", "낮음 (Random 분기)", "A16·A18"], +] +add_table(s, Inches(0.5), Inches(1.1), Inches(12.3), Inches(4.5), + active_data, body_size=10, header_size=11, + col_widths=[0.5, 1.5, 4.8, 2.5, 3]) + +add_text_box(s, Inches(0.5), Inches(5.8), Inches(12), Inches(0.5), + "재미 축 연결", + font_size=13, bold=True, color=NAVY) +add_multiline_text(s, Inches(0.7), Inches(6.3), Inches(12.3), Inches(1.0), + [ + {"text": "A·B·C·F = 축 2 (자동 발동 감상) — 화면 인상 위주 카테고리", + "bullet": True, "size": 11}, + {"text": "D·E = 축 1 (육성 카타르시스) — 누적·스택·전능감 체감", + "bullet": True, "size": 11}, + ]) +add_footer(s, 15, TOTAL_SLIDES) + +# 슬라이드 16 — 패시브 5 카테고리 +s = prs.slides.add_slide(BLANK) +add_solid_bg(s, WHITE) +add_slide_header(s, "패시브 5 카테고리 — 강화 대상·시너지", 16, TOTAL_SLIDES, "3부 카테고리") + +passive_data = [ + ["#", "카테고리", "동작 방식", "주 시너지 액티브", "대표 카드"], + ["P-A", "스탯 상승형", "장착 즉시 상시, 대미지/속도/크리 보정", "전체 (속성 매칭 시 강화)", "P01·P02~P05·P09·P10"], + ["P-B", "주기·증폭형", "쿨다운 단축 / 판정 범위 / 투사체 수 증가", "A·B·E (DPS 증폭 라인)", "P06·P07·P08"], + ["P-C", "생존 강화형", "최대 하트 +1 / 피해 감소 / 회피 / 실드", "C·D (오래 버틸 빌드)", "P11·P12·P13·P14·P15"], + ["P-D", "회복형", "처치/시간 기반 쿼터 자동 회복", "B·E (처치 빈도 높음)", "P16·P17"], + ["P-E", "자원 확장형", "이동·점프·경험치·보물상자 확률", "전체 (간접 가속)", "P18·P19·P20"], +] +add_table(s, Inches(0.5), Inches(1.1), Inches(12.3), Inches(4.0), + passive_data, header_fill=GREEN_OK, body_size=10, header_size=11, + col_widths=[0.5, 1.8, 4.5, 2.5, 3]) + +# 패시브-액티브 상호작용 +add_text_box(s, Inches(0.5), Inches(5.4), Inches(12), Inches(0.5), + "패시브-액티브 상호작용 구조", + font_size=13, bold=True, color=NAVY) +add_multiline_text(s, Inches(0.7), Inches(5.9), Inches(12.3), Inches(1.4), + [ + {"text": "P-A 속성 강화 -> A·B·C·D·E 동일 속성 카드 대미지 배율 상승", + "bullet": True, "size": 11}, + {"text": "P-B 발동 주기 단축 -> A 투사체 / B 근접·범위 / E 상태이상 (DPS·스택 가속)", + "bullet": True, "size": 11}, + {"text": "P-C 생존 강화 -> C 설치·지속 / D 소환 (오래 버텨야 위력 발휘 카테고리 보조)", + "bullet": True, "size": 11}, + {"text": "P-D 회복 -> B·E 처치 속도 빠른 카테고리 (P16 발동 빈도 가속)", + "bullet": True, "size": 11}, + {"text": "P-E 자원 확장 -> 전체 간접 가속 (특히 P20 재물복 + 각성 빌드)", + "bullet": True, "size": 11, "color": ACCENT}, + ]) +add_footer(s, 16, TOTAL_SLIDES) + +# 슬라이드 17 — 각성 4 패턴 +s = prs.slides.add_slide(BLANK) +add_solid_bg(s, WHITE) +add_slide_header(s, "각성 4 진화 패턴 — 카타르시스 4종 분기", 17, TOTAL_SLIDES, "3부 카테고리") + +# 4 패턴 그리드 +patterns = [ + ("1. 스케일업", "ScaleUp", + "원 액티브 그대로 + 규모 대폭 증가\n대미지 / 범위 / 속도 1~2개 폭증", + "AW05 학익천진 (부채꼴 -> 360도)\nAW12 쾌검비경 (속도 극속)", + "낮음 (배율만 적용)", "밸런스 치우침"), + ("2. 새 효과 추가", "AddEffect", + "기존 효과 유지 + 완전히 새 효과 부착\n부가 판정/속성/소환물", + "AW04 봉령결계 (봉인 + DoT)\nAW07 사령결계 (스택 즉시 최대)", + "중간 (이벤트 병렬)", "이벤트 순서 관리"), + ("3. 다중 발동", "MultiFire", + "1회 -> N회 동시 발동\n투사체 2배 / 소환물 3~4기", + "AW10 분신만화 (1->3~4기)\nAW15 귀화유성 (무한 발사)", + "중간 (풀링 용량 ↑)", "파티클 상한 초과"), + ("4. 광역 확산", "GlobalSpread", + "효과 화면 전체로 확산\n런 클라이맥스 연출", + "AW01 천부경문 (화면 전체)\nAW03 천뢰강림 (무한 연쇄)", + "높음 (성능 최적화 필수)", "성능 이슈 고위험"), +] + +col_w = Inches(3.0) +row_h = Inches(2.7) +gap_x = Inches(0.1) +gap_y = Inches(0.15) + +for i, (title, code, desc, examples, complexity, risk) in enumerate(patterns): + col = i % 4 + x = Inches(0.5) + (col_w + gap_x) * col + y = Inches(1.1) + box = s.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, x, y, col_w, row_h) + box.fill.solid() + box.fill.fore_color.rgb = WHITE + box.line.color.rgb = PURPLE + box.line.width = Pt(1.5) + box.shadow.inherit = False + # 제목 헤더 + hd = s.shapes.add_shape(MSO_SHAPE.RECTANGLE, x, y, col_w, Inches(0.5)) + hd.fill.solid() + hd.fill.fore_color.rgb = PURPLE + hd.line.fill.background() + hd.shadow.inherit = False + htf = hd.text_frame + htf.vertical_anchor = MSO_ANCHOR.MIDDLE + hp = htf.paragraphs[0] + hp.alignment = PP_ALIGN.CENTER + hr = hp.add_run() + hr.text = title + hr.font.name = HEADER_FONT + hr.font.size = Pt(12) + hr.font.bold = True + hr.font.color.rgb = WHITE + # 본문 + add_multiline_text(s, x + Inches(0.1), y + Inches(0.55), + col_w - Inches(0.2), Inches(2.1), + [ + {"text": f"({code})", "size": 9, "color": GRAY, "font_name": CODE_FONT}, + {"text": "", "size": 9}, + {"text": desc, "size": 10, "color": DARK_TEXT}, + {"text": "", "size": 9}, + {"text": "예시:", "size": 9, "bold": True, "color": NAVY}, + {"text": examples, "size": 9, "color": DARK_TEXT}, + ]) + +# 패턴별 분배·구현 복잡도 (하단) +add_text_box(s, Inches(0.5), Inches(4.0), Inches(12), Inches(0.5), + "패턴별 분배 · 구현 복잡도 · 주요 리스크", + font_size=13, bold=True, color=NAVY) +risk_data = [ + ["패턴", "종수", "구현 복잡도", "주요 리스크"], + ["1. 스케일업", "6", "낮음 (기존 발동기 + 배율)", "밸런스 치우침"], + ["2. 새 효과 추가", "6", "중간 (원 효과 + 추가 효과 병렬)", "이벤트 순서 관리"], + ["3. 다중 발동", "4", "중간 (동시 N회 + 풀링 용량)", "파티클 상한 초과 (개발팀 확인)"], + ["4. 광역 확산", "4", "높음 (화면 전체 AoE + 연쇄)", "성능 이슈 고위험 (최적화 필수)"], +] +add_table(s, Inches(0.5), Inches(4.6), Inches(12.3), Inches(2.4), + risk_data, header_fill=PURPLE, body_size=10, header_size=11, + col_widths=[2, 1, 4, 4]) +add_footer(s, 17, TOTAL_SLIDES) + +# 슬라이드 18 — 카테고리별 분배 표 (액티브) +s = prs.slides.add_slide(BLANK) +add_solid_bg(s, WHITE) +add_slide_header(s, "액티브 카테고리별 카드 분배 (전체 20종 분류)", 18, TOTAL_SLIDES, "3부 카테고리") + +# 좌측 — 분배 표 +distrib_data = [ + ["카테고리", "종수", "카드 #", "근거"], + ["A. 투사체", "6", "A01·A02·A03·A08·A14·A15", "VS 핵심 + 4속성 균등"], + ["B. 근접·범위", "5", "A04·A05·A12·A13·A19", "밀집 연출 + 냉기/번개/물리"], + ["C. 설치·지속", "3", "A06·A09·A17", "성능 부담 회피 (3종 제한)"], + ["D. 소환", "3", "A10·A11·A20", "원거리 2 + 근접 1 분화"], + ["E. 상태이상", "1", "A07", "순수 오라형 1종 (스택은 A 흡수)"], + ["F. 특수 판정", "2", "A16·A18", "확률 로또감 (패턴화 회피)"], +] +add_table(s, Inches(0.5), Inches(1.1), Inches(12.3), Inches(3.5), + distrib_data, body_size=11, header_size=12, + col_widths=[2, 0.7, 4, 3]) + +# 하단 — 분배 차트 시각화 (간이 막대) +add_text_box(s, Inches(0.5), Inches(4.85), Inches(12), Inches(0.5), + "시각적 분배 (총 20종)", + font_size=13, bold=True, color=NAVY) + +categories_chart = [("A 투사체", 6), ("B 근접범위", 5), ("C 설치지속", 3), + ("D 소환", 3), ("E 상태이상", 1), ("F 특수판정", 2)] +chart_top = Inches(5.4) +chart_left = Inches(1.0) +bar_max_w = Inches(8.0) +bar_h = Inches(0.25) +gap_v = Inches(0.05) + +for i, (label, count) in enumerate(categories_chart): + y = chart_top + (bar_h + gap_v) * i + # 라벨 + add_text_box(s, Inches(0.5), y - Inches(0.02), Inches(2), bar_h + Inches(0.04), + label, font_size=10, color=DARK_TEXT) + # 바 + bar_w = Emu(int(bar_max_w * (count / 6))) + bar = s.shapes.add_shape(MSO_SHAPE.RECTANGLE, + Inches(2.5), y, bar_w, bar_h) + bar.fill.solid() + bar.fill.fore_color.rgb = NAVY + bar.line.fill.background() + bar.shadow.inherit = False + # 카운트 + add_text_box(s, Inches(2.5) + bar_w + Inches(0.05), y - Inches(0.02), + Inches(0.6), bar_h + Inches(0.04), + f"{count}종", font_size=10, bold=True, color=NAVY) + +add_footer(s, 18, TOTAL_SLIDES) + +# 슬라이드 19 — 패시브 카테고리별 분배 +s = prs.slides.add_slide(BLANK) +add_solid_bg(s, WHITE) +add_slide_header(s, "패시브 카테고리별 카드 분배 (전체 20종 분류)", 19, TOTAL_SLIDES, "3부 카테고리") + +p_distrib_data = [ + ["카테고리", "종수", "카드 #", "근거"], + ["P-A. 스탯 상승", "7", "P01 + P02·P03·P04·P05 + P09·P10", "범용 1 + 속성 4 + 크리 2"], + ["P-B. 주기·증폭", "3", "P06·P07·P08", "DPS 증폭 축 응집"], + ["P-C. 생존 강화", "5", "P11·P12·P13·P14·P15", "실드/하트+1 2종/감소/회피"], + ["P-D. 회복", "2", "P16·P17", "처치+시간 기반 (어뷰징 가드)"], + ["P-E. 자원 확장", "3", "P18·P19·P20", "이동/경험치/보물상자"], +] +add_table(s, Inches(0.5), Inches(1.1), Inches(12.3), Inches(3.0), + p_distrib_data, header_fill=GREEN_OK, body_size=11, header_size=12, + col_widths=[2.2, 0.7, 5.3, 4.1]) + +# 핵심 강조 +add_text_box(s, Inches(0.5), Inches(4.4), Inches(12), Inches(0.5), + "핵심 패시브 — 각성 빌드 직결 카드", + font_size=13, bold=True, color=NAVY) + +key_cards = [ + ("P12 생명의 꽃", "최대 하트 +1 (런 내). AW17 등 다수 각성 조건 패시브", PURPLE), + ("P13 강철심장", "최대 하트 +1 (P12와 중첩 가능). 동일 효과 다른 카드 = 빌드 분기 의도", PURPLE), + ("P20 재물복", "보물상자 발견 확률 증가. \"보물상자 각성 특화\" 빌드 핵심", ACCENT), + ("P06 연사술", "모든 액티브 발동 주기 단축. 범용 고부가 + Lv.5 단축 가속", NAVY), +] +for i, (name, desc, color) in enumerate(key_cards): + y = Inches(4.95) + Inches(0.5) * i + icon = s.shapes.add_shape(MSO_SHAPE.OVAL, + Inches(0.7), y + Inches(0.05), Inches(0.3), Inches(0.3)) + icon.fill.solid() + icon.fill.fore_color.rgb = color + icon.line.fill.background() + add_text_box(s, Inches(1.1), y, Inches(3.5), Inches(0.4), + name, font_size=11, bold=True, color=color) + add_text_box(s, Inches(4.6), y, Inches(8.2), Inches(0.4), + desc, font_size=10, color=DARK_TEXT) + +add_footer(s, 19, TOTAL_SLIDES) + +# 슬라이드 20 — 각성 패턴 분배 + 3부 종결 +s = prs.slides.add_slide(BLANK) +add_solid_bg(s, WHITE) +add_slide_header(s, "각성 카테고리·패턴 분배 (전체 20종)", 20, TOTAL_SLIDES, "3부 카테고리") + +aw_distrib_data = [ + ["패턴", "종수", "각성 #", "원 액티브"], + ["1. 스케일업", "6", "AW02·AW05·AW08·AW12·AW13·AW16", "A02·A05·A07·A12·A13·A16"], + ["2. 새 효과 추가", "6", "AW04·AW07·AW11·AW14·AW17·AW18", "A03·A08·A11·A14·A17·A18"], + ["3. 다중 발동", "4", "AW09·AW10·AW15·AW20", "A09·A10·A15·A20"], + ["4. 광역 확산", "4", "AW01·AW03·AW06·AW19", "A01·A04·A06·A19"], +] +add_table(s, Inches(0.5), Inches(1.1), Inches(12.3), Inches(2.7), + aw_distrib_data, header_fill=PURPLE, body_size=11, header_size=12, + col_widths=[2, 0.7, 5.5, 4.1]) + +# 각성 발동 의미 +mean_box = s.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, + Inches(0.5), Inches(4.0), Inches(12.3), Inches(2.7)) +mean_box.fill.solid() +mean_box.fill.fore_color.rgb = LIGHT_BG +mean_box.line.color.rgb = PURPLE +mean_box.line.width = Pt(2) +mean_box.shadow.inherit = False +add_text_box(s, Inches(0.7), Inches(4.15), Inches(12), Inches(0.5), + "각성 발동의 위상 — 한 런의 피날레", + font_size=14, bold=True, color=PURPLE) +add_multiline_text(s, Inches(0.7), Inches(4.65), Inches(12), Inches(2.0), + [ + {"text": "빌드 완성자 — 각성 발동 이후 \"내 빌드가 완성됐다\" 감각. 이후 런은 \"완성된 빌드로 얼마나 버티는가\"", + "bullet": True, "size": 11}, + {"text": "런 피날레 연출 — 풀스크린 연출 (시각·음향). 런의 분기점 명확히 알림", + "bullet": True, "size": 11}, + {"text": "기다림의 보상 — 액티브 Lv.5까지 동일 카드 5번 픽 \"투자\" -> 각성 발동 시 보상의 카타르시스 곡선 완성", + "bullet": True, "size": 11}, + {"text": "한 런 1회 발동 (중복 불가) — 다중 조건 충족 시 플레이어 1개 선택 UI 제공", + "bullet": True, "size": 11, "color": NAVY}, + ]) +add_footer(s, 20, TOTAL_SLIDES) + +# ============================================================ +# 4부 — 동작 메커니즘 (슬라이드 21~25) +# ============================================================ + +# 슬라이드 21 — 픽 알고리즘 +s = prs.slides.add_slide(BLANK) +add_solid_bg(s, WHITE) +add_slide_header(s, "픽 알고리즘 — 가중 무작위 + 빌드 태그 가중", 21, TOTAL_SLIDES, "4부 메커니즘") + +add_text_box(s, Inches(0.5), Inches(1.05), Inches(12), Inches(0.5), + "레벨업 트리거 시 5단계 처리", + font_size=14, bold=True, color=NAVY) + +algo_data = [ + ["단계", "처리 내용", "관여 요소"], + ["1", "현재 레벨·빌드 태그에 따라 액티브 vs 패시브 비율 가중 결정", "balance/02 §4 곡선"], + ["2", "빌드 주력 태그 2개 추출 (현재 보유 카드의 최다 태그)", "PlayerSkillInventory"], + ["3", "전체 풀(40종 = 액티브 20 + 패시브 20)에서 가중 무작위 3장 비복원 추출", "주력 태그 +α 가중"], + ["4", "이미 빌드 편입 카드는 제외 / Lv.5 미만 동일 카드는 재등장 허용 (Lv 업)", "_cardIdToRuntime Dict"], + ["5", "3장 액티브·패시브 혼합 필터 우선 적용 (풀 고갈 시 해제)", "혼합 안 되면 단일 종 가능"], +] +add_table(s, Inches(0.5), Inches(1.55), Inches(12.3), Inches(3.2), + algo_data, body_size=11, header_size=12, + col_widths=[0.5, 7, 4]) + +# 가중치 공식 +add_text_box(s, Inches(0.5), Inches(5.0), Inches(12), Inches(0.5), + "가중치 공식 (개념 — 수치는 balance-designer)", + font_size=13, bold=True, color=NAVY) +formula_box = s.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, + Inches(0.5), Inches(5.55), Inches(12.3), Inches(1.5)) +formula_box.fill.solid() +formula_box.fill.fore_color.rgb = LIGHT_BG +formula_box.line.color.rgb = NAVY +formula_box.line.width = Pt(1) +formula_box.shadow.inherit = False +add_multiline_text(s, Inches(0.7), Inches(5.65), Inches(12), Inches(1.4), + [ + {"text": "Weight(card) = BaseWeight × (1 + TagBonus × MatchedTagCount) × CategoryBonus", + "size": 11, "bold": True, "color": NAVY, "font_name": CODE_FONT}, + {"text": " - BaseWeight: 카드 기본 출현 가중치 (1.0 균등 시작)", + "size": 10, "color": DARK_TEXT, "font_name": CODE_FONT}, + {"text": " - TagBonus: 빌드 주력 태그 매칭 보너스 (예: 0.5)", + "size": 10, "color": DARK_TEXT, "font_name": CODE_FONT}, + {"text": " - MatchedTagCount: 카드의 태그 중 주력 태그와 매칭된 수 (0~2)", + "size": 10, "color": DARK_TEXT, "font_name": CODE_FONT}, + {"text": " - CategoryBonus: 레벨 구간별 액티브 vs 패시브 비율 보정", + "size": 10, "color": DARK_TEXT, "font_name": CODE_FONT}, + ], font_name=CODE_FONT) +add_footer(s, 21, TOTAL_SLIDES) + +# 슬라이드 22 — 스택 업그레이드 시스템 +s = prs.slides.add_slide(BLANK) +add_solid_bg(s, WHITE) +add_slide_header(s, "스택 업그레이드 — Lv.1~Lv.5 (VS 원작 정합)", 22, TOTAL_SLIDES, "4부 메커니즘") + +# Lv 진행 시각화 +lv_positions = [(1, 1.0), (2, 1.2), (3, 1.4), (4, 1.6), (5, 2.0)] +add_text_box(s, Inches(0.5), Inches(1.1), Inches(12), Inches(0.5), + "동일 카드 재픽 시 Lv 상승 (StackLevelFactor)", + font_size=14, bold=True, color=NAVY) + +for i, (lv, factor) in enumerate(lv_positions): + x = Inches(1.0 + i * 2.3) + y = Inches(1.7) + color = ACCENT if lv == 5 else NAVY + box = s.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, + x, y, Inches(2.0), Inches(1.5)) + box.fill.solid() + box.fill.fore_color.rgb = color + box.line.fill.background() + box.shadow.inherit = False + btf = box.text_frame + btf.vertical_anchor = MSO_ANCHOR.MIDDLE + bp = btf.paragraphs[0] + bp.alignment = PP_ALIGN.CENTER + br = bp.add_run() + br.text = f"Lv.{lv}" + br.font.name = HEADER_FONT + br.font.size = Pt(22) + br.font.bold = True + br.font.color.rgb = WHITE if lv != 5 else NAVY + bp2 = btf.add_paragraph() + bp2.alignment = PP_ALIGN.CENTER + br2 = bp2.add_run() + br2.text = f"\nFactor {factor}x" + br2.font.name = CODE_FONT + br2.font.size = Pt(12) + br2.font.color.rgb = WHITE if lv != 5 else NAVY + if lv == 5: + bp3 = btf.add_paragraph() + bp3.alignment = PP_ALIGN.CENTER + br3 = bp3.add_run() + br3.text = "각성 조건 1 충족" + br3.font.name = BODY_FONT + br3.font.size = Pt(9) + br3.font.bold = True + br3.font.color.rgb = NAVY + +# 화살표 (Lv 사이) +for i in range(4): + ar_x = Inches(3.05 + i * 2.3) + ar = s.shapes.add_shape(MSO_SHAPE.RIGHT_ARROW, + ar_x, Inches(2.3), Inches(0.3), Inches(0.3)) + ar.fill.solid() + ar.fill.fore_color.rgb = GRAY + ar.line.fill.background() + ar.shadow.inherit = False + +# 규칙 + Lv.5 이후 +add_text_box(s, Inches(0.5), Inches(3.5), Inches(12), Inches(0.5), + "스택 규칙 · Lv.5 이후 처리", + font_size=13, bold=True, color=NAVY) +add_multiline_text(s, Inches(0.7), Inches(4.0), Inches(12.3), Inches(3.0), + [ + {"text": "동일 카드 재픽마다 Lv.N -> Lv.N+1 (최대 Lv.5)", + "bullet": True, "size": 11}, + {"text": "업그레이드는 \"수치 상향 또는 추가 트리거\" 중 하나 부여 (양자 동시 부여 금지)", + "bullet": True, "size": 11}, + {"text": "Lv.5 도달 -> AwakeningManager.MarkActiveMaxed(data) 자동 호출 (각성 조건 1 마킹)", + "bullet": True, "size": 11, "color": PURPLE}, + {"text": "Lv.5 이상 동일 카드 재픽 시: 재화 보상 또는 랜덤 변형 (balance-designer 결정)", + "bullet": True, "size": 11, "color": ACCENT}, + {"text": "구 Lv.3 상한 폐기 (BT7-Plan 확정 방향 9) -> VS 원작 Lv.5 체계 계승", + "bullet": True, "size": 11, "color": GRAY}, + ]) +add_footer(s, 22, TOTAL_SLIDES) + +# 슬라이드 23 — 각성 발동 시퀀스 다이어그램 +s = prs.slides.add_slide(BLANK) +add_solid_bg(s, WHITE) +add_slide_header(s, "각성 발동 시퀀스 — 3 조건 동시 충족 판정 흐름", 23, TOTAL_SLIDES, "4부 메커니즘") + +# 시퀀스 단계 +seq_steps = [ + ("스테이지 진행", "보물상자 스폰 트리거 (적 처치 누적/위치/엘리트 처치)", NAVY), + ("플레이어 보물상자 접촉", "TreasureChest.OnTriggerEnter2D -> Player.OnTreasureChestOpened()", NAVY), + ("AwakeningManager.CheckAwakeningEligibility() 호출", "전체 AwakeningSkillData 순회", PURPLE), + ("조건 1 검사: _maxedActiveIds.Contains(awData.OriginalActive.CardId)", "Lv.5 도달 액티브 ID HashSet 조회 (O(1))", PURPLE), + ("조건 2 검사: RequiredPassives.Any(p => HasPassive(p.CardId))", "필요 패시브 1+ 보유 확인", PURPLE), + ("조건 3: 보물상자는 이미 개봉됨 (진입 시점 보장)", "별도 검사 불요", GRAY), + ("eligibleAwakenings 분기", "0건: 대체 보상 / 1건: 즉시 발동 / 2+건: 선택 UI", ACCENT), + ("TriggerAwakening(awData)", "풀스크린 연출 + AwakeningSkillRuntime 교체 + alreadyAwakened 마킹", PURPLE), +] + +step_h = Inches(0.6) +gap_v = Inches(0.05) +for i, (step, detail, color) in enumerate(seq_steps): + y = Inches(1.05) + (step_h + gap_v) * i + # 단계 번호 원 + num = s.shapes.add_shape(MSO_SHAPE.OVAL, + Inches(0.5), y + Inches(0.1), Inches(0.4), Inches(0.4)) + num.fill.solid() + num.fill.fore_color.rgb = color + num.line.fill.background() + num.shadow.inherit = False + ntf = num.text_frame + ntf.vertical_anchor = MSO_ANCHOR.MIDDLE + np_ = ntf.paragraphs[0] + np_.alignment = PP_ALIGN.CENTER + nr = np_.add_run() + nr.text = str(i + 1) + nr.font.size = Pt(11) + nr.font.bold = True + nr.font.color.rgb = WHITE + # 단계 이름 + add_text_box(s, Inches(1.05), y + Inches(0.05), Inches(6.5), Inches(0.5), + step, font_size=11, bold=True, color=color) + # 디테일 + add_text_box(s, Inches(1.05), y + Inches(0.32), Inches(11.5), Inches(0.3), + detail, font_size=9, color=DARK_TEXT, font_name=CODE_FONT) + +add_footer(s, 23, TOTAL_SLIDES) + +# 슬라이드 24 — 보물상자 체계 +s = prs.slides.add_slide(BLANK) +add_solid_bg(s, WHITE) +add_slide_header(s, "보물상자 체계 — 각성 게이팅 + 대체 보상", 24, TOTAL_SLIDES, "4부 메커니즘") + +# 좌측 — 흐름 박스 +add_text_box(s, Inches(0.5), Inches(1.1), Inches(6), Inches(0.5), + "보물상자 흐름", + font_size=13, bold=True, color=NAVY) + +flow_steps = [ + ("스폰", "스테이지 진행 중 조건부 (적 처치 수·엘리트 처치·특정 위치)", NAVY), + ("발견", "P20 재물복 패시브 시 발견 확률 증가", ACCENT), + ("획득", "플레이어 접촉 시 OnTreasureChestOpened() 트리거", NAVY), + ("판정", "각성 조건 3종 동시 충족 검사", PURPLE), + ("분기", "충족 -> 각성 발동 / 불충족 -> 대체 보상", PURPLE), +] +for i, (step, desc, color) in enumerate(flow_steps): + y = Inches(1.6) + Inches(0.95) * i + box = s.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, + Inches(0.5), y, Inches(6), Inches(0.85)) + box.fill.solid() + box.fill.fore_color.rgb = LIGHT_BG + box.line.color.rgb = color + box.line.width = Pt(1.5) + box.shadow.inherit = False + add_text_box(s, Inches(0.7), y + Inches(0.05), Inches(1.5), Inches(0.4), + step, font_size=12, bold=True, color=color) + add_text_box(s, Inches(0.7), y + Inches(0.4), Inches(5.7), Inches(0.4), + desc, font_size=9, color=DARK_TEXT) + +# 우측 — 대체 보상 +add_text_box(s, Inches(7.0), Inches(1.1), Inches(5.7), Inches(0.5), + "대체 보상 (조건 불충족 시)", + font_size=13, bold=True, color=NAVY) + +reward_box = s.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, + Inches(7.0), Inches(1.6), Inches(5.7), Inches(2.5)) +reward_box.fill.solid() +reward_box.fill.fore_color.rgb = LIGHT_BG +reward_box.line.color.rgb = ACCENT +reward_box.line.width = Pt(2) +reward_box.shadow.inherit = False +add_multiline_text(s, Inches(7.2), Inches(1.7), Inches(5.5), Inches(2.4), + [ + {"text": "조건 불충족 시 1종 무작위 보상:", + "size": 12, "bold": True, "color": ACCENT}, + {"text": "", "size": 9}, + {"text": "재화 (다음 런 메타 진행 자원)", + "bullet": True, "size": 11}, + {"text": "회복 (1~2 쿼터 즉시 회복)", + "bullet": True, "size": 11}, + {"text": "경험치 (다음 레벨업 가속)", + "bullet": True, "size": 11}, + {"text": "확률·강도는 balance-designer 영역", + "bullet": True, "size": 10, "color": GRAY}, + ]) + +# 다중 각성 충족 +add_text_box(s, Inches(7.0), Inches(4.3), Inches(5.7), Inches(0.5), + "다중 각성 동시 충족 처리", + font_size=13, bold=True, color=PURPLE) +multi_box = s.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, + Inches(7.0), Inches(4.8), Inches(5.7), Inches(2.0)) +multi_box.fill.solid() +multi_box.fill.fore_color.rgb = LIGHT_BG +multi_box.line.color.rgb = PURPLE +multi_box.line.width = Pt(2) +multi_box.shadow.inherit = False +add_multiline_text(s, Inches(7.2), Inches(4.9), Inches(5.5), Inches(1.9), + [ + {"text": "한 보물상자 획득 -> 복수 각성 조건 동시 충족", + "bullet": True, "size": 11}, + {"text": "플레이어 1개 선택 UI 제공", + "bullet": True, "size": 11, "color": PURPLE}, + {"text": "동시 발동 금지 (밸런스 붕괴 방지)", + "bullet": True, "size": 11, "color": RED_HL}, + {"text": "선택되지 않은 각성 조건은 다음 보물상자 획득 시 재판정", + "bullet": True, "size": 10, "color": GRAY}, + ]) +add_footer(s, 24, TOTAL_SLIDES) + +# 슬라이드 25 — HP/하트 메커니즘 + 시너지 발동 +s = prs.slides.add_slide(BLANK) +add_solid_bg(s, WHITE) +add_slide_header(s, "HP/하트 증가 · 시너지 발동 메커니즘", 25, TOTAL_SLIDES, "4부 메커니즘") + +# 좌측 — HP/하트 +add_text_box(s, Inches(0.5), Inches(1.1), Inches(6), Inches(0.5), + "HP/하트 분할 구조", + font_size=13, bold=True, color=NAVY) +hp_box = s.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, + Inches(0.5), Inches(1.6), Inches(6), Inches(5.0)) +hp_box.fill.solid() +hp_box.fill.fore_color.rgb = LIGHT_BG +hp_box.line.color.rgb = NAVY +hp_box.line.width = Pt(1.5) +hp_box.shadow.inherit = False +add_multiline_text(s, Inches(0.7), Inches(1.75), Inches(5.7), Inches(4.7), + [ + {"text": "쿼터 단위 차감 구조 (BT7-Plan 확정 방향 7)", + "size": 11, "bold": True, "color": NAVY}, + {"text": "", "size": 9}, + {"text": "1 하트 = 4 쿼터 (Zelda BotW 방식)", + "bullet": True, "size": 11}, + {"text": "최대 HP = maxHearts × 4 쿼터", + "bullet": True, "size": 11}, + {"text": "i-frame 0.6s 보호 (연속 피격 방지)", + "bullet": True, "size": 11}, + {"text": "", "size": 9}, + {"text": "최대 하트 증가 (런 내):", + "size": 11, "bold": True, "color": NAVY}, + {"text": "P12 생명의 꽃 +1", + "bullet": True, "size": 10}, + {"text": "P13 강철심장 +1 (P12와 중첩 가능)", + "bullet": True, "size": 10}, + {"text": "상한: 5개 (balance-designer 하드캡)", + "bullet": True, "size": 10, "color": GRAY}, + {"text": "런 종료 시 기본 1개로 복귀 (전손)", + "bullet": True, "size": 10, "color": RED_HL}, + {"text": "", "size": 9}, + {"text": "Health.IncreaseMaxHearts(int delta) API", + "bullet": True, "size": 10, "color": GRAY, "font_name": CODE_FONT}, + {"text": "Health.Heal(int quarters) API (P16·P17)", + "bullet": True, "size": 10, "color": GRAY, "font_name": CODE_FONT}, + ]) + +# 우측 — 시너지 발동 +add_text_box(s, Inches(6.8), Inches(1.1), Inches(6), Inches(0.5), + "태그 시너지 발동", + font_size=13, bold=True, color=ACCENT) +syn_box2 = s.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, + Inches(6.8), Inches(1.6), Inches(6), Inches(5.0)) +syn_box2.fill.solid() +syn_box2.fill.fore_color.rgb = LIGHT_BG +syn_box2.line.color.rgb = ACCENT +syn_box2.line.width = Pt(1.5) +syn_box2.shadow.inherit = False +add_multiline_text(s, Inches(7.0), Inches(1.75), Inches(5.7), Inches(4.7), + [ + {"text": "발동 조건", + "size": 11, "bold": True, "color": ACCENT}, + {"text": "동일 태그 카드 K장 이상 빌드 편입 시 패시브 효과 추가 발동", + "bullet": True, "size": 11}, + {"text": "K 임계값 = balance-designer 영역 (예: 화염 4장 이상)", + "bullet": True, "size": 10, "color": GRAY}, + {"text": "", "size": 9}, + {"text": "구현 흐름", + "size": 11, "bold": True, "color": ACCENT}, + {"text": "PlayerSkillInventory.OnSkillEquipped 이벤트 시 태그 카운트 갱신", + "bullet": True, "size": 10}, + {"text": "TagSynergyManager.CheckThreshold(tag) 호출", + "bullet": True, "size": 10, "font_name": CODE_FONT}, + {"text": "K장 도달 시 SynergyEffect 활성화 (PlayerStats 보정)", + "bullet": True, "size": 10}, + {"text": "이하 떨어지면 비활성화 (재진입 가능)", + "bullet": True, "size": 10}, + {"text": "", "size": 9}, + {"text": "교차 빌드의 가능성", + "size": 11, "bold": True, "color": ACCENT}, + {"text": "속성 빌드 (예: 화염 6장) + 유형 빌드 (예: 원거리 5장) 동시 추구 = 제3의 방향", + "bullet": True, "size": 10}, + {"text": "2태그 카드는 두 시너지에 동시 기여", + "bullet": True, "size": 10}, + ]) +add_footer(s, 25, TOTAL_SLIDES) + +# ============================================================ +# 5부 — 60종 카드 명세 (슬라이드 26~28) +# ============================================================ + +# 슬라이드 26 — 액티브 20종 표 +s = prs.slides.add_slide(BLANK) +add_solid_bg(s, WHITE) +add_slide_header(s, "액티브 20종 명세 표 (CSV v0.3 기반)", 26, TOTAL_SLIDES, "5부 60종 명세") + +active_table = [ + ["#", "카드명", "카테고리", "주 태그", "동작 요지"], + ["A01", "진언부", "A 투사체", "[원거리][물리]", "전방 직선 부적 투척, 단일 적 타격"], + ["A02", "화염부", "A 투사체", "[원거리][화염]", "직선 투척 + 적중 시 화염 DoT"], + ["A03", "봉인부", "A 투사체", "[원거리][암흑]", "투척 + 적중 시 행동 정지 저주"], + ["A04", "뇌격부", "B 근접·범위", "[범위][번개]", "주변 번개 연쇄, 밀집 다중 타격"], + ["A05", "학익진", "B 근접·범위", "[근접][범위][물리]", "전방 부채꼴 자동 타격"], + ["A06", "독안개", "C 설치·지속", "[지속][암흑]", "이동 경로 독 구역 잔존, 접촉 DoT"], + ["A07", "혼백박멸", "E 상태이상", "[범위][암흑]", "주변 약화 오라, 공/방 저하"], + ["A08", "저주문", "A 투사체", "[원거리][암흑][지속]", "자동 투척, 저주 스택 N개 시 폭발"], + ["A09", "허수아비", "C 설치·지속", "[지속][방어]", "이동 경로 설치, 어그로 유도 + 완충"], + ["A10", "분신술", "D 소환", "[근접][물리]", "분신 1기, 플레이어 공격 모방"], + ["A11", "도깨비불소환", "D 소환", "[원거리][암흑][지속]", "도깨비불 2기, 랜덤 추적 + DoT"], + ["A12", "쾌속검", "B 근접·범위", "[근접][물리]", "전방 연속 베기, 고빈도 단발"], + ["A13", "천둥발", "B 근접·범위", "[범위][번개]", "원형 번개 판정, 다중 연쇄"], + ["A14", "빙결창", "A 투사체", "[원거리][냉기]", "직선 투창, 적중 시 둔화"], + ["A15", "귀화", "A 투사체", "[원거리][화염][지속]", "유도 화염구, 가장 가까운 적 추적"], + ["A16", "일격필살", "F 특수 판정", "[근접][물리]", "확률 자동 회심 공격"], + ["A17", "결계장벽", "C 설치·지속", "[방어][지속]", "전방 고정 실드 설치, 적 저지"], + ["A18", "무영보", "F 특수 판정", "[방어][근접]", "순간 무적 대시 자동 발동"], + ["A19", "풍백제", "B 근접·범위", "[근접][범위][냉기]", "회오리 생성, 밀어내기 + 지속 타격"], + ["A20", "산군상", "D 소환", "[근접][물리][지속]", "호랑이 정령 소환, 돌진·물어뜯기"], +] +add_table(s, Inches(0.3), Inches(1.0), Inches(12.7), Inches(6.0), + active_table, body_size=8.5, header_size=10, + col_widths=[0.5, 1.5, 2, 2.7, 6]) +add_footer(s, 26, TOTAL_SLIDES) + +# 슬라이드 27 — 패시브 20종 표 +s = prs.slides.add_slide(BLANK) +add_solid_bg(s, WHITE) +add_slide_header(s, "패시브 20종 명세 표 (CSV v0.3 기반)", 27, TOTAL_SLIDES, "5부 60종 명세") + +passive_table = [ + ["#", "카드명", "카테고리", "동작 요지", "주 시너지"], + ["P01", "봉황격", "P-A 스탯", "모든 액티브 대미지 증가 (범용)", "전체 (범용 강화)"], + ["P02", "화염강화", "P-A 스탯", "[화염] 태그 액티브 대미지 증가", "A02·A15"], + ["P03", "냉기강화", "P-A 스탯", "[냉기] 태그 액티브 대미지 증가", "A14·A19"], + ["P04", "뇌전강화", "P-A 스탯", "[번개] 태그 액티브 대미지 증가", "A04·A13"], + ["P05", "어둠강화", "P-A 스탯", "[암흑] 태그 액티브 대미지 증가", "A03·A06·A07·A08·A11"], + ["P06", "연사술", "P-B 주기", "모든 액티브 발동 주기 단축", "전체 (고부가 범용)"], + ["P07", "광역확장", "P-B 주기", "판정 범위 + [지속] 잔존시간 연장", "B·C·A07·A19"], + ["P08", "투사체증폭", "P-B 주기", "[원거리] 액티브 투사체 수 증가", "A 투사체 전체"], + ["P09", "집중술", "P-A 스탯", "크리티컬 확률 상승", "A16 + 전체"], + ["P10", "폭풍혼", "P-A 스탯", "크리티컬 대미지 배율 증가", "A16 + 전체"], + ["P11", "호신부", "P-C 생존", "피격 시 1회 흡수 실드 (조건부)", "C·D"], + ["P12", "생명의 꽃", "P-C 생존", "최대 하트 +1 (런 내)", "각성 조건 핵심"], + ["P13", "강철심장", "P-C 생존", "최대 하트 +1 (P12와 중첩 가능)", "각성 조건 핵심"], + ["P14", "부적방패", "P-C 생존", "받는 피해 % 감소", "C·D"], + ["P15", "회피술", "P-C 생존", "회피 확률 + i-frame 연장", "F·전체"], + ["P16", "단전수련", "P-D 회복", "적 처치 시 1/4 하트 회복 (누적 킬)", "B·E (처치 빈도)"], + ["P17", "감로수", "P-D 회복", "일정 시간마다 1/4 하트 자동 재생", "전체 (시간 기반)"], + ["P18", "질풍보", "P-E 자원", "이동 속도 상승", "전체 (포지셔닝)"], + ["P19", "선견지명", "P-E 자원", "경험치 획득량 증가 (레벨업 가속)", "전체 (빌드 가속)"], + ["P20", "재물복", "P-E 자원", "보물상자 스폰·발견 확률 증가", "전체 (각성 트리거 가속)"], +] +add_table(s, Inches(0.3), Inches(1.0), Inches(12.7), Inches(6.0), + passive_table, header_fill=GREEN_OK, body_size=8.5, header_size=10, + col_widths=[0.5, 1.5, 1.7, 5.0, 4.0]) +add_footer(s, 27, TOTAL_SLIDES) + +# 슬라이드 28 — 각성 20종 표 +s = prs.slides.add_slide(BLANK) +add_solid_bg(s, WHITE) +add_slide_header(s, "각성 20종 명세 표 (CSV v0.3 기반)", 28, TOTAL_SLIDES, "5부 60종 명세") + +awaken_table = [ + ["#", "각성명", "패턴", "원 액티브", "필요 패시브 (1+)", "동작 요지"], + ["AW01", "천부경문", "4 광역", "A01 진언부", "P01·P06·P08", "화면 전체 부적 전개, 전 적 강타"], + ["AW02", "염라화염", "1 스케일업", "A02 화염부", "P02·P07", "범위 대폭 확장 + 점화 무제한"], + ["AW03", "천뢰강림", "4 광역", "A04 뇌격부", "P04·P06·P08", "연쇄 번개 무제한 전파"], + ["AW04", "봉령결계", "2 새효과", "A03 봉인부", "P05·P07", "행동 정지 + DoT 동시 부여"], + ["AW05", "학익천진", "1 스케일업", "A05 학익진", "P01·P07", "부채꼴 -> 360도 전방위"], + ["AW06", "독무유역", "4 광역", "A06 독안개", "P05·P07", "화면 전체 독무 잔존"], + ["AW07", "사령결계", "2 새효과", "A08 저주문", "P05·P06", "스택 즉시 최대 + 폭발 증폭"], + ["AW08", "혼령폭풍", "1 스케일업", "A07 혼백박멸", "P05·P07", "오라 -> 화면 전체 약화"], + ["AW09", "허수군세", "3 다중발동", "A09 허수아비", "P01·P11", "1기 -> 4~5기 동시 설치"], + ["AW10", "분신만화", "3 다중발동", "A10 분신술", "P01·P06", "1기 -> 3~4기 동시 소환"], + ["AW11", "산신령강림", "2 새효과", "A11 도깨비불", "P05·P07", "도깨비불 2기 -> 강력 1기 상주"], + ["AW12", "쾌검비경", "1 스케일업", "A12 쾌속검", "P01·P06", "연타 속도 극속, 무한 연격"], + ["AW13", "천지진동", "1 스케일업", "A13 천둥발", "P04·P07", "원형 번개 화면 전체 확장"], + ["AW14", "빙하시대", "2 새효과", "A14 빙결창", "P03·P07", "투창 + 낙하 영역 빙결"], + ["AW15", "귀화유성", "3 다중발동", "A15 귀화", "P02·P08", "유도 화염구 무한 발사"], + ["AW16", "일격절명", "1 스케일업", "A16 일격필살", "P09·P10", "회심 확률·배율 극한 (보스 외 즉사)"], + ["AW17", "천지음양방호", "2 새효과", "A17 결계장벽", "P11·(P12 또는 P13)", "실드 + 무적 시간 상시 유지"], + ["AW18", "귀보유영", "2 새효과", "A18 무영보", "P15·P18", "무적 대시 무한 + 피격 임박 자동"], + ["AW19", "풍신질주", "4 광역", "A19 풍백제", "P03·P07", "회오리 -> 화면 폭풍, 빙결"], + ["AW20", "산군포효", "3 다중발동", "A20 산군상", "P01·P05", "호랑이 1기 -> 3기, 포효 기절"], +] +add_table(s, Inches(0.2), Inches(1.0), Inches(12.9), Inches(6.0), + awaken_table, header_fill=PURPLE, body_size=7.5, header_size=9, + col_widths=[0.5, 1.5, 1.5, 1.6, 2.0, 5.5]) +add_footer(s, 28, TOTAL_SLIDES) + +# ============================================================ +# 6부 — 구현 가이드 (슬라이드 29~33) +# ============================================================ + +# 슬라이드 29 — 4계층 아키텍처 +s = prs.slides.add_slide(BLANK) +add_solid_bg(s, WHITE) +add_slide_header(s, "Unity 구현 — 4계층 아키텍처", 29, TOTAL_SLIDES, "6부 구현") + +layers = [ + ("계층 4 — 효과 발동", NAVY, + "AttackHitbox · ProjectileSpawner · AuraZone · MinionSpawner · DebuffApplier · Health.Decrement(int)", + "BT7-Dev 일부 재활용 + 신설 5종"), + ("계층 3 — 스킬 런타임", GREEN_OK, + "ActiveSkillRuntime · PassiveSkillRuntime · AwakeningSkillRuntime · PlayerSkillInventory", + "각 카드당 1 인스턴스, 인벤토리 관리"), + ("계층 2 — 스킬 데이터", PURPLE, + "SkillDataAsset (abstract) -> ActiveSkillData · PassiveSkillData · AwakeningSkillData", + "60종 .asset 파일 (ScriptableObject)"), + ("계층 1 — 정적 SOT", ACCENT, + "02_스킬_효과_컨셉_v0.3.csv (60종 캐주얼 명명)", + "기획팀 편집 -> 에디터 툴 -> 자산 재생성"), +] + +for i, (title, color, desc, sub) in enumerate(layers): + y = Inches(1.1) + Inches(1.4) * i + box = s.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, + Inches(0.5), y, Inches(12.3), Inches(1.25)) + box.fill.solid() + box.fill.fore_color.rgb = color + box.line.fill.background() + box.shadow.inherit = False + btf = box.text_frame + btf.margin_left = Inches(0.3) + btf.margin_right = Inches(0.3) + btf.margin_top = Inches(0.15) + bp = btf.paragraphs[0] + br = bp.add_run() + br.text = title + br.font.name = HEADER_FONT + br.font.size = Pt(15) + br.font.bold = True + br.font.color.rgb = WHITE + bp2 = btf.add_paragraph() + bp2.line_spacing = 1.2 + br2 = bp2.add_run() + br2.text = desc + br2.font.name = CODE_FONT + br2.font.size = Pt(11) + br2.font.color.rgb = WHITE + bp3 = btf.add_paragraph() + br3 = bp3.add_run() + br3.text = sub + br3.font.name = BODY_FONT + br3.font.size = Pt(10) + br3.font.color.rgb = ICE + # 위→아래 화살표 + if i < len(layers) - 1: + arr_y = y + Inches(1.25) - Pt(2) + arr = s.shapes.add_shape(MSO_SHAPE.UP_ARROW, + Inches(6.5), arr_y, Inches(0.3), Inches(0.15)) + arr.fill.solid() + arr.fill.fore_color.rgb = GRAY + arr.line.fill.background() + +add_text_box(s, Inches(0.5), Inches(6.85), Inches(12.3), Inches(0.4), + "각 계층 분리 = 신규 카드 추가 시 ScriptableObject 인스턴스 생성만으로 확장 (BT12-Dev §1-1 자원 효율·코드 직관성·범용성)", + font_size=10, color=GRAY, align=PP_ALIGN.CENTER) +add_footer(s, 29, TOTAL_SLIDES) + +# 슬라이드 30 — 인터페이스·이벤트 정의 +s = prs.slides.add_slide(BLANK) +add_solid_bg(s, WHITE) +add_slide_header(s, "주요 인터페이스 · 이벤트 정의 (Unity C#)", 30, TOTAL_SLIDES, "6부 구현") + +# 좌측 — 인터페이스 트리 +add_text_box(s, Inches(0.5), Inches(1.05), Inches(6), Inches(0.5), + "인터페이스 계약 4종", + font_size=13, bold=True, color=NAVY) + +iface_box = s.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, + Inches(0.5), Inches(1.55), Inches(6), Inches(5.3)) +iface_box.fill.solid() +iface_box.fill.fore_color.rgb = LIGHT_BG +iface_box.line.color.rgb = NAVY +iface_box.line.width = Pt(1.5) +iface_box.shadow.inherit = False +add_multiline_text(s, Inches(0.7), Inches(1.65), Inches(5.7), Inches(5.1), + [ + {"text": "ISkillRuntime (공통)", + "size": 12, "bold": True, "color": NAVY, "font_name": CODE_FONT}, + {"text": " SkillDataAsset Data { get; }", + "size": 9, "color": DARK_TEXT, "font_name": CODE_FONT}, + {"text": " int StackLevel { get; }", + "size": 9, "color": DARK_TEXT, "font_name": CODE_FONT}, + {"text": " void OnEquip(PlayerSkillInventory)", + "size": 9, "color": DARK_TEXT, "font_name": CODE_FONT}, + {"text": " void OnUnequip()", + "size": 9, "color": DARK_TEXT, "font_name": CODE_FONT}, + {"text": " void Upgrade()", + "size": 9, "color": DARK_TEXT, "font_name": CODE_FONT}, + {"text": "", "size": 9}, + {"text": "IActiveSkill : ISkillRuntime", + "size": 12, "bold": True, "color": NAVY, "font_name": CODE_FONT}, + {"text": " float BaseCooldown / EffectiveCooldown", + "size": 9, "color": DARK_TEXT, "font_name": CODE_FONT}, + {"text": " float CooldownRemaining", + "size": 9, "color": DARK_TEXT, "font_name": CODE_FONT}, + {"text": " void Fire()", + "size": 9, "color": DARK_TEXT, "font_name": CODE_FONT}, + {"text": " ActiveTrigger Trigger { get; }", + "size": 9, "color": DARK_TEXT, "font_name": CODE_FONT}, + {"text": "", "size": 9}, + {"text": "IPassiveSkill : ISkillRuntime", + "size": 12, "bold": True, "color": GREEN_OK, "font_name": CODE_FONT}, + {"text": " bool IsAlwaysOn", + "size": 9, "color": DARK_TEXT, "font_name": CODE_FONT}, + {"text": " void ApplyModifier(PlayerStats)", + "size": 9, "color": DARK_TEXT, "font_name": CODE_FONT}, + {"text": " void RemoveModifier(PlayerStats)", + "size": 9, "color": DARK_TEXT, "font_name": CODE_FONT}, + {"text": " void OnTrigger(PassiveTriggerContext)", + "size": 9, "color": DARK_TEXT, "font_name": CODE_FONT}, + {"text": "", "size": 9}, + {"text": "IAwakeningSkill : ISkillRuntime", + "size": 12, "bold": True, "color": PURPLE, "font_name": CODE_FONT}, + {"text": " ActiveSkillData OriginalActive", + "size": 9, "color": DARK_TEXT, "font_name": CODE_FONT}, + {"text": " PassiveSkillData[] RequiredPassives", + "size": 9, "color": DARK_TEXT, "font_name": CODE_FONT}, + {"text": " void Awaken(PlayerSkillInventory)", + "size": 9, "color": DARK_TEXT, "font_name": CODE_FONT}, + {"text": " AwakeningPattern Pattern { get; }", + "size": 9, "color": DARK_TEXT, "font_name": CODE_FONT}, + ]) + +# 우측 — 이벤트 + Enum +add_text_box(s, Inches(6.8), Inches(1.05), Inches(6), Inches(0.5), + "이벤트 · Enum 정의", + font_size=13, bold=True, color=NAVY) +ev_box = s.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, + Inches(6.8), Inches(1.55), Inches(6), Inches(5.3)) +ev_box.fill.solid() +ev_box.fill.fore_color.rgb = LIGHT_BG +ev_box.line.color.rgb = NAVY +ev_box.line.width = Pt(1.5) +ev_box.shadow.inherit = False +add_multiline_text(s, Inches(7.0), Inches(1.65), Inches(5.7), Inches(5.1), + [ + {"text": "Simulation.Event 기반 발동 (BT7-Dev 일관)", + "size": 11, "bold": True, "color": NAVY}, + {"text": " SkillFireEvent (액티브 발동)", + "size": 10, "font_name": CODE_FONT, "color": DARK_TEXT}, + {"text": " AwakeningFireEvent (각성 발동)", + "size": 10, "font_name": CODE_FONT, "color": DARK_TEXT}, + {"text": " AwakeningEffectEvent (풀스크린 연출)", + "size": 10, "font_name": CODE_FONT, "color": DARK_TEXT}, + {"text": "", "size": 9}, + {"text": "이벤트 핸들러 (PlayerSkillInventory)", + "size": 11, "bold": True, "color": NAVY}, + {"text": " event Action OnEnemyKilled", + "size": 10, "font_name": CODE_FONT, "color": DARK_TEXT}, + {"text": " event Action OnPlayerDamaged", + "size": 10, "font_name": CODE_FONT, "color": DARK_TEXT}, + {"text": " void OnTreasureChestOpened()", + "size": 10, "font_name": CODE_FONT, "color": DARK_TEXT}, + {"text": " void AddSkillByCardId(string)", + "size": 10, "font_name": CODE_FONT, "color": DARK_TEXT}, + {"text": "", "size": 9}, + {"text": "ActiveTrigger { OnTime · OnHit · OnKill }", + "size": 10, "color": DARK_TEXT, "font_name": CODE_FONT}, + {"text": "AwakeningPattern {", + "size": 10, "color": PURPLE, "font_name": CODE_FONT}, + {"text": " ScaleUp · AddEffect · MultiFire · GlobalSpread }", + "size": 10, "color": PURPLE, "font_name": CODE_FONT}, + {"text": "PassiveTriggerKind {", + "size": 10, "color": GREEN_OK, "font_name": CODE_FONT}, + {"text": " OnPlayerDamaged · OnEnemyKilled · OnTimer }", + "size": 10, "color": GREEN_OK, "font_name": CODE_FONT}, + {"text": "ActiveCategory { Projectile · MeleeArea ·", + "size": 10, "color": DARK_TEXT, "font_name": CODE_FONT}, + {"text": " PlacementPersistent · Minion · Debuff · SpecialJudge }", + "size": 10, "color": DARK_TEXT, "font_name": CODE_FONT}, + {"text": "PassiveCategory { StatUp · CycleAmplify ·", + "size": 10, "color": DARK_TEXT, "font_name": CODE_FONT}, + {"text": " Survival · Recovery · ResourceExpand }", + "size": 10, "color": DARK_TEXT, "font_name": CODE_FONT}, + ]) +add_footer(s, 30, TOTAL_SLIDES) + +# 슬라이드 31 — BT.Framework / BT7-Dev 활용 +s = prs.slides.add_slide(BLANK) +add_solid_bg(s, WHITE) +add_slide_header(s, "BT.Framework Tier 1·2 + BT7-Dev 자산 활용", 31, TOTAL_SLIDES, "6부 구현") + +# BT.Framework +add_text_box(s, Inches(0.5), Inches(1.05), Inches(6), Inches(0.5), + "BT.Framework Tier 1·2 활용 (P29 준수)", + font_size=13, bold=True, color=GREEN_OK) +bt_data = [ + ["자산", "활용 영역"], + ["오브젝트 풀링 Tier 1", "ProjectileSpawner / MinionSpawner / AuraZone 인스턴스 관리"], + ["Log Tier 1", "스킬 발동·각성 트리거 디버그 로그"], + ["ValidationEx Tier 1", "런타임 데이터 무결성 검증 (ScriptableObject 누락 등)"], + ["MathEx Tier 1", "확률 분포·가중치 계산"], + ["EnumEx Tier 1", "AttributeTag·TypeTag Flags 연산"], + ["FormatEx Tier 1", "Lv.N 표시·HUD 텍스트 렌더링"], + ["SafeAreaBorder Tier 1", "각성 풀스크린 연출 Safe Area 보장"], +] +add_table(s, Inches(0.5), Inches(1.55), Inches(6), Inches(3.5), + bt_data, header_fill=GREEN_OK, body_size=9.5, header_size=11, + col_widths=[2, 4]) + +# BT7-Dev +add_text_box(s, Inches(6.8), Inches(1.05), Inches(6), Inches(0.5), + "BT7-Dev 기존 자산 통합 (C39 실측)", + font_size=13, bold=True, color=NAVY) +bt7_data = [ + ["자산", "통합 방식"], + ["Health.cs (Decrement·Heal·IncreaseMaxHearts)", "P-C·P-D 패시브 효과 적용 API (변경 없음)"], + ["Health.OnDamagedEvent (신설)", "Phase 2-C 확장 - OnHit 트리거 발화"], + ["PlayerAttack : Simulation.Event", "기본 무기 발동 유지 (스킬 시스템 별도)"], + ["PlayerAttackTicker", "기본 무기 주기 타이머 유지"], + ["AttackHitbox.Fire(Vector2)", "B 카테고리 효과 발동기 재활용"], + ["PlayerController.Facing", "투사체 발사 방향 / 근접 판정 방향"], + ["Simulation.Schedule()", "스킬 효과 발동 Dispatch 패턴 일관"], +] +add_table(s, Inches(6.8), Inches(1.55), Inches(6), Inches(3.5), + bt7_data, body_size=9.5, header_size=11, + col_widths=[2.5, 3.5]) + +# 하단 — 의존성 +add_text_box(s, Inches(0.5), Inches(5.3), Inches(12), Inches(0.5), + "외부 의존성 (Unity 패키지)", + font_size=13, bold=True, color=NAVY) +add_multiline_text(s, Inches(0.7), Inches(5.8), Inches(12.3), Inches(1.3), + [ + {"text": "Input System (com.unity.inputsystem) — 이동·점프 입력 (Attack 액션 제거 상태 유지)", + "bullet": True, "size": 11}, + {"text": "Cinemachine (com.unity.cinemachine) — 플레이어 추적 카메라", + "bullet": True, "size": 11}, + {"text": "Universal RP (com.unity.render-pipelines.universal) — 2D 렌더링·이펙트", + "bullet": True, "size": 11}, + {"text": "BT.Framework Tier 1 (코어코드/BT.Framework/) — 16/16 완결 자산", + "bullet": True, "size": 11, "color": GREEN_OK}, + ]) +add_footer(s, 31, TOTAL_SLIDES) + +# 슬라이드 32 — Phase 분리 우선순위 +s = prs.slides.add_slide(BLANK) +add_solid_bg(s, WHITE) +add_slide_header(s, "구현 Phase 분리 — P0~P4 우선순위 (BT12-Dev §7-2)", 32, TOTAL_SLIDES, "6부 구현") + +phases = [ + ("P0", "코어 — 인터페이스·ScriptableObject 코드 생성", NAVY, + "ISkillRuntime / IActive / IPassive / IAwakening 4개\nSkillDataAsset 베이스 + 3 파생\nPlayerSkillInventory · PlayerStats · AwakeningManager · SkillRuntimeFactory\nSkillFireEvent · AwakeningFireEvent · AwakeningEffectEvent", + "Sonnet 클라이언트팀 단일 Task"), + ("P1", "데이터 — CSV → ScriptableObject 파이프라인", PURPLE, + "SkillCsvImporter (EditorWindow)\n60종 .asset 파일 일괄 생성 (Active/Passive/Awakening 각 20)\n카테고리·패턴 enum 매핑 테이블 적용", + "에디터 툴 1회 실행 시 60종 자산 생성"), + ("P2", "UI — 픽 UI · HUD 슬롯 · 각성 연출", ACCENT, + "CardPickCanvas (Additive) - 액티브/패시브 분류 표시\nHUD 액티브·패시브 슬롯 6+6 (Lv.5 황금 테두리)\n각성 발동 풀스크린 연출 (Safe Area 적용)", + "UX/02 v0.2 와이어프레임 기준"), + ("P3", "각성 시스템 - 3 조건 매니저 + 패턴 Dispatcher", PURPLE, + "AwakeningManager.CheckAwakeningEligibility()\n4 패턴별 AwakeningFireEvent.Execute() 분기\n다중 조건 충족 시 선택 UI · 단일/복수 처리", + "Phase 1·2 완료 후"), + ("P4", "보물상자 - 스폰·획득·대체 보상", ACCENT, + "TreasureChest 오브젝트 + OnTriggerEnter2D\nP20 재물복 패시브 가중치 반영\n조건 불충족 시 대체 보상 (재화·회복·경험치)", + "스테이지 구조 의존 (level-designer 연계)"), +] +for i, (phase, title, color, desc, note) in enumerate(phases): + y = Inches(1.1) + Inches(1.2) * i + # 좌측 P박스 + pbox = s.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, + Inches(0.5), y, Inches(1.0), Inches(1.05)) + pbox.fill.solid() + pbox.fill.fore_color.rgb = color + pbox.line.fill.background() + pbox.shadow.inherit = False + ptf_ = pbox.text_frame + ptf_.vertical_anchor = MSO_ANCHOR.MIDDLE + pp_ = ptf_.paragraphs[0] + pp_.alignment = PP_ALIGN.CENTER + pr_ = pp_.add_run() + pr_.text = phase + pr_.font.name = HEADER_FONT + pr_.font.size = Pt(22) + pr_.font.bold = True + pr_.font.color.rgb = WHITE + # 우측 본문 + bbox = s.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, + Inches(1.6), y, Inches(11.2), Inches(1.05)) + bbox.fill.solid() + bbox.fill.fore_color.rgb = LIGHT_BG + bbox.line.color.rgb = color + bbox.line.width = Pt(1) + bbox.shadow.inherit = False + add_text_box(s, Inches(1.75), y + Inches(0.05), Inches(10), Inches(0.35), + title, font_size=12, bold=True, color=color) + add_text_box(s, Inches(1.75), y + Inches(0.4), Inches(8.5), Inches(0.6), + desc, font_size=8.5, color=DARK_TEXT) + add_text_box(s, Inches(10.5), y + Inches(0.4), Inches(2.3), Inches(0.6), + note, font_size=8, color=GRAY, align=PP_ALIGN.RIGHT) + +add_footer(s, 32, TOTAL_SLIDES) + +# 슬라이드 33 — 시너지 빌드 예시 +s = prs.slides.add_slide(BLANK) +add_solid_bg(s, WHITE) +add_slide_header(s, "시너지 빌드 예시 — 8종 대표 빌드", 33, TOTAL_SLIDES, "6부 구현") + +build_data = [ + ["빌드명", "핵심 액티브", "핵심 패시브", "각성 후보", "재미 축"], + ["화염 폭격", "A02·A15", "P02·P07", "AW02·AW15", "축 1·2"], + ["번개 연쇄", "A04·A13", "P04·P06·P08", "AW03·AW13", "축 2 (화면 포화)"], + ["암흑 DoT", "A03·A06·A08", "P05·P07", "AW04·AW06·AW07", "축 1 (스택 기대감)"], + ["소환 군주", "A09·A10·A11·A20", "P11·P12·P18", "AW09·AW10·AW11·AW20", "축 1·2 (전능감)"], + ["냉기 제어", "A14·A19", "P03·P07", "AW14·AW19", "축 2 (필드 제어)"], + ["회피 게릴라", "A12·A16·A18", "P09·P10·P15", "AW12·AW16·AW18", "축 1 (예상 밖 쾌감)"], + ["철벽 생존", "A17", "P11·P12·P13·P14", "AW17", "축 3 (영속 위안)"], + ["보물상자 각성", "어떤 액티브든 Lv.5", "P20·P19·P06", "조건 충족 각성", "축 1 (조기 각성)"], +] +add_table(s, Inches(0.3), Inches(1.0), Inches(12.7), Inches(5.5), + build_data, body_size=9, header_size=11, + col_widths=[2, 2.5, 2.5, 3, 2.7]) + +add_text_box(s, Inches(0.5), Inches(6.7), Inches(12.3), Inches(0.5), + "각 빌드는 실제 런 결과를 보장하지 않으며, 픽 단계 가중치·확률에 따라 달라진다 (balance-designer 영역)", + font_size=10, color=GRAY, align=PP_ALIGN.CENTER) +add_footer(s, 33, TOTAL_SLIDES) + +# ============================================================ +# 7부 — 검증·QA (슬라이드 34) +# ============================================================ + +# 슬라이드 34 — EditMode·PlayMode 테스트 + 어뷰징 가드 +s = prs.slides.add_slide(BLANK) +add_solid_bg(s, WHITE) +add_slide_header(s, "검증·QA — EditMode·PlayMode·성능·어뷰징 가드", 34, TOTAL_SLIDES, "7부 검증") + +# 좌상 — EditMode +add_text_box(s, Inches(0.5), Inches(1.05), Inches(6), Inches(0.5), + "EditMode 테스트 (최소 10건)", + font_size=12, bold=True, color=NAVY) +add_multiline_text(s, Inches(0.7), Inches(1.5), Inches(6), Inches(2.7), + [ + {"text": "ScriptableObject 인스턴스 무결성 검증", "bullet": True, "size": 10}, + {"text": "Factory.Create 분기 (Active/Passive/Awakening)", "bullet": True, "size": 10}, + {"text": "StackLevelFactor 곡선 (Lv.1=1.0~Lv.5=2.0)", "bullet": True, "size": 10}, + {"text": "Cooldown 누적 오버플로 방지 (BT7-Dev 패턴)", "bullet": True, "size": 10}, + {"text": "AwakeningManager 3 조건 분기", "bullet": True, "size": 10}, + {"text": "다중 조건 충족 → 선택 UI 진입 분기", "bullet": True, "size": 10}, + {"text": "RequiredPassives.Any 매칭 로직", "bullet": True, "size": 10}, + {"text": "이미 발동된 각성 중복 차단", "bullet": True, "size": 10}, + {"text": "CSV → ScriptableObject 60종 변환", "bullet": True, "size": 10}, + {"text": "PlayerStats 보정 누적·원복", "bullet": True, "size": 10}, + ]) + +# 우상 — PlayMode +add_text_box(s, Inches(6.8), Inches(1.05), Inches(6), Inches(0.5), + "PlayMode 통합 테스트", + font_size=12, bold=True, color=NAVY) +add_multiline_text(s, Inches(7.0), Inches(1.5), Inches(6), Inches(2.7), + [ + {"text": "각 카테고리(A~F) 액티브 1종 실제 발동 확인", "bullet": True, "size": 10}, + {"text": "Health.Decrement 호출 경로 추적", "bullet": True, "size": 10}, + {"text": "픽 UI → 슬롯 편입 → 자동 발동 사이클", "bullet": True, "size": 10}, + {"text": "Lv.5 도달 → MarkActiveMaxed 자동 호출", "bullet": True, "size": 10}, + {"text": "보물상자 획득 → 각성 발동 (단일·다중)", "bullet": True, "size": 10}, + {"text": "각성 발동 후 원 액티브 슬롯 유지 + 효과 변경", "bullet": True, "size": 10}, + {"text": "P12+P13 동시 보유 시 최대 하트 +2", "bullet": True, "size": 10}, + {"text": "P11 호신부 OnPlayerDamaged 트리거", "bullet": True, "size": 10}, + {"text": "P16 단전수련 OnEnemyKilled 회복", "bullet": True, "size": 10}, + ]) + +# 좌하 — 성능 검증 +add_text_box(s, Inches(0.5), Inches(4.4), Inches(6), Inches(0.5), + "성능 검증 포인트 (모바일 60fps 95%+)", + font_size=12, bold=True, color=ACCENT) +add_multiline_text(s, Inches(0.7), Inches(4.85), Inches(6), Inches(2.2), + [ + {"text": "AW01·AW03·AW06·AW13·AW19 광역 확산 4종", "bullet": True, "size": 10, "color": RED_HL}, + {"text": " - 파티클 상한·충돌 연산 배치 처리 필수", "size": 9, "color": GRAY}, + {"text": "AW09·AW10·AW15·AW20 다중 발동 4종", "bullet": True, "size": 10, "color": RED_HL}, + {"text": " - 동시 오브젝트 상한·풀링 용량 검증", "size": 9, "color": GRAY}, + {"text": "A20 산군상 근접 돌진 소환물", "bullet": True, "size": 10}, + {"text": " - 2D 지형 낙하·충돌 대응 (자율형 회피)", "size": 9, "color": GRAY}, + {"text": "Cooldown 하드캡 0.5s 적용 확인", "bullet": True, "size": 10}, + {"text": "Profiler GC 알로케이션 0 / 프레임", "bullet": True, "size": 10}, + ]) + +# 우하 — 어뷰징 가드 +add_text_box(s, Inches(6.8), Inches(4.4), Inches(6), Inches(0.5), + "어뷰징 가드 (밸런스 보호)", + font_size=12, bold=True, color=RED_HL) +add_multiline_text(s, Inches(7.0), Inches(4.85), Inches(6), Inches(2.2), + [ + {"text": "회복 스팸 차단 — P16·P17 회복량 감소 곡선·쿨다운", "bullet": True, "size": 10}, + {"text": "최대 하트 하드캡 5개 (P12+P13 무한 중첩 차단)", "bullet": True, "size": 10}, + {"text": "Cooldown 하드캡 0.5s (이펙트 중첩 혼잡 방지)", "bullet": True, "size": 10}, + {"text": "MoveSpeed 상한 9.0 m/s (P18·P11 무한 가속 차단)", "bullet": True, "size": 10}, + {"text": "Lv.5 이상 동일 카드 재픽 무한 루프 방지", "bullet": True, "size": 10}, + {"text": "각성 1회 발동 후 alreadyAwakened 마킹", "bullet": True, "size": 10}, + {"text": "P20 재물복 Lv.5 보물상자 확률 캡 (balance)", "bullet": True, "size": 10}, + ]) +add_footer(s, 34, TOTAL_SLIDES) + +# ============================================================ +# 8부 — 후속·부록 (슬라이드 35~36) +# ============================================================ + +# 슬라이드 35 — PD 결정 대기 영역 + 후속 안건 +s = prs.slides.add_slide(BLANK) +add_solid_bg(s, WHITE) +add_slide_header(s, "PD 결정 대기 영역 · 후속 안건", 35, TOTAL_SLIDES, "8부 후속") + +# PD 결정 대기 +pd_box = s.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, + Inches(0.5), Inches(1.1), Inches(12.3), Inches(2.8)) +pd_box.fill.solid() +pd_box.fill.fore_color.rgb = LIGHT_BG +pd_box.line.color.rgb = RED_HL +pd_box.line.width = Pt(2) +pd_box.shadow.inherit = False +add_text_box(s, Inches(0.7), Inches(1.2), Inches(12), Inches(0.5), + "PD 결정 대기 영역 (본 기획서 범위 외)", + font_size=14, bold=True, color=RED_HL) +add_multiline_text(s, Inches(0.7), Inches(1.7), Inches(12), Inches(2.2), + [ + {"text": "narrative 한자 카드명 재매핑 — 일반 RPG 용어 11종 -> 조선 퇴마 톤 일괄 재매핑 (BT7-Plan 11)", + "bullet": True, "size": 11, "color": DARK_TEXT}, + {"text": "balance-designer 수치 확정 — 60종 BaseDamage·Cooldown·확률·스택·MultiFireCount·AwakeningBaseDamage", + "bullet": True, "size": 11, "color": DARK_TEXT}, + {"text": "BM·과금 구조 (Phase 3-C) — Lv.5 이상 재픽 보상 방식 / 보물상자 재화 수치 / 메타 진행 자원", + "bullet": True, "size": 11, "color": DARK_TEXT}, + {"text": "아트 톤 결정 — 카드 아이콘·각성 풀스크린 연출·이펙트 색상 가이드", + "bullet": True, "size": 11, "color": DARK_TEXT}, + {"text": "기본 시작 무기 — 퇴마사 고유 무기 1종 (A01~A20 중 1 선택 또는 별도 카드)", + "bullet": True, "size": 11, "color": DARK_TEXT}, + ]) + +# 후속 작업 안건 +suc_box = s.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, + Inches(0.5), Inches(4.1), Inches(12.3), Inches(2.6)) +suc_box.fill.solid() +suc_box.fill.fore_color.rgb = LIGHT_BG +suc_box.line.color.rgb = NAVY +suc_box.line.width = Pt(2) +suc_box.shadow.inherit = False +add_text_box(s, Inches(0.7), Inches(4.2), Inches(12), Inches(0.5), + "후속 작업 안건 (개발팀·기획팀 위임)", + font_size=14, bold=True, color=NAVY) +add_multiline_text(s, Inches(0.7), Inches(4.7), Inches(12), Inches(2.0), + [ + {"text": "Phase 2 클라이언트팀 위임 (Sonnet) — Unity C# 스크립트 25종 + 테스트 10건 + 60종 .asset", + "bullet": True, "size": 11}, + {"text": "Phase 3 개발팀장 검증 (Opus) — 6 검증 항목 (자원·구조·BT7-Dev 호환·BT.Framework 활용·테스트 green·balance 이관)", + "bullet": True, "size": 11}, + {"text": "balance-designer 60종 수치 확정 Task — 기획팀장 경유 위임", + "bullet": True, "size": 11}, + {"text": "narrative-designer 재매핑 Task — PD 후속 검토 후 일괄", + "bullet": True, "size": 11}, + {"text": "content/01 v0.3 동기화 — A19·A20·AW19·AW20 신설 + P25→P20 재편 (기획팀장 연속 작업)", + "bullet": True, "size": 11}, + {"text": "Unity 프로젝트 경로 paths.local.json 설정 — Phase 2 착수 차단 블로커 해소 필요", + "bullet": True, "size": 11, "color": RED_HL}, + ]) + +add_footer(s, 35, TOTAL_SLIDES) + +# 슬라이드 36 — 변경 이력·참조·용어집·종결 +s = prs.slides.add_slide(BLANK) +add_solid_bg(s, WHITE) +add_slide_header(s, "변경 이력 · 참조 SOT · 용어집", 36, TOTAL_SLIDES, "8부 부록") + +# 변경 이력 +add_text_box(s, Inches(0.5), Inches(1.05), Inches(6), Inches(0.5), + "변경 이력", + font_size=12, bold=True, color=NAVY) +hist_data = [ + ["일자", "버전", "변경"], + ["2026-04-22", "BT6-Plan", "Phase 3-B 초안 (system·content)"], + ["2026-04-24", "BT7-Plan", "3분류 구조·VS 순수형·Lv.5"], + ["2026-04-24", "BT11-Plan", "60종 명세 (20+20+20)"], + ["2026-04-24", "BT12-Dev v1", "Unity C# 4계층 설계"], + ["2026-04-26", "본 PPT v1", "통합 기획서 36슬라이드"], +] +add_table(s, Inches(0.5), Inches(1.5), Inches(6), Inches(2.5), + hist_data, body_size=9.5, header_size=10, + col_widths=[1.5, 1.5, 3]) + +# 참조 SOT +add_text_box(s, Inches(6.8), Inches(1.05), Inches(6), Inches(0.5), + "참조 SOT 7종", + font_size=12, bold=True, color=NAVY) +add_multiline_text(s, Inches(7.0), Inches(1.5), Inches(6), Inches(2.5), + [ + {"text": "system/01_카드_시스템.md v0.2", "size": 9, "font_name": CODE_FONT}, + {"text": "content/01_카드_풀.md v0.2", "size": 9, "font_name": CODE_FONT}, + {"text": "content/02_스킬_효과_컨셉.md v0.2", "size": 9, "font_name": CODE_FONT}, + {"text": "content/02_스킬_효과_컨셉_v0.3.csv", "size": 9, "font_name": CODE_FONT}, + {"text": "balance/01_전투_수치.md v0.2", "size": 9, "font_name": CODE_FONT}, + {"text": "balance/02_레벨업_곡선.md v0.2", "size": 9, "font_name": CODE_FONT}, + {"text": "ux/02_HUD_설계.md v0.2", "size": 9, "font_name": CODE_FONT}, + {"text": "개발/spec/스킬_시스템_설계_v1.md", "size": 9, "font_name": CODE_FONT}, + {"text": "개발/06_BT7-Plan_VS순수형_재구조.md", "size": 9, "font_name": CODE_FONT}, + ]) + +# 용어집 +add_text_box(s, Inches(0.5), Inches(4.2), Inches(12.3), Inches(0.5), + "용어집", + font_size=12, bold=True, color=NAVY) +gloss_data = [ + ["용어", "정의"], + ["액티브", "자동 발동 무기·스킬 (주기·판정·대미지). Lv.1~Lv.5 스택"], + ["패시브", "장착 즉시 상시 적용 보정 (스탯·확률·지속). 일부는 조건부 트리거"], + ["각성", "별도 풀의 진화 카드. 3 조건 동시 충족 시 발동. 한 런 1회"], + ["보물상자", "각성 게이팅 트리거. 스테이지 진행 중 조건부 스폰. 불충족 시 대체 보상"], + ["쿼터", "1 하트 = 4 쿼터. 피해는 쿼터 단위 차감 (Zelda BotW 방식)"], + ["StackLevelFactor", "Lv 별 대미지 배율 (Lv.1=1.0 / Lv.5=2.0)"], + ["VS 순수형", "Vampire Survivors 패턴 — 공격 버튼 없이 자동 발동 (BT7-Plan 확정 방향 2)"], + ["i-frame", "피격 후 무적 시간 0.6s. 연속 피격 방지"], +] +add_table(s, Inches(0.5), Inches(4.7), Inches(12.3), Inches(2.4), + gloss_data, body_size=9, header_size=10, + col_widths=[2.5, 9.8]) +add_footer(s, 36, TOTAL_SLIDES) + +# ============================================================ +# 저장 +# ============================================================ +import os +output_path = "스킬시스템_개발기획서_v1.pptx" +prs.save(output_path) +print(f"\n=== 빌드 완료 ===") +print(f"산출물: {os.path.abspath(output_path)}") +print(f"슬라이드 수: {len(prs.slides)}") +print(f"파일 크기: {os.path.getsize(output_path)} bytes") diff --git a/프로젝트/EerieVillage/기획/기묘한고을_초기기획서_v1.docx b/프로젝트/EerieVillage/기획/기묘한고을_초기기획서_v1.docx new file mode 100644 index 0000000000000000000000000000000000000000..b00abeb19aa86d5789a5c7b3428b43ac10257b1d GIT binary patch literal 36464 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
VyFczJMaD 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 literal 0 HcmV?d00001 diff --git a/프로젝트/EerieVillage/기획/스킬시스템_개발기획서_v1.pptx b/프로젝트/EerieVillage/기획/스킬시스템_개발기획서_v1.pptx new file mode 100644 index 0000000000000000000000000000000000000000..7a61a7bd23d9ca338c412fee23a2879797a1164c GIT binary patch literal 122985 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

IWzfB<`=!C{=8LL|#+zF@BL-ik z4*kP?L%NpX& zON(YvtSF2bsW6f4&&R@BeZ%_4B2B`qEw2 zhx&U4ZPwW72uv;#c3w81QxKm*A-Jo!ADd$Y%Oddk>+<`lJ z@)V!oIYI{N#*Lm+^H}SR)u7CIV7biw#r?k6kAqS0i)`T*>K9D^ zAT^*I6A;q9p=r$;2}(rRLns|7=Jlc6?{7c!H|G!dQu4k&7S=qP^?9S zG=*!*zW@WrYx*6EDN5Yff6xciGzH`bEGnRiK}LwOFBn2EB7D&TP+^`$#3RbR3JFa< z==zG{0V?XiQ_(^&Zh6QEQTB`2r5w9D|FzX{R3%W)icn} zlTN4kQiH(y81!CC!=2`f7Jf#YcIX0FQnFx`ZU#ivbV3OKXv>)Wce5gBCim7oxF+FuM)D(78AWfe^y) zFiy=X7mk7Nt|8dAfCn`*9-^^@FuMxA(AFdffe^y)B+n0TE)WG38YQ8H9Frj$TL`mz z;0vXmf)EHH{EngE5r6+25ISXq7D{45G`0|Cm%tbD1{+$xvN!0*RwfsO8MhJhrmPAD zLXqa2Qy+c?8-wVU4bj*f>~4TGf>$i2pCq$&V96emXITURNO;N9nh54J$3a2{DjL_<1cb z>BUJ4u;7+}RRg$63u+-8N9nhL4J+j|Kn$c3eqwjW_pI~=Uw;z#`ol`6??E_@(r+Uh zRx)gY7)T}j%(hT+f7}nMS*-+-}Qa&#Ls+6sdR;m|= za2%xxrZ=A)#6T+Hr}y!Ks#gJE#ce51l|I5aj?x6vJ5>o+2|v9L8n%eVfdyA!g|1Sv zGKAwOO)$OJYd{QSmGINs_^S7le}U2!YqZkZMG%goG{N*Ne=?LLCN)t?POD~9lRKibh z^g|=Lt8k_?2***HV0w4>Lky%6etM%H9K}^?41jQKCC)<~&^tEp)7u~nVjz?dkB30x z&`(<6DlG|za2%xxruTz=5Cf@%pWf&@&2p9Mq9GhdX@co3ng}tFO8DuGzI_*0NiYe* zag-*Q-u@>c22u$>z0o(k;3{ne$Nvypg&d^`rnhYt#6T+Hr#JcvMXr)rHiY9SO)$OF zE