2293 lines
116 KiB
Python
2293 lines
116 KiB
Python
|
|
# -*- 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<EnemyController> OnEnemyKilled",
|
|||
|
|
"size": 10, "font_name": CODE_FONT, "color": DARK_TEXT},
|
|||
|
|
{"text": " event Action<float> 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<T>()", "스킬 효과 발동 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")
|