feat: equipment potential options — storage + granting - #3298
Open
ipdae wants to merge 2 commits into
Open
Conversation
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
force-pushed
the
feature/equipment-potential-grant
branch
from
July 30, 2026 08:41
9b82cf3 to
eb3cabc
Compare
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 layer —
EquipmentPotential+PotentialOptionSlotwith self-containedListserialization (its own version, independent ofItemBase.SerializationVersion). A singlePotentialfield is appended toEquipmentas an optional trailing field (index 23);EQUIPMENT_FIELD_COUNTis kept, so pre-existing equipment (23-field list or legacy Dictionary) deserializes toEquipmentPotential.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) andEquipmentPotentialOptionPoolSheet(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.GrantEquipmentPotentialaction — 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 viaEquipment.SetPotential. Re-running re-rolls and re-charges (does not accumulate slots), matching the spec's cube re-roll loop.Testing
Equipment, and the productionItemFactory.Deserializepath for every equipment sub type, plus legacy List (23-field) and Dictionary formats.ActionEvaluationTest(MessagePack round-trip).Both commits were reviewed by an automated code review; findings addressed.
Equipmentserialization gains a trailing field unconditionally (same pattern as prior added fields likeExp/IconId). This must ship in a coordinated release / hardfork so mixed-version nodes don't diverge on state root.PatchTableSheet) beforeGrantEquipmentPotentialis activated, or the action's sheet load will throw.Out of scope (follow-up)
Option resolution/application — turning stored
(optionRowId, value)into stat effects viaCharacterStats(rune-style modifier layer) andCPHelper, plus content-limited / skill effect kinds.🤖 Generated with Claude Code