You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Proposal: define activity-specific XP contracts for combat disciplines #7
This issue is implemented in the fresh MIT-licensed Go server under the replacement program. Its gameplay and content-design decisions remain authoritative. C, CPython, classic packet, file-path, and enum details in the preserved specification are historical evidence only; do not copy, translate, or structurally port GPL implementation code.
Replacement implementation contract
Preserve every activity-evidence and anti-farming rule. Implement a Go settlement policy over immutable participation snapshots from the encounter ledger; never calculate rewards from mutable current-skill state.
The server remains authoritative, consumes versioned compiled content, and exposes bounded generated Game Protocol 1 messages. Pure rules may use a specifically approved typed CEL environment. Starlark is not part of this issue unless the separate residual-scripting decision explicitly approves it.
Required verification
Preserve every observable rule, balance decision, disclosure boundary, and anti-exploit invariant from the specification below.
Add deterministic Go unit/property tests and wrapper-managed scenario coverage at the appropriate integration boundary.
Add bounded malformed-input and persistence-failure cases where this feature accepts content, network, or stored data.
Add Go/Rust protocol conformance fixtures for every new cross-process field; the client must not reconstruct authoritative rules from prose.
Demonstrate that implementation and tests contain no copied GPL source/test material and execute no runtime Python.
Preserved product/design specification and historical implementation notes
Summary
Replace the assumption that every trainable combat skill is the same kill-XP bar with explicit, activity-specific progression contracts.
The immediate player-facing change should remain the consolidation already owned by #18:
Melee Combat replaces slash, cleave, pierce, and impact weapon XP;
Archery replaces bow, crossbow, and sling XP;
Unarmed and Throwing remain separate because their equipment and action loops are materially different.
This issue owns the complementary decision: what evidence earns XP for each broad discipline, when it is settled, and how all awards remain within one bounded encounter budget. It does not duplicate #18's skill/content migration or #27's weapon profiles and technique trees.
Why change this
The current seven-way split rewards committing to an item taxonomy, not learning meaningfully different play:
114 authored weapon/launcher archetypes carry one-based numeric item_skill values: 105 melee weapons are divided across four damage-family skills and nine launchers across bow/crossbow/sling skills.
living_update_player() applies that one skill level directly to melee WC and damage; arrow_get_wc() and arrow_get_damage() do the equivalent for launchers.
skill_attack() changes chosen_skill from the equipped weapon, while attack_hit() records effective damage under that skill ID and award_kill_exp() settles proportional kill XP.
As a result, replacing a sword with an axe or a bow with a crossbow resets both accuracy/damage progression even though the core player action is unchanged.
Weapon identity should come from damage type, timing, ammunition, reach, shape, and the profiles/techniques in #27—not from making the player repeat the level curve.
Atrinik already has the beginnings of activity-specific progression: books award Literacy on a one-time meaningful read, traps award Find/Remove Traps on successful outcomes, FLAG_STAND_STILL excludes some skills from character XP, and trap XP contributes at a hard-coded 20%. The policy is simply implicit and scattered.
Proposed progression contracts
Every skill should declare or document all of the following:
its authoritative action/source identity;
the meaningful evidence it records;
the terminal event that settles XP;
eligibility, anti-repeat, and anti-farming rules;
its contribution to overall character XP;
which level-dependent mechanics it scales.
Initial contracts:
Discipline
Meaningful evidence
Settlement
Melee Combat
Effective, post-mitigation, non-overkill HP damage caused by an equipped melee weapon
Eligible encounter completion/kill
Archery
The same damage caused by a bow, crossbow, or sling projectile, attributed to the firing action rather than mutable chosen_skill
Eligible encounter completion/kill
Unarmed
Effective damage from an unarmed action
Eligible encounter completion/kill
Throwing
Effective damage from a thrown-object action
Eligible encounter completion/kill
Wizardry / Divine Magic
Effective hostile damage for offensive spells; later, explicitly bounded support evidence for spells whose purpose is healing, cleansing, protection, or control
Eligible encounter completion, never cast count
Magic Devices
The meaningful result caused through the device action; do not also credit the embedded spell's casting discipline
Eligible encounter completion or a one-shot validated device outcome
Literacy
First meaningful read/identification of eligible knowledge
Immediate one-shot success, as today
Find / Remove Traps
A genuine first find or successful disarm against an eligible trap
Immediate anti-reroll success, as today
Crafting skills
A valid completed output, bounded by recipe/input identity and difficulty
Successful completion, not attempts or elapsed time
Do not add a passive Defense skill to the current automatic block/absorb path. Per-block or per-damage-taken XP would reward standing in weak attacks, equipment swapping, and unattended play. If #27 later adds an intentional guard, parry, or interception action, record actual encounter-bound damage prevented and either credit its owning Melee/Unarmed discipline or justify a new discipline with an independent active loop.
Meditation likewise should not gain XP merely from elapsed idle time. Keep it fixed, milestone-trained, or redesign it around an active bounded decision before making it progressive.
Award and anti-farming rules
Record evidence during an encounter, but award only at an existing terminal success. Do not add per-hit, per-cast, per-block, or per-tick XP.
Start from one level-relative encounter award produced by calc_skill_exp() and divide that budget among eligible action sources. Mixed actions must never multiply the pool.
Preserve the current effective-damage rules: after protection/block/absorption, capped to remaining HP, with zero damage and overkill excluded.
Snapshot the initiating action source into projectiles and delayed effects. A later equipment or chosen_skill change must not redirect credit.
Grey/ineligible activity earns no XP and its share must not become bonus XP for another skill.
Support evidence, when implemented through Proposal: add a shared encounter participation and reward-attribution ledger #23, must be effective rather than attempted: no overhealing, redundant cleanse, repeated buff refresh, friendly/self-inflicted damage loops, passive proximity, or PvP trading. Cap support weight against hostile encounter output and the same total encounter budget.
Remove the unreachable two-hand/polearm enum entries unless a real progression loop is approved.
The legacy item packet already sends the referenced skill object's object ID, level, XP, and description rather than exposing item_skill as a wire enum. The basic consolidation therefore should not need a packet-version branch; later technique/tree UI remains owned by #27.
2. Generalize evidence and settlement
Current master already has a bounded combat_contribution_t list on the victim. attack_hit() records player generation, skill ID, and effective damage, and award_kill_exp() distributes the award across participating skills. Use this as the short-term seam and migrate it into #23's shared encounter ledger rather than adding a second tracker.
Replace reliance on mutable skill-object pointers with an explicit action-source/discipline ID captured when the action starts.
Make the settlement helper consume normalized evidence and a single documented XP budget.
Add typed evidence only alongside a real mechanic and its exploit tests; do not create a generic "activity points" counter that incomparable actions can spam.
Move character-XP weighting and progression flags out of special cases in skill_exp_to_character_exp() where practical. A small validated progression-policy table keyed by skill ID is sufficient; action-specific evidence should stay in the owning gameplay subsystem rather than becoming scriptable client input.
Validate every nonzero item_skill before indexing skill_ptr. Current paths such as manual_apply() assume the numeric content reference resolves and directly dereference it; consolidation is a good point to turn malformed content into a startup/collection error rather than a runtime crash.
4. Choose an intentional development-save policy
Do not sum the old nonlinear XP totals: that would create a large Melee/Archery level and double-count overall character progression. Because Atrinik has no compatibility baseline to preserve, the simplest policy is to reject/reset affected development saves. If a one-time conversion is specifically required, use the maximum absolute XP among the four melee skills and among the three launcher skills, remove the superseded skill objects, and recompute character XP from surviving skills. Document and test whichever policy is selected.
atrinik/atrinik#148's effective-damage contribution and proportional combat-skill award behavior was delivered by atrinik/atrinik#172. Treat it as the implementation baseline; this issue owns the broader activity-specific evidence, settlement, and bounded-budget contracts, while #23 owns the generalized encounter lifecycle and participant ledger.
Important
This issue is implemented in the fresh MIT-licensed Go server under the replacement program. Its gameplay and content-design decisions remain authoritative. C, CPython, classic packet, file-path, and enum details in the preserved specification are historical evidence only; do not copy, translate, or structurally port GPL implementation code.
Replacement implementation contract
Preserve every activity-evidence and anti-farming rule. Implement a Go settlement policy over immutable participation snapshots from the encounter ledger; never calculate rewards from mutable current-skill state.
The server remains authoritative, consumes versioned compiled content, and exposes bounded generated Game Protocol 1 messages. Pure rules may use a specifically approved typed CEL environment. Starlark is not part of this issue unless the separate residual-scripting decision explicitly approves it.
Required verification
Preserved product/design specification and historical implementation notes
Summary
Replace the assumption that every trainable combat skill is the same kill-XP bar with explicit, activity-specific progression contracts.
The immediate player-facing change should remain the consolidation already owned by #18:
Melee Combatreplaces slash, cleave, pierce, and impact weapon XP;Archeryreplaces bow, crossbow, and sling XP;This issue owns the complementary decision: what evidence earns XP for each broad discipline, when it is settled, and how all awards remain within one bounded encounter budget. It does not duplicate #18's skill/content migration or #27's weapon profiles and technique trees.
Why change this
The current seven-way split rewards committing to an item taxonomy, not learning meaningfully different play:
item_skillvalues: 105 melee weapons are divided across four damage-family skills and nine launchers across bow/crossbow/sling skills.living_update_player()applies that one skill level directly to melee WC and damage;arrow_get_wc()andarrow_get_damage()do the equivalent for launchers.skill_attack()changeschosen_skillfrom the equipped weapon, whileattack_hit()records effective damage under that skill ID andaward_kill_exp()settles proportional kill XP.Weapon identity should come from damage type, timing, ammunition, reach, shape, and the profiles/techniques in #27—not from making the player repeat the level curve.
Atrinik already has the beginnings of activity-specific progression: books award Literacy on a one-time meaningful read, traps award Find/Remove Traps on successful outcomes,
FLAG_STAND_STILLexcludes some skills from character XP, and trap XP contributes at a hard-coded 20%. The policy is simply implicit and scattered.Proposed progression contracts
Every skill should declare or document all of the following:
Initial contracts:
chosen_skillDo not add a passive Defense skill to the current automatic
block/absorbpath. Per-block or per-damage-taken XP would reward standing in weak attacks, equipment swapping, and unattended play. If #27 later adds an intentional guard, parry, or interception action, record actual encounter-bound damage prevented and either credit its owning Melee/Unarmed discipline or justify a new discipline with an independent active loop.Meditation likewise should not gain XP merely from elapsed idle time. Keep it fixed, milestone-trained, or redesign it around an active bounded decision before making it progressive.
Award and anti-farming rules
calc_skill_exp()and divide that budget among eligible action sources. Mixed actions must never multiply the pool.chosen_skillchange must not redirect credit.Implementation outline from the current codebase
1. Land the broad identities through #18
server/src/include/skills.handserver/src/include/skillist.hwithSK_MELEE_COMBATandSK_ARCHERY.arch/intern/skills/; remove the seven superseded archetypes/icons rather than retaining aliases.item_skill.SKILL_IS_MELEE,SKILL_IS_ARCHERY,bow_get_skill(), item filters/examination, tests, scripts, plugins, tools, tutorial text, and documentation.The legacy item packet already sends the referenced skill object's object ID, level, XP, and description rather than exposing
item_skillas a wire enum. The basic consolidation therefore should not need a packet-version branch; later technique/tree UI remains owned by #27.2. Generalize evidence and settlement
Current master already has a bounded
combat_contribution_tlist on the victim.attack_hit()records player generation, skill ID, and effective damage, andaward_kill_exp()distributes the award across participating skills. Use this as the short-term seam and migrate it into #23's shared encounter ledger rather than adding a second tracker.3. Make skill policy explicit
Move character-XP weighting and progression flags out of special cases in
skill_exp_to_character_exp()where practical. A small validated progression-policy table keyed by skill ID is sufficient; action-specific evidence should stay in the owning gameplay subsystem rather than becoming scriptable client input.Validate every nonzero
item_skillbefore indexingskill_ptr. Current paths such asmanual_apply()assume the numeric content reference resolves and directly dereference it; consolidation is a good point to turn malformed content into a startup/collection error rather than a runtime crash.4. Choose an intentional development-save policy
Do not sum the old nonlinear XP totals: that would create a large Melee/Archery level and double-count overall character progression. Because Atrinik has no compatibility baseline to preserve, the simplest policy is to reject/reset affected development saves. If a one-time conversion is specifically required, use the maximum absolute XP among the four melee skills and among the three launcher skills, remove the superseded skill objects, and recompute character XP from surviving skills. Document and test whichever policy is selected.
Acceptance criteria
item_skillresolves to a valid skill; malformed references fail validation safely.Validation
item_skillvalues.Relationships
Delivered contribution baseline
atrinik/atrinik#148's effective-damage contribution and proportional combat-skill award behavior was delivered by atrinik/atrinik#172. Treat it as the implementation baseline; this issue owns the broader activity-specific evidence, settlement, and bounded-budget contracts, while #23 owns the generalized encounter lifecycle and participant ledger.