@jgengine/core 0.26.0 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +174 -0
- package/dist/ai/policeResponse.d.ts +253 -0
- package/dist/ai/policeResponse.js +421 -0
- package/dist/anim/actionLayer.d.ts +47 -0
- package/dist/anim/actionLayer.js +63 -0
- package/dist/anim/ikSolver.d.ts +14 -0
- package/dist/anim/ikSolver.js +37 -0
- package/dist/anim/locomotionGraph.d.ts +58 -3
- package/dist/anim/locomotionGraph.js +142 -15
- package/dist/anim/ragdollRig.d.ts +53 -0
- package/dist/anim/ragdollRig.js +132 -0
- package/dist/anim/skeletonStandard.d.ts +140 -0
- package/dist/anim/skeletonStandard.js +326 -0
- package/dist/combat/damageRuntime.d.ts +14 -1
- package/dist/combat/damageRuntime.js +62 -4
- package/dist/combat/death.js +7 -3
- package/dist/combat/deathReason.d.ts +7 -1
- package/dist/combat/effects.d.ts +25 -0
- package/dist/combat/effects.js +16 -0
- package/dist/combat/statusRuntime.d.ts +2 -0
- package/dist/combat/statusRuntime.js +1 -0
- package/dist/economy/loanBook.d.ts +182 -0
- package/dist/economy/loanBook.js +303 -0
- package/dist/economy/market.d.ts +161 -0
- package/dist/economy/market.js +248 -0
- package/dist/economy/transactionLedger.d.ts +162 -0
- package/dist/economy/transactionLedger.js +301 -0
- package/dist/editor/creatorStorage.js +3 -1
- package/dist/editor/simulation.d.ts +5 -2
- package/dist/editor/simulation.js +29 -19
- package/dist/game/cameraConfig.d.ts +14 -0
- package/dist/game/clipRoles.d.ts +5 -4
- package/dist/game/clipRoles.js +34 -4
- package/dist/game/events.d.ts +27 -0
- package/dist/game/gameSave.d.ts +142 -0
- package/dist/game/gameSave.js +174 -0
- package/dist/game/playableGame.d.ts +74 -6
- package/dist/game/saveSlotIndex.d.ts +54 -0
- package/dist/game/saveSlotIndex.js +71 -0
- package/dist/game/saveSlots.d.ts +2 -0
- package/dist/game/saveSlots.js +1 -1
- package/dist/game/saveStore.d.ts +8 -0
- package/dist/game/saveStore.js +16 -0
- package/dist/gameplay.d.ts +17 -2
- package/dist/gameplay.js +15 -0
- package/dist/inventory/carryLoad.d.ts +48 -0
- package/dist/inventory/carryLoad.js +44 -0
- package/dist/inventory/equipment.d.ts +95 -0
- package/dist/inventory/equipment.js +169 -0
- package/dist/inventory/inventoryModel.d.ts +15 -6
- package/dist/inventory/inventoryModel.js +54 -5
- package/dist/inventory/shapedGrid.d.ts +26 -0
- package/dist/inventory/shapedGrid.js +47 -0
- package/dist/loot/lootGen.d.ts +186 -0
- package/dist/loot/lootGen.js +437 -0
- package/dist/loot/lootWeapon.d.ts +35 -0
- package/dist/loot/lootWeapon.js +70 -0
- package/dist/meta/changelog.d.ts +1 -1
- package/dist/meta/changelog.js +156 -1
- package/dist/mission/compositions.d.ts +85 -0
- package/dist/mission/compositions.js +130 -0
- package/dist/mission/mission.d.ts +435 -0
- package/dist/mission/mission.js +770 -0
- package/dist/mission/triggers.d.ts +61 -0
- package/dist/mission/triggers.js +108 -0
- package/dist/nav/laneGraph.d.ts +178 -0
- package/dist/nav/laneGraph.js +671 -0
- package/dist/nav/traffic.d.ts +222 -0
- package/dist/nav/traffic.js +918 -0
- package/dist/physics/kinematicVehicle.d.ts +36 -0
- package/dist/physics/kinematicVehicle.js +15 -1
- package/dist/physics/vehicleDamage.d.ts +136 -0
- package/dist/physics/vehicleDamage.js +214 -0
- package/dist/physics/vehicleParts.d.ts +62 -0
- package/dist/physics/vehicleParts.js +65 -0
- package/dist/progression/gearScore.d.ts +56 -0
- package/dist/progression/gearScore.js +59 -0
- package/dist/progression/skillTree.d.ts +129 -0
- package/dist/progression/skillTree.js +265 -0
- package/dist/progression/xpCurve.d.ts +60 -0
- package/dist/progression/xpCurve.js +141 -0
- package/dist/runtime/context/combat.js +11 -0
- package/dist/scene/builtinSceneKinds.js +2 -0
- package/dist/settings/accessibilitySettings.d.ts +81 -0
- package/dist/settings/accessibilitySettings.js +152 -0
- package/dist/settings/graphicsProfile.d.ts +3 -0
- package/dist/settings/graphicsProfile.js +4 -0
- package/dist/settings/settingsModel.d.ts +1 -1
- package/dist/settings/settingsModel.js +1 -0
- package/dist/sim/nearAgents.d.ts +8 -1
- package/dist/sim/nearAgents.js +34 -17
- package/dist/sim/offScreen.d.ts +2 -1
- package/dist/sim/offScreen.js +14 -3
- package/dist/sim/population.d.ts +147 -0
- package/dist/sim/population.js +182 -0
- package/dist/sim/queue.d.ts +90 -0
- package/dist/sim/queue.js +171 -0
- package/dist/sim/rides.d.ts +287 -0
- package/dist/sim/rides.js +471 -0
- package/dist/sim/routine.js +19 -11
- package/dist/ui/loadingTips.d.ts +41 -0
- package/dist/ui/loadingTips.js +64 -0
- package/dist/ui/menuNav.d.ts +79 -0
- package/dist/ui/menuNav.js +147 -0
- package/dist/ui/menuTransition.d.ts +50 -0
- package/dist/ui/menuTransition.js +67 -0
- package/dist/ui.d.ts +2 -0
- package/dist/ui.js +2 -0
- package/dist/vfx/effectLibrary.d.ts +98 -0
- package/dist/vfx/effectLibrary.js +181 -0
- package/dist/vfx/particleBudget.d.ts +40 -0
- package/dist/vfx/particleBudget.js +39 -0
- package/dist/vfx/particleDirector.d.ts +16 -0
- package/dist/vfx/particleDirector.js +18 -0
- package/dist/world/authoredSimulation.js +7 -1
- package/dist/world/captureCamera.d.ts +30 -0
- package/dist/world/captureCamera.js +19 -0
- package/dist/world/decalKind.d.ts +48 -0
- package/dist/world/decalKind.js +86 -0
- package/dist/world/features.d.ts +18 -5
- package/dist/world/features.js +1 -0
- package/dist/world/grassKind.d.ts +5 -0
- package/dist/world/grassKind.js +3 -0
- package/dist/world/terraform.d.ts +8 -0
- package/dist/world/terrain.d.ts +1 -0
- package/dist/world/terrain.js +2 -0
- package/dist/world.d.ts +7 -2
- package/dist/world.js +5 -0
- package/package.json +1 -1
- package/skills/jgengine/api.md +2 -2
- package/skills/jgengine-combat/SKILL.md +9 -1
- package/skills/jgengine-combat/api.md +5 -4
- package/skills/jgengine-combat/reference.md +4 -0
- package/skills/jgengine-gameplay/SKILL.md +86 -0
- package/skills/jgengine-gameplay/api.md +485 -16
- package/skills/jgengine-gameplay/capabilities.md +131 -4
- package/skills/jgengine-gameplay/reference-systems.md +118 -0
- package/skills/jgengine-world/SKILL.md +8 -0
- package/skills/jgengine-world/api.md +243 -11
- package/skills/jgengine-world/capabilities.md +61 -1
- package/skills/jgengine-world/recipes/character-animation.md +25 -2
- package/skills/jgengine-world/recipes/vehicle-feel.md +5 -0
- package/skills/jgengine-world/reference.md +1 -1
|
@@ -79,6 +79,32 @@ export declare function findShapedPlacement<T>(grid: ShapedGrid<T>, footprint: F
|
|
|
79
79
|
* @capability shaped-grid a serializable inventory board with arbitrary cell footprints, rotation, overlap checks, and immutable placement
|
|
80
80
|
*/
|
|
81
81
|
export declare function placeShaped<T>(grid: ShapedGrid<T>, item: ShapedItem<T>, origin: Cell, rotation?: Rotation): ShapedResult<T>;
|
|
82
|
+
/**
|
|
83
|
+
* Why a first-fit placement failed: the footprint cannot fit an empty board at any offered rotation
|
|
84
|
+
* (`too-large`), the board is genuinely full (`no-space`), or the search hit its budget.
|
|
85
|
+
*/
|
|
86
|
+
export type ShapedFitRejection = "duplicate-id" | "invalid-footprint" | "too-large" | "no-space" | "budget-exceeded";
|
|
87
|
+
/** A placed board, or a refusal that names why the item does not fit. */
|
|
88
|
+
export type ShapedFitResult<T> = {
|
|
89
|
+
status: "ok";
|
|
90
|
+
grid: ShapedGrid<T>;
|
|
91
|
+
origin: Cell;
|
|
92
|
+
rotation: Rotation;
|
|
93
|
+
checks: number;
|
|
94
|
+
} | {
|
|
95
|
+
status: "rejected";
|
|
96
|
+
reason: ShapedFitRejection;
|
|
97
|
+
detail: string;
|
|
98
|
+
checks: number;
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* Place a shaped item at the first legal spot, or say why it does not fit. Distinguishes an item that
|
|
102
|
+
* can never fit the board (`too-large`, with its footprint and the board size in `detail`) from a full
|
|
103
|
+
* board (`no-space`) and an exhausted search (`budget-exceeded`, not a full bag).
|
|
104
|
+
*
|
|
105
|
+
* @capability shaped-placement place a shaped item at its first fit and name why it does not fit
|
|
106
|
+
*/
|
|
107
|
+
export declare function fitShapedItem<T>(grid: ShapedGrid<T>, item: ShapedItem<T>, options?: ShapedPlacementSearchOptions): ShapedFitResult<T>;
|
|
82
108
|
/**
|
|
83
109
|
* Remove one placement without mutating the source board.
|
|
84
110
|
* @capability shaped-grid a serializable inventory board with arbitrary cell footprints, rotation, overlap checks, and immutable placement
|
|
@@ -147,6 +147,53 @@ export function placeShaped(grid, item, origin, rotation = 0) {
|
|
|
147
147
|
};
|
|
148
148
|
return { status: "ok", grid: { ...grid, placements: [...grid.placements, placement] } };
|
|
149
149
|
}
|
|
150
|
+
function footprintBounds(footprint) {
|
|
151
|
+
let width = 0;
|
|
152
|
+
let height = 0;
|
|
153
|
+
for (const [c, r] of footprint) {
|
|
154
|
+
width = Math.max(width, c + 1);
|
|
155
|
+
height = Math.max(height, r + 1);
|
|
156
|
+
}
|
|
157
|
+
return { width, height };
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Place a shaped item at the first legal spot, or say why it does not fit. Distinguishes an item that
|
|
161
|
+
* can never fit the board (`too-large`, with its footprint and the board size in `detail`) from a full
|
|
162
|
+
* board (`no-space`) and an exhausted search (`budget-exceeded`, not a full bag).
|
|
163
|
+
*
|
|
164
|
+
* @capability shaped-placement place a shaped item at its first fit and name why it does not fit
|
|
165
|
+
*/
|
|
166
|
+
export function fitShapedItem(grid, item, options = {}) {
|
|
167
|
+
if (grid.placements.some((placement) => placement.id === item.id)) {
|
|
168
|
+
return { status: "rejected", reason: "duplicate-id", detail: `"${item.id}" is already placed`, checks: 0 };
|
|
169
|
+
}
|
|
170
|
+
if (!validFootprint(item.footprint)) {
|
|
171
|
+
return { status: "rejected", reason: "invalid-footprint", detail: `footprint has ${item.footprint.length} cell(s)`, checks: 0 };
|
|
172
|
+
}
|
|
173
|
+
const rotations = options.rotations ?? [0, 1, 2, 3];
|
|
174
|
+
const candidates = rotations.map((rotation) => ({ rotation, bounds: footprintBounds(rotateFootprint(item.footprint, rotation)) }));
|
|
175
|
+
const fitsEmptyBoard = candidates.filter(({ bounds }) => bounds.width <= grid.width && bounds.height <= grid.height);
|
|
176
|
+
if (fitsEmptyBoard.length === 0) {
|
|
177
|
+
const bounds = footprintBounds(normalizeFootprint(item.footprint));
|
|
178
|
+
return {
|
|
179
|
+
status: "rejected",
|
|
180
|
+
reason: "too-large",
|
|
181
|
+
detail: `a ${bounds.width}×${bounds.height} item does not fit a ${grid.width}×${grid.height} board`,
|
|
182
|
+
checks: 0,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
const fit = findShapedPlacement(grid, item.footprint, { ...options, rotations: fitsEmptyBoard.map((entry) => entry.rotation) });
|
|
186
|
+
if (fit.status !== "found") {
|
|
187
|
+
return fit.status === "budget-exceeded"
|
|
188
|
+
? { status: "rejected", reason: "budget-exceeded", detail: `search stopped after ${fit.checks} placements`, checks: fit.checks }
|
|
189
|
+
: { status: "rejected", reason: "no-space", detail: `every position is covered after ${fit.checks} placements`, checks: fit.checks };
|
|
190
|
+
}
|
|
191
|
+
const placed = placeShaped(grid, item, fit.origin, fit.rotation);
|
|
192
|
+
if (placed.status === "rejected") {
|
|
193
|
+
return { status: "rejected", reason: "no-space", detail: placed.reason, checks: fit.checks };
|
|
194
|
+
}
|
|
195
|
+
return { status: "ok", grid: placed.grid, origin: fit.origin, rotation: fit.rotation, checks: fit.checks };
|
|
196
|
+
}
|
|
150
197
|
/**
|
|
151
198
|
* Remove one placement without mutating the source board.
|
|
152
199
|
* @capability shaped-grid a serializable inventory board with arbitrary cell footprints, rotation, overlap checks, and immutable placement
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import type { AffixPool, ItemBaseDef, RarityTier, RolledAffix } from "../item/affix.js";
|
|
2
|
+
import { type MountSlotDef, type PartDef } from "../item/modularItem.js";
|
|
3
|
+
/** Cap on affixes one item may roll, so a bad catalog cannot make a drop cost unbounded work. */
|
|
4
|
+
export declare const MAX_LOOT_AFFIXES = 8;
|
|
5
|
+
/** A part a base can mount: its stats, a pick weight, and an optional word for the item name. */
|
|
6
|
+
export interface LootPartDef extends PartDef {
|
|
7
|
+
/** Relative pick weight among parts eligible for the same slot (default `1`). */
|
|
8
|
+
weight?: number;
|
|
9
|
+
/** Word this part adds to the generated name, e.g. `"Riveted"`. */
|
|
10
|
+
namePart?: string;
|
|
11
|
+
}
|
|
12
|
+
/** A base family (frame, housing, chassis — caller nouns) with its slots, stats and affix pools. */
|
|
13
|
+
export interface LootBaseDef extends ItemBaseDef {
|
|
14
|
+
/** Relative pick weight among bases a manufacturer can produce (default `1`). */
|
|
15
|
+
weight?: number;
|
|
16
|
+
/** Free-form tags for caller filters and UI. */
|
|
17
|
+
tags?: readonly string[];
|
|
18
|
+
/** Mount slots a roll fills; every declared slot receives one part. */
|
|
19
|
+
slots?: readonly MountSlotDef[];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* A maker with a stat personality: its mark goes in the name, `bias` shifts stats additively,
|
|
23
|
+
* `scale` multiplies them, and favored affix pools weigh more when this maker rolls the item.
|
|
24
|
+
*/
|
|
25
|
+
export interface LootManufacturerDef {
|
|
26
|
+
id: string;
|
|
27
|
+
/** The maker's mark as it reads in the item name. */
|
|
28
|
+
name: string;
|
|
29
|
+
/** Relative pick weight among manufacturers (default `1`). */
|
|
30
|
+
weight?: number;
|
|
31
|
+
/** Base ids this maker produces; omitted means every base. */
|
|
32
|
+
bases?: readonly string[];
|
|
33
|
+
/** Flat stat shifts applied after level scaling and rarity scaling. */
|
|
34
|
+
bias?: Readonly<Record<string, number>>;
|
|
35
|
+
/** Per-stat multipliers applied after `bias`. */
|
|
36
|
+
scale?: Readonly<Record<string, number>>;
|
|
37
|
+
/** Affix pool ids this maker favors. */
|
|
38
|
+
favoredPools?: readonly string[];
|
|
39
|
+
/** Weight multiplier for an affix from a favored pool (default `3`). */
|
|
40
|
+
favoredWeight?: number;
|
|
41
|
+
}
|
|
42
|
+
/** Everything a roll reads: bases, parts, affixes, rarity odds, makers and the level curve. */
|
|
43
|
+
export interface LootCatalog {
|
|
44
|
+
bases: readonly LootBaseDef[];
|
|
45
|
+
parts: readonly LootPartDef[];
|
|
46
|
+
pools: readonly AffixPool[];
|
|
47
|
+
rarities: readonly RarityTier[];
|
|
48
|
+
manufacturers: readonly LootManufacturerDef[];
|
|
49
|
+
/** `[level, multiplier]` points, linearly interpolated and clamped; omitted means no level scaling. */
|
|
50
|
+
levelScale?: readonly (readonly [number, number])[];
|
|
51
|
+
}
|
|
52
|
+
/** One part occupying one slot of a rolled item. */
|
|
53
|
+
export interface LootInstalledPart {
|
|
54
|
+
slotId: string;
|
|
55
|
+
partId: string;
|
|
56
|
+
category: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* One rolled item: the base, maker, rarity, level, composed name, chosen parts, rolled affixes and
|
|
60
|
+
* resolved stats. Plain JSON, so a save stores it and the instance registry can key it.
|
|
61
|
+
*/
|
|
62
|
+
export interface LootItem {
|
|
63
|
+
/** Base definition id; also the registry `baseId` a generated drop is stored under. */
|
|
64
|
+
baseId: string;
|
|
65
|
+
manufacturer: string;
|
|
66
|
+
rarity: string;
|
|
67
|
+
level: number;
|
|
68
|
+
name: string;
|
|
69
|
+
parts: readonly LootInstalledPart[];
|
|
70
|
+
affixes: readonly RolledAffix[];
|
|
71
|
+
stats: Readonly<Record<string, number>>;
|
|
72
|
+
}
|
|
73
|
+
/** Pin any part of a roll; omitted fields are drawn from the catalog. */
|
|
74
|
+
export interface LootRollOptions {
|
|
75
|
+
/** Item level, integer `>= 1` (default `1`). */
|
|
76
|
+
level?: number;
|
|
77
|
+
baseId?: string;
|
|
78
|
+
manufacturer?: string;
|
|
79
|
+
rarity?: string;
|
|
80
|
+
}
|
|
81
|
+
/** A defect found by {@link validateLootItem}. */
|
|
82
|
+
export type LootIssueCode = "invalid-level" | "unknown-base" | "unknown-manufacturer" | "manufacturer-base" | "unknown-rarity" | "duplicate-slot" | "unknown-slot" | "missing-slot-part" | "unknown-part" | "part-category" | "unknown-affix" | "duplicate-affix" | "invalid-affix" | "non-finite-stat" | "empty-name";
|
|
83
|
+
/** One reason a rolled item is not legal against its catalog, with the offending value named. */
|
|
84
|
+
export interface LootValidationIssue {
|
|
85
|
+
code: LootIssueCode;
|
|
86
|
+
detail: string;
|
|
87
|
+
}
|
|
88
|
+
/** A per-stat comparison entry; `delta` is `b - a`, so positive means the second item is larger. */
|
|
89
|
+
export interface LootStatDelta {
|
|
90
|
+
stat: string;
|
|
91
|
+
a: number;
|
|
92
|
+
b: number;
|
|
93
|
+
delta: number;
|
|
94
|
+
}
|
|
95
|
+
/** How two items compare: every stat delta plus one weighted score for each. */
|
|
96
|
+
export interface LootComparison {
|
|
97
|
+
/** Union of both items' stats, sorted by stat id. Missing stats count as `0`. */
|
|
98
|
+
deltas: readonly LootStatDelta[];
|
|
99
|
+
scoreA: number;
|
|
100
|
+
scoreB: number;
|
|
101
|
+
/** `scoreB - scoreA`. */
|
|
102
|
+
scoreDelta: number;
|
|
103
|
+
better: "a" | "b" | "equal";
|
|
104
|
+
}
|
|
105
|
+
/** Caller policy for the comparison score. */
|
|
106
|
+
export interface LootComparisonOptions {
|
|
107
|
+
/** Weight per stat in the score (default `1` each). */
|
|
108
|
+
weights?: Readonly<Record<string, number>>;
|
|
109
|
+
/** Stats where a smaller number is better, e.g. reload time; flips their score sign. */
|
|
110
|
+
lowerIsBetter?: readonly string[];
|
|
111
|
+
/** Score difference under which the items count as equal (default `1e-9`). */
|
|
112
|
+
tolerance?: number;
|
|
113
|
+
}
|
|
114
|
+
/** Saved counters of a {@link LootRoller}. */
|
|
115
|
+
export interface LootRollerState {
|
|
116
|
+
rolls: number;
|
|
117
|
+
byRarity: Readonly<Record<string, number>>;
|
|
118
|
+
}
|
|
119
|
+
/** Options for {@link createLootRoller}. */
|
|
120
|
+
export interface LootRollerOptions {
|
|
121
|
+
/** Register a devtools probe under this name reporting roll counts per rarity. */
|
|
122
|
+
devtoolsName?: string;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* A roll counter over one catalog: every roll goes through {@link rollLoot}, and the handle keeps
|
|
126
|
+
* counters (a distribution readout in the debug overlay) that snapshot and restore as plain data.
|
|
127
|
+
*/
|
|
128
|
+
export interface LootRoller {
|
|
129
|
+
roll(rng: () => number, options?: LootRollOptions): LootItem;
|
|
130
|
+
stats(): LootRollerState;
|
|
131
|
+
snapshot(): LootRollerState;
|
|
132
|
+
/** Replace counters; returns false without mutation when the state is malformed. */
|
|
133
|
+
restore(next: LootRollerState): boolean;
|
|
134
|
+
reset(): void;
|
|
135
|
+
/** Drop the devtools probe registered by `devtoolsName`. Safe to call twice. */
|
|
136
|
+
dispose(): void;
|
|
137
|
+
}
|
|
138
|
+
/** Check a catalog before rolling; throws `RangeError` naming the offending entry. */
|
|
139
|
+
export declare function assertLootCatalog(catalog: LootCatalog): void;
|
|
140
|
+
/** Stat multiplier at `level` from the catalog's level curve; `1` when the catalog declares none. */
|
|
141
|
+
export declare function lootLevelScale(catalog: LootCatalog, level: number): number;
|
|
142
|
+
/**
|
|
143
|
+
* Roll one item from a catalog: a base and maker, a weighted rarity, one part per slot, rarity-count
|
|
144
|
+
* affixes, level-scaled stats and a name composed from maker, rarity, part, affix words and base.
|
|
145
|
+
* Deterministic for a given `rng`; every field it reads is caller data. Validate a catalog built
|
|
146
|
+
* outside {@link createLootRoller} once with {@link assertLootCatalog} before rolling from it.
|
|
147
|
+
*
|
|
148
|
+
* @capability loot-generation roll a named item from bases, parts, affixes, rarity weights, manufacturer personalities and level scaling
|
|
149
|
+
*/
|
|
150
|
+
export declare function rollLoot(catalog: LootCatalog, rng: () => number, options?: LootRollOptions): LootItem;
|
|
151
|
+
/**
|
|
152
|
+
* Check one rolled item against its catalog: base, maker and rarity exist, every slot holds an
|
|
153
|
+
* eligible part, affixes belong to the base's pools, stats are finite and the item is named.
|
|
154
|
+
*
|
|
155
|
+
* @capability loot-validation check a rolled item against its catalog and report each defect with its code
|
|
156
|
+
*/
|
|
157
|
+
export declare function validateLootItem(item: LootItem, catalog: LootCatalog): LootValidationIssue[];
|
|
158
|
+
/**
|
|
159
|
+
* Per-stat weighted contribution: `value × weight`, negated for stats listed in `lowerIsBetter`.
|
|
160
|
+
* This is the single weight policy behind {@link scoreLootStats}, {@link compareLootItems} and a
|
|
161
|
+
* gear score, so an item and a whole loadout are never ranked by different arithmetic.
|
|
162
|
+
*
|
|
163
|
+
* @capability loot-score split one stat block into per-stat weighted contributions
|
|
164
|
+
*/
|
|
165
|
+
export declare function lootStatContributions(stats: Readonly<Record<string, number>>, options?: Pick<LootComparisonOptions, "weights" | "lowerIsBetter">): Record<string, number>;
|
|
166
|
+
/**
|
|
167
|
+
* One stat block's weighted score: the sum of `value × weight`, negated for stats listed in
|
|
168
|
+
* `lowerIsBetter`. Pair it with {@link lootStatContributions} when a caller also needs the split.
|
|
169
|
+
*
|
|
170
|
+
* @capability loot-score score one stat block with caller weights and lower-is-better stats
|
|
171
|
+
*/
|
|
172
|
+
export declare function scoreLootStats(stats: Readonly<Record<string, number>>, options?: Pick<LootComparisonOptions, "weights" | "lowerIsBetter">): number;
|
|
173
|
+
/**
|
|
174
|
+
* Compare two rolled items: every stat delta plus one weighted score for each, with caller-named
|
|
175
|
+
* weights and which stats read better when small.
|
|
176
|
+
*
|
|
177
|
+
* @capability loot-comparison compare two rolled items with per-stat deltas and a weighted score
|
|
178
|
+
*/
|
|
179
|
+
export declare function compareLootItems(a: LootItem, b: LootItem, options?: LootComparisonOptions): LootComparison;
|
|
180
|
+
/**
|
|
181
|
+
* Wrap a catalog in a roll counter: same results as {@link rollLoot}, plus counts by rarity for a
|
|
182
|
+
* debug overlay, snapshot/restore of those counts, and an optional devtools probe.
|
|
183
|
+
*
|
|
184
|
+
* @capability loot-roller roll items from one validated catalog while counting drops per rarity for a debug probe
|
|
185
|
+
*/
|
|
186
|
+
export declare function createLootRoller(catalog: LootCatalog, options?: LootRollerOptions): LootRoller;
|