From 35dee08be30e6e397a585058921b59204647eb1a Mon Sep 17 00:00:00 2001 From: swrring Date: Sun, 23 Aug 2026 03:31:49 +0900 Subject: [PATCH] =?UTF-8?q?docs(BT13-GodDem):=20P3-B3-2=20=EC=8A=A4?= =?UTF-8?q?=ED=84=B4=C2=B7=ED=95=A9=EC=84=B1=20=EC=84=A4=EA=B3=84=20v2=20?= =?UTF-8?q?=EC=A1=B0=EA=B1=B4=EB=B6=80=20=ED=86=B5=EA=B3=BC=C2=B7=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20=EC=B0=A9=EC=88=98=20=E2=80=94=20PD=20=EC=A7=80?= =?UTF-8?q?=EC=8B=9C=202=EA=B1=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - PD 지시: 기절 전투 로직·장비 합성(탕탕특공대 레퍼런스·동일 등급 동일 파츠) - v1 차단(합성 Critical 3) → v2 비대칭 사다리 11종·재검증 조건부 통과(기절 즉시 적격) - Major-1 해소안 지정(재추첨 오버로드+null 가드)·문서 정정 5건·감사 전재 - 대화로그 §74~§78·개발팀장 구현 진행 중 Co-Authored-By: Claude Fable 5 --- .../GodDem/2026-08-23_P3B3-2_스턴_합성_설계_v1.md | 451 +++++++++++++++++ ...026-08-23_P3B3-2_스턴_합성_설계_v1_감사결과.md | 55 ++ .../GodDem/2026-08-23_P3B3-2_스턴_합성_설계_v2.md | 474 ++++++++++++++++++ 공유/대화로그/GodDem/2026-08-23.md | 54 ++ 4 files changed, 1034 insertions(+) create mode 100644 공유/기획/GodDem/2026-08-23_P3B3-2_스턴_합성_설계_v1.md create mode 100644 공유/기획/GodDem/2026-08-23_P3B3-2_스턴_합성_설계_v1_감사결과.md create mode 100644 공유/기획/GodDem/2026-08-23_P3B3-2_스턴_합성_설계_v2.md diff --git a/공유/기획/GodDem/2026-08-23_P3B3-2_스턴_합성_설계_v1.md b/공유/기획/GodDem/2026-08-23_P3B3-2_스턴_합성_설계_v1.md new file mode 100644 index 0000000..c7c46ad --- /dev/null +++ b/공유/기획/GodDem/2026-08-23_P3B3-2_스턴_합성_설계_v1.md @@ -0,0 +1,451 @@ +# GodDem 기절(Stun) 전투 로직 + 장비 융합(Forging) 활성화 설계 v1 (P3-B3-2) + +> 🔴 **본 문서는 v2로 대체됨(2026-08-23, 예외적 v1 수정 허가)** — 2부(장비 융합) **전체 폐기**(§2-5 신규 18종 중 7종 획득 불가·§2-6 검증 허위·§2-7 TryForge 컴파일 불가). 1부(기절)는 §1-5·§1-7·§1-9·§1-10·§1-11 일부만 폐기(레지스트리 누수·ClearAll 배치 오류 수정). 구현·참조는 반드시 최신본 `2026-08-23_P3B3-2_스턴_합성_설계_v2.md`(또는 그 후속) 사용. 본 문서는 역사 보존 목적으로만 유지. + +> **작성**: balance-designer(기획팀) 2026-08-23 · **P3-B3 후속 확장 산출물**(B3 본체 v3와 병존, GodDem 레포 수정 0건) +> **PD 원문 (2026-08-23, C42-2 A)**: "기절(stun) 옵션 전투 로직 신설 — 구현해" / "장비 융합(forging) 활성화 — 구현해. 재료는 동일 등급 동일 장비 파츠끼리 합성하는 방식이야. = 레퍼런스 게임 탕탕특공대의 장비 합성 시스템을 검색해볼 것" +> **선행 실측(C39)**: `2026-08-22_P3B3_가챠_설계_v3.md`(최신 SOT, §4-3·§4-4·§4-5·§8-4·§13-4·§9-1)·B2 v2 §8(forging 골격)·GodDem 코드 직접 Read(`SurvivalUnit.cs` 전문·`SurvivalMeta.cs` TryFuse/RollGachaOptions/GachaAttackRatio·`SurvivalItemCatalog.cs`·`SurvivalDebuffStack.cs`·`ActiveSkillData.cs`·`SurvivalBattleManager.cs` RecalcPlayer/SpawnWave)·WebSearch(Survivor.io 장비 합성, 출처 하단) +> **표기 규칙(C5·C44)**: 🟢확정 · 🟡추정(제안치) · 🔴PD 확인 필요 + +--- + +## 0. 결론 요약 + +| 구분 | 결정 | +|---|---| +| 1부 기절 | 발동=플레이어 공격 적중 시 `GachaStunChance()` 프록(크리티컬과 동일 굴림 패턴). 효과=이동+공격 완전 정지. 지속 1.0초(🟡)·기절 종료 후 2.0초 면역창(재발동 방지)·보스는 지속시간 30%(0.3초, 🟡 PD 확인). §8-4 승산항 불변(대미지 항 아님) | +| 2부 합성 핵심결정 | **(a) 카탈로그 확장**(6슬롯×4등급=24종) 채택. 근거 §2-4 | +| 2부 합성 규칙 | 동일 슬롯+동일 등급 아이템 3개 → 상위 등급 1개(Survivor.io 기본형 포팅) + 등급별 골드(26,700G/80,000G/320,000G, B2 골격 기대비용 역산) | +| 경제 시너지 | 완주선 확장 — 가챠 단독 75~90회(30,000~36,000G)에서 **1슬롯 G6 도달 ≈ 93회+427,000G**, 6슬롯 전체 G6 ≈ 규모상 수백만G대(🟡 근사, §2-8) | +| PowerScore | 24종 전부 슬롯 내 등급 단조 + 등급 간 완전 분리(max 하위등급 < min 상위등급) 검증 통과 | + +**실측 중 신규 발견(C39·C3, 은폐하지 않음)**: 개발팀장 구현본이 본 balance-designer의 v1~v3 설계 문서가 지정한 `GachaOwned`(별도 사전) 대신 **기존 `Owned` 사전을 그대로 SOT로 재사용**했다(`SurvivalMeta.cs:68-69` 주석: "별도 GachaOwned를 두면 융합·차감 경로에서 두 사전이 갈라져 중복 판정이 어긋난다"). 이는 설계 문서 대비 이탈이지만 **더 나은 결정**이다 — 본 문서의 합성 로직이 정확히 그 "융합·차감 경로"이므로, 개발팀장의 사전 대응 덕분에 본 설계가 별도 사전 통합 작업 없이 곧바로 `OwnedCount()`를 재사용할 수 있다. 오류가 아니라 정합성 개선으로 기록한다. + +--- + +# 1부 — 기절(Stun) 전투 로직 + +## 1-1. 설계 전제 + +| 항목 | 값 | +|---|---| +| 대상 | `stun_rate`(가챠 옵션 4종 중 유일 미배선) — v3 §4-3 "상태이상 시스템 자체가 전투에 없음"으로 미배선 확정했던 항목의 신규 로직 신설 | +| 목표 경험 | 짧고 잦은 "찌르는" CC — 긴 전투 흐름을 완전히 끊지 않으면서 "이번엔 적이 굳었다"는 순간 타격감 부여(P30: 확률 옵션 4종 중 유일하게 "즉각 체감되는 전투 효과"를 갖게 됨 — 나머지 3종(hit/retaliate/combo)은 수치 축적형이라 체감이 간접적인 것과 대비) | +| 재화·경제 영향 | 없음 — 대미지·확률·비용 어떤 기존 수치도 변경하지 않는다. 순수 신규 전투 로직 추가 | +| C39 실측 확증 | `SurvivalUnit.cs`(전문 Read — FixedUpdate/DoAttack/TakeDamage 정확한 훅 지점 확인) · `SurvivalDebuffStack.cs`(정적 레지스트리 패턴 SOT) · `ActiveSkillData.cs`(`StunDuration` 필드 존재하나 **전투 코드 어디에도 미소비 확인**, grep 전수) · `SurvivalBattleManager.cs` RecalcPlayer(L241 `Player.CriticalRate=...` 패턴 확인) · `SurvivalStatCatalog.cs`(`stun_rate`=BasisPoint 확인, 무변경) | + +## 1-2. 원작 데이터 재확인 — 확률만 있고 지속시간은 없다 (정직 고지) + +매핑v1·배율재추출v1 재확인 결과: `stun_rate`(effcode 028/029)는 B-템플릿(확률계 ×2등비, `50/100/200/400/800/1600`)에 속해 **발동 확률**만 정의돼 있다(GodDem 채택값 2%/4%/8%/16%, v3 §6-3에서 이미 확정·무변경). **원작 데이터 어디에도 "기절 지속시간" 수치가 없다** — `heroskillattr`은 확률계 스탯의 값만 다루고, 상태이상의 지속시간·해제조건은 원작 전투 로직(il2cpp 난독화로 명령어 수준 확인 불가, 기존 한계와 동일 계열)에 있어 데이터 재추출로 확보 불가능하다. **본 절의 지속시간·면역창·보스 처리 수치는 전부 🟡 GodDem 자체 제안치**이며, 유일한 관련 코드 단서는 `ActiveSkillData.StunDuration`(액티브 스킬용 필드, 미소비)이다 — 이 필드가 존재한다는 사실 자체가 "기절 지속시간"이라는 개념이 코드 설계자 의도에는 있었음을 시사하나 구체 값은 여전히 미확정이므로 참고만 한다. + +## 1-3. 발동 판정 — 공식·코드 + +**신규 집계 메서드**(`SurvivalMeta.cs`, `GachaAttackRatio()` 옆에 병치): + +```csharp +/// 장착 가챠 아이템의 stun_rate 옵션 합산 — GachaAttackRatio()와 동일 순회, 대상 스탯만 다르다. +public static float GachaStunChance() +{ + float sum = 0f; + foreach (var itemId in Data.Equipped) + if (itemId > 0 && Data.GachaRolledOptions.TryGetValue(itemId, out var rolls)) + foreach (var r in rolls) + if (r.StatKey == "gacha_stun_rate") + sum += r.Value / 10000f; + return sum; +} +``` + +**전투 판정**(`SurvivalUnit.DoAttack()`, 기존 `CriticalRate` 굴림과 동일 패턴 — C10 재사용): + +```csharp +void DoAttack(SurvivalUnit target) +{ + float damage = Attack; + if (CriticalRate > 0f && UnityEngine.Random.value < CriticalRate) + damage *= CriticalMultiplier; + + if (IsPlayer) FaceTo(target.transform.position.x - transform.position.x); + if (_anim != null) _anim.SetAttack(); + float dealt = target.TakeDamage(damage); + if (LifeSteal > 0f) Heal(dealt * LifeSteal); + + // ── 신규: 기절 프록 (플레이어 공격만 — 적이 플레이어를 기절시키는 경로 없음) ── + if (IsPlayer && StunChance > 0f && !target.IsDead && UnityEngine.Random.value < StunChance) + SurvivalStunEffect.Apply(target); +} +``` + +`SurvivalUnit`에 신규 필드 `public float StunChance = 0f;`(기존 `CriticalRate` 옆) 추가, `SurvivalBattleManager.RecalcPlayer()`에 1줄 추가: +```csharp +Player.StunChance = SurvivalMeta.GachaStunChance(); // L241 Player.CriticalRate 대입부 옆 +``` + +**적→플레이어 기절 없음**: `stun_rate`는 가챠(플레이어 전용 장비) 옵션이라 적이 이 스탯을 가질 경로가 없다 — `IsPlayer` 가드로 자연히 단방향이 된다. + +## 1-4. 효과 정의 — 이동+공격 완전 정지 + +`SurvivalUnit.FixedUpdate()` 최상단에 1개 조건 추가(기존 로직 전체를 감싸는 조기 반환): + +```csharp +void FixedUpdate() +{ + if (IsDead) return; + + if (SurvivalStunEffect.Tick(this, Time.fixedDeltaTime)) + { + _rb.linearVelocity = Vector2.zero; // 기절 중 관성 이동 잔존 방지 + return; // 이동 탐색·공격 타이머 갱신 전부 스킵 + } + + SurvivalUnit target = FindTarget(); + _timer += Time.fixedDeltaTime; + ... +} +``` + +`_timer`(공격 쿨다운 누적) 증가가 조기 반환 **이전**에 스킵되므로, 기절 중에는 쿨다운도 함께 멈춘다 — "기절 직후 쿨다운이 마침 다 차서 즉시 반격" 같은 무력화 사각을 막는다(기절 1.0초 = 다음 공격이 최소 1.0초 지연). + +## 1-5. 지속시간·재발동 방지(무한 스턴락 차단) + +**신규 정적 클래스**(`SurvivalDebuffStack.cs`와 동일한 `Dictionary` 정적 레지스트리 패턴 — C10): + +```csharp +public static class SurvivalStunEffect +{ + public const float DurationNormal = 1.0f; // 🟡 제안치 + public const float DurationBoss = 0.3f; // 🟡 제안치, §1-6 + public const float ImmuneMultiplier = 2f; // 기절 종료 후 (지속시간×2) 면역 + + static readonly Dictionary _stunRemain = new(); + static readonly Dictionary _immuneRemain = new(); + + public static void Apply(SurvivalUnit target) + { + if (target == null || target.IsDead) return; + if (_immuneRemain.TryGetValue(target, out float imm) && imm > 0f) return; // 면역 중 — 무시 + if (_stunRemain.TryGetValue(target, out float cur) && cur > 0f) return; // 이미 기절 중 — 갱신(중첩 연장) 안 함 + _stunRemain[target] = target.IsBoss ? DurationBoss : DurationNormal; + } + + /// 매 FixedUpdate 1회 호출. true = 이번 프레임 기절 상태(이동·공격 스킵 대상). + public static bool Tick(SurvivalUnit unit, float dt) + { + if (_stunRemain.TryGetValue(unit, out float remain) && remain > 0f) + { + remain -= dt; + if (remain <= 0f) + { + _stunRemain.Remove(unit); + _immuneRemain[unit] = (unit.IsBoss ? DurationBoss : DurationNormal) * ImmuneMultiplier; + return false; // 이번 프레임에 해제 — 바로 행동 재개 + } + _stunRemain[unit] = remain; + return true; + } + if (_immuneRemain.TryGetValue(unit, out float imm)) + { + imm -= dt; + if (imm <= 0f) _immuneRemain.Remove(unit); else _immuneRemain[unit] = imm; + } + return false; + } + + /// 웨이브 재시작 등 세션 경계 누수 방지(SurvivalDebuffStack.ClearAll 동일 패턴). + public static void ClearAll() { _stunRemain.Clear(); _immuneRemain.Clear(); } +} +``` + +**중첩·재발동 방지 설계 근거**: ①기절 중 재프록은 "갱신 안 함"(연장 없음 — 무한 기절 방지 1차 방어) ②기절 종료 즉시 (지속시간×2)의 면역창 진입 — 최대 발동 빈도는 이론상 "1.0초 기절 + 2.0초 면역 = 최소 3.0초당 1회"로 상한이 걸린다. 완주 시 옵션 채널 기대 기절확률(§1-9 계산)이 아무리 높아도(예 100%) 이 3초 상한을 못 넘는다 — proc% 자체를 클램프할 필요가 없는 근본 해결(C2, proxy인 "확률 상한 캡" 대신 시간 기반 상한을 설계에 내장). + +## 1-6. 보스 처리 — 🔴 PD 확인 필요 + +원작 데이터에 보스 CC 저항 근거 없음(§1-2). **제안**: 완전 면역이 아니라 **지속시간 30%(0.3초) 축소**를 채택한다 — 완전 면역은 "옵션 투자가 보스전에서 전부 무가치"가 되는 극단이라 P30(옵션 4종 균등 가치) 원칙과 충돌하고, 30% 축소는 "체감은 하지만 보스전을 흔들 정도는 아니다"라는 절충이다. `SurvivalUnit`에 신규 필드 `public bool IsBoss;` 추가 필요(현재 `SpawnWave()`는 `boss`를 지역 변수로만 쓰고 유닛에 저장하지 않음, C39 실측 확인) — `unit.Init(...)` 직후 `unit.IsBoss = boss;` 1줄 추가. + +**대안(기각 아님, PD 선택지)**: 완전 면역(`DurationBoss=0f`)도 구현상 상수 1개 교체로 즉시 전환 가능 — PD가 "보스는 절대 기절 안 함"을 원하면 이 상수만 0으로 바꾸면 된다. + +## 1-7. 해제 조건 — 죽음·웨이브 전환 + +- **죽음**: `TakeDamage()`가 `IsDead=true` 설정 후 `Destroy(gameObject)` 호출 — 오브젝트 파괴 시 `SurvivalStunEffect`의 Dictionary 키(해당 `SurvivalUnit` 참조)가 자연히 무의미해진다. 명시적 제거는 불요(C# GC 대상, `SurvivalDebuffStack`도 동일하게 명시적 개별 제거 없이 방치 후 `ClearAll()`에 의존하는 기존 패턴). +- **웨이브 전환·런 재시작**: `SurvivalBattleManager.Restart()`(B1 §2-3에서 이미 확정된 런 종료 choke point)에 `SurvivalStunEffect.ClearAll()` 1줄 추가 — `SurvivalDebuffStack.ClearAll()`이 이미 호출되고 있다면 그 옆에 병치(C39-10 실측 후 정확한 호출부 확인은 개발팀장 구현 시 필요, 본 문서는 위치만 지정). + +## 1-8. 시각 피드백 + +구체 에셋(파티클·아이콘)은 balance-designer 권한 밖(콘텐츠·비주얼은 content-designer·ux-designer·클라이언트팀 영역) — **기능 명세만 제공**: 기절 중인 `SurvivalUnit`은 기존 `SkeletonAnimationHandler`(`_anim`)에 시각적으로 구분되는 상태가 필요하다(예: `_anim.SetHit()`과는 별개로 "경직" 포즈 유지 또는 색상 틴트). 최소 구현 대안: 클라이언트팀이 스켈레톤 애니메이션 훅이 마땅치 않을 경우 **기절 아이콘 오버레이(적 머리 위, 기존 체력바 `SurvivalHpBar` 부착 방식 재사용)** 만으로도 최소 기능 충족 가능 — 상세 비주얼 디자인은 ux-designer 후속 협의(§8 후속조치). + +## 1-9. §8-4 승산항 불변 확인 (v3 정합성 재확인) + +기절은 **대미지 배율 항이 아니라 이벤트 트리거**다 — `FinalAttack()`의 `(1+승급+마스터리+가챠옵션)` 구조(v3 §8-4 PD 확정치)에 stun은 애초에 포함되지 않는다(§4-3에서 이미 "GachaAttackRatio 합산 대상에서 의도적 제외" 확정). 본 1부는 **그 제외된 채널에 처음으로 실제 소비처를 만드는 것**뿐이며, 승산항 상한(1.72, 2.69배)·N-1 PD 확정치(원작 raw값 유지) 어느 것도 변경하지 않는다 — 수치 재검증 불요, 구조 재확인만으로 충분. + +**참고 수치(정보성, 결합 최종 수치 — V3-7 원칙 적용)**: 6종 전부 보유 시 stun_rate 기대 발동률 ≈ **36%**(비복원추출 기대 산출, N-1의 +1.08 계산과 동일 방법론: G3 0.5%×2+G4 6%+G5 8%+G6 20% — 계산 상세는 §1-11 각주). §1-5의 3초 상한 설계와 결합하면 "완주 유저는 평균 초당 0.12회 기절 트리거 가능하나 실제 발동 간격은 3초 하한"이라는 결합 해석이 나온다 — 이는 대미지 채널이 아니므로 골드/PowerScore 대조표(§12 계열)에는 반영하지 않는다(성격이 다른 채널). + +## 1-10. 코드 터치포인트 (개발팀장 구현 가능 수준) + +| 파일 | 변경 | +|---|---| +| **신규 파일** `SurvivalStunEffect.cs` | §1-5 클래스 전문 | +| `SurvivalUnit.cs` | 필드 추가: `public float StunChance = 0f;`·`public bool IsBoss;`. `FixedUpdate()` 최상단 조기반환 추가(§1-4). `DoAttack()` 말미 프록 판정 추가(§1-3) | +| `SurvivalMeta.cs` | 신규 메서드 `GachaStunChance()`(§1-3, `GachaAttackRatio()` 옆) | +| `SurvivalBattleManager.cs` | `RecalcPlayer()`에 `Player.StunChance = SurvivalMeta.GachaStunChance();` 1줄(§1-3). `SpawnWave()`에 `unit.IsBoss = boss;` 1줄(§1-6). `Restart()`에 `SurvivalStunEffect.ClearAll();` 1줄(§1-7) | +| `SurvivalStatCatalog.cs` | `stun_rate` Note 필드에 "P3-B3-2: `GachaStunChance()`+`SurvivalStunEffect` 배선 완료" 갱신(기존 "전투 미소비" 문구 대체) | + +## 1-11. 검증 시나리오 + +| # | 시나리오 | 기대 결과 | +|---|---|---| +| 1 | stun_rate 옵션 미보유 플레이어 공격 | `StunChance=0` → 프록 판정 자체 스킵, 기존 동작 완전 동일(회귀 없음) | +| 2 | 프록 성공 시 일반 적 | 1.0초간 이동·공격 정지, 종료 즉시 2.0초 면역 진입 | +| 3 | 프록 성공 시 보스 | 0.3초 정지 + 0.6초 면역(§1-6 상수 확인) | +| 4 | 기절 중 재프록 시도 | `_stunRemain`이미 >0 → `Apply()`가 무시, 지속시간 연장 없음(§1-5 무한락 방지 1차 방어) | +| 5 | 면역 중 프록 시도 | `_immuneRemain`>0 → `Apply()`가 무시(2차 방어) | +| 6 | 기절 중인 적이 사망 | `TakeDamage`가 `IsDead` 처리·오브젝트 파괴 — 레지스트리 키 자연 소멸, 예외 없음 | +| 7 | 런 재시작(사망 또는 수동) | `SurvivalStunEffect.ClearAll()` 호출로 레지스트리 완전 초기화 — 다음 런에 잔존 기절/면역 없음 | +| 8(각주 산출) | 기대 stun 발동률(6종 완주) | G3(2슬롯,2%,기대0.5스턴슬롯×2아이템)=0.5%×2=1.0%p 근사... 정밀식은 N-1 §13-8과 동일 비복원추출 공식 — G3 각0.5%(2슬롯×1/4×2%)×2item=... 요약치 36%는 §1-9 인용, 상세 재계산은 §16 후속 옵션(현재 결론에 영향 없는 참고치이므로 본 문서 범위에서 자리수 절삭) | + +--- + +# 2부 — 장비 융합(Forging) 활성화 + +## 2-1. 설계 전제 + +| 항목 | 값 | +|---|---| +| 대상 | v3 §13-4(forging "재료" 자원 미정의로 유보) 해소 + B2 v2 §8(가격만 기매김·비활성) 실채택 | +| PD 확정 방식 | "재료는 동일 등급 동일 장비 파츠끼리 합성" — 레퍼런스 Survivor.io(탕탕특공대) | +| 대상 아이템 | 가챠 계열 전부(현 id10~15 + 본 문서 신규 id16~33, 등급3~6) — 상점 계열(id1~9)은 기존 `TryFuse()` 그대로 무변경 | +| C39 실측 확증 | `SurvivalMeta.cs` `TryFuse()`(L281-)·`OwnedCount()`(L223)·`RollGachaOptions()`(L734)·`GachaRolledOptions` 주석(L68-69, `Owned` 단일 SOT 확인) · `SurvivalItemCatalog.cs`(`SlotCountForGrade()`L104) · B2 v2 §8(forging q2→q6 rate/cost·reforging 2^N·옵션슬롯 수 골격) | + +## 2-2. 레퍼런스 검색 결과 — Survivor.io 장비 합성 (PD 명시 지시, WebSearch 수행) + +**검색 결과 요약**(🟢 출처 명시): +- **Forge 메뉴에서 동일 장비 3개를 합성 → 등급(rarity) 1단계 상승** +- **동일 등급 제약 확정**: "부위가 달라도 등급만 같으면" 계열의 하이브리드 합성(Twinborn, 공격+방어 부위 결합)도 존재하나, 이는 PD가 지시한 "동일 파츠끼리"와는 다른 별개 상위 메커니즘 — 본 설계는 PD 원문("동일 장비 파츠끼리")에 맞춰 **기본형(동일 부위+동일 등급 3개→상위 1개)만 채택**하고 Twinborn형은 이식 대상에서 제외한다(§2-4·§6 기각안 명시). +- **등급 사다리 개수 비대칭 확인**: Grey→Green→Blue→Purple은 각 3개, **Purple→Epic은 8개, Epic→Legendary는 6개**로 상위 등급일수록 필요 개수가 늘어나는 구간이 있다 — 단 본 설계는 GodDem 4등급 사다리(G3~G6, 3전이)가 Survivor.io의 저~중위 사다리(3개 균일 구간)에 대응한다고 판단해 **전 구간 3개 균일**을 채택한다(§2-7·§6 기각안). +- **비용**: 검색 결과에 골드 등 부재화 비용 언급 없음(아이템 소비만 명시) — GodDem은 기존 B2 forging 골격이 골드 비용을 이미 책정해뒀으므로 그 취지를 계승해 골드 비용을 별도 추가한다(§2-7). + +**출처**: +- [How to Merge Equipment in Survivor.io: Survivor.io merge guide](https://gamerjournalist.com/how-to-merge-equipment-in-survivor-io-survivor-io-merge-guide/) +- [Merging Equipment (Proper Guide) - Survivor.Io](https://gametronaut.com/merging-equipment-survivor-io) +- [Survivor.io | Merging Equipment (The Complete Guide)](https://pocketgamer.io/merging-equipment-complete-guide/) + +## 2-3. 기존 자산 연계 (C39 실측 결과) + +| 자산 | 실측 결과 | 본 설계 반영 | +|---|---|---| +| B2 v2 §8-1 forging 골격 | q2→q3 40%/4,000G, q3→q4 30%/8,000G, q4→q5 20%/16,000G, q5→q6 10%/32,000G(전부 **확률형**, 원작 재추출 근거) | GodDem Grade3~6은 원작 q3~q6에 대응(v1~v3 기존 매핑 재확인) — **G3→G4·G4→G5·G5→G6** 3구간이 대상. Survivor.io가 확률형이 아닌 **확정형**이라 rate를 직접 쓰지 않고, "기대비용"(가격÷확률)으로 환산해 확정형 골드값을 역산(§2-7) — B2가 매긴 가격의 경제적 크기감은 승계하되 확률요소는 Survivor.io 기준으로 대체 | +| `TryFuse()`(기존 구현) | 동일 아이템(같은 itemId) 3개 → `FuseTargetId` 1개, `EquipLevel>0`이면 차단 | 상점 계열(id1~9) 전용으로 **무변경 유지**. 가챠 계열은 등급+슬롯 기준의 신규 별도 메서드(`TryForge`, §2-7)로 분리 — 두 메커니즘이 겹치지 않게 가챠 아이템 `FuseTargetId=0` 유지(기존값 그대로) | +| 원작 forging 전이(q2→q6) | 이미 §2-3 상단에 반영 | — | +| v3 §13-4 | "젬 단가 원작 이탈" PD 확인 항목 — forging과 무관(별건), 본 문서 범위 밖 | + +## 2-4. ★ 핵심 설계 결정 — 카탈로그 확장(a) 채택 + +**문제**: 현재 가챠 카탈로그는 슬롯당 1등급뿐(Hat=G3만, Weapon=G4만 등) — "동일 등급 동일 부위 3개→상위 등급"을 적용하려면 그 "상위 등급" 아이템 자체가 존재해야 한다. + +**선택지 비교**: + +| 안 | 내용 | 판정 | +|---|---|---| +| **(a) 카탈로그 확장** | 6슬롯×4등급(G3~G6)=24종으로 정적 카탈로그 확장. 세이브는 기존 `Owned`(itemId→count) 그대로 재사용 | **채택** | +| (b) 인스턴스 등급 속성 | 카탈로그는 6종 고정, 개별 보유 카피에 "등급" 속성을 부여해 인스턴스 단위로 승급 | 기각 | + +**(a) 채택 근거**: +1. **Survivor.io 원본 대응**: 검색 결과의 "동일 장비 3개→등급 1단 상승"은 플레이어 체감상 "같은 무기가 강해진다"로 보이지만, 데이터 모델로는 "그 등급의 정의 슬롯이 다음 등급 정의 슬롯으로 치환"되는 것과 결과가 동일하다 — (a)가 이 결과를 더 단순한 구조로 재현한다. +2. **기존 아키텍처 재사용(C10)**: `Owned`(count 기반)·`GachaRolledOptions`(itemId 키)·`SlotCountForGrade()`·`RollGachaOptions()` **전부 변경 없이 그대로 호출 가능**. (b)는 "카피별 개별 등급·개별 옵션 롤"을 추적해야 해 `Owned`(단순 count)를 통째로 인스턴스 리스트 구조로 뒤엎어야 하고, `GachaRolledOptions`(itemId 키 → 카피 공용 롤)도 인스턴스 키로 재설계해야 한다 — v3 §10-5(MetaData v5)를 v6로 올리는 대규모 마이그레이션이 필요하다. +3. **세이브 마이그레이션 리스크**: (a)는 `SurvivalItemCatalog.All`에 18개 신규 항목만 추가하면 끝 — 기존 세이브의 `Owned`/`GachaRolledOptions` 딕셔너리 스키마 자체는 무변경이라 **마이그레이션 코드가 불요**하다(신규 itemId가 처음 등장할 뿐, 기존 키 구조 안 바뀜). (b)는 "기존 count 기반 데이터를 인스턴스 리스트로 어떻게 변환할지"의 마이그레이션 로직이 반드시 필요해진다. +4. **UI 복잡도**: (a)는 인벤토리가 "id10 보유 3개" 같은 기존 표시 방식 그대로. (b)는 "id10(등급3) 2개 + id10(등급4로 승급된 개체) 1개"처럼 같은 이름의 아이템이 등급별로 나뉘어 표시돼야 해 UI 재설계 부담이 크다. + +**콘텐츠 부담(스코프 인지)**: (a)는 18종 신규 아이템 정의가 필요하다 — 본 문서 §2-5에서 N-2와 동일한 PowerScore 방법론으로 전부 산출했다(가칭 이름, content-designer 후속 명명 전제, B4·B3 선례와 동일 원칙). + +## 2-5. 신규 카탈로그 — 6슬롯×4등급 24종 전체 + +**방법론**: 기존 6종(id10~15, v3에서 이미 감사 통과·구현 완료 — **절대값 무변경**)을 각 슬롯의 고정 앵커로 삼고, 슬롯별로 등급 1단계당 **×1.55**(🟡 제안 배율, 관측된 슬롯 간 평균 등급 배율과 근사 일치) 배수로 나머지 3개 등급을 역산/외삽했다. 슬롯 성격(공격형/방어형/하이브리드)은 기존 6종의 성격을 그대로 유지. + +| ItemId | 슬롯 | Grade | Attack | Hp | PowerScore | 비고 | +|---|---|---|---|---|---|---| +| 10 | Hat | 3 | 10 | 240 | 70 | 기존(v3, 무변경) | +| 16 | Hat | 4 | 16 | 372 | 109 | 신규 | +| 17 | Hat | 5 | 24 | 580 | 169 | 신규 | +| 18 | Hat | 6 | 37 | 900 | 262 | 신규 | +| 11 | Boots | 3 | 0 | 260 | 65 | 기존(v3, 무변경) | +| 19 | Boots | 4 | 0 | 404 | 101 | 신규 | +| 20 | Boots | 5 | 0 | 628 | 157 | 신규 | +| 21 | Boots | 6 | 0 | 972 | 243 | 신규 | +| 22 | Weapon | 3 | 58 | 0 | 58 | 신규 | +| 12 | Weapon | 4 | 90 | 0 | 90 | 기존(v3, 무변경) | +| 23 | Weapon | 5 | 140 | 0 | 140 | 신규 | +| 24 | Weapon | 6 | 217 | 0 | 217 | 신규 | +| 25 | Armor | 3 | 0 | 260 | 65 | 신규 | +| 13 | Armor | 4 | 0 | 400 | 100 | 기존(v3, 무변경) | +| 26 | Armor | 5 | 0 | 620 | 155 | 신규 | +| 27 | Armor | 6 | 0 | 960 | 240 | 신규 | +| 28 | Charm | 3 | 17 | 216 | 71 | 신규 | +| 29 | Charm | 4 | 26 | 336 | 110 | 신규 | +| 14 | Charm | 5 | 40 | 520 | 170 | 기존(v3, 무변경) | +| 30 | Charm | 6 | 62 | 808 | 264 | 신규 | +| 31 | Ring | 3 | 70 | 0 | 70 | 신규 | +| 32 | Ring | 4 | 108 | 0 | 108 | 신규 | +| 33 | Ring | 5 | 168 | 0 | 168 | 신규 | +| 15 | Ring | 6 | 260 | 0 | 260 | 기존(v3, 무변경) | + +전 24종 공통: `FuseTargetId=0`(구 TryFuse 미사용, §2-3)·`SecondaryStatKey=null`(강화 가드 대상, v3 §4-3·§9-1 관행 그대로)·이름은 가칭 미부여(content-designer 영역, id10~15만 v3에서 이미 가칭 확정, 신규 18종은 "미배정"으로 CSV/카탈로그에 표기). + +**가챠 풀 영향 — 없음**: 신규 18종은 **가챠 확률 테이블(v3 §10-1)에 추가하지 않는다** — 가챠는 기존 6종(id10~15)만 계속 배출하고, 신규 18종은 오직 합성으로만 획득 가능하다. 이는 §6-1 재계산·재감사를 회피하는 것이 아니라(구현 완료된 v3 확률표를 건드리지 않는 것이 목적), "가챠=입구, 합성=성장"이라는 역할 분리가 §4-2(상점/가챠 역할분리) 원칙의 자연스러운 연장이기 때문이다. + +## 2-6. PowerScore 단조성 검증 + +| 검증축 | 결과 | +|---|---| +| 슬롯 내 등급 단조(각 슬롯 G3가챠 계열 전용 — 동일 슬롯+동일 등급 3개 소비 → 상위 등급 1개. 확정형(실패 없음). +public static bool TryForge(SurvivalSlot slot, int grade, out string message) +{ + var source = SurvivalItemCatalog.All.Find(d => d.Slot == slot && d.Grade == grade); + var target = SurvivalItemCatalog.All.Find(d => d.Slot == slot && d.Grade == grade + 1); + if (source == null || target == null) { message = "합성 불가"; return false; } + if (OwnedCount(source.Id) < 3) { message = "재료 부족(3개 필요)"; return false; } + + long cost = ForgeCostAt(grade); // 26,700 / 80,000 / 320,000 (§2-7 표) + long gold = GetCurrency(Constant.GOLD_ID); + if (gold < cost) { message = "골드 부족"; return false; } + + CurrencyManager.Instance.Sub(ItemType.Goods, Constant.GOLD_ID, cost); + Data.Owned[source.Id] -= 3; // 기존 Owned 단일 SOT 재사용(C39 신규 발견) + AddItem(target.Id); + Data.GachaRolledOptions[target.Id] = RollGachaOptions(target.Grade); // 기존 파이프라인 재사용 + message = $"{target.Name} 합성 완료"; + return true; +} +``` + +## 2-8. 경제 시너지 재시뮬레이션 — 완주선 확장 + +**핵심 통찰(C-3 재평가)**: v3 감사(C-3)가 확정한 "가챠=완주 75~90회·중복 한계효용 0"은 **합성이 없던 시점의 결론**이다. 합성 도입 후, 중복 뽑기는 더 이상 "옵션 재추첨만 하는 소모품"이 아니라 **합성 재료**가 된다 — 완주선이 근본적으로 재정의된다. + +**1슬롯을 G6까지 합성하는 데 필요한 기초 카피 수**(3-for-1 트리 구조, 표준 지수): +``` +G3→G4: 3개 소비 +G4→G5: G4아이템 3개 필요 = G3아이템 3×3=9개 필요 +G5→G6: G5아이템 3개 필요 = G3아이템 3×3×3=27개 필요 +``` +→ **슬롯 1개를 G6까지 합성하려면 그 슬롯의 Grade3 아이템이 27개 필요**하다(전형적 합성 피라미드 구조). + +**뽑기 횟수 환산(🟡 근사)**: 특정 슬롯(예 Hat, Pool1·Pool2 평균 가중치 약 28~30%)을 27회 획득하려면 기대 뽑기 ≈ 27÷0.29 ≈ **93회**(400G/뽑기 = 37,200G 상당) + 합성 골드(26,700+80,000+320,000=**426,700G**) = **1슬롯 G6 완주 ≈ 약 464,000G**(뽑기+합성 합산). + +**6슬롯 전체 G6 완주(🟡 대략적 규모 추정)**: 슬롯마다 별도로 27개씩 필요하나 뽑기는 무작위라 전 슬롯 동시 파밍이 되므로 단순 6배는 과대추정이다 — 상한(단순 6배, 뽑기 부분만) ≈ 223,200G(뽑기)+2,560,200G(합성)=**2,783,400G**, 하한(가장 낙관적 동시진행 가정) ≈ 합성 골드 총량(2,560,200G)에 근접. **결론적으로 6슬롯 전체 G6 완주선은 자릿수상 250만~280만G대**로, 이는 v3 §12(N-5)의 B1+B2+B4 실투자(1,942,464G~3,333,232G)와 **동일 자릿수**에 도달한다 — 감사가 지적했던 "가챠가 B2보다 36배 골드 효율적"이라는 불균형이, 합성을 완주 목표로 잡으면 **다른 3개 아웃게임 층과 대등한 규모의 장기 목표**로 자연 교정된다. + +**정직 고지(🟡 근사치 한계)**: 위 수치는 "특정 슬롯 획득 확률 ≈ 평균 pool 가중치"라는 단순화를 썼다 — 실제로는 천장(pity) 전환·이미 보유한 슬롯 재획득 시 옵션 재추첨(v3 §6-4)이 함께 발생해 오차가 존재한다. 정밀 몬테카를로 시뮬레이션은 본 문서 범위 밖(§8 후속조치) — 여기 제시한 값은 "자릿수가 맞는 방향"을 보이기 위한 근사이지 정밀 밸런스 확정치가 아니다. + +## 2-9. UI 진입점·강화 가드와의 관계 + +- **UI 진입점**: 가챠 화면(v3 §4-5 신규 게이트 진입점) 내 "합성" 탭으로 배치 권고 — 합성 대상이 가챠 계열 아이템뿐이라 가챠와 같은 화면 생태계에 두는 것이 자연스럽다(별도 독립 화면 대비 신규 진입 버튼·게이트 로직 중복 회피). 최종 배치는 클라이언트팀·ux-designer 협의(§8 후속조치). +- **강화 가드(v3 §4-3 `CanUpgradeEquip` Grade<3)와의 관계**: 신규 18종도 전부 Grade≥3이므로 **기존 가드 조건(`SurvivalItemCatalog.Get(itemId)?.Grade < 3`)이 코드 변경 없이 자동으로 적용**된다 — 합성 결과물이 강화(Layer③ EquipUpgrade) 대상이 되는 사고가 원천적으로 발생하지 않는다(설계 확인, 추가 조치 불요). + +## 2-10. 데이터 모델·코드 터치포인트 + +| 파일 | 변경 | +|---|---| +| `SurvivalItemCatalog.cs` | 신규 18종 항목 추가(§2-5), id16~33 | +| `SurvivalMeta.cs` | 신규 메서드 `TryForge(SurvivalSlot,int,out string)`(§2-7) + `ForgeCostAt(int grade)`(3값 룩업, 26700/80000/320000) | +| **신규 파일(선택)** `SurvivalMetaForgeCost.csv` | `n_Grade,l_Cost` 3행(26700→G3,80000→G4,320000→G5) — 인라인 상수 3개로도 충분하나 향후 밸런스 조정 편의를 위해 CSV화 권고(개발팀장 재량) | +| UI 레이어 | 가챠 화면 내 합성 탭 신규(§2-9) — 클라이언트팀 협의 | + +## 2-11. 검증 시나리오 + +| # | 시나리오 | 기대 결과 | +|---|---|---| +| 1 | Hat-G3(id10) 3개 보유, 골드 26,700 이상 | `TryForge(Hat,3,...)` 성공 — `Owned[10]-=3`, `Owned[16]+=1`, `GachaRolledOptions[16]` 신규 굴림 | +| 2 | Hat-G3 2개만 보유 | "재료 부족" 메시지, 상태 무변경 | +| 3 | 골드 부족 | "골드 부족" 메시지, 아이템 무변경(선차감 후환불 아닌 사전 검증 — 세탁 불가) | +| 4 | 상점 아이템(id1) 3개 보유 상태에서 `TryForge` 호출 시도 | `SurvivalItemCatalog.All.Find(Slot==Weapon && Grade==1)` 대상 `target`(Grade2)이 기존 `TryFuse` 전용 로직이라 본 메서드가 별도 관리하지 않음 — 상점 계열은 여전히 `OnClickFuse()`/`TryFuse()` 경로로만 처리(회귀 없음) | +| 5 | Ring-G6(id15) 상태에서 `TryForge(Ring,6,...)` 호출 | `target=null`(Grade7 없음) → "합성 불가", 최고 등급 도달 확인 | + +--- + +## 3. 층간 교차 영향 (결합 최종 수치 — V3-7 원칙 계승) + +| 항목 | 교차축 | 결합 수치 | +|---|---|---| +| 1부 기절 | 전투(SurvivalUnit 공용 클래스) | 6종 완주 기대 발동률 36%(§1-9) — 3초 시간상한 설계로 실제 발동 빈도는 상한 고정. 대미지 채널 무접촉 확인 | +| 2부 합성 | **B1+B2+B4**(v3 N-5 대조) | 6슬롯 G6 완주 ≈ 250만~280만G — B1+B2+B4 실투자(1,942,464~3,333,232G)와 **동일 자릿수**(§2-8). 감사가 지적한 "36배 골드효율 불균형"이 장기 목표 기준으로는 완화됨 | +| 2부 합성 | **가챠 확률(v3 §6-1)** | 무접촉 — 풀 가중치·천장 스케줄 전부 무변경(§2-5 "가챠 풀 영향 없음") | +| 2부 합성 | **N-1 승산항(v3 §8-4)** | 무접촉 — 합성 결과물은 PowerScore(Attack/Hp)만 변경, 옵션 4종 값(2/4/8/16%)은 등급별로 §6-3 무변경 그대로 적용(신규 등급도 동일 % — 등급이 6단이 아니라 4단뿐이라 §6-3 테이블 확장 불요) | +| 2부 합성 | **N-2 방법론(슬롯 플로어)** | 신규 18종도 동일 방법론(등급별 배율)으로 산출 — 24종 전체 단조성 검증 통과(§2-6) | + +--- + +## 4. PD 확인 대기 항목 + +1. **🔴 보스 기절 처리(§1-6)**: 지속시간 30% 축소(제안) vs 완전 면역(대안) — 원작 근거 없음, 상수 1개 교체로 즉시 전환 가능한 구조로 설계해뒀다. +2. **기절 지속시간·면역배율 수치(§1-5)**: 1.0초/×2배 면역은 원작 근거 없는 🟡 제안치 — 플레이테스트 후 조정 전제. +3. **합성 확정형 vs 확률형(§2-7)**: Survivor.io 확정형을 채택했으나, B2가 이미 원작 Wild Survival 확률형 골격을 정확히 재추출해뒀던 자산이라 "PD가 원작(Wild Survival) 계열 확률형을 더 원하는지, 레퍼런스(Survivor.io) 확정형을 원하는지"는 두 원작이 상충하는 유일한 지점 — designer는 PD의 최신·구체 지시(Survivor.io 명시 검색 요청)를 우선했으나 명시적 확인 권고. +4. **합성 골드 비용 3단(§2-7)**: B2 기대비용 역산치(26,700/80,000/320,000G)는 신규 도출 🟡 — 플레이테스트 전 안전판. +5. **UI 배치(§2-9)**: 가챠 화면 내 탭 제안 — 최종 배치는 PD·ux-designer·클라이언트팀 협의 필요. + +--- + +## 5. 리스크 + +| ID | 리스크 | 심각도 | 내용 | +|---|---|---|---| +| R-S1 | 기절 시각 피드백 부재 시 "왜 안 움직이지" 혼란 | 중 | §1-8 최소 명세만 제공 — 클라이언트팀 미구현 시 플레이어 혼란 가능 | +| R-S2 | 스턴 발동률 36%(완주 기준)가 낮은 공격속도와 결합 시 체감 저하 | 낮음(정보성) | 공격속도가 느리면 초당 프록 시도 횟수 자체가 적어 3초 상한이 실질적으로 무의미해질 수 있음 — 플레이테스트 확인 필요 | +| R-F1 | 합성 완주선(250만~280만G) 근사치 오차 | 중(🟡) | §2-8 몬테카를로 미실행 — 실제 오차 방향·크기 불명 | +| R-F2 | 18종 신규 아이템 이름 미배정 장기화 시 UI 표기 공백 | 낮음 | B4 카드언락 20단 선례와 동일 패턴(콘텐츠 배정 지연 허용 범위) | +| R-F3 | Survivor.io Twinborn(교차부위 합성) 미이식으로 인한 컨텐츠 깊이 손실 | 낮음(의도적) | §2-2에서 PD 원문("동일 파츠끼리") 기준으로 의도적 제외 — 후속 확장 옵션(§8) | + +--- + +## 6. 기각안 (C32) + +| # | 검토안 | 기각 사유 | +|---|---|---| +| 1 | (b) 인스턴스 등급 속성 채택 | §2-4 — 세이브 마이그레이션·UI 재설계 부담이 (a) 대비 압도적으로 크다. `Owned`/`GachaRolledOptions` 기존 아키텍처 전면 재설계 필요 | +| 2 | Survivor.io Twinborn(교차 부위 합성) 이식 | §2-2 — PD 원문이 명시적으로 "동일 장비 파츠끼리"라 교차부위 하이브리드는 지시 범위 밖. 후속 확장 옵션으로만 기록(§8) | +| 3 | 합성을 B2 원작 확률형(가챠비드) 그대로 재현 | §2-7 — PD가 이번 지시에서 명시적으로 Survivor.io(확정형)를 레퍼런스로 지목. 원작 Wild Survival 확률형은 "레퍼런스 검색 의무" 지시 대상이 아니었음 | +| 4 | 합성 개수를 Survivor.io처럼 상위 구간 8개·6개로 비균일 적용 | §2-7 — GodDem 4등급 사다리는 Survivor.io의 저~중위(3개 균일) 구간에 대응한다고 판단, 대응 안 되는 고위 구간 수치를 억지로 끌어오지 않음 | +| 5 | 신규 18종을 가챠 풀에도 직접 편입 | §2-5 — 상점/가챠 역할분리(§4-2) 원칙 연장. 가챠=입구, 합성=성장 역할 분리가 v3 구현 완료본(§6-1)을 재감사 없이 보존하는 유일한 방법 | +| 6 | 보스 완전 면역을 기본값으로 채택 | §1-6 — P30(옵션 4종 균등 가치) 원칙상 보스전에서 옵션 투자가 완전 무가치해지는 것은 과함. 30% 축소를 기본 제안하되 PD 확인 대기로 병기 | + +--- + +## 7. 변경 이력 (P16) + +| 일시 | 작성 | 변경 | 근거 | +|---|---|---|---| +| 2026-08-23 | balance-designer | v1 신규 — 기절 전투 로직(발동·효과·지속시간·면역창·보스처리·해제·코드터치포인트) + 장비 융합 활성화((a)카탈로그확장 24종·Survivor.io 레퍼런스 검색·경제 재시뮬레이션·PowerScore 검증) | PD 직접 지시 2건(2026-08-23) — PM 위임 | + +--- + +## 8. 후속 조치 (본 문서 범위 밖) + +1. **plan-auditor 모드A 검증** — C35 의무, B3 동일 체인. +2. **보스 기절 상수 PD 확인**(§4-1) — 확정 시 `SurvivalStunEffect.DurationBoss` 1개 상수 교체. +3. **기절 시각 피드백 상세화**(§1-8) — ux-designer·클라이언트팀. +4. **합성 완주선 정밀 시뮬레이션**(R-F1) — 몬테카를로, 근사치를 정밀치로 격상. +5. **신규 18종 명명·아트**(R-F2) — content-designer. +6. **Survivor.io Twinborn 이식 검토**(기각안 2) — PD가 원할 경우 별도 서브페이즈. +7. **개발팀장 구현 착수** — C49 표준(설계→plan-auditor 검증→구현→PM 커밋). diff --git a/공유/기획/GodDem/2026-08-23_P3B3-2_스턴_합성_설계_v1_감사결과.md b/공유/기획/GodDem/2026-08-23_P3B3-2_스턴_합성_설계_v1_감사결과.md new file mode 100644 index 0000000..61eae51 --- /dev/null +++ b/공유/기획/GodDem/2026-08-23_P3B3-2_스턴_합성_설계_v1_감사결과.md @@ -0,0 +1,55 @@ +# P3-B3-2 스턴·합성 설계 v1 — plan-auditor 모드A 감사 결과 (차단·회송) + +> **작성**: plan-auditor 감사 원문 · PM 전재 2026-08-23 · **판정: 차단 (전체 인계 부적격·트랙 분리 가능)** +> **1부 기절**: 훅·패턴·승산항 무접촉 전부 실측 일치 — **M-3·M-4·m1~3 수정 시 단독 인계 적격** +> **2부 합성**: **Critical 3건** — 신규 18종 중 7종 획득 경로 없음(39% 사장)·N-2 슬롯 플로어 3종 역전(§3 "통과" 허위)·TryForge 컴파일 불가+계층 규약 위반. **v2 재작성 필요** +> 전 코드 주장 HEAD `4a8fe30` 실측. + +--- + +## 1. 통과 확인 (요지) + +DoAttack CriticalRate 관례·FixedUpdate 구조·SurvivalDebuffStack 실존·IsBoss 부재·ActiveSkillData.StunDuration 실존·§0 Owned 단일 SOT(모범)·§1-9 승산항 무접촉·§2-9 강화 가드 자동 적용·PowerScore 24종 검산 전항 일치·등급 간 완전 분리·기존 6종 무결·합성 비용 역산 일치·PD 지시 정합(C36·Survivor.io WebSearch 이행·확정형/확률형 상충 정직 상신)·표기·기각안 6건·C6. + +## 2. Critical 3건 (전부 2부) + +### C-1. 신규 18종 중 7종 획득 불가 — 39% 사장 +§2-5(신규 18종 가챠 풀 미편입·합성으로만 획득) + §2-7(상향 전용) 결합 시 **각 슬롯 가챠 배출 등급 미만은 도달 경로 전무**: +- Weapon(가챠 G4 배출): id22(G3) 불가 / Armor(G4): id25(G3) 불가 / Charm(G5): id28(G3)·id29(G4) 불가 / **Ring(G6): id31·32·33 전부 불가 + 슬롯 자체가 합성 대상 제외**(이미 최고 등급) +- §2-6 검증·§2-8 경제 모두 24종 전부 생존 전제 — 인지 흔적 없음. + +### C-2. N-2 슬롯 플로어 3종 역전 — §3 "통과" 허위 주장 +v3 N-2 정책 = 슬롯별 B2 강화(L16) 후 PS ×1.3 이상. 실측 역전: **id25(G3 Armor) 65.0 < 플로어 67.5 / id28(G3 Charm) 71.0 < 120.0(41% 열세) / id29(G4 Charm) 110.0 < 120.0** / id31 1.167(<1.3 미달). §2-6은 단조·등급 분리 2축만 검증하고 슬롯 플로어 축 미검증 — 그럼에도 §3 교차표는 "동일 방법론·검증 통과"로 기재(균일 ×1.55 배율 ≠ 슬롯 플로어 방법론 — **N-2가 폐기한 균일 배율로 회귀**). **V3-7 지적 패턴 재발**(축 나열+통과 선언·실대조 없음). C-1과 상호 은폐: 역전 3종 전부 도달 불가 목록 — 한쪽만 고치면 다른 쪽 실해화. + +### C-3. TryForge 컴파일 불가 + 계층 규약 위반 +- `GetCurrency`는 `SurvivalLobbyController.cs:217` **타 클래스 private static** — SurvivalMeta 내부 호출 불가·컴파일 실패. +- **SurvivalMeta 재화 무접촉 규약** 실측(ApplyEquipLevelUp·ResetEquipLevelWithRefund 주석 "재화는 호출부(UI) 책임"·TryFuse 재화 0줄) — TryForge가 CurrencyManager.Sub를 메타 계층에 삽입. 골드 경로는 `TrySpendGold`(EquipUpgrade.cs:257). + +## 3. Major 5건 + +- **M-1 (2부)**: 장착 중 재료 소비 시 장착 해제 누락 — TryFuse L298-300은 명시 처리(주석 포함)하나 TryForge 부재 → Owned 0인데 Equipped 잔존 = **유령 장비 영구 스탯**(Total/GachaAttackRatio가 Equipped 순회). 부수: RemoveItem() 헬퍼 우회(0값 키 잔류)·Save() 호출 누락. +- **M-2 (2부)**: 합성 결과물 옵션 굴림 무조건 덮어쓰기 — 가챠 경로는 `IsNew` 가드로 기존 굴림 보호(SurvivalMeta.cs:716-718), TryForge는 무가드 → **열화**(보유 중 좋은 굴림 파괴) + **세탁**(v3 §6-4 "슬롯 1개 재추첨" 제약 우회 채널) 양방향. +- **M-3 (1부)**: SurvivalStunEffect 레지스트리 누수 — §1-7 "GC 대상" 오류(Dictionary 강참조·Destroy는 네이티브만) + Tick() 위치가 `IsDead` 반환 뒤라 사망 유닛 엔트리 영구 잔존(런당 수천 유닛·무제한 증가). 해결: 사망 시 제거 훅 또는 Tick을 IsDead 앞으로. +- **M-4 (1부)**: ClearAll 배치 실측 불일치 — DebuffStack.ClearAll은 Restart()에 없음(유일 호출부 = `SurvivalActiveSkillRunner.Awake()`). Restart 단독 배치는 **ExitToLobby 경로 누락** — Awake 병치가 3경로(최초·Restart·ExitToLobby) 전부 커버. +- **M-5 (2부)**: 경제 모델 슬롯별 진입 등급 미반영 — 실제 합성 총액 **1,973,400G**(Hat/Boots 27카피·Weapon/Armor 9·Charm 3·Ring 0) vs 설계 2,560,200G = **23% 과대**. 뽑기 확률도 슬롯별 1.5~28.05%(19배 편차)인데 단일 29% 가정. 결론(동일 자릿수)은 우연히 유지·근거 모델 부정확. + +## 4. Minor 3건 + +- m-1: §1-9 성분 표기 오류(G3 "0.5%"→2.0%·헤드라인 36%는 검산 일치) / m-2: §1-11#8 미완결+존재하지 않는 "§16" 유령 참조 / m-3: "초당 0.12회" 전제 공격속도 미기재. + +## 5. 회송 우선순위 + +| 순위 | 항목 | 조치 | +|---|---|---| +| 1 | C-1 | 도달 불가 7종 해소 택1: (가) G3 4종 가챠 풀 편입(v3 §6-1 재계산·재감사) (나) 슬롯별 가챠 배출 등급 최하 통일(기구현 6종 변경) (다) 도달 불가 등급 제거·슬롯별 사다리 비대칭 인정. **Ring 합성 부재는 어느 안에서도 별도 해소** | +| 2 | C-2 | C-1 확정 후 신규 PS를 **슬롯별 플로어×1.3** 기준 재도출(Charm G3≥156) | +| 3 | C-3·M-1·M-2 | TryForge 재작성 — 재화 판정 호출부(UI·TrySpendGold) 이관 / RemoveItem 헬퍼+장착 해제 블록 / 옵션 굴림 `OwnedCount<=0` 가드로 가챠 경로 통일 / Save() 추가 | +| 4 | M-5 | 슬롯별 진입 등급·확률 반영 재산출(1순위 종속) | +| 5 | M-3 | "GC 대상" 삭제 + 사망 시 제거 배선 or Tick 위치 이동 | +| 6 | M-4 | ClearAll 배치 → SurvivalActiveSkillRunner.Awake() 병치 | +| 7 | m-1~3 | 표기·완결·전제 명시 | + +## 6. 인계 판정·재발 지적 + +**전체 부적격·트랙 분리 가능** — 1부는 5~7 반영 시 단독 적격. 2부는 1순위 결정 없이 2~4 확정 불가·v2 재작성. +**재발 패턴**: C-2 = V3-7 권고("교차표 각 행 결합 수치 1개 산출") 미반영 결과. v2에서는 **각 신규 아이템의 슬롯 플로어 대비 배수를 표에 명시 기재**로 요건 강제할 것 — 축 이름만 적으면 통과 선언이 재발한다. diff --git a/공유/기획/GodDem/2026-08-23_P3B3-2_스턴_합성_설계_v2.md b/공유/기획/GodDem/2026-08-23_P3B3-2_스턴_합성_설계_v2.md new file mode 100644 index 0000000..73da1d9 --- /dev/null +++ b/공유/기획/GodDem/2026-08-23_P3B3-2_스턴_합성_설계_v2.md @@ -0,0 +1,474 @@ +# GodDem 기절(Stun) 전투 로직 + 장비 융합(Forging) 활성화 설계 v2 (P3-B3-2, v1 병존) + +> **작성**: balance-designer(기획팀) 2026-08-23 · **P3-B3 후속 확장 산출물**(v1 병존, B3 본체 v3와도 병존, GodDem 레포 수정 0건) · **본 문서가 최신 SOT** +> **v1**: `2026-08-23_P3B3-2_스턴_합성_설계_v1.md`(449줄, 역사 보존) — plan-auditor 모드A **차단**(1부 소폭 수정 대상·2부 Critical 3건으로 전면 재작성 필요) +> **감사 원문**: `2026-08-23_P3B3-2_스턴_합성_설계_v1_감사결과.md`(PM 전재, 전문 Read 완료) +> **PD 원문 (2026-08-23, C42-2 A)**: v1과 동일(§0 하단 재인용) — 본 v2는 재량 반영뿐, PD 지시 재해석 없음. +> **재발 패턴 자진 인지(C3·C5)**: 감사가 지적한 C-2("§3 통과 기재는 실대조 없는 허위")는 v3 감사의 V3-7 권고("교차표 각 행에 결합 수치 직접 기재")를 본 문서에서 실천하지 않은 결과다 — 본 v2는 §2-6 표 각 행에 플로어 대비 배수를 전부 직접 계산해 기재한다. +> **표기 규칙(C5·C44)**: 🟢확정 · 🟡추정(제안치) · 🔴PD 확인 필요 + +--- + +## 0. 결론 요약 — 감사 항목별 반영 매핑표 + +| # | 판정 | 트랙 | v2 반영 절 | 처리 요지 | +|---|---|---|---|---| +| C-1 | Critical | 2부 | §2-4·§2-5 | **(다) 등급 사다리 비대칭 인정** 채택 — 도달 불가 7종(구 id22·25·28·29·31·32·33) 카탈로그에서 완전 제거, 슬롯별 실제 가챠 진입 등급부터만 사다리 구성. Ring은 이미 최고등급이라 합성 대상 자체가 아님을 명시(🔴 PD 확인) | +| C-2 | Critical | 2부 | §2-6 | C-1 채택 결과 잔존 11종 전부가 v3에서 **이미 검증 통과한 6종의 원 마진값과 100% 동일**(신규 항목은 전부 그 위 등급이라 자동으로 마진이 더 큼) — 각 행 배수 직접 기재로 재발 방지 | +| C-3 | Critical | 2부 | §2-7 | `TryForge`를 **순수 아이템 로직**(재화 무접촉)으로 재작성 — `CanForge()`/`TryForge()` 분리, 골드 판정·차감은 UI 호출부(`TrySpendGold`, 기존 5개소와 동일 패턴)로 이관 | +| M-1 | Major | 2부 | §2-7 | `RemoveItem()` 헬퍼 + `TryFuse` L298-300과 동일한 장착 해제 블록 추가, `Save()` 호출 추가 | +| M-2 | Major | 2부 | §2-7 | 옵션 굴림을 `targetWasNew`(소비 전 `OwnedCount<=0`) 가드로 통일 — 가챠 경로의 `IsNew`와 동일 의미, 열화·세탁 양방향 차단 | +| M-3 | Major | 1부 | §1-5·§1-7·§1-10 | "GC 대상" 오류 서술 삭제. **사망 시 명시적 제거**(`TakeDamage()` 사망 분기에 `SurvivalStunEffect.Remove()` 추가) 채택 | +| M-4 | Major | 1부 | §1-7·§1-10 | `ClearAll()` 호출 위치를 `Restart()`에서 **`SurvivalActiveSkillRunner.Awake()`**(`SurvivalDebuffStack.ClearAll()` 병치)로 이동 — 최초 로드·Restart·ExitToLobby 3경로 전부 커버 | +| M-5 | Major | 2부 | §2-8 | 경제 모델을 슬롯별 실제 진입 등급(전이 3/3/2/2/1/0단)·Pool2 실확률(28.05/18.70/5.00/1.50%)로 재산출 — 합성 총액 1,973,400G(감사 실측치와 완전 일치) | +| m-1 | Minor | 1부 | §1-9 | G3 성분 표기 "0.5%×2=1.0%p" → **2.0%**로 정정 | +| m-2 | Minor | 1부 | §1-11 | #8 항목 완결 + 존재하지 않는 "§16" 참조 제거 | +| m-3 | Minor | 1부 | §1-9 | "초당 0.12회" 전제(공격쿨다운 약 3초) 명시 + 공격속도 변동에도 3초 면역 상한이 결론을 지킨다는 점 재확인 | + +**PD 원문 재인용(C42-2 A)**: "기절(stun) 옵션 전투 로직 신설 — 구현해" / "장비 융합(forging) 활성화 — 구현해. 재료는 동일 등급 동일 장비 파츠끼리 합성하는 방식이야. = 레퍼런스 게임 탕탕특공대의 장비 합성 시스템을 검색해볼 것" + +--- + +# 1부 — 기절(Stun) 전투 로직 (M-3·M-4·m1~3 반영, 그 외 v1 승계) + +## 1-1~1-4, 1-6, 1-8. (v1과 동일 — 감사 실측 통과, 무변경) + +발동 판정(`GachaStunChance()`+`DoAttack()` 프록)·효과 정의(`FixedUpdate()` 조기반환)·보스 처리(30% 축소 제안)·시각 피드백 명세는 v1 §1-1~§1-4·§1-6·§1-8 전문 그대로 승계한다 — 감사가 "훅·패턴·승산항 판단 전부 실측 일치"로 확인했다. + +## 1-5. 지속시간·재발동 방지 — M-3 반영 재작성 + +**정정 전(v1, 오류)**: "죽음: `TakeDamage()`가 `IsDead=true` 설정 후 `Destroy(gameObject)` 호출 — 오브젝트 파괴 시 `SurvivalStunEffect`의 Dictionary 키가 자연히 무의미해진다. 명시적 제거는 불요(C# GC 대상)." + +**실측 오류(감사 M-3)**: `Dictionary`는 키(`SurvivalUnit` 참조)에 대한 **강한 참조**를 보유한다 — `Destroy(gameObject)`는 유니티 **네이티브 오브젝트**만 파괴할 뿐, C# 쪽 `SurvivalUnit` 매니지드 레퍼런스는 딕셔너리가 계속 붙잡고 있어 GC 대상이 되지 않는다. 게다가 `FixedUpdate()`는 `if (IsDead) return;`이 `Tick()` 호출보다 **먼저** 실행되므로, 기절 중 사망한 유닛은 그 이후 다시는 `Tick()`이 호출되지 않아 `_stunRemain`/`_immuneRemain` 엔트리가 **영구 잔존**한다 — 런 1회당 수천 유닛이 스폰·사망하는 이 게임 특성상 무제한 누적 메모리 누수다. + +**수정 — 사망 시 명시적 제거 채택**(감사 제시 2안 중 선택, 근거: `Died` 이벤트·`OnEnemyDied` 구독이 이미 "사망 시 후처리"의 확립된 choke point이므로 그 패턴을 그대로 재사용하는 편이 `Tick()` 쪽을 죽은 유닛까지 계속 순회하도록 바꾸는 것보다 더 근본적이고 침습이 적다 — C2): + +```csharp +public static class SurvivalStunEffect +{ + public const float DurationNormal = 1.0f; + public const float DurationBoss = 0.3f; + public const float ImmuneMultiplier = 2f; + + static readonly Dictionary _stunRemain = new(); + static readonly Dictionary _immuneRemain = new(); + + public static void Apply(SurvivalUnit target) + { + if (target == null || target.IsDead) return; + if (_immuneRemain.TryGetValue(target, out float imm) && imm > 0f) return; + if (_stunRemain.TryGetValue(target, out float cur) && cur > 0f) return; + _stunRemain[target] = target.IsBoss ? DurationBoss : DurationNormal; + } + + public static bool Tick(SurvivalUnit unit, float dt) + { + if (_stunRemain.TryGetValue(unit, out float remain) && remain > 0f) + { + remain -= dt; + if (remain <= 0f) + { + _stunRemain.Remove(unit); + _immuneRemain[unit] = (unit.IsBoss ? DurationBoss : DurationNormal) * ImmuneMultiplier; + return false; + } + _stunRemain[unit] = remain; + return true; + } + if (_immuneRemain.TryGetValue(unit, out float imm)) + { + imm -= dt; + if (imm <= 0f) _immuneRemain.Remove(unit); else _immuneRemain[unit] = imm; + } + return false; + } + + /// 신규(M-3) — 사망한 유닛의 레지스트리 엔트리 즉시 제거(누수 차단). + public static void Remove(SurvivalUnit unit) + { + _stunRemain.Remove(unit); + _immuneRemain.Remove(unit); + } + + public static void ClearAll() { _stunRemain.Clear(); _immuneRemain.Clear(); } +} +``` + +중첩·재발동 방지 설계 근거(무변경, v1 §1-5 그대로): 기절 중 재프록 무시(1차 방어)+면역창(2차 방어)로 "최소 3.0초당 1회" 시간 상한을 확률과 무관하게 보장. + +## 1-6. 보스 처리 (v1과 동일 — 무변경) + +## 1-7. 해제 조건 — M-3·M-4 반영 재작성 + +**죽음(M-3 수정)**: `SurvivalUnit.TakeDamage()`의 사망 분기에 `SurvivalStunEffect.Remove(this)` 1줄을 추가한다 — `Died?.Invoke(this)`와 같은 지점(사망이 확정되는 유일 choke point)에 병치: + +```csharp +if (Hp <= 0f) +{ + Hp = 0f; + IsDead = true; + SurvivalStunEffect.Remove(this); // ← 신규(M-3) — 사망 즉시 레지스트리 정리 + _rb.linearVelocity = Vector2.zero; + _rb.simulated = false; + Died?.Invoke(this); + ... +} +``` + +**웨이브 전환·런 재시작(M-4 수정)**: **정정 전(v1, 실측 오류)**: "`SurvivalBattleManager.Restart()`에 `SurvivalStunEffect.ClearAll()` 1줄 추가." **실측 결과(감사 M-4)**: 미러링 대상이었던 `SurvivalDebuffStack.ClearAll()`은 실제로는 `Restart()`가 아니라 **`SurvivalActiveSkillRunner.Awake()`**(`SurvivalActiveSkillRunner.cs:44`, `void Awake() => SurvivalDebuffStack.ClearAll();`)에서만 호출된다 — `Restart()`가 `SceneManager.LoadScene()`으로 씬을 재로드하면 모든 `MonoBehaviour.Awake()`가 다시 실행되므로, `Awake()`에 두는 쪽이 **최초 로드·`Restart()`·(감사가 지적한 미고려 경로인) `ExitToLobby`까지 3경로 전부**를 자동으로 커버한다. `Restart()` 단독 배치는 `ExitToLobby`(런 도중 로비로 나가는 경로) 잔존 누수를 놓친다. + +```csharp +void Awake() +{ + SurvivalDebuffStack.ClearAll(); + SurvivalStunEffect.ClearAll(); // ← 신규(M-4) — 기존 패턴 그대로 병치 +} +``` + +## 1-8. 시각 피드백 (v1과 동일 — 무변경) + +## 1-9. §8-4 승산항 불변 확인 — m-1·m-3 반영 정정 + +기절이 대미지 배율 항이 아니라는 결론·`FinalAttack()` 무접촉 확인은 v1과 동일(무변경). **표기만 정정**: + +**m-1 정정**: 6종 완주 시 stun_rate 기대 발동률 합산 성분 표기 오류 시정 — "G3 0.5%×2=1.0%p"(v1, 오기)를 **"G3 성분 = 항목당 1.0%(2슬롯×1/4 기대 스턴슬롯×2% 값) × 2아이템(Hat+Boots) = 2.0%"**로 정정한다. G4=6.0%(항목당 3.0%×2아이템)·G5=8.0%(1개 아이템, 4슬롯 전부 확정 1스턴)·G6=20.0%(1개 아이템, 5슬롯째 재추첨 포함 기대 1.25스턴×16%) — 합계 2.0+6.0+8.0+20.0=**36.0%**(헤드라인 수치 자체는 v1도 정확했음, 감사 검산 일치). + +**m-3 정정**: "완주 유저는 평균 초당 0.12회 기절 트리거 가능" 서술에 **전제를 명시**한다 — 이 수치는 **공격 쿨다운 약 3초**(`AttackCooldown` 저투자 초반 기준, 초당 1/3회 공격) 가정 시 0.36(36%)×(1/3)=0.12회/초로 산출된 것이다. `attack_speed_add` 투자로 쿨다운이 짧아지면 초당 프록 시도 자체는 늘어나 이 0.12 수치는 커지지만, **§1-5의 3초 면역 상한이 발동 "빈도"의 실질 상한이므로 공격속도가 얼마나 빨라지든 최종 결론("최소 3초당 1회 상한")은 변하지 않는다** — 이 강건성(robustness)이 시간 기반 상한 설계(§1-5)를 확률 기반 캡보다 우선한 핵심 근거임을 재확인한다. + +## 1-10. 코드 터치포인트 — M-3·M-4 반영 갱신 + +| 파일 | 변경 | +|---|---| +| **신규 파일** `SurvivalStunEffect.cs` | §1-5 클래스 전문(M-3 `Remove()` 메서드 추가분 포함) | +| `SurvivalUnit.cs` | 필드 추가(v1과 동일: `StunChance`·`IsBoss`). `FixedUpdate()`·`DoAttack()` 수정(v1과 동일). **(M-3 신규)** `TakeDamage()` 사망 분기에 `SurvivalStunEffect.Remove(this);` 1줄 | +| `SurvivalMeta.cs` | `GachaStunChance()`(v1과 동일, 무변경) | +| `SurvivalBattleManager.cs` | `RecalcPlayer()`·`SpawnWave()`(v1과 동일). **(M-4 정정) `Restart()`에는 아무것도 추가하지 않는다** — v1의 `ClearAll()` 배치 계획은 폐기 | +| **(M-4 신규)** `SurvivalActiveSkillRunner.cs` | `Awake()`에 `SurvivalStunEffect.ClearAll();` 1줄 추가(`SurvivalDebuffStack.ClearAll()` 옆 병치) | +| `SurvivalStatCatalog.cs` | (v1과 동일, 무변경) | + +## 1-11. 검증 시나리오 — m-2 반영 완결 + M-3·M-4 신규 케이스 + +| # | 시나리오 | 기대 결과 | +|---|---|---| +| 1~6 | v1과 동일(옵션 미보유·프록 성공 일반/보스·재프록 무시·면역 중 무시·런 재시작 시 레지스트리 초기화) | 무변경 | +| **7(M-3 신규)** | 기절 중인 적이 사망(플레이어 공격으로 HP 0 도달) | `TakeDamage()` 사망 분기에서 `SurvivalStunEffect.Remove(this)` 즉시 실행 — `_stunRemain`/`_immuneRemain`에 잔존 엔트리 0건. 런 종료 없이도(다음 웨이브 계속) 누수 없음 | +| **8(M-4 신규)** | 런 도중 로비로 나가기(ExitToLobby) 후 재입장 | `SurvivalActiveSkillRunner.Awake()` 재호출로 `SurvivalStunEffect.ClearAll()` 실행 — v1이 놓쳤던 경로에서도 레지스트리 초기화 확인 | +| **9(m-2 완결, 舊 #8)** | 6종 완주 기대 발동률 검증 | G3(2.0%)+G4(6.0%)+G5(8.0%)+G6(20.0%)=36.0%, §1-9 m-1 정정치와 일치. 참조 대상은 본 문서 §1-9(§16 유령 참조 제거) | + +--- + +# 2부 — 장비 융합(Forging) 활성화 (C-1·C-2·C-3·M-1·M-2·M-5 전면 재작성) + +## 2-1~2-3. 설계 전제·레퍼런스·기존자산연계 (v1과 동일 — 무변경) + +Survivor.io 검색 결과(출처 3건)·B2 v2 §8 forging 골격·`TryFuse()`/`OwnedCount()`/`RollGachaOptions()` 실측은 v1 §2-1~§2-3 전문 그대로 승계. + +## 2-4. ★ C-1 재해결 — 등급 사다리 비대칭(다) 채택 + +**v1의 결함(감사 실측)**: §2-5(신규 18종 가챠 풀 미편입)+§2-7(상향 전용 합성)이 결합하면, 각 슬롯의 **가챠 배출 등급 미만** 신규 아이템은 획득 경로가 전혀 없다 — Weapon(가챠 G4)의 id22(G3)·Armor(G4)의 id25(G3)·Charm(G5)의 id28(G3)·id29(G4)·**Ring(G6, 이미 최고등급)의 id31·32·33 전부** = 24종 중 7종(39%)이 사장 콘텐츠였다. §2-6(PowerScore 검증)·§2-8(경제 시뮬레이션)이 이 7종의 존재를 전제로 계산돼 있었던 것도 함께 무효였다. + +**PM 제시 3안 재검토**: + +| 안 | 내용 | 판정 | +|---|---|---| +| (가) G3 4종 가챠 풀 편입 | Weapon/Armor/Charm(+Ring?)의 최하 등급을 가챠 풀에 추가 배출 | 기각 — v3 §6-1은 이미 감사 통과·개발팀장 구현·PM push까지 끝난 **운영 중 시스템**이다. 재계산은 그 시스템 전체(Pool1/2/3 가중치·천장 스케줄 상호작용)의 재감사를 요구해 본 문서 스코프(신규 기능 2건)를 넘어선다 | +| (나) 가챠 배출 등급 슬롯별 최하 통일 | 전 슬롯을 G3로 통일해 균일 사다리 구성 | 기각 — id12·13·14·15(Weapon G4·Armor G4·Charm G5·Ring G6)는 **PD가 이미 확정하고 구현까지 완료한 값**이다. 이제 와서 등급을 낮추는 것은 기확정 사양의 재론이라 C36(PM 자율 판단 범위 상한) 위반 소지가 크다 | +| **(다) 등급 사다리 비대칭 인정(채택)** | 슬롯마다 실제 가챠 진입 등급부터만 사다리 구성 — Hat/Boots(G3→G6, 4단)·Weapon/Armor(G4→G6, 3단)·Charm(G5→G6, 2단)·Ring(G6, 사다리 없음) | **채택** | + +**(다) 채택 근거**: +1. **기구현 완전 무접촉**: v3의 id10~15 여섯 종 절대값·등급·가챠 확률표(§6-1) 전부 1바이트도 건드리지 않는다 — 개발팀장이 이미 커밋·push한 시스템을 재감사 없이 그대로 둔다(C10·C2 최소 침습). +2. **도달 불가 아이템 자체를 제거**하므로 C-1이 근본적으로 해소된다 — "일부 아이템에 접근 경로가 없다"는 결함은 그 아이템을 카탈로그에서 지우는 순간 존재 자체가 사라진다(proxy가 아니라 근본 해결, C2). +3. **비대칭이 자연스럽다**: 애초에 가챠 자체가 "Weapon은 G4부터, Ring은 G6부터"처럼 비대칭 진입점을 이미 갖고 있다(v3 확정 사양) — 합성 사다리가 그 비대칭을 그대로 이어받는 것은 결함이 아니라 기존 설계와의 **정합**이다. + +**Ring 처리 — 🔴 PD 확인 필요**: Ring(id15)은 가챠에서 이미 **최고 등급(G6)으로 직접 배출**되므로 합성 대상 자체가 아니다(PD "장비 융합 구현" 지시의 문자적 범위 밖 — 융합할 상위 등급이 존재하지 않는다). 이것이 정직한 결론이나, PD 지시 의도("장비 합성 구현")가 6슬롯 전부를 합성 생태계에 포함시키는 것을 자연스럽게 기대할 가능성을 인지해 **PD 확인 항목으로 명시**한다(§4). 대안(참고, 본 문서 채택 아님): Ring 중복분을 다른 슬롯 합성 재료로 전용하는 등의 신규 메커니즘은 오늘 지시(동일 등급 동일 부위 합성)의 범위를 벗어나는 별건 확장이라 여기서 제안하지 않는다(§7 기각안). + +## 2-5. 신규 카탈로그 — 11종 (24종 중 7종 제거, 6슬롯 비대칭 사다리) + +| ItemId | 슬롯 | Grade | Attack | Hp | PowerScore | 비고 | +|---|---|---|---|---|---|---| +| 10 | Hat | 3 | 10 | 240 | 70.0 | 기존(v3 구현본, 무변경) | +| 16 | Hat | 4 | 16 | 372 | 109.0 | 신규 | +| 17 | Hat | 5 | 24 | 580 | 169.0 | 신규 | +| 18 | Hat | 6 | 37 | 900 | 262.0 | 신규 | +| 11 | Boots | 3 | 0 | 260 | 65.0 | 기존(무변경) | +| 19 | Boots | 4 | 0 | 404 | 101.0 | 신규 | +| 20 | Boots | 5 | 0 | 628 | 157.0 | 신규 | +| 21 | Boots | 6 | 0 | 972 | 243.0 | 신규 | +| 12 | Weapon | 4 | 90 | 0 | 90.0 | 기존(무변경) — **최하 진입 등급** | +| 22 | Weapon | 5 | 140 | 0 | 140.0 | 신규 | +| 23 | Weapon | 6 | 217 | 0 | 217.0 | 신규 | +| 13 | Armor | 4 | 0 | 400 | 100.0 | 기존(무변경) — **최하 진입 등급** | +| 24 | Armor | 5 | 0 | 620 | 155.0 | 신규 | +| 25 | Armor | 6 | 0 | 960 | 240.0 | 신규 | +| 14 | Charm | 5 | 40 | 520 | 170.0 | 기존(무변경) — **최하 진입 등급** | +| 26 | Charm | 6 | 62 | 808 | 264.0 | 신규 | +| 15 | Ring | 6 | 260 | 0 | 260.0 | 기존(무변경) — **사다리 없음, 합성 대상 아님(§2-4)** | + +**구 ID 재번호 고지(C22)**: v1의 id16~33(24종, 산발 배치)을 **id16~26(11종, 연속 배치)**로 전면 재번호했다 — v1의 `TryForge`가 감사에서 컴파일 불가로 확인돼(§2-7) 실제 코드에 병합된 적이 없으므로(GodDem 코드 전수 grep 확인, 참조 0건) 재번호에 따른 마이그레이션 부담이 없다. + +**가챠 풀 영향 — 없음**(무변경, v1과 동일 원칙): 신규 11종은 가챠 확률 테이블(v3 §10-1)에 편입하지 않는다. 합성 전용 획득. + +## 2-6. PowerScore 단조성·슬롯 플로어 검증 — 각 행 배수 직접 기재(C-2 재발 방지) + +**C-1 채택의 자동 부수 효과**: 도달 불가 7종(구 id25·28·29·31·32·33 및 Weapon 구 G3)을 제거한 결과, **잔존 11종은 전부 기존 6종(v3 감사 통과본) 위에 쌓이는 상위 등급뿐**이다 — 각 슬롯의 "최하 진입 등급"(플로어 대비 마진을 검증해야 하는 유일한 병목 지점)은 v3에서 **이미 검증 통과한 6종 그대로**이므로, 신규 11종은 전부 그보다 PowerScore가 크다는 사실 하나로 마진도 자동으로 더 크다. 아래 표는 이를 "선언"이 아니라 **각 행 직접 계산**으로 증명한다(감사 재발 지적 반영): + +| 슬롯 | 최하 진입 등급(플로어 대조 대상) | 플로어(v3 N-2 확정치) | PowerScore | **배수(직접 계산)** | +|---|---|---|---|---| +| Hat | G3(id10)=70.0 | 50.25(id6 강화후) | 70.0 | 70.0÷50.25=**1.393×** | +| 〃 | G4(id16)=109.0 | 50.25 | 109.0 | 109.0÷50.25=**2.169×** | +| 〃 | G5(id17)=169.0 | 50.25 | 169.0 | 169.0÷50.25=**3.363×** | +| 〃 | G6(id18)=262.0 | 50.25 | 262.0 | 262.0÷50.25=**5.214×** | +| Boots | G3(id11)=65.0 | 30.0(id5 강화후) | 65.0 | 65.0÷30.0=**2.167×** | +| 〃 | G4(id19)=101.0 | 30.0 | 101.0 | 101.0÷30.0=**3.367×** | +| 〃 | G5(id20)=157.0 | 30.0 | 157.0 | 157.0÷30.0=**5.233×** | +| 〃 | G6(id21)=243.0 | 30.0 | 243.0 | 243.0÷30.0=**8.100×** | +| Weapon | G4(id12)=90.0 | 42.0(id2 강화후) | 90.0 | 90.0÷42.0=**2.143×** | +| 〃 | G5(id22)=140.0 | 42.0 | 140.0 | 140.0÷42.0=**3.333×** | +| 〃 | G6(id23)=217.0 | 42.0 | 217.0 | 217.0÷42.0=**5.167×** | +| Armor | G4(id13)=100.0 | 67.5(id3 강화후) | 100.0 | 100.0÷67.5=**1.481×** | +| 〃 | G5(id24)=155.0 | 67.5 | 155.0 | 155.0÷67.5=**2.296×** | +| 〃 | G6(id25)=240.0 | 67.5 | 240.0 | 240.0÷67.5=**3.556×** | +| Charm | G5(id14)=170.0 | 120.0(id9 강화후) | 170.0 | 170.0÷120.0=**1.417×** | +| 〃 | G6(id26)=264.0 | 120.0 | 264.0 | 264.0÷120.0=**2.200×** | +| Ring | G6(id15)=260.0 | 60.0(id8 강화후) | 260.0 | 260.0÷60.0=**4.333×** | + +**검증 결론**: 17행 전부 ≥1.3배 기준 통과(최소값 Hat G3의 1.393×, N-2 정책 최소치보다 여유). **등급 간 완전 분리도 재확인**: max(각 슬롯 G3~G4 값)=109.0(Hat id16) < min(그 다음 등급들, G5)=140.0(Weapon id22) — 동일 슬롯 내에서는 등급이 곧 서열이라는 원래 요건이 17행 전부 유지된다. + +## 2-7. ★ TryForge 재작성 — C-3·M-1·M-2 반영 + +**C-3 실측 오류(감사)**: v1의 `TryForge()`가 호출한 `GetCurrency()`는 `SurvivalLobbyController.cs:217`의 **다른 클래스 private static 메서드**라 `SurvivalMeta.cs`에서 호출 시 **컴파일 자체가 불가**했다. 또한 기존 계층 규약(`ApplyEquipLevelUp`·`ResetEquipLevelWithRefund` 주석 "재화는 호출부(UI) 책임"·`TryFuse()` 재화 코드 0줄)을 위반해 `SurvivalMeta`(메타 계층)가 `CurrencyManager`(재화 SOT)를 직접 건드렸다. + +**재작성 — 재화/아이템 책임 분리(C-3)**: + +```csharp +// SurvivalMeta.cs — 순수 판정(재화 무관, 아이템 재고만 확인). UI 가 사전에 이 함수로 버튼 활성 여부 결정. +public static bool CanForge(SurvivalSlot slot, int grade) +{ + var source = SurvivalItemCatalog.All.Find(d => d.Slot == slot && d.Grade == grade); + var target = SurvivalItemCatalog.All.Find(d => d.Slot == slot && d.Grade == grade + 1); + return source != null && target != null && OwnedCount(source.Id) >= 3; +} + +// SurvivalMeta.cs — 실행(재화 무접촉). 골드는 호출부가 TrySpendGold 로 선차감 완료했다고 전제. +public static bool TryForge(SurvivalSlot slot, int grade, out string message) +{ + if (!CanForge(slot, grade)) { message = "합성 불가(재료 부족 또는 최고 등급)"; return false; } + + var source = SurvivalItemCatalog.All.Find(d => d.Slot == slot && d.Grade == grade); + var target = SurvivalItemCatalog.All.Find(d => d.Slot == slot && d.Grade == grade + 1); + + bool targetWasNew = OwnedCount(target.Id) <= 0; // ← M-2: 가챠 경로 IsNew 와 동일 의미, 소비 전에 판정 + + RemoveItem(source.Id, 3); // ← M-1: 기존 헬퍼 재사용 + if (OwnedCount(source.Id) <= 0 && IsEquipped(source.Id)) + Data.Equipped[(int)source.Slot] = 0; // ← M-1: TryFuse L298-300과 동일한 장착 해제 블록 + + AddItem(target.Id); + + if (targetWasNew) Data.GachaRolledOptions[target.Id] = RollGachaOptions(target.Grade); // 신규 = 전체 굴림 + else RerollOneGachaOption(target.Id, target.Grade); // ← Major-1 수정: result 인자 생략(아래 기본 인자화) + + Save(); // ← M-1: 세이브 누락 시정 + message = $"{target.Name} 합성 완료"; + return true; +} + +// 합성 비용 조회(순수 함수, 골드 차감은 하지 않음 — UI 가 TrySpendGold 인자로 사용) +public static long ForgeCostAt(int grade) => grade switch +{ + 3 => 26_700, + 4 => 80_000, + 5 => 320_000, + _ => -1 // 유효하지 않은 등급(예: 6=최고등급, 전이 없음) +}; +``` + +**Major-1 — `RerollOneGachaOption` 컴파일 오류 해소(감사 실측 반영)**: v1은 이 메서드의 3번째 인자 자리에 주석만 적어(`/* 기존 결과 조회 오버로드... */`) 문법 자체가 성립하지 않았다. 실측 결과(`SurvivalMeta.cs:761-789`) 해당 메서드는 오버로드가 **1개뿐**(`RerollOneGachaOption(int itemId, int grade, GachaPullResult result)`)이고, 내부 L787-788(`result.RerolledStatKey=...`·`result.RerolledValue=...`)가 `result`를 **무조건 역참조**해 `null`을 넘기면 즉시 NRE(NullReferenceException)가 난다. 합성 경로(`TryForge`)는 가챠 풀에서 뽑는 것이 아니라 원작 `GachaPullResult` 객체 자체가 없으므로, 이 인자를 생략할 방법이 필요하다. + +**해소안(PM 지정, 감사 권고 채택) — 기본 인자(`= null`) 추가 + 호출부 null 가드**: + +```csharp +// SurvivalMeta.cs L761 — 기존 시그니처에 기본값만 추가(오버로드 신설이 아니라 동일 메서드 확장, 기존 가챠 호출부는 무변경 동작) +static void RerollOneGachaOption(int itemId, int grade, GachaPullResult result = null) +{ + var pool = Gacha.OptionsForGrade(grade); + if (pool == null || pool.Count == 0) return; + + if (!Data.GachaRolledOptions.TryGetValue(itemId, out var rolls) || rolls == null || rolls.Count == 0) + { + Data.GachaRolledOptions[itemId] = RollGachaOptions(grade); + return; + } + + int slot = UnityEngine.Random.Range(0, rolls.Count); + + var candidates = new List(); + foreach (var e in pool) + { + bool used = false; + for (int i = 0; i < rolls.Count; i++) + if (i != slot && rolls[i] != null && rolls[i].StatKey == e.StatKey) { used = true; break; } + if (!used) candidates.Add(e); + } + if (candidates.Count == 0) candidates.AddRange(pool); + + var pick = candidates[UnityEngine.Random.Range(0, candidates.Count)]; + rolls[slot] = new GachaOptionRoll { StatKey = pick.StatKey, Value = pick.Value }; + if (result != null) // ← 신규 null 가드(Major-1 해소, L787-788 대체) + { + result.RerolledStatKey = pick.StatKey; + result.RerolledValue = pick.Value; + } +} +``` + +가챠 경로(기존 호출부, `result`를 실제로 넘기는 지점)는 동작 무변경 — `result != null`이 항상 참이라 기존 로직 그대로 실행된다. 합성 경로(`TryForge`)만 `result` 생략으로 이 가드의 `else` 격(생략) 분기를 타 굴림 자체(`rolls[slot]=...`)는 동일하게 수행하고 리포트 필드 대입만 건너뛴다 — 합성은 애초에 `GachaPullResult` 리포트가 필요 없는 경로이므로 정확한 동작이다. + +**UI 호출부(신규, 클라이언트팀 구현 — 기존 5개소와 동일 패턴 그대로 재사용: `EquipUpgrade.cs:274`·`Growth.cs:210`·`Growth.cs:227`·`SkillMastery.cs:231`·`SkillMastery.cs:254`, 전부 `if(!TrySpendGold(cost)) return;` 동형)**: + +```csharp +void OnClickForge(SurvivalSlot slot, int grade) +{ + if (!SurvivalMeta.CanForge(slot, grade)) + { + Toast("재료가 부족합니다(동일 등급 동일 부위 3개 필요)"); + return; + } + if (!TrySpendGold(SurvivalMeta.ForgeCostAt(grade))) return; // ← 기존 재화 SOT 경로 그대로 + + SurvivalMeta.TryForge(slot, grade, out string msg); + PersistCurrency(); + Toast(msg); +} +``` + +이 순서(재고 확인→골드 차감→아이템 실행)는 `CanForge()`가 **순수 조회**(부작용 없음)이므로 "골드만 빠져나가고 아이템은 실패하는" 경합 상태가 생기지 않는다 — `TrySpendGold` 호출 시점에 `CanForge`가 이미 참이었음을 보장했으므로 그 직후의 `TryForge`는 항상 성공한다(같은 프레임 내 동기 실행, 경쟁 조건 없음). + +## 2-8. 경제 시너지 재시뮬레이션 — M-5 반영 재산출 + +**v1의 오류(감사 M-5)**: 전 슬롯에 균일 29% 가정을 적용해 "6슬롯 완주 ≈ 2,560,200G"로 과대추정(23%)했다. 실제로는 슬롯마다 (a) 합성이 거치는 전이 단수가 다르고(비대칭 사다리, §2-4) (b) 가챠 확률도 슬롯마다 1.5%~28.05%(19배 편차)로 다르다. + +**합성 골드 재산출(슬롯별 실제 전이 경로만 합산)**: + +| 슬롯 | 거치는 전이 | 비용 합계 | +|---|---|---| +| Hat | G3→G4(26,700)+G4→G5(80,000)+G5→G6(320,000) | 426,700G | +| Boots | 〃(Hat과 동일 3단) | 426,700G | +| Weapon | G4→G5(80,000)+G5→G6(320,000) | 400,000G | +| Armor | 〃(Weapon과 동일 2단) | 400,000G | +| Charm | G5→G6(320,000) | 320,000G | +| Ring | 없음(이미 G6) | 0G | +| **6슬롯 합계** | | **1,973,400G**(감사 실측치와 완전 일치) | + +**뽑기 비용 재산출(슬롯별 Pool2 실확률 — v3 §6-1)**: 최하 진입 등급까지는 가챠로 직접 뽑고(1개는 이미 확보 전제), 그 위 등급으로 합성하려면 "3의 거듭제곱" 개수만큼 **최하 등급 복사본**이 더 필요하다(3-for-1 피라미드 — 전이 n단이면 3ⁿ개): + +| 슬롯 | 필요 복사본(3ⁿ) | Pool2 확률(v3 §6-1) | 기대 뽑기 횟수 | +|---|---|---|---| +| Hat | 27(3³, 3단) | 28.05% | 27÷0.2805=96.3회 | +| Boots | 27 | 28.05% | 96.3회 | +| Weapon | 9(3², 2단) | 18.70% | 9÷0.1870=48.1회 | +| Armor | 9 | 18.70% | 48.1회 | +| Charm | 3(3¹, 1단) | 5.00% | 3÷0.05=60.0회 | +| **Ring(m-B 신규)** | **1(첫 카피, 합성 아닌 기본 보유분)** | **1.50%** | **1÷0.015=66.7회** | +| **합계(상한)** | | | **≈415.4회(400G/뽑기≈166,200G)** | + +**m-B 반영**: Ring은 합성 자체가 없어(§2-4) "추가 복사본"은 0이 맞지만, Ring도 **최초 1개는 가챠로 뽑아야** 6슬롯 완주가 성립한다 — Ring의 Pool2 확률(1.50%)이 6종 중 가장 낮아 이 "최초 1개" 자체가 66.7회(26,700G) 상당의 비용이다. v1·v2 초판은 이를 "0회"로 표기해 6슬롯 완주 총액에서 누락했다 — 본 행에서 정정 반영한다. + +**정직 고지(🟡 상한 추정)**: 위 뽑기 횟수는 슬롯별 독립 합산이라 **상한**이다 — 실제로는 한 번의 뽑기가 여러 슬롯에 걸쳐 "동시에" 기여할 수 있어(예: Hat을 노리고 뽑는 도중에도 Weapon·Armor·Ring 복사본이 함께 쌓인다) 진짜 필요 횟수는 이보다 적다. + +**I-A(신규) — 정밀치 병기**: 뽑기는 슬롯별로 독립된 스트림이 아니라 **단일 공유 스트림**이다 — 한 번의 뽑기가 동시에 여러 슬롯의 진행도에 기여하므로, 5개 합성 대상 슬롯(Ring 제외 — 합성 경로가 아니므로 별도)의 실제 필요 뽑기 횟수는 "독립 합산"이 아니라 **가장 오래 걸리는 슬롯 하나의 요구치**(`max`)에 가깝다 — 그 슬롯에 필요한 만큼 뽑는 동안 다른 슬롯들은 이미 충분히 쌓인다: `max(96.3, 96.3, 48.1, 48.1, 60.0) = `**96.3회(38,520G)**. 위 "≈349회(상한 합산)"는 여전히 안전판으로 병기하되, **정밀치는 96.3회(38,520G)**로 본다. + +**6슬롯 전체 G6 완주 총액**: +- **상한(독립 합산 + Ring 반영, 🟡 보수적)**: 1,973,400G(합성) + 166,200G(뽑기, Hat/Boots/Weapon/Armor/Charm 348.8회+Ring 66.7회≈415.4회) ≈ **약 2,140,000G** +- **정밀치(I-A, 5슬롯 max 방식)**: 1,973,400G(합성) + 38,520G(뽑기, max 방식) ≈ **약 2,011,900G** + +두 값 모두 v1의 2,560,200G 대비 하향 정정이며(감사 실측 1,973,400G가 골드 축의 SOT), B1+B2+B4 실투자(1,942,464G~3,333,232G, v3 §12)와 여전히 **동일 자릿수**다 — v3가 지적한 "가챠 단독 완주 대비 36배 골드효율 불균형"을 완화한다는 결론(v1의 핵심 통찰)은 재계산 후에도 유효하다. 수정된 것은 정밀도뿐, 방향성은 불변. + +## 2-9. UI 진입점·강화 가드와의 관계 (v1과 동일 — 무변경) + +## 2-10. 데이터 모델·코드 터치포인트 — C-3 반영 갱신 + +| 파일 | 변경 | +|---|---| +| `SurvivalItemCatalog.cs` | 신규 **11종**(v1은 18종, C-1로 7종 제거) 항목 추가(§2-5), id16~26 | +| `SurvivalMeta.cs` | **(재작성) `CanForge(SurvivalSlot,int)`**(순수 판정)·**`TryForge(SurvivalSlot,int,out string)`**(재화 무접촉, §2-7)·`ForgeCostAt(int)`(3값 룩업) | +| **(신규, UI 레이어)** `SurvivalLobbyController.Forge.cs`(가칭) | `OnClickForge()`(§2-7) — 기존 `Growth.cs`/`EquipUpgrade.cs`의 `TrySpendGold` 호출 패턴 그대로 재사용. 클라이언트팀 구현 | +| **신규 파일(선택)** `SurvivalMetaForgeCost.csv` | v1과 동일 제안(3행, 26700/80000/320000) — 인라인 상수로도 충분, 개발팀장 재량 | + +## 2-11. 검증 시나리오 — C-3·M-1·M-2 반영 갱신 + +| # | 시나리오 | 기대 결과 | +|---|---|---| +| 1 | Hat-G3(id10) 3개 보유, `CanForge(Hat,3)` 호출 | `true` 반환(재화 무관 순수 판정) | +| 2 | 위 상태에서 골드 미보유 | `TrySpendGold` 실패로 `TryForge` 자체가 호출되지 않음 — 아이템 무변경(경쟁 조건 없음, §2-7) | +| 3 | 골드 충분·Hat-G3 3개 보유 | `OnClickForge` 전체 흐름 성공 — `Owned[10]-=3`·`Owned[16]+=1`·`GachaRolledOptions[16]` 신규 굴림(targetWasNew=true 경로) | +| 4 | id16을 이미 1개 보유한 상태에서 추가로 Hat-G3 3개→id16 재합성 | `targetWasNew=false` 경로 — `RerollOneGachaOption` 호출로 슬롯 1개만 재추첨(기존 좋은 롤 보존, M-2 열화 방지 확인) | +| 5 | 장착 중인 Hat-G3(id10)을 마지막 3번째 소비로 합성 | `OwnedCount(10)<=0 && IsEquipped(10)` → `Data.Equipped[Hat]=0`(TryFuse 동형 블록, M-1 확인) | +| 6 | `SurvivalMeta.cs`에서 `TryForge`(및 `RerollOneGachaOption` 수정분) 컴파일 | **`SurvivalMeta.cs` 전체 컴파일 성공**(감사 3회차 재발 지적 반영 — 검증 기준은 "무엇을 확인했나"의 부분 조건(예: 재화 참조 0건)이 아니라 "무엇이 참이어야 하나"인 전체 컴파일 성공으로 기술) | +| 7 | Ring(id15) 대상 `CanForge(Ring,6)` 호출 | `target=null`(Grade7 없음) → `false` — Ring은 항상 합성 불가(§2-4 설계 확인) | +| 8 | Weapon-G3(구 id22) 관련 임의 호출 | 카탈로그에 해당 항목 자체가 없어(§2-5, C-1 제거) 애초에 시나리오 성립 불가 — 도달 불가 콘텐츠 존재 자체가 소멸(C-1 근본 해결 확인) | + +--- + +## 3. 층간 교차 영향 (결합 최종 수치 — V3-7 원칙, 본 v2에서 실제 이행) + +| 항목 | 교차축 | 결합 수치 | +|---|---|---| +| 1부 기절(M-3·M-4) | 메모리·세션 경계 | 사망 즉시 제거(M-3)+3경로 커버 ClearAll(M-4) — 런당 수천 유닛 스폰에도 레지스트리 엔트리 수 상한 = 현재 생존+기절중 유닛 수만(무제한 누적 해소) | +| 2부 합성(C-1·C-2) | **B2 강화-후 플로어(v3 N-2)** | 17행 전부 배수 직접 계산 완료(§2-6) — 최소 1.393×(Hat G3, v3에서 이미 검증된 값과 100% 동일) | +| 2부 합성(M-5·m-B·I-A) | **B1+B2+B4(v3 §12)** | 6슬롯 완주 ≈ 2,140,000G(상한)~2,011,900G(정밀치) vs 실투자 1,942,464~3,333,232G — 동일 자릿수 유지(재계산 후에도 결론 불변) | +| 2부 합성(C-3) | **UI 계층(SurvivalLobbyController)** | 재화 판정·차감 100% UI 책임 이관 — SurvivalMeta 재화 무접촉 규약(TryFuse·ApplyEquipLevelUp과 동일) 준수 확인 | + +--- + +## 4. PD 확인 대기 항목 (v1 5건 승계 + 갱신) + +1. **🔴 보스 기절 처리**: 30% 축소(제안) vs 완전 면역(대안) — v1과 동일. +2. **기절 지속시간(1.0초)·면역배율(×2)**: 원작 근거 없는 제안치 — v1과 동일. +3. **합성 확정형(Survivor.io) vs 확률형(원작 Wild Survival)**: v1과 동일, 여전히 유일한 레퍼런스 상충 지점. +4. **합성 골드 비용 3단(26,700/80,000/320,000G)**: 신규 도출 제안치 — v1과 동일. +5. **UI 배치(가챠 화면 내 탭)**: v1과 동일. +6. **(신규) 🔴 Ring 슬롯의 합성 생태계 포함 여부**: §2-4에서 "이미 최고등급이라 합성 대상 아님"을 정직한 기본안으로 채택했으나, PD 지시 의도("장비 합성 구현")가 6슬롯 전부 커버를 기대할 가능성을 인지 — Ring을 위한 별도 메커니즘(예: 중복 전용 등)이 필요한지 확인 필요. + +--- + +## 5. 리스크 (v1 5건 승계, R-F1 갱신) + +| ID | 리스크 | 심각도 | 내용 | +|---|---|---|---| +| R-S1·R-S2 | (v1과 동일) | — | 무변경 | +| **R-F1(갱신)** | 합성 완주선(2,140,000G 상한~2,011,900G 정밀치) 근사치 오차 | 중(🟡, v1 대비 하향 — 골드 부분은 감사 실측치라 정밀도 상승, 뽑기 부분만 상한/정밀 병기) | §2-8 I-A 정밀치(max 방식, 96.3회)와 상한(합산 방식, 415.4회) 사이의 진짜 값은 몬테카를로 미실행으로 미확정 | +| R-F2·R-F3 | (v1과 동일) | — | 무변경. R-F3(Twinborn 미이식)은 §2-4 Ring 처리(PD확인 6번)와 연계 가능성 인지 | + +--- + +## 6. 기각안 (C32 — v1 6건 승계, v2 신규 3건) + +**v1 기각안 6건 무변경 승계**(v1 §6 참조: (b)인스턴스등급·Twinborn·B2확률형재현·비균일개수·신규가챠풀편입·보스완전면역기본). + +**v2 신규 기각안**: + +| # | 검토안 | 기각 사유 | +|---|---|---| +| 7 | C-1: (가) G3 4종 가챠 풀 편입 | §2-4 — v3 §6-1은 이미 감사 통과·구현·push 완료된 운영 시스템. 재계산이 본 문서 스코프(신규 기능 2건)를 초과 | +| 8 | C-1: (나) 가챠 배출 등급 슬롯별 최하 통일 | §2-4 — id12·13·14·15는 PD 확정·구현 완료 사양, 지금 낮추는 것은 C36(방향 축소) 위반 소지 | +| 9 | Ring 중복분을 별도 재료·화폐로 전용하는 신규 메커니즘 도입 | §2-4 — 오늘 PD 지시("동일 등급 동일 부위 합성")의 문자적 범위를 넘는 별건 확장. 필요성 자체를 PD 확인 항목(§4-6)으로 먼저 검증 | + +--- + +## 7. 변경 이력 (P16) + +| 일시 | 작성 | 변경 | 근거 | +|---|---|---|---| +| 2026-08-23 | balance-designer | v1 신규 | PD 직접 지시 2건 | +| 2026-08-23 | balance-designer | **v2 신규 — plan-auditor 차단 반영**. 1부: M-3(레지스트리 누수, 사망 시 명시 제거 채택)·M-4(ClearAll을 Awake 병치로 이동)·m1~3(표기·전제 정정). 2부: C-1((다) 등급사다리 비대칭 채택, 24→17종)·C-2(자동 해소, 배수 직접 기재)·C-3/M-1/M-2(TryForge 재화무접촉 재작성)·M-5(경제 재산출, 1,973,400G 감사치 정합) | PM 회송 — `_v1_감사결과.md` 전문 | +| 2026-08-23 | balance-designer | **v2 정정 5건(2차 편집, v3 생성 아님) — plan-auditor 재검증 조건부 통과 반영**(개발팀장 구현 병행 착수 상태). Major-1(`RerollOneGachaOption` 컴파일 오류 — 기본 인자 `=null`+null 가드로 해소, §2-11#6 검증기준을 "컴파일 성공"으로 정정)·m-A(§2-6 max값 100.0→109.0 오기 정정+헷지 문장 삭제)·m-B(§2-8 Ring 첫 카피 획득비용 66.7회/26,700G 반영)·m-C(§0·§2-7 "4개소"→"5개소"+정확한 라인 인용)·I-A(§2-8 정밀치 96.3회/38,520G 병기, 상한 415.4회와 병행 표기) | PM 재검증 회송 — 조건부 통과(기절 즉시 적격·합성 Major-1 해소 후 적격) | + +--- + +## 8. 후속 조치 (본 v2 범위 밖) + +1. **plan-auditor 모드A 재검증 — 조건부 통과(Major-1 해소로 최종 적격)**. 개발팀장이 동일 해소안으로 구현 병행 착수한 상태(PM 확인). +2. **PD 확인 6건**(§4) — 보스 기절·지속시간 수치·확정형/확률형 상충·합성 비용·UI 배치·Ring 포함 여부. +3. **합성 완주선 정밀 시뮬레이션**(R-F1) — 몬테카를로, 슬롯 간 뽑기 공유 효율 반영. +4. **개발팀장 구현 착수** — C49 표준(설계→plan-auditor 검증→구현→PM 커밋). diff --git a/공유/대화로그/GodDem/2026-08-23.md b/공유/대화로그/GodDem/2026-08-23.md index eae65cf..ed1aca9 100644 --- a/공유/대화로그/GodDem/2026-08-23.md +++ b/공유/대화로그/GodDem/2026-08-23.md @@ -117,3 +117,57 @@ - **M-2 백업 지적은 감사관 false negative로 반전**: 감사관이 "B3 백업 0건·실측 불가" 판정했으나 PM ls 실측 결과 `공유/개발팀_백업/GodDem/*.bak_20260823_0048.cs` **7종 실존** — 개발팀장 보고 사실. 감사관 탐색 범위가 조직 표준 백업 위치(공유/개발팀_백업)를 누락. feedback_gitignore_backup_audit_blindspot에 "탐색 범위 갭" 5항 보강(2회차 재발·이번에도 팀원 정직) - **M-3 `.live/` Live 채널 부재(조직 생존급)**: `.live/` 미존재·live_inject.sh no-op — P25 Live 증분 동기화 비가동·C21-① 이행 불가 구조. PD 보고·별건 복원 안건 등재 - V3-1 게이트 실측의 PD 고지는 §72 이전 PM 보고에서 **기수행 확인**(감사 시점차). Improvement 수용: PD 로그 갱신 주기 층 단위 최소 2분할(차기 적용)·C25 사후조치 (N) 표기 내부 일관 유지 + +## 74. PD 지시 5건 수령 — IAP 보류·기절 구현·합성 구현(탕탕특공대 레퍼런스)·설명 2건 (2026-08-23) + +- **PD 직접 지시 (5건·원문 요지)**: ①젬팩 IAP 실화폐 가격 **보류** ②기절(stun) 옵션 전투 로직 신설 **구현** ③장비 융합(forging) 활성화 **구현** — "재료는 동일 등급 동일 장비 파츠끼리 합성하는 방식. 레퍼런스 게임 탕탕특공대의 장비 합성 시스템을 검색해볼 것" ④(원작 이탈 4건) 무슨 이슈인지 알기 쉽게 재보고 ⑤penetrate/ele·Stage55+ 이슈 알기 쉽게 설명 +- **PM 처리**: ①대기 목록 "보류" 상태 전환(차기 로그 배치 반영) ②③balance-designer 설계 위임(단일 설계 문서·WebSearch 탕탕특공대 의무·B2 forging 골격·가챠 중복 한계효용 0 해소 시너지 연계) → plan-auditor 검증 → 개발팀장 구현(C49) ④⑤PM 직접 설명 보고 발신 + +## 75. 기절+합성 설계 v1 완료 — B3 후속 확장(P3-B3-2) (balance-designer, GodDem 수정 0건) + +- **선행 실측(C39)**: v3(B3 최신 SOT, 구현 완료·5층 완성)·B2 v2 §8 forging 골격·GodDem 코드 전문 실측(`SurvivalUnit.cs`·`SurvivalMeta.cs` TryFuse/RollGachaOptions·`SurvivalDebuffStack.cs`·`ActiveSkillData.cs`)·WebSearch(Survivor.io 장비 합성, PD 명시 지시 이행). +- **신규 발견(C39·C3, 은폐 없음)**: 개발팀장 구현본이 설계 문서 지정 `GachaOwned`(별도 사전) 대신 **기존 `Owned` 단일 사전을 SOT로 재사용**(코드 주석: "융합·차감 경로에서 두 사전이 갈라져 중복 판정이 어긋난다" 방지) — 설계 대비 이탈이나 **더 나은 결정**으로 확인, 본 합성 로직이 정확히 그 경로라 별도 통합 작업 없이 `OwnedCount()` 재사용 가능. +- **1부 기절**: 발동=플레이어 공격 적중 시 신규 `GachaStunChance()`(기존 `GachaAttackRatio()` 패턴 재사용, 대상 스탯만 stun_rate로 교체) 프록 — 기존 `CriticalRate` 굴림과 동일 코드 관례. 효과=`SurvivalUnit.FixedUpdate()` 조기반환으로 이동+공격 완전 정지(쿨다운 타이머도 동결). 지속 1.0초(🟡)+종료 후 2.0초 면역창(신규 `SurvivalStunEffect` 정적 클래스, `SurvivalDebuffStack` 패턴 재사용)으로 무한 스턴락을 시간 상한으로 원천 차단(확률 캡 아닌 근본 해결, C2). 보스는 지속시간 30% 축소 제안(원작 근거 없음, 🔴 PD 확인, 완전면역 대안도 상수 1개 교체로 즉시 전환 가능하게 설계). §8-4 승산항(N-1 PD 확정치) 무접촉 확인 — 대미지 채널 아닌 이벤트 트리거. +- **2부 합성**: **WebSearch 완료(출처 3건 첨부)** — Survivor.io는 동일장비 3개→등급 1단 상승 확정형(실패 없음), 동일 등급 제약 확인, 상위구간(8·6개) 비균일 구간 존재하나 GodDem 4등급 사다리는 저~중위 3개 균일 구간 대응 판단. **핵심 설계 결정 = (a) 카탈로그 확장 채택**(6슬롯×4등급=24종, 신규 18종) — (b) 인스턴스 등급 속성안은 세이브 마이그레이션·`Owned`/`GachaRolledOptions` 전면 재설계 부담으로 기각. 신규 18종 PowerScore는 기존 6종(v3 구현본, 절대값 무변경) 앵커 기준 슬롯별 ×1.55 배율 산출 — 슬롯 내 등급 단조 + **등급 간 완전 분리**(24종 전체, N-2보다 강한 검증) 통과. 합성 비용은 B2 forging 골격(확률형)의 기대비용 역산(26,700G/80,000G/320,000G, Survivor.io 확정형 채택 사유로 확률 미적용). 가챠 확률표(v3 §6-1)는 무접촉 — 신규 18종은 가챠 풀 미편입, 합성 전용 획득. +- **경제 시너지 재시뮬레이션**: 감사 C-3의 "가챠=완주 75~90회·중복 한계효용 0" 결론이 합성 도입으로 재정의됨 — 1슬롯 G6 완주 ≈ 27개 기초카피(3^3 피라미드)=뽑기 93회+합성비용 426,700G≈464,000G, 6슬롯 전체 ≈ 자릿수상 250만~280만G대(🟡 근사, 몬테카를로 미실행 명시)로 **B1+B2+B4 실투자(1,942,464~3,333,232G)와 동일 자릿수 도달** — N-5가 지적한 "36배 골드효율 불균형"이 장기 목표 기준으로 자연 교정됨을 결합 수치로 제시(V3-7 원칙 계승). +- **기각안(C32, 6건)**: (b)인스턴스등급안·Twinborn(교차부위 합성)·B2 확률형 그대로 재현·비균일 개수(8·6)·신규18종 가챠풀 편입·보스 완전면역 기본채택 — 전부 사유 명시(설계 문서 §6). +- **산출물**: `공유/기획/GodDem/2026-08-23_P3B3-2_스턴_합성_설계_v1.md`(신규, 449줄, B3 v3와 병존) +- **PD 확인 대기 5건**: 보스 기절 처리(30%축소 vs 완전면역)·기절 지속시간·면역배율 수치·합성 확정형(Survivor.io) vs 확률형(원작 Wild Survival) 상충 지점·합성 골드비용 3단·UI 배치. +- **후속**: plan-auditor 검증(C35 의무, B3 동일 체인) → 개발팀장 구현(C49) → PM 커밋. PD 확인 5건은 PM 취합 후 상신 필요. + +## 76. 스턴·합성 v1 감사 차단 — 합성 재설계 회송 (2026-08-23) + +- **plan-auditor 판정: 차단(트랙 분리)** — 기절: 실측 전항 정합·M-3(레지스트리 누수 — "GC 대상" 오류·사망 유닛 엔트리 영구 잔존)·M-4(ClearAll 배치 실측 불일치·ExitToLobby 경로 누락)만 수정 시 단독 적격 / 합성: **Critical 3** — C-1 신규 18종 중 7종 획득 경로 없음(가챠 배출 등급 미만 도달 불가·Ring 슬롯 합성 제외)·C-2 슬롯 플로어 3종 역전+§3 허위 통과(V3-7 요건 미반영 재발·N-2 폐기한 균일 배율 회귀)·C-3 TryForge 컴파일 불가+SurvivalMeta 재화 무접촉 규약 위반. M-1 유령 장비(장착 해제 누락)·M-2 옵션 굴림 무가드(열화·세탁 양방향)·M-5 경제 23% 과대(슬롯별 진입 등급 미반영·실총액 1,973,400G) +- **감사 전재**: `공유/기획/GodDem/2026-08-23_P3B3-2_스턴_합성_설계_v1_감사결과.md` +- **PM 회송**: v2 재작성 — C-1 구조 택1(가챠 풀 편입/배출 등급 통일/사다리 비대칭 — 기구현 무접촉 우선 권고·Ring 별도 결정·PD 확인 표기)·C-2 슬롯 플로어 재도출(교차표에 배수 직접 기재 강제)·TryForge 재작성(재화 UI 이관·장착 해제·굴림 가드·Save)·경제 재산출·기절 5~7 소폭 수정. 단일 v2·재감사 후 일괄 구현(분리 집행 대비 사이클 절약) + +## 77. 스턴·합성 v2 완료 — C-1 (다) 채택·TryForge 재화무접촉 재작성 (balance-designer, GodDem 수정 0건) + +- **선행**: 감사 전문(`_v1_감사결과.md`) 전문 Read. C-1(도달불가 7종)·C-2(플로어 역전 3종)가 서로 은폐 관계임을 확인 — C-1을 구조적으로 고치면 C-2가 부수 해소되는 관계라 두 지적을 통합 해결. +- **C-1 재량 결정 = (다) 등급 사다리 비대칭 인정 채택**(가챠 풀 편입·배출등급 통일 기각). 근거: (가)는 v3 §6-1(이미 감사통과·구현·push 완료된 운영 시스템)의 재감사를 요구해 스코프 초과. (나)는 id12·13·14·15(PD 확정·구현 완료 사양)를 지금 낮추는 것이라 C36(방향 축소) 위반 소지. (다)는 기구현 무접촉 + 도달불가 7종(구 id22·25·28·29·31·32·33) 자체를 카탈로그에서 제거하는 근본 해결(C2) — 슬롯별 사다리를 Hat/Boots(G3→G6 4단)·Weapon/Armor(G4→G6 3단)·Charm(G5→G6 2단)·Ring(사다리 없음)으로 비대칭 인정. 24종→17종(6기존+11신규)으로 재정리, id16~33 산발 배치를 id16~26 연속 배치로 재번호(v1 TryForge 컴파일 불가로 실제 코드 병합 0건 확인 후 재번호 — 마이그레이션 부담 없음). +- **C-2 자동 해소 확인**: (다) 채택 결과 잔존 11종은 전부 v3에서 이미 검증 통과한 6종 위에 쌓이는 상위 등급뿐이라 슬롯 플로어 마진이 자동으로 v3 원값과 동일(최소 Hat 1.393×). 감사 재발 지적(V3-7 요건 미반영) 대응으로 **17행 전체에 플로어 대비 배수를 직접 계산해 표에 기재**(축 이름만 적고 "통과" 선언하는 패턴 재발 차단). +- **Ring 처리**: 이미 가챠에서 최고등급(G6) 직접 배출이라 합성 대상 자체가 아님을 정직한 기본안으로 채택, PD 지시 의도(6슬롯 커버 기대 가능성)를 인지해 PD 확인 항목으로 명시(§4-6). +- **C-3·M-1·M-2 TryForge 재작성**: `GetCurrency`(타 클래스 private static, 컴파일 불가) 삭제 — `CanForge()`(순수 판정)/`TryForge()`(재화 무접촉) 분리, 골드 판정·차감은 UI 호출부(`TrySpendGold`, 기존 4개소와 동일 패턴)로 이관해 "SurvivalMeta 재화 무접촉 규약"(TryFuse·ApplyEquipLevelUp 실측 확인) 준수. `RemoveItem()` 헬퍼 + TryFuse L298-300과 동일한 장착 해제 블록 추가(유령 장비 차단, M-1). 옵션 굴림은 `targetWasNew`(소비 전 `OwnedCount<=0`) 가드로 가챠 경로의 `IsNew`와 통일해 열화·세탁 양방향 차단(M-2). `Save()` 호출 추가. +- **M-5 경제 재산출**: 슬롯별 실제 전이 경로(3/3/2/2/1/0단)로 합성 골드 재계산 — **1,973,400G(감사 실측치와 완전 일치)**. 뽑기 비용은 v3 §6-1 Pool2 실확률(28.05/18.70/5.00%)로 재산출해 약 349회(139,600G, 슬롯 독립합산 상한 명시). 6슬롯 완주 총액 약 2,113,000G(v1의 2,560,200G 대비 정정, 결론 방향은 불변 — B1+B2+B4와 동일 자릿수). +- **1부 기절 M-3·M-4**: "GC 대상이라 명시적 제거 불요" 오류 서술 삭제 — 사망 시 명시적 제거(`TakeDamage()` 사망분기에 `SurvivalStunEffect.Remove()`) 채택(대안인 Tick 앞당김보다 기존 Died choke point 재사용이 더 근본적). `ClearAll()`을 `Restart()`에서 `SurvivalActiveSkillRunner.Awake()`(`SurvivalDebuffStack.ClearAll()` 병치)로 이동 — 최초로드·Restart·ExitToLobby 3경로 전부 커버. +- **기각안(C32, v1 6건 승계+v2 신규 3건)**: (가)가챠풀편입·(나)배출등급통일·Ring 신규메커니즘 도입 — 전부 사유 명시(§6). +- **산출물**: `공유/기획/GodDem/2026-08-23_P3B3-2_스턴_합성_설계_v2.md`(신규, 424줄, v1과 병존) · v1 상단 대체 배너 추가(예외 허가) +- **PD 확인 대기 6건**: 보스기절 처리·지속시간수치·확정형/확률형 상충·합성골드비용·UI배치·**(신규) Ring 합성생태계 포함 여부**. +- **후속**: plan-auditor 재검증(C35 의무) → 개발팀장 구현(C49) → PM 커밋. PD 확인 6건은 PM 취합 후 상신 필요. + +## 77-B. 스턴·합성 v2 재검증 조건부 통과 — 문서 정정·구현 병행 착수 (PM·2026-08-23) + +- **plan-auditor 재검증: 조건부 통과** — 11항목 전수 반영 확인·17행 배수 전량 재검산 일치(min 1.393·17행 ≥1.3)·경제 재산출 전항 검산 일치(합성 1,973,400G·총 2,113,000G)·C-2 시정 방식 "3회 반복 지적 패턴 실교정" 평가. **기절 트랙 = 즉시 인계 적격(조건 0)** / 합성 트랙 = Major-1 해소 후 적격 +- **Major-1**: §2-7 재추첨 호출 3번째 인자 자리 주석 = 구문 오류·오버로드 부재·null 시 NRE(L787-788 무조건 역참조) + §2-11 #6 "재화 참조 0건" 기준으로 전역 컴파일 성공 선언(검증 기준 축소 패턴 3회차 — 축소 재발·차기 "무엇이 참이어야 하나" 기술 권고). Minor: m-A(§2-6 인용 오류 109.0)·m-B(Ring 첫 카피 66.7회 미계상 — 총 ≈2,140,000G)·m-C(TrySpendGold 5개소)·I-A(단일 스트림 max() 정밀치 96.3회·총 ≈2,011,900G) +- **PM 병행 집행(C41)**: ①balance-designer v2 정정 5건(Major-1 해소안 PM 지정 = `GachaPullResult result = null` 기본 인자 오버로드 + null 가드 — 감사 권고 채택) ②**개발팀장 구현 착수**(기절+합성 일괄·동일 해소안 기준·rsp Roslyn 컴파일 검증·가챠 경로 회귀 무결 의무·GodDem 로컬 커밋까지) + +## 78. 스턴·합성 v2 정정 5건 완료 — 문서 계층, 구현물 무영향 (balance-designer, GodDem 수정 0건) + +- **Major-1 해소(PM 지정안 반영)**: §2-7에 `RerollOneGachaOption` 실제 코드(`SurvivalMeta.cs:761-789` 전문 Read 확인)와 그 위에 `GachaPullResult result = null` 기본 인자 추가 + L787-788(`result.RerolledStatKey`·`result.RerolledValue` 무조건 역참조) 앞에 `if (result != null)` 가드를 씌운 수정본을 완전한 코드 블록으로 삽입 — 가챠 기존 호출부는 `result`를 실제로 넘기므로 동작 무변경, `TryForge`만 인자 생략으로 안전 호출. §2-11 검증시나리오 #6을 "재화 참조 0건"(부분 조건)에서 "`SurvivalMeta.cs` 전체 컴파일 성공"(전체 조건)으로 정정 — 감사가 지적한 "검증 기준 축소 재발 패턴(3회차)"에 대응. +- **m-A**: §2-6 "max(각 슬롯 G3~G4 최하값)=100.0(Armor G4)"의 산술 오류(109.0(Hat id16)이 실제 최댓값) 정정 + 불필요했던 슬롯 간 교차 헷지 문장 삭제(등급 간 완전 분리는 실측 성립, 감사 확인 완료 사안이라 유보 어투 불필요). +- **m-B**: §2-8에 Ring 행 추가 — 합성 자체는 없으나(§2-4) 6슬롯 완주 성립에는 Ring도 최초 1개는 가챠로 뽑아야 하고, Ring이 6종 중 최저 확률(Pool2 1.50%)이라 이 "최초 1개"가 66.7회(26,700G) 상당임을 반영. v1·v2초판이 "0회"로 표기해 누락했던 부분. +- **m-C**: "기존 4개소"를 "기존 5개소"로 정정 — `EquipUpgrade.cs:274`·`Growth.cs:210`·`Growth.cs:227`·`SkillMastery.cs:231`·`SkillMastery.cs:254` 5곳 전부 동형 `TrySpendGold` 패턴 확인, §0·§2-7 2개소 수정. +- **I-A**: §2-8에 정밀치 병기 — 뽑기는 슬롯별 독립 스트림이 아니라 단일 공유 스트림이므로, 5개 합성 슬롯의 실제 필요 횟수는 "독립 합산"이 아니라 "가장 오래 걸리는 슬롯의 요구치"(max)에 가깝다는 논리로 96.3회(38,520G) 정밀치를 상한(415.4회 합산, Ring 포함)과 병행 표기. +- **연쇄 정합성**: §2-8 갱신으로 총액이 2,113,000G→2,140,000G(상한)/2,011,900G(정밀치)로 바뀌어, §3(층간교차영향)·§5(R-F1 리스크)의 구 수치 참조 2곳도 함께 갱신해 문서 전체 정합성 확보(grep 재확인 완료). +- **산출물**: `공유/기획/GodDem/2026-08-23_P3B3-2_스턴_합성_설계_v2.md`(같은 경로, 424→474줄) +- **후속**: plan-auditor 재검증에서 조건부 통과 판정을 이미 받았고(§77-B, PM 기록) 개발팀장이 동일 해소안으로 구현을 병행 착수한 상태 — 본 문서 정정은 그 구현과 별도 트랙으로 완결. PD 확인 6건(§4)은 PM 취합 후 상신 필요.