Skip to content

feat: equipment potential options — storage + granting - #3298

Open
ipdae wants to merge 2 commits into
developmentfrom
feature/equipment-potential-grant
Open

feat: equipment potential options — storage + granting#3298
ipdae wants to merge 2 commits into
developmentfrom
feature/equipment-potential-grant

Conversation

@ipdae

@ipdae ipdae commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds the equipment potential option (장비 잠재 옵션) feature to lib9c, as an independent latent-option layer stored directly on Equipment (rather than a separate account state). This PR covers storage + granting; option interpretation/application to stats/CP is intentionally a later phase.

Design plan: 장비 잠재 옵션 — 부여 구현 계획 (lib9c) · Reference spec: 장비 잠재 옵션 시스템 기획 v1

Commits

1. Storage layerEquipmentPotential + PotentialOptionSlot with self-contained List serialization (its own version, independent of ItemBase.SerializationVersion). A single Potential field is appended to Equipment as an optional trailing field (index 23); EQUIPMENT_FIELD_COUNT is kept, so pre-existing equipment (23-field list or legacy Dictionary) deserializes to EquipmentPotential.Empty (no migration). Each slot stores only (int OptionRowId, long Value), neutral to how it is later applied. The 7 equipment subclasses inherit serialization unchanged.

2. Granting pipeline

  • EquipmentPotentialGradeSheet (grade → slot count + material cost) and EquipmentPotentialOptionPoolSheet (weighted option pool per equipment sub type), with CSVs.
  • PotentialHelper.Roll — deterministic weighted selection from the pool (filtered by sub type) with an inclusive value roll.
  • GrantEquipmentPotential action — validates ownership / sub type (Weapon/Armor/Belt/Necklace/Ring; Aura/Grimoire excluded) / grade, consumes the per-grade material cost, rolls the grade's slot count, and stores the result via Equipment.SetPotential. Re-running re-rolls and re-charges (does not accumulate slots), matching the spec's cube re-roll loop.

Testing

  • Storage: present/absent round-trips across the model, direct Equipment, and the production ItemFactory.Deserialize path for every equipment sub type, plus legacy List (23-field) and Dictionary formats.
  • Grant: success, insufficient material, ineligible sub type, grade without slots, item not owned, re-grant overwrite + recharge, determinism, and a golden roll-output test that locks the algorithm against consensus-breaking changes.
  • Action registered in ActionEvaluationTest (MessagePack round-trip).
  • ✅ Full suite: 3718 passed / 6 skipped; build + docs checks pass.

Both commits were reviewed by an automated code review; findings addressed.

⚠️ Deployment notes

  • The Equipment serialization gains a trailing field unconditionally (same pattern as prior added fields like Exp/IconId). This must ship in a coordinated release / hardfork so mixed-version nodes don't diverge on state root.
  • The two new table sheets must be present in on-chain state (genesis / PatchTableSheet) before GrantEquipmentPotential is activated, or the action's sheet load will throw.

Out of scope (follow-up)

Option resolution/application — turning stored (optionRowId, value) into stat effects via CharacterStats (rune-style modifier layer) and CPHelper, plus content-limited / skill effect kinds.

🤖 Generated with Claude Code

Introduce an independent latent-option ("potential") layer stored directly
on Equipment as an alternative to a separate account state. This phase
covers storage + serialization only; option interpretation/application
(stat and CP calculation) is intentionally out of scope.

- Add EquipmentPotential + PotentialOptionSlot with self-contained List
  serialization and its own version, so the potential schema can evolve
  independently of the shared ItemBase.SerializationVersion.
- Wire a single Potential field onto Equipment as an optional trailing
  field (index 23). EQUIPMENT_FIELD_COUNT (min 23) is intentionally kept,
  so equipment serialized before this change deserializes to
  EquipmentPotential.Empty (no migration required).
- Options are stored as (optionRowId, rolledValue), neutral with respect
  to how they are later applied.
- Tests cover present/absent cases across the model, direct Equipment, and
  the production ItemFactory.Deserialize path for every equipment subtype,
  plus legacy List (23 fields) and Dictionary formats.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ipdae
ipdae force-pushed the feature/equipment-potential-grant branch from 9b82cf3 to eb3cabc Compare July 30, 2026 08:41
Implements the granting phase of the equipment potential option feature on
top of the storage layer.

- Add EquipmentPotentialGradeSheet (grade -> slot count + material cost) and
  EquipmentPotentialOptionPoolSheet (weighted option pool per equipment sub
  type), with CSVs.
- Add PotentialHelper.Roll: deterministic weighted selection from the pool
  filtered by sub type, with an inclusive value roll.
- Add GrantEquipmentPotential action: validates ownership / sub type / grade,
  consumes the per-grade material cost, rolls the grade's slot count, and
  stores the result via Equipment.SetPotential. Re-running re-rolls and
  re-charges (it does not accumulate slots).
- Register the action in ActionEvaluationTest (MessagePack round-trip) and add
  the grade/pool sheet properties to the test TableSheets helper.
- Tests cover grant success, insufficient material, ineligible sub type, grade
  without slots, item not owned, re-grant overwrite, determinism, and a golden
  roll-output test that locks the algorithm against consensus-breaking changes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ipdae ipdae changed the title feat: add potential option layer to Equipment (grant-phase storage) feat: equipment potential options — storage + granting Aug 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant