Skip to content

Proposal: add a shared encounter participation and reward-attribution ledger #23

Description

@zoeyrose

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

Implement a bounded Go encounter ledger keyed by stable entity/player identities with immutable purpose-specific eligibility snapshots and idempotent completion events. Preserve all disclosure and anti-exploit rules.

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

Add one bounded, server-authoritative encounter ledger that records who caused and meaningfully participated in a hostile encounter, then make reward, quest, reputation, metric, and anti-leech policies consume that evidence.

Today attack_kill() credits the final hitter/owner, party XP is shared with same-map members, and the was_provoked marker is only a coarse flag. This is insufficient for group bosses, assists, pet/projectile/status ownership, luring penalties, support contribution, and consistent quest or achievement credit.

This issue owns the reusable evidence and eligibility layer. atrinik/atrinik#148 remains the narrower policy for splitting one credited player's existing combat-skill XP across the skills that dealt damage.

Existing foundations

  • server/src/server/attack.c already resolves hitter ownership, observes post-mitigation damage in attack_hit(), and centralizes kill handling in attack_kill().
  • share_kill_exp() already has party membership and same-map eligibility.
  • Monster runtime state has an appropriate disposable owner in monster_data_t.
  • Object references already pair pointers with count/generation values to reject reused slots.
  • Projectiles, spells, pets, traps, diseases, and delayed effects already carry owner relationships, although the propagation rules need auditing.
  • Faction kill handling already distinguishes was_provoked from an ordinary kill.

Proposed model

Encounter identity and lifecycle

Create an encounter record owned by the hostile head object or its monster runtime data. It starts on an authoritative provocation, aggro acquisition, or effective hostile action and receives a monotonic encounter ID for diagnostics.

End or reset it on death, destruction, map teardown, a documented full-reset/de-aggro condition, or an inactivity deadline. Transforming or multipart monsters must explicitly retain or replace the record; they must never duplicate awards.

Bounded participant evidence

Key participants by validated player object reference plus generation. Resolve pets, projectiles, traps, spells, reflected attacks, and status effects to an originating player and action source before recording evidence.

The MVP should record:

Later support evidence can add effective healing, damage prevented, control, dispels, and revives only after each has an authoritative definition. Do not award credit for spam, overhealing, passive proximity, or merely joining a party.

Use a fixed small participant table with deterministic eviction/rejection rules and clear diagnostics rather than an unbounded event log.

Separate evidence from policy

Expose helpers that evaluate a snapshot of encounter evidence for a named purpose:

  • kill and assist metrics;
  • XP and loot eligibility;
  • quest/boss completion;
  • achievements and hunting-journal discoveries;
  • faction/reputation consequences;
  • named elite and group encounter rewards.

Each policy declares thresholds for contribution, recency, distance, alive/disconnected state, party membership, and minimum participation. The shared ledger must not hard-code a single universal threshold.

Provocation and luring provenance

Replace the one-bit was_provoked interpretation with causal provenance:

  • who first performed an intentional hostile action;
  • who caused the hostile to acquire or retain a protected target;
  • whether forced movement, charm, pet control, or scripted behavior changed the pursuit;
  • when the causal chain expired or was superseded.

This gives atrinik/atrinik#17 enough evidence to penalize deliberate luring into a faction area without blaming bystanders, victims, ordinary path crossings, or a player who only defended the settlement.

Events and consumers

Emit one idempotent encounter-completed event containing stable encounter subject IDs and eligible participant IDs. Metrics (#123), achievements (#125), rare encounters (#137/#140), quests, and the hunting journal (#150) should consume that event rather than independently inspecting the final hit.

Delivery plan

  1. Audit owner/action-source propagation for every damage path.
  2. Add encounter lifecycle and a bounded effective-damage/provocation ledger to monster runtime state.
  3. Make Credit combat skill XP from meaningful damage contribution atrinik#148 use the per-skill slice of the shared ledger.
  4. Introduce purpose-specific eligibility helpers and completion events.
  5. Migrate kill metrics, quests, achievements, named encounters, and faction luring policy.
  6. Add support-role evidence only alongside concrete support mechanics.

Acceptance criteria

  • Direct, projectile, spell, pet, trap, reflected, and delayed effects have explicit tested attribution.
  • Effective damage is post-mitigation, capped at remaining HP, and cannot count twice.
  • Object reuse, reconnect, transformation, multipart death, despawn, and map teardown cannot inherit or duplicate credit.
  • Encounter reset and expiry use deterministic deadlines.
  • Reward policies consume immutable evidence and declare their own eligibility thresholds.
  • Same-party proximity alone does not grant contribution credit.
  • Credit combat skill XP from meaningful damage contribution atrinik#148 can split a player's skill award from the same ledger without inflating the encounter pool.
  • Luring enemies to factions should lose reputation atrinik#17 can distinguish deliberate luring from defense, incidental proximity, and unaffiliated monster movement.
  • Completion events are idempotent and suitable for Implement QUIC transport, sessions, and authentication #33/#125/#137/#140/#150.

Validation

Add focused server tests for solo and party combat, multiple skills, pets/projectiles/status damage, healing/reset, reconnect, out-of-range participants, lure chains, protected-area entry, object generation reuse, transformations, multipart monsters, and duplicate death callbacks. Assert both positive eligibility and anti-leech rejection.

Related: atrinik/atrinik#17, #33, #31, #30, atrinik/content#23, atrinik/content#22, atrinik/atrinik#148, #24.

Absorbed faction-luring policy

This issue absorbs atrinik/atrinik#17 as the first faction-policy consumer of encounter provenance. Deliberately causing hostile faction enemies to acquire or retain targets inside a protected faction area must apply a bounded, idempotent reputation penalty to the responsible player. Defense of the settlement, incidental proximity/path crossing, ordinary monster movement, forced movement without player causation, and unaffiliated bystanders must not be penalized. The policy must declare protected areas/factions, causal expiry, repeated-lure bounds, party/pet/charm attribution, and operator diagnostics.

Delivered contribution slice

atrinik/atrinik#148's current effective-damage contribution and proportional combat-skill XP behavior was delivered by atrinik/atrinik#172. Preserve and migrate that implementation into this shared encounter lifecycle rather than rebuilding a second tracker. Remaining activity-specific award policy is coordinated with #7.

Metadata

Metadata

Assignees

No one assigned

    Fields

    Priority

    None yet

    Start date

    None yet

    Target date

    None yet

    Effort

    None yet

    Projects

    Status
    Backlog

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions