Skip to content

Proposal: salvage & reforging — melt surplus gear into scraps, forge the piece you want (3:1) #156

Description

@milez770

남는 장비를 조각으로 녹이고, 원하는 장비를 벼린다 (3:1). English version below.

문제

REPEAT_FARMING.md 3부가 이미 지목한 문제다. 드랍이 유일한 출처인 장비(iron_sword, morningstar, steel_longsword, leather_armor, chain_mail)가 기본가 40%에 상인에게 팔려 소멸한다 — 23시간에 iron_sword만 893,000코퍼어치. 상인은 무에서 지불하므로 이것이 서버 최대 골드 파우셋이다. 같은 문서가 장터만으로는 흡수가 안 된다고 결론짓고(장비는 내구재, 수요는 하루 몇 개·공급은 수백 개), 우선순위까지 적었다: "저급 장비 소모처(분해·제련)가 장터보다 먼저."

이 이슈는 그 소모처의 구체 설계다. 신규 장비 0개, 채집 노드 0개, 레시피 표 0개 — 모든 수치가 이미 라이브인 basePrice에서 파생된다.

제안

행동 두 개:

  1. 분해 (Salvage) — 어디서나, 인벤토리 행동: 장비를 부수고 재질 조각을 받는다.
  2. 재련 (Reforge) — 대장장이 앞에서만: 같은 재질 대역의 조각 + 골드 수수료를 내고, 그 대역의 원하는 장비 하나를 받는다.

조각 아이템 (전부 스택형, basePrice 없음 — 상인이 안 사니 새 파우셋이 아니고, 가치는 사용처와 플레이어 거래에서 나온다):

조각 출처 / 재련 대상
Leather Scraps 가죽 장비 (가죽 세트 대역)
Crude Scraps 티어 1 잡무기 (goblin_sword, small_sword — 설명문부터 "crude")
Iron Scraps 철·체인 대역 (dagger, spear, morningstar, iron_sword, 철 투구·부츠, chain_mail)
Steel Scraps 강철·판금 대역 (steel_longsword, 판금 파츠, breastplate)
Wood / Cloth Scraps 목재·천 장비

금속 갈래는 코드에서 아이템 정체(세트 소속)로 파생한다. CSV material 컬럼은 건드리지 않는다 — material-impact-sounds.json이 그 값을 키로 쓴다.

수치 (초기 튜닝값 — 구현 상수, 플레이테스트 후 조정)

조각 1개 = 기본가 1,000코퍼(10실버)어치.

분해 산출  S = floor(basePrice / 1000)     — S = 0이면 분해 불가
재련 비용  C = 3 × S(산출물)
수수료     F = 산출물 basePrice의 10~20%, 골드 (소각)

1,000c 미만 아이템(torch, fishing_rod, greatclub, leather_belt)은 산출이 없어 분해가 거부된다 — 최소 1조각 규칙을 두면 상점 횃불 50c가 1,000c어치 제작력이 되는 무한 펌프가 열린다. floor만 쓰면 조각에 담긴 가치가 항상 출처 기본가 이하라 아래 손해 부등식이 전 구간에서 성립한다. 1,000c 단위 자체도 튜닝 레버다 (500c로 내리면 반올림 손실 절반, 수량 두 배).

장비 분해 재련 비용
dagger (2,500c) 철 2 철 6
iron_sword (10,000c) 철 10 철 30
chain_mail (25,000c) 철 25 철 75
steel_longsword (16,000c) 강철 16 강철 48
breastplate (40,000c) 강철 40 강철 120

장비 간 교환비는 표 없이 가격에서 나온다: chain_mail 하나 = 철 75조각 ≈ iron_sword 7.5자루 분해분 ≈ 같은 값 장비라면 "3개 녹여 1개". basePrice를 나중에 조정하면 분해 경제 전체가 자동으로 따라온다.

불변식 (서버 검증 — 인챈트 밴드 불변식과 같은 지위)

제1 규칙: 분해·재련을 어떤 순서로 합성해도 골드 가치는 절대 늘지 않는다. 분해는 정의상 손해이고, 유일한 이득은 종류다 — 원하는 장비를 손에 쥐는 것.

이를 강제하는 구조 보증 세 개:

  1. 조각 1개에는 항상 기본가 1,000c 이상이 담긴다 (S = floor, 올림 없음, 최소 1 규칙 없음).
  2. 꺼낼 때는 산출물 1,000c당 조각 3개를 요구한다 (C = 3 × S) + 골드 수수료.
  3. 조각은 basePrice가 없어 상인에게 현금화할 수 없다.

따름 성질들: 분해→재련 순환은 바퀴당 3분의 2 소멸 / 재련→상인 판매는 기본가 3V어치를 녹여 0.4V를 받는 경로라 항상 손해(재료를 그냥 팔았으면 1.2V) / 무가격 시작 장비(worn_*)는 분해 자체가 안 된다.

