콘텐츠로 이동
GameDesign

드랍 시스템 (신규 제안) 초안미구현밸런싱미완료

본 문서는 아이템 드랍을 코드 베이스를 무시하고 새로 설계한 제안서다. 현재 구현의 구조적 문제(100% 드랍, 같은 아이템 폭주, 밸런싱 불가)는 패치로 덧대기 어렵고 구조에서 비롯되므로, 이상적인 모델을 먼저 정의하고 코드를 거기에 맞춘다.

현재 구현의 진단·버그 목록은 아이템·루팅·드랍 “코드–기획 불일치” 절 참조. 태그 연계는 태그 시스템.

항목내용
적용 대상몹 드랍 우선. 상자·낱개 아이템은 같은 3단계를 공유하되 1단계(착용) 대신 그룹 정의를 쓴다 (§6, 후속 전환).
전투력과 무관몹 전투력은 MonsterStat이 결정한다. 착용 장비는 전투 스탯에 영향을 주지 않는다. 장비 역할은 외형·루팅 후보뿐. “강한 몹”은 MonsterStat로, “좋은 걸 주는 몹”은 드랍 수치셋으로 따로 만든다.
루팅 UI시체 루팅은 인벤토리 팝업이다. 플레이어가 몹의 착용 부위를 1:1로 대조하지 못하므로, 노출 굴림에서 빠진 장비가 “보이는데 못 줍는” 부정합은 발생하지 않는다.
이 문서가 엎는 것기존 (monsterType, level) → 8개 값 → tier 2단 변환 → 개수, worthRarity 단일 축, 단일 잡템 풀, 100% 노출.

현재 구조는 (monsterType, level)로 시트에서 8개 값 + 5개 태그 쿼리를 뽑고, 각 값을 다시 tier로 변환해 개수를 정한다. 밸런싱이 통제 불가능한 이유는 다음과 같다.

#문제결과
12단 변환 (값 → tier → 개수)디자이너가 “무기 1개”를 직접 못 적고 350 같은 추상값을 역산. 값을 바꿔도 결과 예측 불가.
2손잡이 엉킴dropEquipKindsValue 하나가 무기·방어구 개수를 동시에 좌우. 독립 조정 불가.
3worthRarity 한 축에 게이트+가중 혼재”자주 나오게” 하려고 worth를 낮추면 “싼 몹도 줄 수 있게” 게이트가 같이 풀림. 두 의도 충돌.
4단일 잡템 풀Utility·Material·Accessory 등을 한 통에 섞어 추첨 → 등록 수 많은 카테고리가 독점(재료만 우수수, 장신구는 안 나옴).
5100% 노출노출 단계 자체가 없어 착용분이 전부 드랍. 익스트랙션의 “한 방” 긴장 소멸.
6비스택 칸 복제 버그스택 분배가 stack=1 아이템을 구분 못 해 빗자루가 한 시체에 5개로 복제.

핵심 진단: 개수는 과도하게 복잡(2단 변환)하고, 품질·노출은 과도하게 단순. 복잡도가 거꾸로 배치되어 있고, 한 숫자가 여러 일을 겸해 손잡이가 엉켜 있다.

세 가지 원칙으로 다시 짠다.

  1. 3단계 분리 — 생성(무엇을 가질 수 있나) → 노출(그중 얼마를 드러내나) → 품질(각각 어떤 옵션인가). 단계 간 손잡이가 섞이지 않는다.
  2. 축 직교화 — 손잡이 하나 = 효과 하나. 개수·가치·빈도·노출·상한을 각각 다른 컬럼이 담당.
  3. 직접 입력 — tier 2단 변환 폐기. 시트에 결과값(개수·확률)을 그대로 적는다. 일괄 조정은 “드랍 수치셋” 공유로 대체.
무엇을 조정손잡이누가 가짐
몇 종류 등장슬롯Count (카테고리별)드랍 수치셋
얼마나 값진 것까지 (=등급 상한)valueCap드랍 수치셋
자주/드물게 출현dropWeight아이템
그 아이템의 가치·등급value아이템
얼마나 드러나나exposure × 수량스탯수치셋 × 플레이어
운 좋으면 더 값진 것valueCap 보정행운스탯

등급은 컬럼이 아니다. value 구간을 사람이 읽기 쉽게 나눈 라벨(흰템/녹템/…)일 뿐. value가 오르면 자동으로 더 높은 등급으로 표시된다.

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

