@jgengine/core 0.11.0 → 0.13.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 +52 -0
- package/dist/ai/populationDirector.d.ts +103 -0
- package/dist/ai/populationDirector.js +190 -0
- package/dist/ai/pursuit.d.ts +56 -0
- package/dist/ai/pursuit.js +53 -0
- package/dist/authoring.d.ts +1 -1
- package/dist/authoring.js +1 -1
- package/dist/combat/effects.d.ts +11 -4
- package/dist/combat/effects.js +24 -17
- package/dist/combat/magazine.d.ts +13 -0
- package/dist/combat/magazine.js +27 -0
- package/dist/combat/vfxPresets.d.ts +176 -0
- package/dist/combat/vfxPresets.js +74 -0
- package/dist/combat/weaponFire.d.ts +114 -0
- package/dist/combat/weaponFire.js +96 -0
- package/dist/combat.d.ts +5 -2
- package/dist/combat.js +4 -1
- package/dist/devtools/controls.d.ts +38 -0
- package/dist/devtools/controls.js +181 -0
- package/dist/devtools/devtools.d.ts +5 -197
- package/dist/devtools/devtools.js +38 -774
- package/dist/devtools/discover.d.ts +32 -0
- package/dist/devtools/discover.js +240 -0
- package/dist/devtools/fallbackSeams.d.ts +50 -0
- package/dist/devtools/fallbackSeams.js +111 -0
- package/dist/devtools/frame.d.ts +15 -0
- package/dist/devtools/frame.js +247 -0
- package/dist/devtools/logs.d.ts +15 -0
- package/dist/devtools/logs.js +86 -0
- package/dist/devtools/overrides.d.ts +16 -0
- package/dist/devtools/overrides.js +66 -0
- package/dist/devtools/types.d.ts +212 -0
- package/dist/devtools/types.js +1 -0
- package/dist/devtools/urlFlags.d.ts +22 -0
- package/dist/devtools/urlFlags.js +62 -0
- package/dist/economy/auctionBook.d.ts +122 -0
- package/dist/economy/auctionBook.js +213 -0
- package/dist/economy/priceHistory.d.ts +44 -0
- package/dist/economy/priceHistory.js +89 -0
- package/dist/economy/unlockPoints.d.ts +92 -0
- package/dist/economy/unlockPoints.js +103 -0
- package/dist/editor/commandApply.d.ts +5 -0
- package/dist/editor/commandApply.js +755 -0
- package/dist/editor/commands.d.ts +48 -3
- package/dist/editor/commands.js +40 -754
- package/dist/editor/directives.d.ts +94 -0
- package/dist/editor/directives.js +206 -0
- package/dist/editor/document.d.ts +37 -2
- package/dist/editor/document.js +422 -6
- package/dist/editor/entityCatalog.d.ts +42 -0
- package/dist/editor/entityCatalog.js +101 -0
- package/dist/editor/environment.d.ts +74 -0
- package/dist/editor/environment.js +169 -0
- package/dist/editor/index.d.ts +26 -1
- package/dist/editor/index.js +8 -1
- package/dist/editor/minimap.d.ts +31 -0
- package/dist/editor/minimap.js +73 -0
- package/dist/editor/streamer.d.ts +66 -0
- package/dist/editor/streamer.js +68 -0
- package/dist/editor/types.d.ts +143 -0
- package/dist/editor/world.d.ts +136 -0
- package/dist/editor/world.js +303 -0
- package/dist/game/breeding.d.ts +161 -0
- package/dist/game/breeding.js +181 -0
- package/dist/game/cameraConfig.d.ts +451 -0
- package/dist/game/cameraConfig.js +1 -0
- package/dist/game/clipRoles.d.ts +51 -0
- package/dist/game/clipRoles.js +142 -0
- package/dist/game/defineGame.d.ts +16 -9
- package/dist/game/defineGame.js +14 -6
- package/dist/game/defineSystem.d.ts +2 -0
- package/dist/game/defineSystem.js +2 -0
- package/dist/game/events.d.ts +28 -0
- package/dist/game/partAnimation.d.ts +78 -0
- package/dist/game/partAnimation.js +147 -0
- package/dist/game/playableGame.d.ts +72 -440
- package/dist/game/playableGame.js +1 -1
- package/dist/game/progression.d.ts +35 -0
- package/dist/game/progression.js +22 -1
- package/dist/game/quest.js +1 -3
- package/dist/game/tribe.d.ts +184 -0
- package/dist/game/tribe.js +432 -0
- package/dist/gameplay.d.ts +3 -1
- package/dist/gameplay.js +3 -1
- package/dist/inventory/encumbrance.d.ts +69 -0
- package/dist/inventory/encumbrance.js +68 -0
- package/dist/inventory/inventoryModel.d.ts +24 -8
- package/dist/inventory/inventoryModel.js +47 -8
- package/dist/item/durability.js +1 -3
- package/dist/meta/changelog.d.ts +1 -1
- package/dist/meta/changelog.js +48 -1
- package/dist/movement/movementModel.d.ts +15 -1
- package/dist/movement/movementModel.js +33 -15
- package/dist/movement/playerMovement.js +102 -2
- package/dist/multiplayer/combatSnapshot.js +13 -8
- package/dist/multiplayer/presenceModel.d.ts +2 -0
- package/dist/multiplayer/presenceModel.js +8 -0
- package/dist/physics/drivableVehicle.d.ts +2 -0
- package/dist/physics/drivableVehicle.js +1 -1
- package/dist/physics/flightDynamics.d.ts +82 -0
- package/dist/physics/flightDynamics.js +165 -0
- package/dist/physics/gravityField.d.ts +25 -0
- package/dist/physics/gravityField.js +41 -0
- package/dist/physics/kinematicVehicle.d.ts +87 -0
- package/dist/physics/kinematicVehicle.js +193 -11
- package/dist/physics/physicsWorld.d.ts +26 -0
- package/dist/physics/physicsWorld.js +109 -117
- package/dist/physics/vehicleObstacles.d.ts +44 -0
- package/dist/physics/vehicleObstacles.js +115 -0
- package/dist/random/rng.d.ts +4 -1
- package/dist/random/rng.js +4 -1
- package/dist/runtime/adapter.d.ts +13 -0
- package/dist/runtime/adapter.js +13 -0
- package/dist/runtime/context/combat.d.ts +51 -0
- package/dist/runtime/context/combat.js +131 -0
- package/dist/runtime/context/combatFx.js +15 -5
- package/dist/runtime/context/deathLoot.d.ts +30 -0
- package/dist/runtime/context/deathLoot.js +39 -0
- package/dist/runtime/context/player.d.ts +48 -0
- package/dist/runtime/context/player.js +125 -0
- package/dist/runtime/context/scene.d.ts +60 -0
- package/dist/runtime/context/scene.js +329 -0
- package/dist/runtime/context/snapshotCodecs.d.ts +12 -0
- package/dist/runtime/context/snapshotCodecs.js +26 -0
- package/dist/runtime/descriptors/baseline.js +26 -3
- package/dist/runtime/descriptors/features.d.ts +5 -0
- package/dist/runtime/descriptors/features.js +20 -2
- package/dist/runtime/gameContext.d.ts +2 -428
- package/dist/runtime/gameContext.js +133 -500
- package/dist/runtime/gameContextTypes.d.ts +500 -0
- package/dist/runtime/gameContextTypes.js +1 -0
- package/dist/runtime/headlessRunner.d.ts +17 -2
- package/dist/runtime/headlessRunner.js +15 -0
- package/dist/runtime/hostPolicy.d.ts +51 -0
- package/dist/runtime/hostPolicy.js +68 -0
- package/dist/runtime/hostedGameRunner.d.ts +3 -1
- package/dist/runtime/hostedGameRunner.js +1 -0
- package/dist/runtime/hostedWorldSession.d.ts +3 -1
- package/dist/runtime/hostedWorldSession.js +1 -0
- package/dist/runtime/worldSnapshot.d.ts +13 -1
- package/dist/runtime/worldSnapshot.js +15 -3
- package/dist/scene/assetCatalog.d.ts +7 -0
- package/dist/scene/assetSpace.js +1 -3
- package/dist/scene/authoredTriggers.d.ts +50 -0
- package/dist/scene/authoredTriggers.js +114 -0
- package/dist/scene/builtinSceneKinds.js +8 -3
- package/dist/scene/colliders.d.ts +79 -0
- package/dist/scene/colliders.js +170 -0
- package/dist/scene/collisionMesh.d.ts +94 -0
- package/dist/scene/collisionMesh.js +699 -0
- package/dist/scene/companion.d.ts +147 -0
- package/dist/scene/companion.js +193 -0
- package/dist/scene/entityStats.d.ts +7 -9
- package/dist/scene/entityStats.js +19 -15
- package/dist/scene/sceneKinds.d.ts +16 -0
- package/dist/scene/sceneKinds.js +4 -0
- package/dist/scene/sceneRaycast.js +15 -0
- package/dist/stats/spawnLevelStats.d.ts +110 -0
- package/dist/stats/spawnLevelStats.js +140 -0
- package/dist/stats/statModifiers.d.ts +16 -0
- package/dist/stats/statModifiers.js +30 -1
- package/dist/stats/statPool.d.ts +70 -0
- package/dist/stats/statPool.js +62 -0
- package/dist/store/changeSignal.d.ts +3 -0
- package/dist/store/changeSignal.js +2 -0
- package/dist/store/observableKeyedStore.d.ts +2 -0
- package/dist/store/observableKeyedStore.js +1 -0
- package/dist/survival/decayMeter.js +1 -3
- package/dist/survival/regionHealth.js +1 -3
- package/dist/ui/hudLayout.d.ts +5 -0
- package/dist/ui/hudLayout.js +17 -1
- package/dist/ui/panelModel.d.ts +120 -0
- package/dist/ui/panelModel.js +168 -0
- package/dist/ui.d.ts +1 -0
- package/dist/ui.js +1 -0
- package/dist/world/authoredEntities.d.ts +29 -0
- package/dist/world/authoredEntities.js +29 -0
- package/dist/world/authoredObjects.d.ts +15 -1
- package/dist/world/authoredObjects.js +13 -1
- package/dist/world/authoredSpawn.d.ts +39 -0
- package/dist/world/authoredSpawn.js +37 -0
- package/dist/world/buildSockets.d.ts +152 -0
- package/dist/world/buildSockets.js +188 -0
- package/dist/world/buildingLots.d.ts +84 -0
- package/dist/world/buildingLots.js +119 -0
- package/dist/world/buildings.d.ts +6 -0
- package/dist/world/cityBlocks.d.ts +152 -0
- package/dist/world/cityBlocks.js +670 -0
- package/dist/world/cityContent.d.ts +77 -0
- package/dist/world/cityContent.js +261 -0
- package/dist/world/cityGenerator.d.ts +41 -0
- package/dist/world/cityGenerator.js +58 -0
- package/dist/world/cityGeometry.d.ts +114 -0
- package/dist/world/cityGeometry.js +573 -0
- package/dist/world/cityKind.d.ts +314 -0
- package/dist/world/cityKind.js +1578 -0
- package/dist/world/environmentSummary.js +57 -1
- package/dist/world/features.d.ts +53 -5
- package/dist/world/features.js +15 -3
- package/dist/world/grassKind.js +2 -2
- package/dist/world/markers.d.ts +50 -4
- package/dist/world/markers.js +49 -0
- package/dist/world/massing.js +1 -1
- package/dist/world/minimapBake.d.ts +78 -0
- package/dist/world/minimapBake.js +208 -0
- package/dist/world/minimapTrack.d.ts +17 -0
- package/dist/world/minimapTrack.js +22 -0
- package/dist/world/place.d.ts +166 -0
- package/dist/world/place.js +96 -0
- package/dist/world/placeAsset.js +3 -1
- package/dist/world/poleLineKind.d.ts +40 -0
- package/dist/world/poleLineKind.js +97 -0
- package/dist/world/polyline.js +9 -2
- package/dist/world/resourceNode.d.ts +109 -0
- package/dist/world/resourceNode.js +140 -0
- package/dist/world/roads.d.ts +19 -2
- package/dist/world/roads.js +60 -3
- package/dist/world/scatter.js +2 -20
- package/dist/world/streetGenerator.d.ts +159 -0
- package/dist/world/streetGenerator.js +684 -0
- package/dist/world/streets.d.ts +103 -1
- package/dist/world/streets.js +273 -0
- package/dist/world/terraform.js +58 -88
- package/dist/world/terrain.d.ts +65 -1
- package/dist/world/terrain.js +119 -2
- package/dist/world.d.ts +14 -5
- package/dist/world.js +12 -3
- package/package.json +1 -1
- package/skills/game-design/SKILL.md +28 -0
- package/skills/game-design/agents/openai.yaml +4 -0
- package/skills/game-design/references/application-playbook.md +170 -0
- package/skills/game-design/references/field-guide.md +288 -0
- package/skills/jgengine/SKILL.md +8 -4
- package/skills/jgengine/api.md +182 -81
- package/skills/jgengine/capabilities.md +104 -2
- package/skills/jgengine/recipes/minimal-game.md +88 -0
- package/skills/jgengine-combat/SKILL.md +19 -1
- package/skills/jgengine-combat/api.md +75 -2
- package/skills/jgengine-combat/capabilities.md +61 -1
- package/skills/jgengine-combat/recipes/portable-damage-effects.md +197 -0
- package/skills/jgengine-combat/recipes/portable-runtime-state.md +154 -0
- package/skills/jgengine-combat/recipes/portable-stat-pools.md +122 -0
- package/skills/jgengine-combat/recipes/portable-weapon-plumbing.md +156 -0
- package/skills/jgengine-combat/recipes/visible-attacks.md +81 -0
- package/skills/jgengine-combat/reference.md +33 -4
- package/skills/jgengine-gameplay/SKILL.md +8 -0
- package/skills/jgengine-gameplay/api.md +182 -26
- package/skills/jgengine-gameplay/capabilities.md +96 -2
- package/skills/jgengine-gameplay/recipes/portable-xp-leveling.md +168 -0
- package/skills/jgengine-gameplay/reference-systems.md +10 -5
- package/skills/jgengine-world/SKILL.md +13 -0
- package/skills/jgengine-world/api.md +453 -21
- package/skills/jgengine-world/capabilities.md +112 -2
- package/skills/jgengine-world/recipes/commanding-entities.md +128 -0
- package/skills/jgengine-world/reference.md +43 -4
- package/skills/jgengine/reference-cartridge.md +0 -72
package/dist/combat/magazine.js
CHANGED
|
@@ -92,5 +92,32 @@ export function createMagazine(config) {
|
|
|
92
92
|
}
|
|
93
93
|
reloadElapsedMs = null;
|
|
94
94
|
},
|
|
95
|
+
snapshot() {
|
|
96
|
+
return {
|
|
97
|
+
loaded,
|
|
98
|
+
reloadElapsedMs,
|
|
99
|
+
reserve: isInfiniteReserve ? null : reserve.current(),
|
|
100
|
+
};
|
|
101
|
+
},
|
|
102
|
+
restore(snapshot) {
|
|
103
|
+
if (isInfiniteReserve !== (snapshot.reserve === null))
|
|
104
|
+
return false;
|
|
105
|
+
if (!isInfiniteReserve) {
|
|
106
|
+
const desired = Math.max(0, snapshot.reserve);
|
|
107
|
+
const current = Math.max(0, reserve.current());
|
|
108
|
+
if (desired > current && reserve.gain === undefined)
|
|
109
|
+
return false;
|
|
110
|
+
if (desired < current && !reserve.spend(current - desired))
|
|
111
|
+
return false;
|
|
112
|
+
if (desired > current)
|
|
113
|
+
reserve.gain?.(desired - current);
|
|
114
|
+
}
|
|
115
|
+
loaded = clampLoaded(snapshot.loaded);
|
|
116
|
+
reloadElapsedMs =
|
|
117
|
+
snapshot.reloadElapsedMs === null
|
|
118
|
+
? null
|
|
119
|
+
: Math.max(0, Math.min(reloadMs, snapshot.reloadElapsedMs));
|
|
120
|
+
return true;
|
|
121
|
+
},
|
|
95
122
|
};
|
|
96
123
|
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import type { VfxKind } from "../game/events.js";
|
|
2
|
+
/**
|
|
3
|
+
* A named visual flavor for a one-shot `combat.vfx` burst: the archetype (`kind`),
|
|
4
|
+
* a `0xRRGGBB` tint, and optional default `durationMs`/`radius`. Purely presentation —
|
|
5
|
+
* a preset never touches damage, range, or any authoritative value; it just answers
|
|
6
|
+
* "what does this attack look like" so a game does not hand-roll colors and archetypes.
|
|
7
|
+
*/
|
|
8
|
+
export interface VfxPreset {
|
|
9
|
+
kind: VfxKind;
|
|
10
|
+
/** `0xRRGGBB` tint. */
|
|
11
|
+
color: number;
|
|
12
|
+
/** Overrides the shell's per-`kind` default lifetime when set. */
|
|
13
|
+
durationMs?: number;
|
|
14
|
+
/** Default effect radius for `nova`/aura flavors. */
|
|
15
|
+
radius?: number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Ready-made visual flavors for the things players actually shoot, swing, and cast —
|
|
19
|
+
* so `ctx.scene.entity.vfx({ preset: "arrow", from, to })` renders a visible bolt with
|
|
20
|
+
* zero tuning, and `"lightning"`, `"web"`, `"slash"`, `"shield"`, `"heal"`, `"explosion"`
|
|
21
|
+
* likewise just work. Each entry only picks a `kind` (`projectile | beam | nova | glow |
|
|
22
|
+
* spark`), a color, and a lifetime; it is visual vocabulary (like named CSS colors), not a
|
|
23
|
+
* gameplay archetype — combat numbers stay in the caller's own effect/ability data. Any
|
|
24
|
+
* field passed to `vfx()` overrides the preset, and unknown names fall back to `spark` so a
|
|
25
|
+
* flavor typo still shows *something* rather than nothing.
|
|
26
|
+
*
|
|
27
|
+
* @capability vfx-presets render a named attack visual (arrow, fireball, lightning, web, slash, shield, heal, explosion) in one call
|
|
28
|
+
*/
|
|
29
|
+
export declare const vfxPresets: {
|
|
30
|
+
readonly arrow: {
|
|
31
|
+
readonly kind: "projectile";
|
|
32
|
+
readonly color: 14207392;
|
|
33
|
+
};
|
|
34
|
+
readonly bolt: {
|
|
35
|
+
readonly kind: "projectile";
|
|
36
|
+
readonly color: 16777215;
|
|
37
|
+
};
|
|
38
|
+
readonly fireball: {
|
|
39
|
+
readonly kind: "projectile";
|
|
40
|
+
readonly color: 16738842;
|
|
41
|
+
readonly durationMs: 460;
|
|
42
|
+
};
|
|
43
|
+
readonly firebolt: {
|
|
44
|
+
readonly kind: "projectile";
|
|
45
|
+
readonly color: 16742954;
|
|
46
|
+
};
|
|
47
|
+
readonly frostbolt: {
|
|
48
|
+
readonly kind: "projectile";
|
|
49
|
+
readonly color: 9360127;
|
|
50
|
+
};
|
|
51
|
+
readonly ice: {
|
|
52
|
+
readonly kind: "projectile";
|
|
53
|
+
readonly color: 9360127;
|
|
54
|
+
};
|
|
55
|
+
readonly poison: {
|
|
56
|
+
readonly kind: "projectile";
|
|
57
|
+
readonly color: 8841322;
|
|
58
|
+
};
|
|
59
|
+
readonly shadowbolt: {
|
|
60
|
+
readonly kind: "projectile";
|
|
61
|
+
readonly color: 10116592;
|
|
62
|
+
};
|
|
63
|
+
readonly arcane: {
|
|
64
|
+
readonly kind: "projectile";
|
|
65
|
+
readonly color: 14256895;
|
|
66
|
+
};
|
|
67
|
+
readonly magicMissile: {
|
|
68
|
+
readonly kind: "projectile";
|
|
69
|
+
readonly color: 14256895;
|
|
70
|
+
};
|
|
71
|
+
readonly holybolt: {
|
|
72
|
+
readonly kind: "projectile";
|
|
73
|
+
readonly color: 16771488;
|
|
74
|
+
};
|
|
75
|
+
readonly rock: {
|
|
76
|
+
readonly kind: "projectile";
|
|
77
|
+
readonly color: 11049606;
|
|
78
|
+
};
|
|
79
|
+
readonly bullet: {
|
|
80
|
+
readonly kind: "projectile";
|
|
81
|
+
readonly color: 16773808;
|
|
82
|
+
readonly durationMs: 140;
|
|
83
|
+
};
|
|
84
|
+
readonly lightning: {
|
|
85
|
+
readonly kind: "beam";
|
|
86
|
+
readonly color: 12576511;
|
|
87
|
+
readonly durationMs: 200;
|
|
88
|
+
};
|
|
89
|
+
readonly laser: {
|
|
90
|
+
readonly kind: "beam";
|
|
91
|
+
readonly color: 16731469;
|
|
92
|
+
};
|
|
93
|
+
readonly beam: {
|
|
94
|
+
readonly kind: "beam";
|
|
95
|
+
readonly color: 9360127;
|
|
96
|
+
};
|
|
97
|
+
readonly web: {
|
|
98
|
+
readonly kind: "beam";
|
|
99
|
+
readonly color: 15790320;
|
|
100
|
+
readonly durationMs: 320;
|
|
101
|
+
};
|
|
102
|
+
readonly chain: {
|
|
103
|
+
readonly kind: "beam";
|
|
104
|
+
readonly color: 16771488;
|
|
105
|
+
};
|
|
106
|
+
readonly slash: {
|
|
107
|
+
readonly kind: "spark";
|
|
108
|
+
readonly color: 14078148;
|
|
109
|
+
};
|
|
110
|
+
readonly sword: {
|
|
111
|
+
readonly kind: "spark";
|
|
112
|
+
readonly color: 14078148;
|
|
113
|
+
};
|
|
114
|
+
readonly melee: {
|
|
115
|
+
readonly kind: "spark";
|
|
116
|
+
readonly color: 14078148;
|
|
117
|
+
};
|
|
118
|
+
readonly spark: {
|
|
119
|
+
readonly kind: "spark";
|
|
120
|
+
readonly color: 16773808;
|
|
121
|
+
};
|
|
122
|
+
readonly hit: {
|
|
123
|
+
readonly kind: "spark";
|
|
124
|
+
readonly color: 16765562;
|
|
125
|
+
};
|
|
126
|
+
readonly explosion: {
|
|
127
|
+
readonly kind: "nova";
|
|
128
|
+
readonly color: 16747066;
|
|
129
|
+
readonly radius: 3;
|
|
130
|
+
};
|
|
131
|
+
readonly blast: {
|
|
132
|
+
readonly kind: "nova";
|
|
133
|
+
readonly color: 16747066;
|
|
134
|
+
readonly radius: 3;
|
|
135
|
+
};
|
|
136
|
+
readonly shockwave: {
|
|
137
|
+
readonly kind: "nova";
|
|
138
|
+
readonly color: 12576511;
|
|
139
|
+
readonly radius: 3;
|
|
140
|
+
};
|
|
141
|
+
readonly frostNova: {
|
|
142
|
+
readonly kind: "nova";
|
|
143
|
+
readonly color: 9360127;
|
|
144
|
+
readonly radius: 3;
|
|
145
|
+
};
|
|
146
|
+
readonly heal: {
|
|
147
|
+
readonly kind: "glow";
|
|
148
|
+
readonly color: 8841322;
|
|
149
|
+
};
|
|
150
|
+
readonly buff: {
|
|
151
|
+
readonly kind: "glow";
|
|
152
|
+
readonly color: 16771488;
|
|
153
|
+
};
|
|
154
|
+
readonly shield: {
|
|
155
|
+
readonly kind: "glow";
|
|
156
|
+
readonly color: 9360127;
|
|
157
|
+
};
|
|
158
|
+
readonly cast: {
|
|
159
|
+
readonly kind: "glow";
|
|
160
|
+
readonly color: 14256895;
|
|
161
|
+
};
|
|
162
|
+
};
|
|
163
|
+
/** A named key into {@link vfxPresets} (`"arrow" | "fireball" | "lightning" | "web" | "slash" | "shield" | "heal" | ...`). */
|
|
164
|
+
export type VfxPresetName = keyof typeof vfxPresets;
|
|
165
|
+
/** The fallback flavor used when a `vfx()` call names an unknown preset — so a typo still shows a spark instead of nothing. */
|
|
166
|
+
export declare const DEFAULT_VFX_PRESET: VfxPresetName;
|
|
167
|
+
/**
|
|
168
|
+
* Resolve a named visual flavor into a concrete `{ kind, color, durationMs?, radius? }`,
|
|
169
|
+
* with any provided `overrides` winning field by field. An unknown name resolves to
|
|
170
|
+
* {@link DEFAULT_VFX_PRESET} rather than throwing, so a flavor typo degrades to a visible
|
|
171
|
+
* spark. Used by `ctx.scene.entity.vfx({ preset })`; call it directly when you need the raw
|
|
172
|
+
* numbers (e.g. to seed a retained `vfxInstance` from the same vocabulary).
|
|
173
|
+
*
|
|
174
|
+
* @capability vfx-preset-resolve turn a named attack flavor into concrete vfx kind/color/duration with per-field overrides
|
|
175
|
+
*/
|
|
176
|
+
export declare function resolveVfxPreset(name: string | undefined, overrides?: Partial<VfxPreset>): VfxPreset;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ready-made visual flavors for the things players actually shoot, swing, and cast —
|
|
3
|
+
* so `ctx.scene.entity.vfx({ preset: "arrow", from, to })` renders a visible bolt with
|
|
4
|
+
* zero tuning, and `"lightning"`, `"web"`, `"slash"`, `"shield"`, `"heal"`, `"explosion"`
|
|
5
|
+
* likewise just work. Each entry only picks a `kind` (`projectile | beam | nova | glow |
|
|
6
|
+
* spark`), a color, and a lifetime; it is visual vocabulary (like named CSS colors), not a
|
|
7
|
+
* gameplay archetype — combat numbers stay in the caller's own effect/ability data. Any
|
|
8
|
+
* field passed to `vfx()` overrides the preset, and unknown names fall back to `spark` so a
|
|
9
|
+
* flavor typo still shows *something* rather than nothing.
|
|
10
|
+
*
|
|
11
|
+
* @capability vfx-presets render a named attack visual (arrow, fireball, lightning, web, slash, shield, heal, explosion) in one call
|
|
12
|
+
*/
|
|
13
|
+
export const vfxPresets = {
|
|
14
|
+
// Traveling bolts — a thing flies from caster to target.
|
|
15
|
+
arrow: { kind: "projectile", color: 0xd8c9a0 },
|
|
16
|
+
bolt: { kind: "projectile", color: 0xffffff },
|
|
17
|
+
fireball: { kind: "projectile", color: 0xff6a1a, durationMs: 460 },
|
|
18
|
+
firebolt: { kind: "projectile", color: 0xff7a2a },
|
|
19
|
+
frostbolt: { kind: "projectile", color: 0x8ed2ff },
|
|
20
|
+
ice: { kind: "projectile", color: 0x8ed2ff },
|
|
21
|
+
poison: { kind: "projectile", color: 0x86e86a },
|
|
22
|
+
shadowbolt: { kind: "projectile", color: 0x9a5df0 },
|
|
23
|
+
arcane: { kind: "projectile", color: 0xd98aff },
|
|
24
|
+
magicMissile: { kind: "projectile", color: 0xd98aff },
|
|
25
|
+
holybolt: { kind: "projectile", color: 0xffe9a0 },
|
|
26
|
+
rock: { kind: "projectile", color: 0xa89a86 },
|
|
27
|
+
bullet: { kind: "projectile", color: 0xfff2b0, durationMs: 140 },
|
|
28
|
+
// Connecting lines — a beam/tether links caster and target.
|
|
29
|
+
lightning: { kind: "beam", color: 0xbfe6ff, durationMs: 200 },
|
|
30
|
+
laser: { kind: "beam", color: 0xff4d4d },
|
|
31
|
+
beam: { kind: "beam", color: 0x8ed2ff },
|
|
32
|
+
web: { kind: "beam", color: 0xf0f0f0, durationMs: 320 },
|
|
33
|
+
chain: { kind: "beam", color: 0xffe9a0 },
|
|
34
|
+
// Melee / impact — a spark scatters at the point of contact.
|
|
35
|
+
slash: { kind: "spark", color: 0xd6d0c4 },
|
|
36
|
+
sword: { kind: "spark", color: 0xd6d0c4 },
|
|
37
|
+
melee: { kind: "spark", color: 0xd6d0c4 },
|
|
38
|
+
spark: { kind: "spark", color: 0xfff2b0 },
|
|
39
|
+
hit: { kind: "spark", color: 0xffd27a },
|
|
40
|
+
// Ground bursts — an expanding ring/shockwave from a point.
|
|
41
|
+
explosion: { kind: "nova", color: 0xff8a3a, radius: 3 },
|
|
42
|
+
blast: { kind: "nova", color: 0xff8a3a, radius: 3 },
|
|
43
|
+
shockwave: { kind: "nova", color: 0xbfe6ff, radius: 3 },
|
|
44
|
+
frostNova: { kind: "nova", color: 0x8ed2ff, radius: 3 },
|
|
45
|
+
// Auras — a soft glow that lingers on caster or target.
|
|
46
|
+
heal: { kind: "glow", color: 0x86e86a },
|
|
47
|
+
buff: { kind: "glow", color: 0xffe9a0 },
|
|
48
|
+
shield: { kind: "glow", color: 0x8ed2ff },
|
|
49
|
+
cast: { kind: "glow", color: 0xd98aff },
|
|
50
|
+
};
|
|
51
|
+
/** The fallback flavor used when a `vfx()` call names an unknown preset — so a typo still shows a spark instead of nothing. */
|
|
52
|
+
export const DEFAULT_VFX_PRESET = "spark";
|
|
53
|
+
/**
|
|
54
|
+
* Resolve a named visual flavor into a concrete `{ kind, color, durationMs?, radius? }`,
|
|
55
|
+
* with any provided `overrides` winning field by field. An unknown name resolves to
|
|
56
|
+
* {@link DEFAULT_VFX_PRESET} rather than throwing, so a flavor typo degrades to a visible
|
|
57
|
+
* spark. Used by `ctx.scene.entity.vfx({ preset })`; call it directly when you need the raw
|
|
58
|
+
* numbers (e.g. to seed a retained `vfxInstance` from the same vocabulary).
|
|
59
|
+
*
|
|
60
|
+
* @capability vfx-preset-resolve turn a named attack flavor into concrete vfx kind/color/duration with per-field overrides
|
|
61
|
+
*/
|
|
62
|
+
export function resolveVfxPreset(name, overrides) {
|
|
63
|
+
const base = name !== undefined && name in vfxPresets
|
|
64
|
+
? vfxPresets[name]
|
|
65
|
+
: vfxPresets[DEFAULT_VFX_PRESET];
|
|
66
|
+
const durationMs = overrides?.durationMs ?? base.durationMs;
|
|
67
|
+
const radius = overrides?.radius ?? base.radius;
|
|
68
|
+
return {
|
|
69
|
+
kind: overrides?.kind ?? base.kind,
|
|
70
|
+
color: overrides?.color ?? base.color,
|
|
71
|
+
...(durationMs === undefined ? {} : { durationMs }),
|
|
72
|
+
...(radius === undefined ? {} : { radius }),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { type DamageHitInput, type DamageHitResolution } from "./damageResolution.js";
|
|
2
|
+
import { type Magazine, type MagazineConfig } from "./magazine.js";
|
|
3
|
+
/** Tuning for {@link createFireCadence}: the minimum interval between actions and whether it starts ready. */
|
|
4
|
+
export interface FireCadenceConfig {
|
|
5
|
+
/** Minimum milliseconds between successful `fire()` calls. `<= 0` disables the limit (always ready). */
|
|
6
|
+
intervalMs: number;
|
|
7
|
+
/** Start ready to fire (default) or mid-cooldown. */
|
|
8
|
+
ready?: boolean;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* A minimal minimum-interval rate gate for a repeated action — weapon fire, ability
|
|
12
|
+
* spam, any "no faster than N per second" rule. Deterministic and serializable: its
|
|
13
|
+
* whole state is the elapsed time since the last action, exposed via {@link FireCadence.elapsedMs}.
|
|
14
|
+
*/
|
|
15
|
+
export interface FireCadence {
|
|
16
|
+
/** True when at least `intervalMs` has elapsed since the last successful `fire()`. */
|
|
17
|
+
ready(): boolean;
|
|
18
|
+
/** Progress toward ready in `[0, 1]`; `1` when ready. */
|
|
19
|
+
readyFraction(): number;
|
|
20
|
+
/** Milliseconds until ready; `0` when ready. */
|
|
21
|
+
remainingMs(): number;
|
|
22
|
+
/** Consume the gate: resets the interval and returns `true`, or returns `false` without effect when not `ready()`. */
|
|
23
|
+
fire(): boolean;
|
|
24
|
+
/** Advance the internal clock by `dtSeconds`. */
|
|
25
|
+
tick(dtSeconds: number): void;
|
|
26
|
+
/** Elapsed milliseconds since the last successful `fire()` (capped at `intervalMs`) — the full serializable state. */
|
|
27
|
+
elapsedMs(): number;
|
|
28
|
+
/** Restore a prior {@link FireCadence.elapsedMs} value (e.g. from a save/replay snapshot). */
|
|
29
|
+
restore(elapsedMs: number): void;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Build a {@link FireCadence} rate gate. Reach for this instead of hand-tracking a
|
|
33
|
+
* `lastFiredAt` timestamp and comparing against a fire interval per game.
|
|
34
|
+
*
|
|
35
|
+
* @capability fire-cadence a serializable minimum-interval rate gate for repeated actions (weapon fire, ability spam)
|
|
36
|
+
*/
|
|
37
|
+
export declare function createFireCadence(config: FireCadenceConfig): FireCadence;
|
|
38
|
+
/** Why a {@link WeaponRuntime.fire} attempt resolved the way it did. */
|
|
39
|
+
export type WeaponFireStatus = "fired" | "cooling" | "empty" | "reloading";
|
|
40
|
+
/**
|
|
41
|
+
* The result of a {@link WeaponRuntime.fire} attempt. On `"fired"`, `hits` is whatever the
|
|
42
|
+
* caller's raycast returned and `resolutions` holds the portable damage provenance for each hit
|
|
43
|
+
* that produced a {@link DamageHitInput}; on any blocked status both are empty and no round was spent.
|
|
44
|
+
*/
|
|
45
|
+
export interface WeaponFireResult<THit> {
|
|
46
|
+
status: WeaponFireStatus;
|
|
47
|
+
/** The hits the caller's `resolveHits` returned (empty when the shot was blocked). */
|
|
48
|
+
hits: readonly THit[];
|
|
49
|
+
/** One {@link DamageHitResolution} per hit that mapped to a {@link DamageHitInput}. */
|
|
50
|
+
resolutions: readonly DamageHitResolution[];
|
|
51
|
+
/** Loaded rounds remaining after the attempt, or `null` when the weapon has no magazine. */
|
|
52
|
+
loaded: number | null;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Configuration for {@link createWeaponRuntime}. Everything time/ammo-related is plain data; the
|
|
56
|
+
* two callbacks are where the caller keeps ownership of aiming, its own raycaster/projectile query,
|
|
57
|
+
* and how a hit maps to damage. There is deliberately no default weapon, projectile, or damage
|
|
58
|
+
* table here — those are game content.
|
|
59
|
+
*/
|
|
60
|
+
export interface WeaponRuntimeConfig<TAim, THit> {
|
|
61
|
+
/** Minimum milliseconds between shots. From a rounds-per-second fire rate, pass `1000 / roundsPerSecond`. */
|
|
62
|
+
cadenceMs: number;
|
|
63
|
+
/** Optional discrete-ammo model; omit for an unlimited-fire weapon. */
|
|
64
|
+
magazine?: MagazineConfig;
|
|
65
|
+
/** Start the cadence ready to fire (default) or mid-cooldown. */
|
|
66
|
+
ready?: boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Caller-owned aim → hits. This is where the game runs its OWN raycaster, projectile sweep, or
|
|
69
|
+
* spatial query and returns whatever hit shape it likes. Called once per fired shot.
|
|
70
|
+
*/
|
|
71
|
+
resolveHits: (aim: TAim) => readonly THit[];
|
|
72
|
+
/**
|
|
73
|
+
* Map one resolved hit into a portable {@link DamageHitInput}, or `null` to skip damage for that
|
|
74
|
+
* hit (e.g. a wall). The runtime feeds the result to {@link resolveDamageHit}.
|
|
75
|
+
*/
|
|
76
|
+
damageFor: (hit: THit, aim: TAim) => DamageHitInput | null;
|
|
77
|
+
/** Deterministic RNG forwarded to status rolls in {@link resolveDamageHit} when a hit's input omits its own. */
|
|
78
|
+
rng?: () => number;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* A composed weapon fire controller: a {@link FireCadence} gate, an optional {@link Magazine}, the
|
|
82
|
+
* caller's raycast, and portable {@link resolveDamageHit} damage resolution wired together. The
|
|
83
|
+
* caller retains ownership of models, animations, muzzle flash, audio, input, camera, aiming, and
|
|
84
|
+
* the raycaster itself.
|
|
85
|
+
*/
|
|
86
|
+
export interface WeaponRuntime<TAim, THit> {
|
|
87
|
+
/**
|
|
88
|
+
* Attempt one shot with the given aim. Gates on cadence, reload state, and ammo (in that order);
|
|
89
|
+
* only a `"fired"` result spends a round, resets the cadence, runs `resolveHits`, and resolves damage.
|
|
90
|
+
*/
|
|
91
|
+
fire(aim: TAim): WeaponFireResult<THit>;
|
|
92
|
+
/** Whether {@link WeaponRuntime.fire} would fire right now (cadence ready, not reloading, ammo available). */
|
|
93
|
+
canFire(): boolean;
|
|
94
|
+
/** Begin a magazine reload if possible; always `false` for a weapon with no magazine. */
|
|
95
|
+
startReload(): boolean;
|
|
96
|
+
/** Abort an in-progress reload. */
|
|
97
|
+
cancelReload(): void;
|
|
98
|
+
/** Advance the cadence gate and any magazine reload timer by `dtSeconds`. */
|
|
99
|
+
tick(dtSeconds: number): void;
|
|
100
|
+
/** The underlying cadence gate (for HUD readouts and snapshot/restore). */
|
|
101
|
+
readonly cadence: FireCadence;
|
|
102
|
+
/** The magazine, or `null` when the weapon has no ammo model. */
|
|
103
|
+
readonly magazine: Magazine | null;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Compose a portable weapon fire controller from the existing generic primitives — a
|
|
107
|
+
* {@link FireCadence} gate, an optional {@link Magazine}, a caller-provided raycast, and portable
|
|
108
|
+
* {@link resolveDamageHit} damage resolution. No `GameContext`, entity store, renderer, or default
|
|
109
|
+
* weapon is involved; the caller owns aiming, its raycaster, and all presentation, and the result
|
|
110
|
+
* carries full damage provenance for authority to apply and replicate.
|
|
111
|
+
*
|
|
112
|
+
* @capability weapon-runtime compose cadence, magazine, a caller-owned raycast, and portable damage resolution into a fire controller
|
|
113
|
+
*/
|
|
114
|
+
export declare function createWeaponRuntime<TAim, THit>(config: WeaponRuntimeConfig<TAim, THit>): WeaponRuntime<TAim, THit>;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { resolveDamageHit } from "./damageResolution.js";
|
|
2
|
+
import { createMagazine } from "./magazine.js";
|
|
3
|
+
/**
|
|
4
|
+
* Build a {@link FireCadence} rate gate. Reach for this instead of hand-tracking a
|
|
5
|
+
* `lastFiredAt` timestamp and comparing against a fire interval per game.
|
|
6
|
+
*
|
|
7
|
+
* @capability fire-cadence a serializable minimum-interval rate gate for repeated actions (weapon fire, ability spam)
|
|
8
|
+
*/
|
|
9
|
+
export function createFireCadence(config) {
|
|
10
|
+
const intervalMs = Math.max(0, config.intervalMs);
|
|
11
|
+
let elapsed = config.ready === false ? 0 : intervalMs;
|
|
12
|
+
const ready = () => intervalMs <= 0 || elapsed >= intervalMs;
|
|
13
|
+
return {
|
|
14
|
+
ready,
|
|
15
|
+
readyFraction: () => (intervalMs <= 0 ? 1 : Math.min(1, elapsed / intervalMs)),
|
|
16
|
+
remainingMs: () => (ready() ? 0 : intervalMs - elapsed),
|
|
17
|
+
fire() {
|
|
18
|
+
if (!ready())
|
|
19
|
+
return false;
|
|
20
|
+
elapsed = 0;
|
|
21
|
+
return true;
|
|
22
|
+
},
|
|
23
|
+
tick(dtSeconds) {
|
|
24
|
+
if (dtSeconds <= 0 || elapsed >= intervalMs)
|
|
25
|
+
return;
|
|
26
|
+
elapsed = Math.min(intervalMs, elapsed + dtSeconds * 1000);
|
|
27
|
+
},
|
|
28
|
+
elapsedMs: () => elapsed,
|
|
29
|
+
restore(value) {
|
|
30
|
+
elapsed = Math.max(0, Math.min(intervalMs, value));
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Compose a portable weapon fire controller from the existing generic primitives — a
|
|
36
|
+
* {@link FireCadence} gate, an optional {@link Magazine}, a caller-provided raycast, and portable
|
|
37
|
+
* {@link resolveDamageHit} damage resolution. No `GameContext`, entity store, renderer, or default
|
|
38
|
+
* weapon is involved; the caller owns aiming, its raycaster, and all presentation, and the result
|
|
39
|
+
* carries full damage provenance for authority to apply and replicate.
|
|
40
|
+
*
|
|
41
|
+
* @capability weapon-runtime compose cadence, magazine, a caller-owned raycast, and portable damage resolution into a fire controller
|
|
42
|
+
*/
|
|
43
|
+
export function createWeaponRuntime(config) {
|
|
44
|
+
const cadence = createFireCadence({
|
|
45
|
+
intervalMs: config.cadenceMs,
|
|
46
|
+
...(config.ready !== undefined ? { ready: config.ready } : {}),
|
|
47
|
+
});
|
|
48
|
+
const magazine = config.magazine === undefined ? null : createMagazine(config.magazine);
|
|
49
|
+
const loadedOf = () => (magazine === null ? null : magazine.loaded());
|
|
50
|
+
const blocked = (status) => ({
|
|
51
|
+
status,
|
|
52
|
+
hits: [],
|
|
53
|
+
resolutions: [],
|
|
54
|
+
loaded: loadedOf(),
|
|
55
|
+
});
|
|
56
|
+
const canFire = () => {
|
|
57
|
+
if (magazine !== null && magazine.isReloading())
|
|
58
|
+
return false;
|
|
59
|
+
if (!cadence.ready())
|
|
60
|
+
return false;
|
|
61
|
+
if (magazine !== null && !magazine.canFire(1))
|
|
62
|
+
return false;
|
|
63
|
+
return true;
|
|
64
|
+
};
|
|
65
|
+
return {
|
|
66
|
+
cadence,
|
|
67
|
+
magazine,
|
|
68
|
+
canFire,
|
|
69
|
+
startReload: () => (magazine === null ? false : magazine.startReload()),
|
|
70
|
+
cancelReload: () => magazine?.cancelReload(),
|
|
71
|
+
tick(dtSeconds) {
|
|
72
|
+
cadence.tick(dtSeconds);
|
|
73
|
+
magazine?.tick(dtSeconds);
|
|
74
|
+
},
|
|
75
|
+
fire(aim) {
|
|
76
|
+
if (magazine !== null && magazine.isReloading())
|
|
77
|
+
return blocked("reloading");
|
|
78
|
+
if (!cadence.ready())
|
|
79
|
+
return blocked("cooling");
|
|
80
|
+
if (magazine !== null && !magazine.canFire(1))
|
|
81
|
+
return blocked("empty");
|
|
82
|
+
cadence.fire();
|
|
83
|
+
magazine?.fire(1);
|
|
84
|
+
const hits = config.resolveHits(aim);
|
|
85
|
+
const resolutions = [];
|
|
86
|
+
for (const hit of hits) {
|
|
87
|
+
const input = config.damageFor(hit, aim);
|
|
88
|
+
if (input === null)
|
|
89
|
+
continue;
|
|
90
|
+
const withRng = config.rng !== undefined && input.rng === undefined ? { ...input, rng: config.rng } : input;
|
|
91
|
+
resolutions.push(resolveDamageHit(withRng));
|
|
92
|
+
}
|
|
93
|
+
return { status: "fired", hits, resolutions, loaded: loadedOf() };
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
}
|
package/dist/combat.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ export { createDownedState } from "./combat/downed.js";
|
|
|
16
16
|
export { createEffectSystem, type ReceiveMap } from "./combat/effects.js";
|
|
17
17
|
export { BUILTIN_COMPLETION_PREDICATES, BUILTIN_SPAWN_PROVIDERS, activePhaseId, createEncounterState, encounterProgress, forceCompletePhase, injectPhase, phaseStatus, startEncounter, updateEncounter, type CompletionPredicate, type EncounterConfig, type EncounterContext, type EncounterEvent, type EncounterPhase, type EncounterSignals, type EncounterSpawnRequest, type EncounterState, type EncounterStep, type PhaseCompletionRef, type PhaseInjectAt, type PhaseRuntime, type PhaseSpawnRef, type PhaseStatus, type PredicateContext, type SpawnProvider, type SpawnProviderContext, } from "./combat/encounterSequence.js";
|
|
18
18
|
export { impactPresets, resolveHitReaction, type HitReactionConfig } from "./combat/hitReaction.js";
|
|
19
|
-
export { createMagazine, type Magazine, type MagazineReserve } from "./combat/magazine.js";
|
|
19
|
+
export { createMagazine, type Magazine, type MagazineConfig, type MagazineReserve, type MagazineSnapshot, } from "./combat/magazine.js";
|
|
20
20
|
export { createProjectileSystem, type ObjectRaycastHit, type ProjectileSystemDeps, type RaycastHit, } from "./combat/projectiles.js";
|
|
21
21
|
export { resolveReceivedDamage, type DamageContext, type DamagePredicate, type ReceivedDamageResult, type ReceivedModifier, type ReceivedPolicy, } from "./combat/receivedDamage.js";
|
|
22
22
|
export { createRegenShield } from "./combat/regenShield.js";
|
|
@@ -28,7 +28,10 @@ export { DEFAULT_EYE_HEIGHT, convergeShot, eyeHeightFromColliders, resolveShot,
|
|
|
28
28
|
export { resolveStatusApplication, type StatusApplicationOutcome, type StatusApplicationSpec, type StatusImmunity, type StatusInstance, type StatusStackPolicy, } from "./combat/statusApplication.js";
|
|
29
29
|
export { type TelegraphConfig, type TelegraphShape } from "./combat/telegraph.js";
|
|
30
30
|
export { createThresholdTracker, type CrossingDirection, type CrossingPolicy, type CrossingTrigger, type ThresholdCrossing, type ThresholdCrossingConfig, type ThresholdMark, type ThresholdTracker, type ThresholdTrackerSnapshot, } from "./combat/thresholdCrossings.js";
|
|
31
|
+
export { DEFAULT_VFX_PRESET, resolveVfxPreset, vfxPresets, type VfxPreset, type VfxPresetName, } from "./combat/vfxPresets.js";
|
|
32
|
+
export { createFireCadence, createWeaponRuntime, type FireCadence, type FireCadenceConfig, type WeaponFireResult, type WeaponFireStatus, type WeaponRuntime, type WeaponRuntimeConfig, } from "./combat/weaponFire.js";
|
|
31
33
|
export { createAccumulatorMeter, tierAt, type MeterAddResult } from "./stats/accumulatorMeter.js";
|
|
32
34
|
export { createEventMeter, type EventMeter, type EventMeterFeedResult } from "./stats/eventMeter.js";
|
|
33
35
|
export { rollCheck, type CheckAdvantage, type CheckResult } from "./stats/rollCheck.js";
|
|
34
|
-
export { createStats, type Stats } from "./stats/statModifiers.js";
|
|
36
|
+
export { createStats, type Stats, type StatsSnapshot } from "./stats/statModifiers.js";
|
|
37
|
+
export { applyStatPoolDelta, changeStatPool, createStatPool, patchStatPool, type StatPool, type StatPoolAccess, type StatPoolAccessResult, type StatPoolChange, type StatPoolInput, type StatPoolPatch, } from "./stats/statPool.js";
|
package/dist/combat.js
CHANGED
|
@@ -16,7 +16,7 @@ export { createDownedState } from "./combat/downed.js";
|
|
|
16
16
|
export { createEffectSystem } from "./combat/effects.js";
|
|
17
17
|
export { BUILTIN_COMPLETION_PREDICATES, BUILTIN_SPAWN_PROVIDERS, activePhaseId, createEncounterState, encounterProgress, forceCompletePhase, injectPhase, phaseStatus, startEncounter, updateEncounter, } from "./combat/encounterSequence.js";
|
|
18
18
|
export { impactPresets, resolveHitReaction } from "./combat/hitReaction.js";
|
|
19
|
-
export { createMagazine } from "./combat/magazine.js";
|
|
19
|
+
export { createMagazine, } from "./combat/magazine.js";
|
|
20
20
|
export { createProjectileSystem, } from "./combat/projectiles.js";
|
|
21
21
|
export { resolveReceivedDamage, } from "./combat/receivedDamage.js";
|
|
22
22
|
export { createRegenShield } from "./combat/regenShield.js";
|
|
@@ -28,7 +28,10 @@ export { DEFAULT_EYE_HEIGHT, convergeShot, eyeHeightFromColliders, resolveShot,
|
|
|
28
28
|
export { resolveStatusApplication, } from "./combat/statusApplication.js";
|
|
29
29
|
export {} from "./combat/telegraph.js";
|
|
30
30
|
export { createThresholdTracker, } from "./combat/thresholdCrossings.js";
|
|
31
|
+
export { DEFAULT_VFX_PRESET, resolveVfxPreset, vfxPresets, } from "./combat/vfxPresets.js";
|
|
32
|
+
export { createFireCadence, createWeaponRuntime, } from "./combat/weaponFire.js";
|
|
31
33
|
export { createAccumulatorMeter, tierAt } from "./stats/accumulatorMeter.js";
|
|
32
34
|
export { createEventMeter } from "./stats/eventMeter.js";
|
|
33
35
|
export { rollCheck } from "./stats/rollCheck.js";
|
|
34
36
|
export { createStats } from "./stats/statModifiers.js";
|
|
37
|
+
export { applyStatPoolDelta, changeStatPool, createStatPool, patchStatPool, } from "./stats/statPool.js";
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { ChangeSignal } from "../store/changeSignal.js";
|
|
2
|
+
import { type AngleUnit, type DevtoolsControlKind, type ResolvedAxisBounds, type TunableChoice, type TunableOptions } from "./tunableSchema.js";
|
|
3
|
+
import type { Devtools, Tunable } from "./types.js";
|
|
4
|
+
/** Internal mutable record backing a registered control: schema metadata, current value, and change listeners. */
|
|
5
|
+
export interface ControlRecord {
|
|
6
|
+
name: string;
|
|
7
|
+
kind: DevtoolsControlKind;
|
|
8
|
+
label: string;
|
|
9
|
+
group: string;
|
|
10
|
+
initial: unknown;
|
|
11
|
+
value: unknown;
|
|
12
|
+
min?: number;
|
|
13
|
+
max?: number;
|
|
14
|
+
step?: number;
|
|
15
|
+
options?: readonly unknown[];
|
|
16
|
+
choices?: readonly TunableChoice[];
|
|
17
|
+
unit?: AngleUnit;
|
|
18
|
+
displayUnit?: AngleUnit;
|
|
19
|
+
wrap?: boolean;
|
|
20
|
+
integer?: boolean;
|
|
21
|
+
axisBounds?: ResolvedAxisBounds;
|
|
22
|
+
hasAlpha?: boolean;
|
|
23
|
+
schemaVersion: number;
|
|
24
|
+
listeners: Set<(value: unknown) => void>;
|
|
25
|
+
}
|
|
26
|
+
/** @internal */
|
|
27
|
+
export declare function isStructuralKind(kind: DevtoolsControlKind): boolean;
|
|
28
|
+
/** Controls subsystem: the public controls facade plus internal register/write helpers and the record map. */
|
|
29
|
+
export interface ControlsModule {
|
|
30
|
+
controls: Devtools["controls"];
|
|
31
|
+
register: <T>(name: string, initial: T, options?: TunableOptions<T>) => Tunable<T>;
|
|
32
|
+
writeControl: (record: ControlRecord, raw: unknown) => boolean;
|
|
33
|
+
controlRecords: Map<string, ControlRecord>;
|
|
34
|
+
}
|
|
35
|
+
/** Create the controls subsystem that registers, validates, and mutates tunable controls, notifying on change. */
|
|
36
|
+
export declare const createControlsModule: (deps: {
|
|
37
|
+
signal: ChangeSignal;
|
|
38
|
+
}) => ControlsModule;
|