드랍 시스템 (신규 제안) 초안미구현밸런싱미완료
본 문서는 아이템 드랍을 코드 베이스를 무시하고 새로 설계한 제안서다. 현재 구현의 구조적 문제(100% 드랍, 같은 아이템 폭주, 밸런싱 불가)는 패치로 덧대기 어렵고 구조에서 비롯되므로, 이상적인 모델을 먼저 정의하고 코드를 거기에 맞춘다.
현재 구현의 진단·버그 목록은 아이템·루팅·드랍 “코드–기획 불일치” 절 참조. 태그 연계는 태그 시스템.
0. 범위와 전제
섹션 제목: “0. 범위와 전제”| 항목 | 내용 |
|---|---|
| 적용 대상 | 몹 드랍 우선. 상자·낱개 아이템은 같은 3단계를 공유하되 1단계(착용) 대신 그룹 정의를 쓴다 (§6, 후속 전환). |
| 전투력과 무관 | 몹 전투력은 MonsterStat이 결정한다. 착용 장비는 전투 스탯에 영향을 주지 않는다. 장비 역할은 외형·루팅 후보뿐. “강한 몹”은 MonsterStat로, “좋은 걸 주는 몹”은 드랍 수치셋으로 따로 만든다. |
| 루팅 UI | 시체 루팅은 인벤토리 팝업이다. 플레이어가 몹의 착용 부위를 1:1로 대조하지 못하므로, 노출 굴림에서 빠진 장비가 “보이는데 못 줍는” 부정합은 발생하지 않는다. |
| 이 문서가 엎는 것 | 기존 (monsterType, level) → 8개 값 → tier 2단 변환 → 개수, worthRarity 단일 축, 단일 잡템 풀, 100% 노출. |
1. 기존 드랍의 문제 (AS-IS)
섹션 제목: “1. 기존 드랍의 문제 (AS-IS)”현재 구조는 (monsterType, level)로 시트에서 8개 값 + 5개 태그 쿼리를 뽑고, 각 값을 다시 tier로 변환해 개수를 정한다. 밸런싱이 통제 불가능한 이유는 다음과 같다.
| # | 문제 | 결과 |
|---|---|---|
| 1 | 2단 변환 (값 → tier → 개수) | 디자이너가 “무기 1개”를 직접 못 적고 350 같은 추상값을 역산. 값을 바꿔도 결과 예측 불가. |
| 2 | 손잡이 엉킴 | dropEquipKindsValue 하나가 무기·방어구 개수를 동시에 좌우. 독립 조정 불가. |
| 3 | worthRarity 한 축에 게이트+가중 혼재 | ”자주 나오게” 하려고 worth를 낮추면 “싼 몹도 줄 수 있게” 게이트가 같이 풀림. 두 의도 충돌. |
| 4 | 단일 잡템 풀 | Utility·Material·Accessory 등을 한 통에 섞어 추첨 → 등록 수 많은 카테고리가 독점(재료만 우수수, 장신구는 안 나옴). |
| 5 | 100% 노출 | 노출 단계 자체가 없어 착용분이 전부 드랍. 익스트랙션의 “한 방” 긴장 소멸. |
| 6 | 비스택 칸 복제 버그 | 스택 분배가 stack=1 아이템을 구분 못 해 빗자루가 한 시체에 5개로 복제. |
핵심 진단: 개수는 과도하게 복잡(2단 변환)하고, 품질·노출은 과도하게 단순. 복잡도가 거꾸로 배치되어 있고, 한 숫자가 여러 일을 겸해 손잡이가 엉켜 있다.
2. 해결 방향 (TO-BE 원칙)
섹션 제목: “2. 해결 방향 (TO-BE 원칙)”세 가지 원칙으로 다시 짠다.
- 3단계 분리 — 생성(무엇을 가질 수 있나) → 노출(그중 얼마를 드러내나) → 품질(각각 어떤 옵션인가). 단계 간 손잡이가 섞이지 않는다.
- 축 직교화 — 손잡이 하나 = 효과 하나. 개수·가치·빈도·노출·상한을 각각 다른 컬럼이 담당.
- 직접 입력 — tier 2단 변환 폐기. 시트에 결과값(개수·확률)을 그대로 적는다. 일괄 조정은 “드랍 수치셋” 공유로 대체.
2.1 직교화된 손잡이 (한눈에)
섹션 제목: “2.1 직교화된 손잡이 (한눈에)”| 무엇을 조정 | 손잡이 | 누가 가짐 |
|---|---|---|
| 몇 종류 등장 | 슬롯Count (카테고리별) | 드랍 수치셋 |
| 얼마나 값진 것까지 (=등급 상한) | valueCap | 드랍 수치셋 |
| 자주/드물게 출현 | dropWeight | 아이템 |
| 그 아이템의 가치·등급 | value | 아이템 |
| 얼마나 드러나나 | exposure × 수량스탯 | 수치셋 × 플레이어 |
| 운 좋으면 더 값진 것 | valueCap 보정 | 행운스탯 |
→ 등급은 컬럼이 아니다. value 구간을 사람이 읽기 쉽게 나눈 라벨(흰템/녹템/…)일 뿐. value가 오르면 자동으로 더 높은 등급으로 표시된다.
3. 3단계 파이프라인 (개념도)
섹션 제목: “3. 3단계 파이프라인 (개념도)”flowchart TD subgraph S1 [1단계 · 생성 · 몹 스폰 시] A[카테고리별 슬롯 개수 굴림<br/>수치셋: weaponCnt · armorCnt · ...] B[카테고리 분기 → 태그 매칭<br/>dropTags ↔ entityTags] C[valueCap 컷<br/>+ 행운 보정] D[dropWeight 가중 추첨<br/>+ itemName 중복 제외] E[로드아웃/후보 확정] end subgraph S2 [2단계 · 노출 · 루팅 시] F[슬롯별 노출률<br/>exposure × 수량스탯] G[항목별 노출 굴림] end subgraph S3 [3단계 · 품질 · 루팅 시] H[value로 등급 라벨 확정<br/>장비는 value별 개체] I[접사 굴림] J[스탯 분산] end K[시체 인벤토리 적재] A --> B --> C --> D --> E E -->|루팅| F --> G G -->|노출분만| H --> I --> J --> K classDef s1 fill:#ede9fe,stroke:#7c3aed,stroke-width:2px,color:#4c1d95 classDef s2 fill:#fed7aa,stroke:#ea580c,stroke-width:2px,color:#7c2d12 classDef s3 fill:#bbf7d0,stroke:#16a34a,stroke-width:2px,color:#14532d class A,B,C,D,E s1 class F,G s2 class H,I,J s3
각 단계는 독립적으로 밸런싱·디버그·테스트된다. 한 단계의 버그가 다른 단계로 번지지 않는다.
4. AS-IS → TO-BE (개념 변화)
섹션 제목: “4. AS-IS → TO-BE (개념 변화)”각 변화가 무엇을 어떻게 바꾸고 왜 그런지를 정리한다. 실제 시트 컬럼 before/after는 §5.
4.1 개수 결정 — 2단 변환 폐기
섹션 제목: “4.1 개수 결정 — 2단 변환 폐기”| AS-IS | TO-BE | |
|---|---|---|
| 방식 | 값 → tier → 개수 2단 변환 | 수치셋에 개수를 직접 입력 |
| 예 | dropEquipKindsValue=350 → tier 3 → 무기 1개 | weaponCnt = 1 |
| 일괄 조정 | tier 변환표 수정 | 드랍 수치셋 공유로 대체 |
왜: 추상값→tier 변환이 입력과 결과의 인과를 끊어 밸런싱 예측이 불가능했다. 직접 입력은 “적은 값 = 결과”라 인과가 보인다. 전 몹 일괄 조정은 변환표가 아니라 여러 몹이 같은 수치셋을 참조하는 방식으로 해결한다.
4.2 worthRarity 한 축 → value + dropWeight 두 축
섹션 제목: “4.2 worthRarity 한 축 → value + dropWeight 두 축”AS-IS의 worthRarity 하나가 두 가지를 겸해 충돌했다.
| 겸하던 역할 | TO-BE 분리 |
|---|---|
| ① 가치 게이트 (valueCap이 자르는 기준) | value |
② 추첨 가중치 (1/worthRarity) | dropWeight |
왜: “자주 나오게” 하려고 worth를 낮추면 게이트(가치 상한)가 같이 풀려 “싼 몹도 줄 수 있게” 돼버렸다. 두 손잡이를 찢어야 “흔하지만 값진 것”, “드물지만 싼 것”을 자유롭게 표현한다.
4.3 등급 — 별도 굴림 → value 구간 라벨 (장비)
섹션 제목: “4.3 등급 — 별도 굴림 → value 구간 라벨 (장비)”| AS-IS | TO-BE | |
|---|---|---|
| 등급 결정 | dropGradeValue → tier → 등급 굴림 + 행운 +등급 | value 구간이 곧 등급 (별도 굴림 없음) |
| 같은 무기의 고급 버전 | 단일 아이템에 등급만 다르게 굴림 | value별 별개 아이템(녹슨도끼_저급/고급) |
| 행운(Luck) 역할 | 등급 직접 +1 | valueCap 상향 → 더 높은 value(=고등급) 후보 진입 |
왜: 등급을 별도 축으로 두면 “가치”와 “등급”이 따로 놀아 또 손잡이가 엉킨다. 등급을 value 구간의 라벨로 정의하면 (value 100~300=Common, 300~700=Rare…) value 하나가 가치·등급·게이트를 일관되게 담당한다. 행운은 등급을 직접 올리는 대신 상한을 열어 고가치(=고등급) 아이템이 후보에 들어오게 한다 → “운 좋으면 더 좋은 게 나온다”가 자연 성립.
4.4 잡템 단일 풀 → 카테고리별 개수 분리
섹션 제목: “4.4 잡템 단일 풀 → 카테고리별 개수 분리”| AS-IS | TO-BE | |
|---|---|---|
| 풀 구성 | Utility+Material+Accessory+… 한 통 | 카테고리별 풀 분리 |
| 개수 | miscCnt 하나 | utilityCnt / materialCnt / accessoryCnt 각각 |
왜: 한 통에 섞어 추첨하면 등록 수 많은 카테고리(재료)가 독점해 장신구는 안 나왔다. 카테고리별 개수를 따로 두면 “이 몹은 약초 위주, 장신구는 가끔”이 컨트롤된다.
4.5 100% 노출 → 슬롯별 노출 굴림
섹션 제목: “4.5 100% 노출 → 슬롯별 노출 굴림”| AS-IS | TO-BE | |
|---|---|---|
| 노출 | 후보 전체 100% 적재 | 슬롯별 exposure × 수량스탯, 항목별 굴림 |
| 수량(Quantity) 역할 | 없음 | 노출률 보정 (부피 = 얼마나 많이 드러나나) |
왜: 노출 단계가 없어 착용분이 전부 떨어졌다. 슬롯별 차등 노출로 “무기는 귀하게, 잡템은 흔하게”를 만들고, 수량 스탯이 노출량을 끌어올려 빌드 의미를 부여한다. (루팅 UI가 인벤토리 팝업이라 노출 실패분이 “보이는데 못 줍는” 부정합을 만들지 않음 — §0)
4.6 비스택 칸 복제 → 스택 분배에서 제외
섹션 제목: “4.6 비스택 칸 복제 → 스택 분배에서 제외”| AS-IS | TO-BE | |
|---|---|---|
stack=1 처리 | 스택 포인트 배정 시 새 칸 복제 (빗자루 5개) | 스택 분배 대상에서 제외, 1개 고정 |
| 중복 제거 기준 | (잡템) 누락 | itemName 기준 중복 제외 |
왜: 스택 로직이 비스택 아이템을 구분 못 해 칸을 복제했다. stack=1은 분배에서 빼고, 같은 종류 반복은 itemName으로 막는다.
4.7 스탯 역할 정리 (요약)
섹션 제목: “4.7 스탯 역할 정리 (요약)”| 스탯 | AS-IS | TO-BE |
|---|---|---|
| 수량(Quantity) | 미사용/혼재 | 노출량 (부피) |
| 행운(Luck) | 등급 직접 +1 | valueCap 상향 (고가치=고등급 후보 허용) |
→ 두 스탯이 각각 노출과 가치상한을 담당해 역할이 직교한다.
5. 테이블 구조 변경 (Before / After)
섹션 제목: “5. 테이블 구조 변경 (Before / After)”실제 시트 컬럼이 무엇이 생기고 사라지는지. 개념적 “왜”는 §4.
5.1 몹 시트
섹션 제목: “5.1 몹 시트”| Before | After | |
|---|---|---|
| 드랍 정의 | dropWorthValue, dropEquipKindsValue, dropPartsRateValue, dropMiscKindsValue, dropGradeValue, dropMoneyValue, dropStackCountValue, dropStackCountAlpha (8값) | dropSetId (수치셋 참조 1개) |
| 태그 | weaponQueryTags·mainPartsQueryTags·subPartsQueryTags·armorQueryTags·miscQueryTags (5분리) | dropTags (의미 태그 1통합) |
| 특수 | — | signatureDropId (선택, §8) |
→ 몹 한 줄이 13컬럼 → 2~3컬럼. 카테고리 분기는 enum이 하므로 태그 쿼리를 카테고리별로 쪼갤 필요 없음 (태그 시스템).
5.2 드랍 수치셋 시트 (신규)
섹션 제목: “5.2 드랍 수치셋 시트 (신규)”몹이 dropSetId로 참조하는 프리셋. 내용은 전부 숫자, 이름만 식별 문자열.
| 그룹 | 컬럼 | 의미 |
|---|---|---|
| 식별 | setId | 수치셋 이름 ("잡병_경장") |
| 개수 | weaponCnt / armorCnt / accessoryCnt / utilityCnt / materialCnt (각 min~max) | 카테고리별 등장 종류 수 |
| 돈 | moneyDrop (min~max) | 돈 양 범위 |
| 가치상한 | valueCap | 후보 value 상한 (= 등급 상한) |
| 노출 | exposureWeapon / exposureArmor / exposureAccessory / exposureUtility / exposureMaterial / exposureMoney (%) | 카테고리별 노출 확률 |
| 스택 | stackTotal / stackAlpha | 스택 분배 곡선 (stack>1 한정) |
5.3 아이템 시트
섹션 제목: “5.3 아이템 시트”| Before | After | |
|---|---|---|
| 가치/등급/빈도 | worthRarity (1개, 게이트+가중 겸함) | value (가치=등급 라벨) + dropWeight (출현 빈도) |
| 등급 | (드랍 시 굴림) | 장비: value 구간 파생 / 잡템·재료: 고유 고정 |
| 태그 | EntityTags | entityTags (가족별: Area/Force/Location/Type) |
| 스택 | stack | stack (유지, 1=비스택) |
5.4 보정 곡선 시트
섹션 제목: “5.4 보정 곡선 시트”| 컬럼 | 의미 |
|---|---|
quantityToExposure | 수량 스탯 → 노출 배수 (§8 미정 곡선) |
luckToValueCap | 행운 스탯 → valueCap 상향량 |
valueToGrade | value 구간 → 등급 라벨 매핑 (흰/녹/청/…) |
5.5 폐기되는 것
섹션 제목: “5.5 폐기되는 것”ConfigManager.GetTierFrom*Value,Get*DropKinds— tier 2단 변환 전부.dropGradeValue → tier → 등급 굴림경로.- 단일 잡템 풀(
miscQueryTags통합 추첨). Corpse.Setup의 무조건 100% 적재.
6. 수치 정의 사전
섹션 제목: “6. 수치 정의 사전”각 컬럼이 정확히 무엇을 조정하는지 1:1로 정의한다.
6.1 드랍 수치셋
섹션 제목: “6.1 드랍 수치셋”setId "잡병_경장" # 수치셋 식별 이름(문자열). 몹이 dropSetId로 참조.
# [개수] 카테고리별로 몇 종류를 생성할지 (총 개수 아님 — 종류 수)weaponCnt 1~1 # 무기 종류 수. 최소 1 보장(항상 무기 1개 착용).armorCnt 1~2 # 방어구 부위 수 (Head/Torso/…중 몇 부위).accessoryCnt 0~1 # 장신구 종류 수.utilityCnt 0~2 # 소모품 종류 수.materialCnt 1~3 # 재료 종류 수.moneyDrop 0~30 # 돈 양 범위(종류 아님, 금액).
# [가치 상한] 이 몹이 줄 수 있는 가치/등급의 천장valueCap 350 # 후보 아이템 value가 이 값 이하만 후보 진입. # = 등급 상한 (value 구간이 등급이므로). # 행운 스탯이 런타임에 이 값을 일시 상향.
# [노출] 생성된 후보 중 실제 시체에 드러낼 확률 (%)exposureWeapon 25exposureArmor 45exposureAccessory 40exposureUtility 80exposureMaterial 80exposureMoney 100 # 돈은 항상이면 100. # 최종 = 위 값 × 플레이어 수량배수, 0~100% clamp.
# [스택] stack>1 아이템을 몇 개씩 쌓을지stackTotal 200 # 스택 분배 총량.stackAlpha 0.5 # 분배 곡선 계수(쏠림 vs 분산). # stack=1(빗자루 등)은 분배 제외, 1개 고정.6.2 아이템
섹션 제목: “6.2 아이템”value 350 # 이 아이템의 가치. valueCap이 자르는 기준이자 등급 라벨의 근거. # value 구간 → 등급(흰/녹/청…). 장비는 등급 버전별 별개 행. # 잡템·재료는 고유 고정값(등급 라벨 안 씀).dropWeight 80 # 후보 풀에서 뽑힐 가중치. value와 무관하게 출현 빈도만 조절. # 높을수록 자주 등장.entityTags # 의미 태그(가족별). 몹 dropTags와 매칭(같은가족 OR/다른가족 AND).stack 1 # 한 칸 최대 스택. 1이면 비스택 → 스택 분배 제외.6.3 플레이어 스탯
섹션 제목: “6.3 플레이어 스탯”Quantity # 수량. 노출 배수를 끌어올림(부피). 가치·등급엔 관여 안 함.Luck # 행운. valueCap을 일시 상향 → 더 값진(고등급) 후보 진입.7. 드랍 플로우 (구체 예시)
섹션 제목: “7. 드랍 플로우 (구체 예시)”실제 숫자를 끝까지 추적한다. 추상 흐름은 §3 개념도.
전제 데이터
몹: 산적_Lv3 → dropSetId="잡병_경장", dropTags=Force:Outlaw, Area:Mountain수치셋 "잡병_경장": weaponCnt 1 / armorCnt 1~2 / utilityCnt 0~2 / materialCnt 1~3 / valueCap 350 / exposure 무25·방45·잡80 / stack 200·0.5플레이어: Quantity → 노출 ×1.2, Luck → valueCap +50
아이템: 녹슨도끼_저급 Weapon/Axe value=120 weight=80 tags=Force:Outlaw stack=1 산적두건 Armor/Head value=80 weight=60 tags=Force:Outlaw,Area:Mountain stack=1 가죽갑옷 Armor/Torso value=150 weight=40 tags=Force:Outlaw stack=1 들꽃 Material value=20 weight=100 tags=Area:Mountain stack=20 빗자루 Utility value=30 weight=50 tags=(없음) stack=1 금반지 Accessory value=500 weight=10 tags=Type:Valuable stack=17-① 생성 (스폰 시)
섹션 제목: “7-① 생성 (스폰 시)”개수 굴림: weapon 1, armor 2(Head/Torso), utility 1, material 1valueCap = 350 + Luck보정 50 = 400
무기 슬롯: 카테고리 분기 → Weapon 풀 태그 매칭: dropTags(Force:Outlaw, Area:Mountain) ↔ 녹슨도끼(Force:Outlaw) Force: Outlaw∩Outlaw 통과 / Area: 도끼 빈칸 → 통과 → 매칭 ✓ valueCap: 120 ≤ 400 ✓ dropWeight 가중 추첨 → 녹슨도끼_저급방어구 ×2: 산적두건(80✓), 가죽갑옷(150✓) → 둘 다 통과, itemName 중복 아님재료 ×1: 들꽃(20✓)소모품 ×1: 빗자루(30✓)금반지: value 500 > 400 → 컷 (이 몹은 그만큼 값진 건 안 줌)
→ 로드아웃: 녹슨도끼, 산적두건, 가죽갑옷, 들꽃, 빗자루7-② 노출 (루팅 시, 항목별 굴림)
섹션 제목: “7-② 노출 (루팅 시, 항목별 굴림)”무기 25%×1.2=30% → 녹슨도끼 굴림 → 실패 ✗방어구 45%×1.2=54% → 산적두건 ✓ / 가죽갑옷 ✗재료 80%×1.2=96% → 들꽃 ✓소모품 80%×1.2=96% → 빗자루 ✓→ 노출: 산적두건, 들꽃, 빗자루 (녹슨도끼·가죽갑옷 은닉=소멸)7-③ 수량 / 스택 (노출분 중 stack>1만)
섹션 제목: “7-③ 수량 / 스택 (노출분 중 stack>1만)”들꽃 stack=20 → stackTotal 200·alpha 0.5로 누적 → ×7빗자루 stack=1 → 비스택 → 분배 제외, ×1 고정산적두건 stack=1 → ×17-④ 품질 (노출분 개별)
섹션 제목: “7-④ 품질 (노출분 개별)”산적두건(장비): value 80 → 등급 라벨 = (구간표 기준) Common 접사 굴림: ItemAffixTable(Armor/Head, value대) → 접사 1~2개 스탯 분산 적용들꽃·빗자루(잡템): 등급 고유 고정, 접사 없음최종 시체 인벤토리: 산적두건(Common·접사), 들꽃 ×7, 빗자루 ×1
→ 무기는 은닉돼 안 나왔지만 방어구·재료 확보. “도끼까지 나왔으면…” 하는 아쉬움이 다음 사냥 동기. 무장한 몹(무기 착용 외형)을 우선 노리는 정보 기반 플레이가 생긴다.
8. 열린 질문 / 후속 결정
섹션 제목: “8. 열린 질문 / 후속 결정”| 항목 | 내용 |
|---|---|
| 접사 굴림 범위 | 등급(value) 고정인데 접사는 드랍 시 굴린다(인스턴스 다양성). 접사 개수·값 범위의 구체 규칙 미정. |
| 수량→노출 곡선 | quantityToExposure 함수 형태 미정 (수량 100이 ×몇인지). 밸런싱 단계. |
| 행운→valueCap 곡선 | luckToValueCap 상향량 곡선 미정. |
| value→등급 구간표 | 어느 value가 흰/녹/청/…인지 매핑 미정. |
| 상자·낱개 노출 | 100% vs 몹과 같은 노출 굴림. |
| 시그니처 드랍 | 별도 DropRule 레이어로 분리. 보이는 장비면 착용 강제 + 노출 우회. 세부 미정. |
| 무기 후보 0개 폴백 | weaponCnt 최소 1인데 태그+컷 통과 무기가 없을 때 처리 (맨손 vs 태그 완화). |
| 마이그레이션 | 신규 경로 병렬 신설 → 몹 전환 → 상자/맵 → tier 함수 제거 순. |