서버는 부팅 시 전 아이템 정의에 대해 보증을 검증한다 — 1000 × S(item) ≤ basePrice, C = 3 × S, 조각 무가격. 나중의 공식 수정이나 CSV 편집이 조용히 펌프를 다시 열 수 없다 (TRADE.md가 경고한 변환기 무음 통과 실패 모드).

경계

  • 재질 대역 잠금. 강철 장비는 강철 조각으로만, 강철 조각은 강철 장비에서만. ITEM_TIERS.md의 세트 사다리(가죽→철→강철)를 티어 숫자 없이 세계의 말로 인코딩한다.
  • 월드 드랍 전용 희소템 제외. 특수 망토·amulet_of_life_saving 등은 재련 목록에서 뺀다 — 유저 간 거래의 축으로 지정된 아이템들이다.
  • 분해 시 인챈트 소멸 (확인 대화상자, 보너스 조각 없음). 잘 키운 장비를 녹이는 것이 인챈트 파괴 싱크와 경쟁하면 안 된다.
  • 열린 논점 — 세트 완성. 재련은 "마지막 파츠 뽑기"를 우회할 수 있다 (Orc Warrens 철 파츠 셋을 녹여 안 나오던 chain_mail을 벼린다). 완화인지 침식인지는 저자 판단이다. 레버는 ×3 비율과, 필요하면 다음 티어 세트 핵심 파츠의 재련 제외.

경제 효과

  • 과잉이 드디어 탄다. +9 무기 캠페인의 기대 베이스가 steel_longsword 약 85자루(ENCHANT.md) — 판금 잡템 재련으로 대면 기본가 약 410만 코퍼어치가 녹고 수수료 13.6만~27.2만 코퍼가 소각된다. 인챈트 도전이 루팅 과잉의 최종 흡수처가 된다.
  • 최대 파우셋이 너프 없이 준다. 상인행 대신 녹는 잡템 1,000코퍼마다 무에서 찍힐 골드 400코퍼가 발행되지 않는다. 매입가를 건드릴 필요가 없다 — 분해가 유용성으로 경쟁한다.
  • 새 직접 골드 싱크 (수수료). DESIGN_DIRECTION.md가 정한 형태: 내구도가 아니라 수수료·서비스.
  • 장터가 제 역할을 얻는다. 조각이 "모두가 계속 쓰는 재료"다. 좌판·위탁은 이후 내구재가 아니라 재료를 거래하게 된다.
  • 범위 밖 후속 연결: 하우징의 스크롤+재료 구상과 GATHERING.md의 목재가 같은 조각을 소모할 수 있다.

대장장이

