/** * One indivisible reward to distribute among participants — an opaque result id (a rolled drop, a * currency bundle, a quest token) with an optional stack `count` and free-form `tags` for eligibility * and provenance. Allocation never interprets the id; generation (loot tables, roll formulas) owns * what it means, keeping the seam genre-agnostic. */ export interface RewardResult { id: string; count?: number; tags?: readonly string[]; } /** * A participant that may receive rewards — an opaque recipient id (player, team, party slot) with an * optional split `weight` (shared policy), eligibility `tags`, and an `eligible` gate. Ineligible * recipients are excluded before any allocation decision so they never perturb others' streams. */ export interface RewardRecipient { id: string; weight?: number; tags?: readonly string[]; eligible?: boolean; } /** The distribution policies allocation ships — each a distinct answer to "who gets this result". */ export type RewardPolicyKind = "instanced" | "shared" | "copy" | "roundRobin" | "assigned" | "claimed"; /** A `{ result, count }` slice of a reward — the unit shared pools and grants are expressed in. */ export interface RewardShare { result: string; count: number; } /** * An authoritative, serializable award of one result stack to one recipient — carries `via` (the * policy that produced it) and `private` (replication scope) so provenance and visibility survive * save/load and viewer projection. Applying a grant twice with the same identity is the caller's * idempotency contract; this seam only decides who is owed what. */ export interface RewardGrant { recipient: string; result: string; count: number; via: RewardPolicyKind; private: boolean; } /** * A serializable pool of results left open for later claiming — first-come contested drops or a * `reservedFor` personal reward. Tracks `eligible` claimants, optional `expiresAtMs`, and the * authoritative `claimedBy` winner so reconnect and duplicate-claim attempts resolve idempotently. */ export interface ClaimablePool { id: string; via: RewardPolicyKind; results: RewardShare[]; eligible: string[]; reservedFor: string | null; expiresAtMs: number | null; claimedBy: string | null; } /** How a `claimed` allocation exposes its pool: open first-come (`first`) or `reserved` to one recipient. */ export interface RewardClaimSpec { mode: "first" | "reserved"; reservedFor?: string; expiresAtMs?: number; } /** * The inputs one allocation pass consumes. `allocationSeed` governs distribution decisions * (ordering, round-robin rotation, remainder splits, reservation) while the separate optional * `generationSeed` seeds per-recipient `instanced` generation — keeping join order from perturbing * other players' rolls. Provide `results` for pre-rolled policies, `generate` for `instanced`, * `assignment` for `assigned`, and `claim` for `claimed`. */ export interface AllocationRequest { recipients: readonly RewardRecipient[]; allocationSeed: string | number; generationSeed?: string | number; results?: readonly RewardResult[]; generate?: (rng: () => number, recipient: RewardRecipient) => readonly RewardResult[]; assignment?: Record; claim?: RewardClaimSpec; nowMs?: number; private?: boolean; } /** The serializable result of an allocation pass — immediate `grants` plus any deferred `pools`. */ export interface AllocationOutcome { grants: RewardGrant[]; pools: ClaimablePool[]; } /** The outcome of a claim attempt — the updated pool and the grants owed (empty when the claim is refused). */ export interface ClaimOutcome { pool: ClaimablePool; grants: RewardGrant[]; } /** * Allocate reward results among participants under a named policy, returning immediate grants and/or * claimable pools. Distribution is deterministic and serializable: the same seeds, recipients, and * results yield an identical outcome on host and every peer regardless of join order, so allocation * replicates as data without re-rolling. Reward *generation* stays upstream (loot tables, roll * formulas); this seam only decides who is owed what. * * @capability reward-allocation distribute reward results among multiplayer participants deterministically */ export declare function allocateRewards(kind: RewardPolicyKind, request: AllocationRequest): AllocationOutcome; /** * Resolve an authoritative claim against a pool. Idempotent: re-claiming an already-owned pool returns * the same grants without re-awarding, a losing claimant gets no grants, and eligibility, reservation, * and expiry are all enforced here — the authority, not UI hiding, decides ownership. Returns the * updated (serializable) pool plus the grants owed. * * @capability reward-allocation resolve idempotent authoritative claims against a reward pool */ export declare function resolveClaim(pool: ClaimablePool, claimantId: string, options?: { nowMs?: number; private?: boolean; }): ClaimOutcome; /** * Project an allocation outcome for one viewer, enforcing replication authoritatively: private grants * belonging to other recipients are dropped, and pools the viewer cannot claim (not eligible, or * reserved for someone else) are hidden — so private rewards never leak across the wire while * provenance on the viewer's own grants is preserved. * * @capability reward-allocation filter reward grants and pools to a viewer so private rewards never leak */ export declare function filterOutcomeFor(outcome: AllocationOutcome, viewerId: string): AllocationOutcome;