각 단계는 독립적으로 밸런싱·디버그·테스트된다. 한 단계의 버그가 다른 단계로 번지지 않는다.

각 변화가 무엇을 어떻게 바꾸고 왜 그런지를 정리한다. 실제 시트 컬럼 before/after는 §5.

AS-ISTO-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-ISTO-BE
등급 결정dropGradeValue → tier → 등급 굴림 + 행운 +등급value 구간이 곧 등급 (별도 굴림 없음)
같은 무기의 고급 버전단일 아이템에 등급만 다르게 굴림value별 별개 아이템(녹슨도끼_저급/고급)
행운(Luck) 역할등급 직접 +1valueCap 상향 → 더 높은 value(=고등급) 후보 진입

왜: 등급을 별도 축으로 두면 “가치”와 “등급”이 따로 놀아 또 손잡이가 엉킨다. 등급을 value 구간의 라벨로 정의하면 (value 100~300=Common, 300~700=Rare…) value 하나가 가치·등급·게이트를 일관되게 담당한다. 행운은 등급을 직접 올리는 대신 상한을 열어 고가치(=고등급) 아이템이 후보에 들어오게 한다 → “운 좋으면 더 좋은 게 나온다”가 자연 성립.

4.4 잡템 단일 풀 → 카테고리별 개수 분리

섹션 제목: “4.4 잡템 단일 풀 → 카테고리별 개수 분리”
AS-ISTO-BE
풀 구성Utility+Material+Accessory+… 한 통카테고리별 풀 분리
개수miscCnt 하나utilityCnt / materialCnt / accessoryCnt 각각

왜: 한 통에 섞어 추첨하면 등록 수 많은 카테고리(재료)가 독점해 장신구는 안 나왔다. 카테고리별 개수를 따로 두면 “이 몹은 약초 위주, 장신구는 가끔”이 컨트롤된다.

4.5 100% 노출 → 슬롯별 노출 굴림

섹션 제목: “4.5 100% 노출 → 슬롯별 노출 굴림”
AS-ISTO-BE
노출후보 전체 100% 적재슬롯별 exposure × 수량스탯, 항목별 굴림
수량(Quantity) 역할없음노출률 보정 (부피 = 얼마나 많이 드러나나)

왜: 노출 단계가 없어 착용분이 전부 떨어졌다. 슬롯별 차등 노출로 “무기는 귀하게, 잡템은 흔하게”를 만들고, 수량 스탯이 노출량을 끌어올려 빌드 의미를 부여한다. (루팅 UI가 인벤토리 팝업이라 노출 실패분이 “보이는데 못 줍는” 부정합을 만들지 않음 — §0)

4.6 비스택 칸 복제 → 스택 분배에서 제외

섹션 제목: “4.6 비스택 칸 복제 → 스택 분배에서 제외”
AS-ISTO-BE
stack=1 처리스택 포인트 배정 시 새 칸 복제 (빗자루 5개)스택 분배 대상에서 제외, 1개 고정
중복 제거 기준(잡템) 누락itemName 기준 중복 제외

왜: 스택 로직이 비스택 아이템을 구분 못 해 칸을 복제했다. stack=1은 분배에서 빼고, 같은 종류 반복은 itemName으로 막는다.

스탯AS-ISTO-BE
수량(Quantity)미사용/혼재노출량 (부피)
행운(Luck)등급 직접 +1valueCap 상향 (고가치=고등급 후보 허용)

→ 두 스탯이 각각 노출과 가치상한을 담당해 역할이 직교한다.

5. 테이블 구조 변경 (Before / After)

섹션 제목: “5. 테이블 구조 변경 (Before / After)”

실제 시트 컬럼이 무엇이 생기고 사라지는지. 개념적 “왜”는 §4.

BeforeAfter
드랍 정의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이 하므로 태그 쿼리를 카테고리별로 쪼갤 필요 없음 (태그 시스템).

몹이 dropSetId로 참조하는 프리셋. 내용은 전부 숫자, 이름만 식별 문자열.

그룹컬럼의미
식별setId수치셋 이름 ("잡병_경장")
개수weaponCnt / armorCnt / accessoryCnt / utilityCnt / materialCnt (각 min~max)카테고리별 등장 종류 수
moneyDrop (min~max)돈 양 범위
가치상한valueCap후보 value 상한 (= 등급 상한)
노출exposureWeapon / exposureArmor / exposureAccessory / exposureUtility / exposureMaterial / exposureMoney (%)카테고리별 노출 확률
스택stackTotal / stackAlpha스택 분배 곡선 (stack>1 한정)
BeforeAfter
가치/등급/빈도worthRarity (1개, 게이트+가중 겸함)value (가치=등급 라벨) + dropWeight (출현 빈도)
등급(드랍 시 굴림)장비: value 구간 파생 / 잡템·재료: 고유 고정
태그EntityTagsentityTags (가족별: Area/Force/Location/Type)
스택stackstack (유지, 1=비스택)
컬럼의미
quantityToExposure수량 스탯 → 노출 배수 (§8 미정 곡선)
luckToValueCap행운 스탯 → valueCap 상향량
valueToGradevalue 구간 → 등급 라벨 매핑 (흰/녹/청/…)
  • ConfigManager.GetTierFrom*Value, Get*DropKinds — tier 2단 변환 전부.
  • dropGradeValue → tier → 등급 굴림 경로.
  • 단일 잡템 풀(miscQueryTags 통합 추첨).
  • Corpse.Setup의 무조건 100% 적재.

각 컬럼이 정확히 무엇을 조정하는지 1: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 25
exposureArmor 45
exposureAccessory 40
exposureUtility 80
exposureMaterial 80
exposureMoney 100 # 돈은 항상이면 100.
# 최종 = 위 값 × 플레이어 수량배수, 0~100% clamp.
# [스택] stack>1 아이템을 몇 개씩 쌓을지
stackTotal 200 # 스택 분배 총량.
stackAlpha 0.5 # 분배 곡선 계수(쏠림 vs 분산).
# stack=1(빗자루 등)은 분배 제외, 1개 고정.
value 350 # 이 아이템의 가치. valueCap이 자르는 기준이자 등급 라벨의 근거.
# value 구간 → 등급(흰/녹/청…). 장비는 등급 버전별 별개 행.
# 잡템·재료는 고유 고정값(등급 라벨 안 씀).
dropWeight 80 # 후보 풀에서 뽑힐 가중치. value와 무관하게 출현 빈도만 조절.
# 높을수록 자주 등장.
entityTags # 의미 태그(가족별). 몹 dropTags와 매칭(같은가족 OR/다른가족 AND).
stack 1 # 한 칸 최대 스택. 1이면 비스택 → 스택 분배 제외.
Quantity # 수량. 노출 배수를 끌어올림(부피). 가치·등급엔 관여 안 함.
Luck # 행운. valueCap을 일시 상향 → 더 값진(고등급) 후보 진입.

실제 숫자를 끝까지 추적한다. 추상 흐름은 §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=1
개수 굴림: weapon 1, armor 2(Head/Torso), utility 1, material 1
valueCap = 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 → ×1
산적두건(장비): value 80 → 등급 라벨 = (구간표 기준) Common
접사 굴림: ItemAffixTable(Armor/Head, value대) → 접사 1~2개
스탯 분산 적용
들꽃·빗자루(잡템): 등급 고유 고정, 접사 없음

최종 시체 인벤토리: 산적두건(Common·접사), 들꽃 ×7, 빗자루 ×1

→ 무기는 은닉돼 안 나왔지만 방어구·재료 확보. “도끼까지 나왔으면…” 하는 아쉬움이 다음 사냥 동기. 무장한 몹(무기 착용 외형)을 우선 노리는 정보 기반 플레이가 생긴다.

항목내용
접사 굴림 범위등급(value) 고정인데 접사는 드랍 시 굴린다(인스턴스 다양성). 접사 개수·값 범위의 구체 규칙 미정.
수량→노출 곡선quantityToExposure 함수 형태 미정 (수량 100이 ×몇인지). 밸런싱 단계.
행운→valueCap 곡선luckToValueCap 상향량 곡선 미정.
value→등급 구간표어느 value가 흰/녹/청/…인지 매핑 미정.
상자·낱개 노출100% vs 몹과 같은 노출 굴림.
시그니처 드랍별도 DropRule 레이어로 분리. 보이는 장비면 착용 강제 + 노출 우회. 세부 미정.
무기 후보 0개 폴백weaponCnt 최소 1인데 태그+컷 통과 무기가 없을 때 처리 (맨손 vs 태그 완화).
마이그레이션신규 경로 병렬 신설 → 몹 전환 → 상자/맵 → tier 함수 제거 순.