import type { EntityPosition } from "../scene/entityStore.js"; import { type LootFilterItem, type LootFilterRule } from "./lootFilter.js"; import type { Drop } from "./lootTable.js"; /** Scene-entity catalog name every dropped-item instance spawns under (see the three buckets: worldItem is an entity, never an inventory item or object). */ export declare const WORLD_ITEM_ENTITY_NAME = "world_item"; export declare const DEFAULT_RARITY = "common"; export declare const DEFAULT_PICKUP_RADIUS = 2; export interface ScatterOptions { radius: number; minRadius?: number; height?: number; } export declare const DEFAULT_SCATTER: ScatterOptions; /** Random offset within an annulus `[minRadius, radius]` around the origin — the on-death scatter impulse. * @internal */ export declare function scatterOffset(rng: () => number, options?: ScatterOptions): EntityPosition; /** @internal */ export declare function scatterPosition(origin: EntityPosition, rng: () => number, options?: ScatterOptions): EntityPosition; export interface WorldItemRecord { instanceId: string; itemId: string; rarity: string; baseType: string; count: number; affixTier?: number; source?: string; droppedAt: number; } export interface WorldItemSpawnInput { itemId: string; position: EntityPosition; rarity?: string; baseType?: string; count?: number; affixTier?: number; source?: string; } export interface WorldItemStoreDeps { spawnEntity(position: EntityPosition): string; despawnEntity(instanceId: string): boolean; resolvePosition(instanceId: string): EntityPosition | undefined; now?(): number; } export interface WorldItemStore { spawn(input: WorldItemSpawnInput): WorldItemRecord; get(instanceId: string): WorldItemRecord | null; list(): readonly WorldItemRecord[]; nearestInRadius(from: EntityPosition, radius: number, filter?: (record: WorldItemRecord) => boolean): string | null; /** Detaches the record for a pickup: caller is expected to grant its contents (e.g. `loot.grantToPlayer`) itself. */ take(instanceId: string): WorldItemRecord | null; /** Consumes/destroys the record with no grant implied (decay, an explosion, a cleanup sweep) — same despawn path as `take`, leaves no orphaned record. */ remove(instanceId: string): WorldItemRecord | null; } /** Pure pickup-radius + nearest-item selection, usable without a live store (click-to-grab, proximity prompts). * @internal */ export declare function selectNearestWorldItem(candidates: readonly { instanceId: string; position: EntityPosition; }[], from: EntityPosition, radius: number): string | null; /** * Spawn and track pickup-able items scattered in the world, including drops that scatter on death. * * @internal */ export declare function createWorldItemStore(deps: WorldItemStoreDeps): WorldItemStore; export interface ResolveDeathDropsOptions { mode: "grant" | "world"; origin: EntityPosition; resolveRarity(itemId: string): string; resolveBaseType?(itemId: string): string; scatter?: ScatterOptions; rng?(): number; source?: string; } export interface ResolvedDeathDrops { worldSpawns: WorldItemSpawnInput[]; grants: Drop[]; } /** * Splits rolled death drops between direct grants and scattered ground items. * `mode: "grant"` is the legacy behavior (loot straight to inventory); `mode: * "world"` routes item drops through a scatter impulse and leaves currency * drops granting directly (coins fly to the killer, gear hits the ground). * @internal */ export declare function resolveDeathDrops(drops: readonly Drop[], options: ResolveDeathDropsOptions): ResolvedDeathDrops; /** * Per-rarity look of a dropped item: beam, color and label. Set via `defineGame({ worldItem: { rarityStyle } })`. * * @capability loot-beams rarity-colored loot beams and labels on dropped items via defineGame({ worldItem: { rarityStyle, beamHeight } }) */ export interface RarityStyle { color?: string; beam?: boolean; label?: string; } export interface WorldItemPresentation { hidden: boolean; color?: string; beam: boolean; label?: string; } /** * Composes the baseline rarity→beam/color/label render binding (#32, catalog * data the game supplies) with the loot-filter rule overrides (#33). A * matching rule wins field-by-field; unmatched fields fall back to the * rarity's baseline style. * @internal */ export declare function resolveWorldItemPresentation(item: LootFilterItem, rarityStyle: Record | undefined, rules: readonly LootFilterRule[] | undefined): WorldItemPresentation;