import type { InstalledPart, PartDef } from "./modularItem.js"; /** * The declarative identity of a built modular item: a caller-named family, its * provenance tags, and the parts occupying its slots. This is the "what an item * is" layer above the raw stat rollup in ./modularItem — a plain, serializable * value with no game noun baked in ("gun", "manufacturer", "potion" are all * caller data in `family`/`tags`). */ export interface ItemIdentity { family: string; tags: readonly string[]; parts: readonly InstalledPart[]; } /** * A predicate over an {@link ItemIdentity}, expressed as data so a whole rule * set round-trips through JSON. An empty query matches every identity; each * present field narrows the match and all present fields must hold (AND). */ export interface IdentityQuery { /** Match only this family id; omit to match any family. */ family?: string; /** Every listed tag must be present on the identity. */ allTags?: readonly string[]; /** At least one listed tag must be present on the identity. */ anyTags?: readonly string[]; /** A part of this category must occupy some slot. */ hasCategory?: string; /** A part with this id must occupy some slot. */ hasPart?: string; } /** * A rule that requires a second condition to hold whenever the first matches — * e.g. "a scoped rifle requires a stock". Checked at completeness time, not * during incremental placement, because the `then` side may be satisfied by a * part chosen later in a generation pass. */ export interface RequireRule { id: string; kind: "require"; when: IdentityQuery; then: IdentityQuery; message?: string; } /** * A rule that forbids a combination — e.g. "an incendiary barrel cannot pair * with a cryo core". A forbid rule can never become satisfiable by adding more * parts, so it is the check a backtracking generator runs on each candidate. */ export interface ForbidRule { id: string; kind: "forbid"; when: IdentityQuery; forbid: IdentityQuery; message?: string; } /** * A cross-slot compatibility rule constraining which part/tag/family * combinations a modular item may hold. */ export type CompatibilityRule = RequireRule | ForbidRule; /** * A match/set bonus: extra stats granted when enough parts (or a tag) of a * given kind are present — e.g. "3 Blackwood parts grant +recoil control". * Counting is declarative (`countBy`/`value`) so the whole catalog is data. */ export interface SetBonus { id: string; /** Dimension counted for membership: a part category, a part id, or an identity tag. */ countBy: "category" | "partId" | "tag"; /** The value counted; membership is the number of matching parts (or 0/1 for a tag). */ value: string; /** Minimum matching count for the bonus to activate. */ min: number; /** Additive stat deltas applied when the bonus is active. */ stats: Record; /** Optional name fragment recorded in provenance/UI when active. */ namePart?: string; } /** * One failed {@link CompatibilityRule}, carrying the rule id, its kind, and a * human-readable message for UI or generator diagnostics. */ export interface ConstraintViolation { ruleId: string; kind: "require" | "forbid"; message: string; } /** * A part proposed for a slot during generation, before it is committed to an * identity. Used by the backtracking contract to test a placement in isolation. */ export interface CandidatePlacement { slotId: string; part: PartDef; } /** * The serializable record of how an item was generated: its family, tags, * per-slot part selection, applied set-bonus ids, and the deterministic seed. * Enough for UI provenance display and byte-exact regeneration. */ export interface ItemProvenance { family: string; tags: readonly string[]; /** slotId -> partId of the selected parts. */ parts: Readonly>; /** Ids of the set bonuses that were active, for display and re-derivation. */ bonuses: readonly string[]; /** Seed of the roll that produced this item; omit for hand-authored items. */ seed?: number; } /** * Assemble an {@link ItemIdentity} from a family, tags, and installed parts. * * @capability item-identity assemble a serializable modular-item identity from family, tags, and installed parts */ export declare function identityOf(family: string, tags: readonly string[], parts: readonly InstalledPart[]): ItemIdentity; /** * Test whether an identity satisfies a declarative {@link IdentityQuery}. * * @capability item-identity evaluate a data-defined compatibility query against a modular-item identity */ export declare function matchesQuery(identity: ItemIdentity, query: IdentityQuery): boolean; /** * Collect every compatibility rule a completed identity violates. An empty * result means the identity is legal. * * @capability item-identity validate a completed modular item against its compatibility rule set */ export declare function validateIdentity(identity: ItemIdentity, rules: readonly CompatibilityRule[]): ConstraintViolation[]; /** * Convenience predicate: true when {@link validateIdentity} finds no violations. * * @capability item-identity check whether a completed modular item is compatibility-valid */ export declare function isIdentityValid(identity: ItemIdentity, rules: readonly CompatibilityRule[]): boolean; /** * The generic backtracking contract for procedural generation (see #908): given * a partial identity and a candidate part, return the first forbid rule the * placement would violate, or null if it stays viable. Require rules are ignored * here because they may still be satisfied by a later placement. * * @capability item-identity test a candidate part placement against forbid rules for generation backtracking */ export declare function candidateViolatesForbid(partial: ItemIdentity, candidate: CandidatePlacement, rules: readonly CompatibilityRule[]): ForbidRule | null; /** * Count how many parts (or tags) contribute to a set bonus on an identity. * * @capability item-identity count set-bonus membership across an item's parts and tags */ export declare function countSetMembers(identity: ItemIdentity, bonus: SetBonus): number; /** * Select the set bonuses whose membership count meets their threshold, in the * order they were declared. * * @capability item-identity resolve which match/set bonuses an item qualifies for */ export declare function activeSetBonuses(identity: ItemIdentity, bonuses: readonly SetBonus[]): SetBonus[]; /** * Fold a set of active bonuses' additive stats onto a stat map, returning a new * map (the input is not mutated). * * @capability item-identity apply active set-bonus stats onto an item's resolved stats */ export declare function applySetBonuses(stats: Record, bonuses: readonly SetBonus[]): Record; /** * Capture the provenance of a generated item — family, tags, per-slot parts, * active bonus ids, and optional seed — as a JSON-safe record. * * @capability item-identity capture serializable provenance for UI display and deterministic regeneration */ export declare function captureProvenance(identity: ItemIdentity, activeBonuses: readonly SetBonus[], seed?: number): ItemProvenance;