Files
maplecontest/docs/superpowers/specs/2026-06-12-rogue-map-design.md

5.7 KiB
Raw Blame History

P8 — 로그라이크 절차 생성 맵·층 시스템·유물 방 설계

날짜: 2026-06-12 (사용자 승인 완료) 브랜치: feature/p8-rogue-map 선행: P7 (유물 19종 — 유물 방이 PickNewRelic 재사용)

범위

  1. 절차 생성 맵 — 막 시작마다 8층×최대 4열 DAG를 Lua 런타임 생성 (런·막마다 다른 맵). data/map.json 정적 맵 제거
  2. 층(depth) 시스템 — 노드를 지날 때마다 층 +1 (층 = 행), 층별 노드 타입 등장 규칙
  3. 유물 방(보물 노드) — 상자 열리는 모션 + 유물(PickNewRelic)·메소 획득, 노드 타입 treasure 추가
  4. 맵 UI 정비 — 노드 연결 점선(도트 3개 보간), 타입별 아이콘 색/라벨, 상태 4단(방문/현재/도달 가능/잠김)
  5. 메소 표기 — 화폐 표시 텍스트 "골드" → "메소" (메이플 IP, 표시만 — 내부 변수 Gold 유지)

비범위: 이벤트 노드(?), 경로 교차 방지(시각 교차 허용 — 점선이라 식별 가능), 저장.

절차 생성 알고리즘 (StS 방식)

그리드: 행 17 × 열 14 + 8행 보스 단일 노드. 노드 id = "r{row}c{col}", 보스 = "boss".

  1. 시작 열: {1,2,3,4} 셔플 후 앞 2개 = 경로 1·2의 시작(서로 다름 보장), 경로 3·4는 랜덤
  2. 경로 4개를 각각 1행→7행으로 걸어 올림: 다음 열 = clamp(열 + random(-1..1), 1, 4). 지나는 칸마다 노드 생성(중복은 병합), (r,c) → (r+1,c') 간선 추가(중복 간선 병합)
  3. 7행의 모든 노드 → 보스 간선
  4. MapStart = 1행에 생성된 노드들

타입 배정 (행 오름차순)

규칙
1~2행 combat 고정
3행 combat 45 / shop 12 / rest 12 (가중 추첨, 합계로 정규화)
4~6행 combat 45 / elite 16 / shop 12 / rest 12 / treasure 15
7행 (보스 직전) rest 50 / combat 25 / shop 10 / elite 8 / treasure 7
8행 boss 고정

추가 제약: 부모(간선으로 들어오는 이전 행 노드) 중 elite가 있으면 해당 노드는 elite 금지 (연속 엘리트 방지).

층 카운터

Depth prop: PickNodeDepth = node.row. 막 전환·런 시작 시 0. TopBar Floor 텍스트를 막 F/3 · D층으로 확장.

노드 enemy 필드 제거

몬스터는 P4 이후 node.type 그룹 필터(BuildMonsters)로 결정되므로 enemy 필드·CurrentEnemyId 대입은 제거(CurrentEnemyId = "" 유지). data/map.json·luaMapNodesTable·luaStartArray·MAX_ROW 제거.

유물 방 (TreasureHud)

  • PickNode 분기에 treasureShowTreasure 추가 (ShowState("treasure")·HideGameHud 등록)
  • UI: 어두운 패널 + 타이틀("보물 상자") + 중앙 상자 버튼(닫힌 상자 RUID) + 보상 텍스트(초기 숨김) + 나가기 버튼
  • OpenChest: 1회 가드(ChestOpened) → 흔들림 모션(anchoredPosition ±8px, 0.08s × 6스텝 타이머 체인) → 열린 상자 RUID로 교체 → 보상 지급·표시
    • 메소: 40 + random(0..20)
    • 유물: PickNewRelic() — 미보유 추첨, 전부 보유 시 메소 +30 대체
    • 보상 텍스트 예: 유물 획득: 황소 투구 · 메소 +52
  • 상자 닫힘/열림 스프라이트는 공식 maplestory 리소스 검색("상자"/"보물상자") 후 메이커 선별
  • 나가기 → LeaveNode(기존 → ShowMap)

맵 UI

정적 그리드 (생성기, MapHud 섹션 재작성)

  • 노드 버튼 28개(Node_r{1..7}c{1..4}, 56×56) + Node_boss(72×72, 상단 중앙) + 각 노드 Label(타입 한글)
  • 배치: 행 y = -330 + (row-1)*105 (보스 y=405), 열 x = -270 + (col-1)*180, 보스 x=0
  • 점선 도트: 모든 가능 간선(행 1~6: c→c±1/c, 행 7→보스)에 대해 도트 3개(8×8, t=0.25/0.5/0.75 보간 위치). 엔티티 Dot_r{r}c{c}_{c'}_{k} (보스행은 Dot_r7c{c}_b_{k})
  • 모든 노드·도트는 기본 비활성, RenderMap이 토글

RenderMap 재작성 (상태 4단 + 점선)

  • 노드: 맵에 없으면 숨김. 있으면 Label = 타입명, 색:
    • 방문(VisitedNodes에 포함) → 어둡게 (0.18,0.19,0.22)
    • 현재 위치 → 골드 (0.95,0.8,0.3)
    • 도달 가능(IsReachable) → 타입색 밝게 + 버튼 활성
    • 잠김 → 타입색 45% 어둡게 + 버튼 비활성
  • 타입색: 전투 (0.78,0.36,0.32) / 엘리트 (0.62,0.4,0.85) / 상점 (0.9,0.75,0.35) / 휴식 (0.4,0.75,0.45) / 보물 (0.35,0.7,0.75) / 보스 (0.85,0.25,0.25)
  • 도트: 간선 존재 시 표시. 현재 노드(또는 시작 전 1행 진입선)에서 나가는 간선 = 골드, 그 외 = 회색 (0.5,0.5,0.55)
  • VisitedNodes(any prop): PickNode 시 추가

메소 표기

표시 문자열 "골드" → "메소": TopBar Gold·ShopHud Gold·상점 가격(N 메소)·유물 소진 토스트. 내부 prop Gold 유지.

검증

  1. JS 미러 + 단위 테스트: tools/map/rogue-map.mjsgenerateMap(rng) 동일 로직(시드 PRNG 주입) + rogue-map.test.mjs — 모든 노드가 시작점에서 도달 가능·보스 수렴·1~2행 combat만·elite/treasure 4행부터·간선 인접 열만·elite 부모 연속 금지·결정성(동일 시드 동일 맵). ⚠️ Lua GenerateMap과 로직 동기화 유지(sim-balance 패턴)
  2. 기존 sim-balance 21건 유지 (맵과 무관)
  3. 메이커: 빌드 0에러, 플레이테스트 — 맵 생성/점선/상태색, 노드 진행(층 증가), 유물 방 상자 연출·보상, 보스 클리어 → 다음 막 새 맵

결정 사항

  • 경로 4개·8층×4열 (사용자 승인 규모)
  • 점선 도트 방식 채택 (UI 회전 리스크 회피, StS 원작 미감)
  • 시각적 간선 교차는 허용 (점선이라 추적 가능 — YAGNI)
  • RUN_LENGTH/ACT_MAPS 막 시스템은 변경 없음 (막마다 새 맵 생성만 추가)