거주 LLM NPC(대장장이) 신설. 재련은 그 앞에서만 — 분해는 어디서나. 수수료는 기존 딜/검증 인프라에 태우고, 흥정은 평소처럼 서버 밴드 안이다. 에이전트 클라이언트에는 salvage_item / reforge_item을 같은 서버 검증으로 연다 (#104/#108/#127의 에이전트-사람 동등 원칙).

구현 순서

  1. 조각 아이템 정의, 분해 서버 경로 + 확인 대화상자, salvage_item 에이전트 액션.
  2. 대장장이 NPC(일과·초상·페르소나), 재련 서버 경로 + 수수료 소각 + 대역 잠금, reforge_item.
  3. 부팅 시 불변식 검증. 테스트: 3:1 순환 손실, 상인 판매 손해 부등식, worn_* 거부, 대역 잠금, 인챈트 확인, 희소템 제외.

전체든 일부든 구현까지 맡을 수 있다. 위 수치는 저자가 다시 정하기 위한 초기값이다.


English version

Problem

REPEAT_FARMING.md part 3 already names it: equipment whose only source is drops (iron_sword, morningstar, steel_longsword, leather_armor, chain_mail) ends up vendored at 40% of base price and destroyed — 893,000c of iron_sword alone in one 23-hour window. Merchants pay out of thin air, so this is the server's largest gold faucet. The doc also concludes a player market alone cannot absorb the surplus (gear is durable; demand is a few pieces a day, supply is hundreds), and sets the priority: "a consumer for low-grade gear (salvage or smelting) comes before the market."

This is a concrete design for that consumer. It adds no new equipment, no gathering nodes, and no recipe tables — every number derives from basePrice values that are already live.

Proposal

Two actions:

  1. Salvage (anywhere, inventory action): destroy a piece of equipment, receive material scraps.
  2. Reforge (at the blacksmith only): spend scraps of the same material band + a gold fee, receive one piece of gear of your choice from that band.

Scrap items (all stackable, no basePrice — merchants refuse them, so no new faucet; their value is use-value and player trade):

scrap comes from / forges
Leather Scraps leather gear (leather set band)
Crude Scraps tier-1 junk blades (goblin_sword, small_sword — already "crude" in their descriptions)
Iron Scraps iron/chain band (dagger, spear, morningstar, iron_sword, iron helm/boots, chain_mail)
Steel Scraps steel/plate band (steel_longsword, plate pieces, breastplate)
Wood / Cloth Scraps wooden and cloth gear

The metal split is derived in code from item identity (set membership); the CSV material column is untouched — material-impact-sounds.json keys on it.

Numbers (initial tuning; constants, adjust after playtest)

One scrap represents 1,000c (10s) of base price.

salvage yield  S = floor(basePrice / 1000)     — S = 0 means the item cannot be salvaged
reforge cost   C = 3 × S(output)
smith fee      F = 10–20% of output basePrice, in gold (burned)

Items under 1,000c (torch, fishing_rod, greatclub, leather_belt) yield nothing and are refused — a minimum-1 rule would turn a 50c shop torch into 1,000c of forging power, an infinite pump. With floor only, a scrap always embodies at most its source's base price, so the loss inequalities below hold everywhere. The 1,000c unit is itself a tuning lever (500c halves rounding loss, doubles stack counts).

item salvage reforge cost
dagger (2,500c) 2 iron 6 iron
iron_sword (10,000c) 10 iron 30 iron
chain_mail (25,000c) 25 iron 75 iron
steel_longsword (16,000c) 16 steel 48 steel
breastplate (40,000c) 40 steel 120 steel

Cross-item exchange rates fall out of prices with no table: one chain_mail costs 75 iron scraps ≈ 7.5 melted iron_swords ≈ "melt three of a kind to forge one" for same-priced gear. If basePrice is ever rebalanced, the whole salvage economy follows automatically.

Invariants (server-verified, like the enchant band invariant)

Master rule: no composition of salvage and reforge may ever increase gold value. Salvage is a loss by definition; the only gain is in kind — ending up holding the piece you wanted.

Three structural guarantees enforce it:

  1. A scrap always embodies at least 1,000c of melted base price (S = floor, never rounded up, no minimum-1).
  2. Forging demands three scraps per 1,000c of output (C = 3 × S), plus the gold fee.
  3. Scraps have no basePrice, so they cannot be cashed out at a merchant.

Consequences, each checkable in isolation: a salvage→reforge cycle loses two thirds per pass; reforge-to-vendor returns 0.4V for 3V of melted base price (vendoring the inputs directly would have paid 1.2V); unpriced starting gear (worn_*) cannot be salvaged at all.

The server asserts the guarantees at boot over every item definition — 1000 × S(item) ≤ basePrice, C = 3 × S, scrap defs priceless — so a later formula tweak or CSV edit cannot silently reopen a pump (the silent-pass converter failure mode TRADE.md warns about).

Boundaries

  • Material band lock. Steel gear needs Steel Scraps; Steel Scraps only come from steel gear. This encodes the tier ladder in the world's own language (leather → iron → steel, the set progression of ITEM_TIERS.md) without a tier number appearing anywhere.
  • World-drop-only rares excluded. Special capes, amulet_of_life_saving etc. stay out of the reforge list — ITEM_TIERS.md reserves them as the axis of player trading.
  • Enchantment is lost on salvage (confirm dialog; no bonus scraps). Melting a well-enchanted piece must never compete with the enchant-destruction sink.
  • Open point — set completion. Reforging can shortcut the "last missing piece" grind (melt three Orc Warrens iron pieces, forge the chain_mail you never rolled). Whether that is relief or erosion is your call; levers are the ×3 ratio and, if needed, excluding set-core pieces of the next tier.

Why this helps the economy

  • The surplus finally burns. A +9 weapon campaign expects ~85 base steel_longswords (ENCHANT.md); reforged from plate junk that is ~4.1M copper of base price melted, plus 136k–272k c of fees burned. The enchant challenge becomes the final absorber of loot oversupply.
  • The top faucet shrinks without a nerf. Every 1,000c of junk melted instead of vendored is 400c of thin-air gold never issued. Vendor prices need no change — salvage competes on usefulness.
  • A new direct gold sink (the fee), the form DESIGN_DIRECTION.md prescribes: fees and services, not durability.
  • The market gets its role. Scraps are the continuously-consumed commodity part 3 says a market needs; stalls/consignment can then trade materials rather than surplus durables.
  • Future hooks, not in scope: housing's planned scroll+materials model and GATHERING.md wood can consume the same scrap kinds.

The smith

A new resident LLM NPC (blacksmith). Reforging happens only in front of them — salvage works anywhere. The fee rides the existing deal/validation infrastructure; haggling stays inside the server band as usual. Agent clients get salvage_item / reforge_item with identical server validation (agent–human parity, as in #104/#108/#127).

Implementation sketch

  1. Scrap item definitions; salvage server path + confirm dialog; salvage_item agent action.
  2. Blacksmith NPC (schedule, portrait, persona); reforge server path + fee burn + band lock; reforge_item.
  3. Invariant checks at boot; tests: 3:1 cycle loss, vendor-loss inequality, worn_* refusal, band lock, enchant confirm, rare-list exclusion.

I'm happy to implement the whole thing, or any slice of it — numbers above are opening values for you to reset.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions