@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
|
@@ -36,12 +36,15 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
36
36
|
|
|
37
37
|
- `cancelJob` (function) · `import { cancelJob } from "@jgengine/core/gameplay"`
|
|
38
38
|
|
|
39
|
-
## carry-encumbrance —
|
|
39
|
+
## carry-encumbrance — gate a pickup against the carrier's remaining capacity
|
|
40
40
|
|
|
41
|
+
- `canCarry` (function) · `import { canCarry } from "@jgengine/core/inventory/carryLoad"`
|
|
42
|
+
- `characterLoad` (function) · `import { characterLoad } from "@jgengine/core/inventory/carryLoad"`
|
|
41
43
|
- `resolveEncumbrance` (function) · `import { resolveEncumbrance } from "@jgengine/core/inventory/encumbrance"`
|
|
42
44
|
|
|
43
|
-
## carry-load —
|
|
45
|
+
## carry-load — read carried stacks out of one or more inventories for a weight query
|
|
44
46
|
|
|
47
|
+
- `carriedEntries` (function) · `import { carriedEntries } from "@jgengine/core/inventory/carryLoad"`
|
|
45
48
|
- `totalLoad` (function) · `import { totalLoad } from "@jgengine/core/inventory/encumbrance"`
|
|
46
49
|
|
|
47
50
|
## cell-grid — immutable 2D board of cells with row clears, gravity collapse, and match runs
|
|
@@ -148,6 +151,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
148
151
|
|
|
149
152
|
- `enqueue` (function) · `import { enqueue } from "@jgengine/core/gameplay"`
|
|
150
153
|
|
|
154
|
+
## equipment-slot-inventory — wear gear by slot with item-kind rules, two-handed blocking and replace-on-equip
|
|
155
|
+
|
|
156
|
+
- `createEquipment` (function) · `import { createEquipment } from "@jgengine/core/inventory/equipment"`
|
|
157
|
+
|
|
151
158
|
## event-bus — typed publish/subscribe bus for gameplay events
|
|
152
159
|
|
|
153
160
|
- `createGameEvents` (function) · `import { createGameEvents } from "@jgengine/core/gameplay"`
|
|
@@ -180,14 +187,23 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
180
187
|
|
|
181
188
|
- `ActionCodesMap` (type) · `import { ActionCodesMap } from "@jgengine/core/gameplay"`
|
|
182
189
|
|
|
183
|
-
## game-save — save
|
|
190
|
+
## game-save — one versioned save document with per-system sections, named slots, caller-policy autosave, migration and a state digest
|
|
184
191
|
|
|
192
|
+
- `createGameSave` (function) · `import { createGameSave } from "@jgengine/core/gameplay"`
|
|
185
193
|
- `createSaveStore` (function) · `import { createSaveStore } from "@jgengine/core/gameplay"`
|
|
186
194
|
|
|
195
|
+
## game-save-digest — hash a save document's state for a determinism test or a diff
|
|
196
|
+
|
|
197
|
+
- `gameSaveDigest` (function) · `import { gameSaveDigest } from "@jgengine/core/gameplay"`
|
|
198
|
+
|
|
187
199
|
## game-system — declare a composable capability with its own schedule and lifecycle
|
|
188
200
|
|
|
189
201
|
- `SystemDefinition` (interface) · `import { SystemDefinition } from "@jgengine/core/gameplay"`
|
|
190
202
|
|
|
203
|
+
## gear-score — score a loadout from stat weights, level, rarity and slot coverage
|
|
204
|
+
|
|
205
|
+
- `gearScore` (function) · `import { gearScore } from "@jgengine/core/gameplay"`
|
|
206
|
+
|
|
191
207
|
## group-credits — turn a flat list of credited things into ordered credit sections
|
|
192
208
|
|
|
193
209
|
- `groupCredits` (function) · `import { groupCredits } from "@jgengine/core/game/credits"`
|
|
@@ -212,7 +228,7 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
212
228
|
|
|
213
229
|
- `createEmptyInventory` (function) · `import { createEmptyInventory } from "@jgengine/core/inventory/inventoryModel"`
|
|
214
230
|
|
|
215
|
-
## inventory-split — split a stack into a target or first-empty slot
|
|
231
|
+
## inventory-split — split a stack into a target or first-empty slot, honoring a stack limit
|
|
216
232
|
|
|
217
233
|
- `splitStack` (function) · `import { splitStack } from "@jgengine/core/inventory/inventoryModel"`
|
|
218
234
|
|
|
@@ -279,6 +295,14 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
279
295
|
|
|
280
296
|
- `createLoadouts` (function) · `import { createLoadouts } from "@jgengine/core/gameplay"`
|
|
281
297
|
|
|
298
|
+
## loan-schedule — build a loan's interest and principal repayment schedule in integer minor units
|
|
299
|
+
|
|
300
|
+
- `buildLoanSchedule` (function) · `import { buildLoanSchedule } from "@jgengine/core/gameplay"`
|
|
301
|
+
|
|
302
|
+
## loans — draw, schedule, service and default a loan with interest, posted to a ledger
|
|
303
|
+
|
|
304
|
+
- `createLoanBook` (function) · `import { createLoanBook } from "@jgengine/core/gameplay"`
|
|
305
|
+
|
|
282
306
|
## local-save — persist a game to on-device localStorage (offline)
|
|
283
307
|
|
|
284
308
|
- `localSaveBackend` (function) · `import { localSaveBackend } from "@jgengine/core/gameplay"`
|
|
@@ -287,20 +311,45 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
287
311
|
|
|
288
312
|
- `RarityStyle` (interface) · `import { RarityStyle } from "@jgengine/core/gameplay"`
|
|
289
313
|
|
|
314
|
+
## loot-comparison — compare two rolled items with per-stat deltas and a weighted score
|
|
315
|
+
|
|
316
|
+
- `compareLootItems` (function) · `import { compareLootItems } from "@jgengine/core/gameplay"`
|
|
317
|
+
|
|
290
318
|
## loot-filter — filter and highlight drops by rarity/name rules
|
|
291
319
|
|
|
292
320
|
- `evaluateLootFilter` (function) · `import { evaluateLootFilter } from "@jgengine/core/gameplay"`
|
|
293
321
|
|
|
322
|
+
## loot-generation — roll a named item from bases, parts, affixes, rarity weights, manufacturer personalities and level scaling
|
|
323
|
+
|
|
324
|
+
- `rollLoot` (function) · `import { rollLoot } from "@jgengine/core/gameplay"`
|
|
325
|
+
|
|
294
326
|
## loot-pipeline — compose ordered loot pools with fallbacks, roll modifiers, and provenance
|
|
295
327
|
|
|
296
328
|
- `createLootPipeline` (function) · `import { createLootPipeline } from "@jgengine/core/gameplay"`
|
|
297
329
|
- `defineLootPipeline` (function) · `import { defineLootPipeline } from "@jgengine/core/gameplay"`
|
|
298
330
|
|
|
331
|
+
## loot-roller — roll items from one validated catalog while counting drops per rarity for a debug probe
|
|
332
|
+
|
|
333
|
+
- `createLootRoller` (function) · `import { createLootRoller } from "@jgengine/core/gameplay"`
|
|
334
|
+
|
|
335
|
+
## loot-score — split one stat block into per-stat weighted contributions
|
|
336
|
+
|
|
337
|
+
- `lootStatContributions` (function) · `import { lootStatContributions } from "@jgengine/core/gameplay"`
|
|
338
|
+
- `scoreLootStats` (function) · `import { scoreLootStats } from "@jgengine/core/gameplay"`
|
|
339
|
+
|
|
299
340
|
## loot-table — register loot tables and roll weighted randomized drops
|
|
300
341
|
|
|
301
342
|
- `createLootRegistry` (function) · `import { createLootRegistry } from "@jgengine/core/gameplay"`
|
|
302
343
|
- `lootTable` (function) · `import { lootTable } from "@jgengine/core/gameplay"`
|
|
303
344
|
|
|
345
|
+
## loot-validation — check a rolled item against its catalog and report each defect with its code
|
|
346
|
+
|
|
347
|
+
- `validateLootItem` (function) · `import { validateLootItem } from "@jgengine/core/gameplay"`
|
|
348
|
+
|
|
349
|
+
## loot-weapon — feed a rolled item into a weapon definition so generated gear fires through the weapon system
|
|
350
|
+
|
|
351
|
+
- `lootWeaponDefinition` (function) · `import { lootWeaponDefinition } from "@jgengine/core/gameplay"`
|
|
352
|
+
|
|
304
353
|
## maturation-stage — resolve the baby/juvenile/adolescent/adult stage from elapsed maturation
|
|
305
354
|
|
|
306
355
|
- `maturationStage` (function) · `import { maturationStage } from "@jgengine/core/game/breeding"`
|
|
@@ -309,6 +358,36 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
309
358
|
|
|
310
359
|
- `mergeCredits` (function) · `import { mergeCredits } from "@jgengine/core/game/credits"`
|
|
311
360
|
|
|
361
|
+
## mission-compositions — build escort, chase and defend missions from the shared objective kinds
|
|
362
|
+
|
|
363
|
+
- `chaseMission` (function) · `import { chaseMission } from "@jgengine/core/gameplay"`
|
|
364
|
+
- `defendMission` (function) · `import { defendMission } from "@jgengine/core/gameplay"`
|
|
365
|
+
- `escortMission` (function) · `import { escortMission } from "@jgengine/core/gameplay"`
|
|
366
|
+
|
|
367
|
+
## mission-events — count constrained kills and fail a mission on a matching world event
|
|
368
|
+
|
|
369
|
+
- `MissionWorldEvent` (interface) · `import { MissionWorldEvent } from "@jgengine/core/gameplay"`
|
|
370
|
+
|
|
371
|
+
## mission-rewards — pay mission rewards through the quest appliers and the loot registry
|
|
372
|
+
|
|
373
|
+
- `applyMissionRewards` (function) · `import { applyMissionRewards } from "@jgengine/core/gameplay"`
|
|
374
|
+
|
|
375
|
+
## mission-runtime — missions as a data-driven objective state machine with fail states, timers, branches and rewards
|
|
376
|
+
|
|
377
|
+
- `createMissionRuntime` (function) · `import { createMissionRuntime } from "@jgengine/core/gameplay"`
|
|
378
|
+
|
|
379
|
+
## mission-triggers — start, advance and fail a mission from authored scene markers
|
|
380
|
+
|
|
381
|
+
- `MISSION_TRIGGER_ACTIONS` (const) · `import { MISSION_TRIGGER_ACTIONS } from "@jgengine/core/gameplay"`
|
|
382
|
+
- `createMissionTriggerBridge` (function) · `import { createMissionTriggerBridge } from "@jgengine/core/gameplay"`
|
|
383
|
+
- `missionMarkers` (function) · `import { missionMarkers } from "@jgengine/core/gameplay"`
|
|
384
|
+
- `registerMissionTriggerActions` (function) · `import { registerMissionTriggerActions } from "@jgengine/core/gameplay"`
|
|
385
|
+
|
|
386
|
+
## mission-validation — tell whether an objective kind completes from a counter alone
|
|
387
|
+
|
|
388
|
+
- `isCounterObjective` (function) · `import { isCounterObjective } from "@jgengine/core/gameplay"`
|
|
389
|
+
- `validateMissionCatalog` (function) · `import { validateMissionCatalog } from "@jgengine/core/gameplay"`
|
|
390
|
+
|
|
312
391
|
## modular-item — attach parts into item mount slots to compute combined stats
|
|
313
392
|
|
|
314
393
|
- `slotAccepts` (function) · `import { slotAccepts } from "@jgengine/core/gameplay"`
|
|
@@ -482,6 +561,21 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
482
561
|
|
|
483
562
|
- `createVfxInstanceStore` (function) · `import { createVfxInstanceStore } from "@jgengine/core/gameplay"`
|
|
484
563
|
|
|
564
|
+
## ride-appeal — how much one guest likes one ride, from its ratings and their taste
|
|
565
|
+
|
|
566
|
+
- `rideAppeal` (function) · `import { rideAppeal } from "@jgengine/core/gameplay"`
|
|
567
|
+
|
|
568
|
+
## ride-choice — guests pick rides by taste and queue tolerance through the utility brain
|
|
569
|
+
|
|
570
|
+
- `createRideChooser` (function) · `import { createRideChooser } from "@jgengine/core/gameplay"`
|
|
571
|
+
- `rideChoiceCandidates` (function) · `import { rideChoiceCandidates } from "@jgengine/core/gameplay"`
|
|
572
|
+
- `rideChoiceOptions` (function) · `import { rideChoiceOptions } from "@jgengine/core/gameplay"`
|
|
573
|
+
- `rideQueueCostWeight` (function) · `import { rideQueueCostWeight } from "@jgengine/core/gameplay"`
|
|
574
|
+
|
|
575
|
+
## ride-sim — rides with capacity, cycles, queues, ratings, breakdowns and maintenance
|
|
576
|
+
|
|
577
|
+
- `createRideSystem` (function) · `import { createRideSystem } from "@jgengine/core/gameplay"`
|
|
578
|
+
|
|
485
579
|
## routine-timeline — authored daily routines (home, work, meal) resolved against the world clock
|
|
486
580
|
|
|
487
581
|
- `resolveRoutine` (function) · `import { resolveRoutine } from "@jgengine/core/gameplay"`
|
|
@@ -496,6 +590,14 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
496
590
|
|
|
497
591
|
- `createRunDraft` (function) · `import { createRunDraft } from "@jgengine/core/gameplay"`
|
|
498
592
|
|
|
593
|
+
## save-slot-index — refresh a save-select index from the game's save documents
|
|
594
|
+
|
|
595
|
+
- `refreshSaveSlots` (function) · `import { refreshSaveSlots } from "@jgengine/core/game/saveSlotIndex"`
|
|
596
|
+
|
|
597
|
+
## save-slot-meta — project a save document onto save-select display metadata
|
|
598
|
+
|
|
599
|
+
- `saveSlotMeta` (function) · `import { saveSlotMeta } from "@jgengine/core/game/saveSlotIndex"`
|
|
600
|
+
|
|
499
601
|
## save-slots — serializable save-slot / profile metadata index — write/clear/rename/mostRecent over free-string per-slot meta, powering New/Continue/Load/Delete menus, with snapshot/restore
|
|
500
602
|
|
|
501
603
|
- `createSaveSlots` (function) · `import { createSaveSlots } from "@jgengine/core/gameplay"`
|
|
@@ -523,11 +625,16 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
523
625
|
## shaped-placement — find a shaped inventory item's first fit with ordered rotations, row-major placement, and an explicit search budget
|
|
524
626
|
|
|
525
627
|
- `findShapedPlacement` (function) · `import { findShapedPlacement } from "@jgengine/core/inventory/shapedGrid"`
|
|
628
|
+
- `fitShapedItem` (function) · `import { fitShapedItem } from "@jgengine/core/inventory/shapedGrid"`
|
|
526
629
|
|
|
527
630
|
## shop-grid — serializable vendor/shop stock with buy/sell over a caller-owned wallet — finite/unlimited qty, sell-back, restock/setPrice, snapshot/restore
|
|
528
631
|
|
|
529
632
|
- `createShopStock` (function) · `import { createShopStock } from "@jgengine/core/gameplay"`
|
|
530
633
|
|
|
634
|
+
## skill-tree — spend, refuse and refund points over an authored tree with passives, actives and synergies
|
|
635
|
+
|
|
636
|
+
- `createSkillTree` (function) · `import { createSkillTree } from "@jgengine/core/gameplay"`
|
|
637
|
+
|
|
531
638
|
## social-emotes — emotes and social interactions between nearby players
|
|
532
639
|
|
|
533
640
|
- `createSocial` (function) · `import { createSocial } from "@jgengine/core/gameplay"`
|
|
@@ -552,6 +659,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
552
659
|
|
|
553
660
|
- `statModifierContributions` (function) · `import { statModifierContributions } from "@jgengine/core/gameplay"`
|
|
554
661
|
|
|
662
|
+
## supply-demand-pricing — price goods from finite stock and live demand on a stated curve
|
|
663
|
+
|
|
664
|
+
- `createMarket` (function) · `import { createMarket } from "@jgengine/core/gameplay"`
|
|
665
|
+
|
|
555
666
|
## system-schedule — compile fixed/frame/interval system ticks into deterministic ordered stages
|
|
556
667
|
|
|
557
668
|
- `compileSystemSchedule` (function) · `import { compileSystemSchedule } from "@jgengine/core/gameplay"`
|
|
@@ -582,6 +693,10 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
582
693
|
- `setTouchControlsMode` (function) · `import { setTouchControlsMode } from "@jgengine/core/gameplay"`
|
|
583
694
|
- `touchButtonShape` (function) · `import { touchButtonShape } from "@jgengine/core/gameplay"`
|
|
584
695
|
|
|
696
|
+
## transaction-ledger — record every money movement with its reason over per-account integer minor-unit balances
|
|
697
|
+
|
|
698
|
+
- `createTransactionLedger` (function) · `import { createTransactionLedger } from "@jgengine/core/gameplay"`
|
|
699
|
+
|
|
585
700
|
## tribe-group — shared-ownership group (tribe/guild/clan) with ranked permissions, group vs personal assets, alliances, and a bounded event log
|
|
586
701
|
|
|
587
702
|
- `createTribe` (function) · `import { createTribe } from "@jgengine/core/game/tribe"`
|
|
@@ -617,6 +732,14 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
617
732
|
|
|
618
733
|
- `createUnlockCatalog` (function) · `import { createUnlockCatalog } from "@jgengine/core/gameplay"`
|
|
619
734
|
|
|
735
|
+
## visitor-population — a crowd whose on-site and daily counts are the bodies the game made
|
|
736
|
+
|
|
737
|
+
- `createVisitorPopulation` (function) · `import { createVisitorPopulation } from "@jgengine/core/gameplay"`
|
|
738
|
+
|
|
739
|
+
## wait-queue — a real line whose wait estimate comes from its own measured throughput
|
|
740
|
+
|
|
741
|
+
- `createWaitQueue` (function) · `import { createWaitQueue } from "@jgengine/core/gameplay"`
|
|
742
|
+
|
|
620
743
|
## wallet — hold currency balances with charge and affordability checks
|
|
621
744
|
|
|
622
745
|
- `createEmptyWallet` (function) · `import { createEmptyWallet } from "@jgengine/core/gameplay"`
|
|
@@ -660,3 +783,7 @@ Reach for these before hand-rolling. Each row is *the thing you need* → *the p
|
|
|
660
783
|
## work-queued-jobs — list jobs waiting for a slot, in selection order
|
|
661
784
|
|
|
662
785
|
- `queuedJobs` (function) · `import { queuedJobs } from "@jgengine/core/gameplay"`
|
|
786
|
+
|
|
787
|
+
## xp-curve — resolve an authored xp growth rule into per-level thresholds, totals and a level cap
|
|
788
|
+
|
|
789
|
+
- `defineXpCurve` (function) · `import { defineXpCurve } from "@jgengine/core/gameplay"`
|
|
@@ -28,6 +28,124 @@ and level state, then emits every reached level in ascending order. State stays
|
|
|
28
28
|
in the caller's save format and round-trips as ordinary JSON. See the
|
|
29
29
|
[portable XP/leveling recipe](recipes/portable-xp-leveling.md).
|
|
30
30
|
|
|
31
|
+
## Procedural gear
|
|
32
|
+
|
|
33
|
+
`loot/lootGen` rolls a whole named item from a caller-authored `LootCatalog`:
|
|
34
|
+
bases (`baseStats`, affix `pools`, mount `slots`), parts, affix pools, weighted
|
|
35
|
+
`RarityTier`s, `LootManufacturerDef`s (name, flat `bias`, per-stat `scale`,
|
|
36
|
+
favored pools) and a `levelScale` curve of `[level, multiplier]` points. A roll
|
|
37
|
+
picks maker, base, rarity, one part per slot and `affixCount` affixes; stats are
|
|
38
|
+
`base × rarity.statScale × levelScale`, plus part stats/multipliers, maker
|
|
39
|
+
personality, then additive affixes and multiplicative ones. Additive affix
|
|
40
|
+
rolls scale with level; multiplicative ones do not. Names follow one rule:
|
|
41
|
+
maker, rarity word, first part word, first prefix affix, base name, first suffix
|
|
42
|
+
affix. Every random draw uses the injected `rng`, so a seed reproduces the item.
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
import { compareLootItems, createLootRoller, lootWeaponDefinition, seededRng } from "@jgengine/core/gameplay";
|
|
46
|
+
|
|
47
|
+
const roller = createLootRoller(catalog, { devtoolsName: "loot" });
|
|
48
|
+
const item = roller.roll(seededRng(dropSeed), { level: 30 });
|
|
49
|
+
const delta = compareLootItems(item, equipped, { lowerIsBetter: ["reload"] });
|
|
50
|
+
const weapon = lootWeaponDefinition(item, { template, stats: { damage: "power", roundsPerMinute: "cadence" } });
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
`validateLootItem` returns coded issues (`unknown-base`, `part-category`,
|
|
54
|
+
`missing-slot-part`, `unknown-affix`, `empty-name`…) and the roller's counters
|
|
55
|
+
snapshot/restore as plain data. Register a roll through
|
|
56
|
+
`proceduralLootEntry` into `item/itemInstanceRegistry` and hand its runtime id
|
|
57
|
+
to `game/lootTable`; the weapon projection only maps stats it is told to, so a
|
|
58
|
+
catalog without weapon stats stays usable for non-weapon gear. Check a
|
|
59
|
+
distribution with a fixed seed over 10,000 drops against each tier's 4σ
|
|
60
|
+
binomial bound rather than eyeballing shares.
|
|
61
|
+
|
|
62
|
+
## Progression and gear score
|
|
63
|
+
|
|
64
|
+
`progression/xpCurve` turns one authored growth rule into the level table, the cap and a
|
|
65
|
+
plain-words rule line, so the balance lives in save-visible data:
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
import { createSkillTree, defineXpCurve, gearScore } from "@jgengine/core/gameplay";
|
|
69
|
+
|
|
70
|
+
const xp = defineXpCurve({ growth: "power", step: 100, growthRate: 1.5, maxLevel: 40, round: "floor" });
|
|
71
|
+
// rule: "power: 100 x level^1.5, floor (levels 1-40)"; xpForLevel(2) is 282, xpForLevel(40) is 0
|
|
72
|
+
xp.levelForXp(xp.totalXpFor(7)).level; // 7
|
|
73
|
+
xp.track(); // the same thresholds as a `leveling` track for a stat adapter
|
|
74
|
+
|
|
75
|
+
const tree = createSkillTree({ nodes, synergies, points: 6 }, { devtoolsName: "skills" });
|
|
76
|
+
tree.spend("strike"); // { ok: true, spent: 1, pointsAvailable: 5 }
|
|
77
|
+
tree.canSpend("sight"); // { ok: false, reason: "requires", detail: '...needs rank 1 of "focus"' }
|
|
78
|
+
const { stats, actives, synergies: live } = tree.resolved();
|
|
79
|
+
tree.respec(); // { refunded: 6, pointsAvailable: 6 }
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
A `SkillNodeDef` is `{ id, branch?, cost?, maxRank?, requires?, requiresPointsInBranch?,
|
|
83
|
+
excludes?, passives?, actives?, tags? }`; a `SkillSynergyDef` lists at least two `requires` and
|
|
84
|
+
adds passives/actives only while they all hold. `excludes` is symmetric, so two nodes named as
|
|
85
|
+
alternatives block each other in both directions. Actives are `{ id, cooldownMs?, resourceCost?,
|
|
86
|
+
castType?, groups? }`, shaped to bind into `createAbilityKit` slots. Snapshot/restore carries
|
|
87
|
+
`{ points, ranks }`; restore refuses unknown nodes, over-ranked nodes and negative points without
|
|
88
|
+
mutating. A tree where breadth beats depth is the point: in the test fixture, four points down
|
|
89
|
+
`strike` give `damage +3`, while the same four points in `strike x2`, `focus`, `sight` give
|
|
90
|
+
`damage +4` plus the `overload` synergy and its action.
|
|
91
|
+
|
|
92
|
+
`gearScore(set, options)` scores `slot -> { stats, level?, rarity? }` as
|
|
93
|
+
`Σ_stat value × weight × (lowerIsBetter ? -1 : 1) + levelWeight × level + rarityScore[rarity]`,
|
|
94
|
+
summed over filled slots, minus `emptySlotPenalty` per expected-but-empty slot; it also returns
|
|
95
|
+
`bySlot`, `byStat`, `average`, `coverage` and `emptySlots`. `compareGearSets` ranks two loadouts.
|
|
96
|
+
The stat term comes from `lootStatContributions`, the same function behind `scoreLootStats` and
|
|
97
|
+
`compareLootItems`, so per-item and whole-loadout scores cannot drift apart.
|
|
98
|
+
|
|
99
|
+
## Inventory, equipment and weight
|
|
100
|
+
|
|
101
|
+
A carried bag and a stash are two declared inventories, so they hold separate plain state from the
|
|
102
|
+
first frame and persist as `InventorySet.snapshot()`:
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
import { createInventorySet } from "@jgengine/core/inventory/inventoryModel";
|
|
106
|
+
import { canCarry, characterLoad } from "@jgengine/core/inventory/carryLoad";
|
|
107
|
+
import { createEquipment } from "@jgengine/core/inventory/equipment";
|
|
108
|
+
|
|
109
|
+
const items = createInventorySet({ bag: { slots: 24 }, stash: { slots: 60 } }, traits);
|
|
110
|
+
items.move("bag", 3, "stash", 0); // across inventories; a rejected move leaves both untouched
|
|
111
|
+
const saved = items.snapshot(); // detached; JSON-safe; restore() refuses a bad save without mutating
|
|
112
|
+
|
|
113
|
+
const gear = createEquipment(
|
|
114
|
+
[{ id: "weapon", blocks: ["offhand"] }, { id: "offhand" }, { id: "chest", accepts: ["armor"] }],
|
|
115
|
+
(itemId) => baseDefs[registry.get(itemId)?.baseId ?? itemId]?.gear, // rolled item -> its base's gear facts
|
|
116
|
+
{ devtoolsName: "gear" },
|
|
117
|
+
);
|
|
118
|
+
gear.equip("chest", "plate"); // { status: "ok", replaced: null, ... }
|
|
119
|
+
gear.equipBest("greatsword"); // first free preferred slot, else the first one it may replace
|
|
120
|
+
|
|
121
|
+
const load = characterLoad({
|
|
122
|
+
carried: [items.state("bag")],
|
|
123
|
+
worn: gear.worn().map((entry) => entry.itemId),
|
|
124
|
+
weightOf: (itemId) => baseDefs[itemId]?.weight ?? 0,
|
|
125
|
+
capacity: 60 + stats.value("carryCapacity"),
|
|
126
|
+
});
|
|
127
|
+
load.moveMultiplier; // 1 unencumbered, decays across the soft band, 0 at capacity
|
|
128
|
+
canCarry(load, 12); // gate a pickup; the overload policy stays the game's
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
`EquipSlotDef` owns `accepts` (item kinds) and `blocks` (slots it occupies while filled), and
|
|
132
|
+
`EquipItemDef` owns the `slots` an item may occupy plus its `kind`; a filled slot swaps and returns
|
|
133
|
+
the replaced item, so nothing is silently destroyed, and `state()` / `restore()` carry
|
|
134
|
+
`{ slots: [[slotId, itemId]] }`. The stash is simply left out of `carried`, so its contents add no
|
|
135
|
+
weight, and declaring it `tier: "banked"` keeps it out of `partitionOnDeath`'s lost half.
|
|
136
|
+
|
|
137
|
+
For a footprint bag, `fitShapedItem` (`inventory/shapedGrid`) places the first legal spot or names
|
|
138
|
+
why it does not fit — `too-large` with both sizes, `no-space` for a full board, `budget-exceeded` for
|
|
139
|
+
an exhausted search. Stack rules stay in `ItemTraits`: `putItem` fills partial stacks then opens new
|
|
140
|
+
ones up to the max stack, `moveItem` merges with a remainder, and `splitStack(..., limit)` refuses an
|
|
141
|
+
`over-stack` merge instead of breaking the cap.
|
|
142
|
+
|
|
143
|
+
The rendered side is the engine's: `<InventoryGrid inventoryId="bag" />` (`packages/react`) binds a
|
|
144
|
+
live declared inventory with drag, swap, merge and split through the `inventory.move` /
|
|
145
|
+
`inventory.split` commands, and `<EquipmentSlots items={...} />` paints the worn slots from
|
|
146
|
+
`gear.worn()`. What the grid cannot yet do is drag from one inventory to another (bag to stash), so a
|
|
147
|
+
stash transfer goes through `InventorySet.move` behind a button or command.
|
|
148
|
+
|
|
31
149
|
## Coherent authored content
|
|
32
150
|
|
|
33
151
|
Keep stable ids and canonical facts for characters, factions, places, and world rules in the game's authored data. Record each chapter's prerequisites, consequences, and which facts it may introduce or change. The game's creative pillars, story voice, content palette, and desired player experience come from its author; generated prose, items, art, and assets must serve those constraints. Reuse constrained generation and validation code across games while each game owns its content and visual identity; do not fill catalogs from default genre kits or mass generic content.
|
|
@@ -63,6 +63,14 @@ Route on an editor-baked polygon nav mesh through `createNavRuntime` (`nav/navRu
|
|
|
63
63
|
|
|
64
64
|
Move many agents across that mesh with `createNavCrowd` (`nav/navCrowd`): it plans corridors, follows the funnel-smoothed waypoints, keeps them apart with `createRvoCrowd` (`ai/rvo`) reciprocal velocity obstacles, bounds path searches to a per-tick time and count budget, and serializes through `snapshot`/`restore`. Give a crowd converging on one spot a `spread` radius so agents fan out (`ai/crowd`'s stable per-id offset) instead of stacking. Avoidance keeps agents inside the mesh's outer bounds; interior walls remain the game's collision layer.
|
|
65
65
|
|
|
66
|
+
### Street traffic
|
|
67
|
+
|
|
68
|
+
Vehicles on roads do not path-find: they follow authored lane spans. `createLaneGraph` (`nav/laneGraph`) resolves those spans — `traffic_lane` paths, or `road` paths from the editor's street bake, split where streets cross — into junctions, crossings with a signal program or first-come right-of-way, and parking spots; `laneGraphFromDocument` reads that straight off the scene document, so editing a road moves its traffic. `createTraffic` (`nav/traffic`) then drives cars on it: IDM car following and braking, one car at a time through each intersection box (only once the exit lane has room, which is what keeps a blocked crossing from wedging the network), signals with phases, lane changes across authored `left`/`right` neighbours, parking that reserves a spot, and `setDemand(count)` for fleet size — the time-of-day curve is the caller's, not the engine's. Cars are posed, not driven: when a player or a chase needs real handling, feed intent into `physics/kinematicVehicle` and let this seam keep the ambient city.
|
|
69
|
+
|
|
70
|
+
### Heat and police response
|
|
71
|
+
|
|
72
|
+
A crime only counts when a witness holds the suspect. `createPoliceResponse` (`ai/policeResponse`) reads witness facts from `sensor/perception` memory — `memoryOf` per observer, keeping the sighting's `sourceId` and `sourceTick` — and adds heat on the shared `ai/heatSystem` curve, so there is no second sight path and no second decay. The caller's tier table decides what police do at each heat: patrol, investigate, pursue, roadblock, with a pursuer budget per tier. The search area sits on the suspect's last known position, grows while the trail is cold, and a roadblock tier cordons it with sites `policeRoadsFromLaneGraph` reads off the lane graph (`traffic_roadblock` markers projected onto the lane they block, else the graph's intersections). Breaking sight for `escapeSeconds` is what starts the decay; standing in view keeps the heat. Heat, curve, tiers and search shape are caller policy with defaults, `state()`/`restore()` round-trip mid-chase, and the injected generator is the only source of variety.
|
|
73
|
+
|
|
66
74
|
### Fallback-seam diagnostics
|
|
67
75
|
|
|
68
76
|
Render seams fall back to placeholders when content is unauthored: default green ground (no environment), primitive capsule/box actors (no `entityModels`/`objectModels` mapping), stylized proxy foliage (no scatter `resolveItem`). These placeholders are sometimes intended, so runtime never changes — but a dev-only, opt-in probe (`@jgengine/core/devtools/fallbackSeams`) tells "unauthored/misconfigured" apart from "intended". The shell arms it via `armFallbackSeams(devtoolsEnabled)`; each seam reports at its choice site (`reportFallbackSeam`), and counts surface through the devtools `fallbacks` probe. Disarmed (production) it is a pure, allocation-free no-op.
|