incanto 0.34.0 → 0.35.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/dist/2d.d.ts +5 -5
- package/dist/2d.js +3 -3
- package/dist/3d.d.ts +122 -14
- package/dist/3d.js +5 -5
- package/dist/{audit-C4kmDK0o.js → audit-C5oZGAru.js} +37 -0
- package/dist/{behavior-CtPScDMo.d.ts → behavior-CGSCWOHB.d.ts} +310 -22
- package/dist/{create-game-CFNqoqOX.js → create-game-B0Wfhi2-.js} +6 -5
- package/dist/{create-game-QTfghzwM.js → create-game-BUD89Kqh.js} +20 -6
- package/dist/debug.d.ts +1 -1
- package/dist/{duplicate-DlOvknDO.js → duplicate-C716f-97.js} +1 -1
- package/dist/{editor-switch-BJb-CWfA.d.ts → editor-switch-DyXEtH36.d.ts} +1 -1
- package/dist/editor.js +1739 -1312
- package/dist/env.d.ts +1 -1
- package/dist/{environment-presets-B6WiUsaO.js → environment-presets-TAGvmM3z.js} +240 -74
- package/dist/{errors-1dXlIwoR.d.ts → errors-BY2kL0hv.d.ts} +1 -1
- package/dist/{gameplay-BxFtmfSe.js → gameplay-BvhcQbfJ.js} +75 -11
- package/dist/gameplay.d.ts +12 -5
- package/dist/gameplay.js +1 -1
- package/dist/index.d.ts +22 -7
- package/dist/index.js +6 -6
- package/dist/{loader-DmXfj6Uv.d.ts → loader-CUcj00M8.d.ts} +19 -2
- package/dist/{loader-BwR0DxeM.js → loader-Mig5fY4n.js} +97 -18
- package/dist/net.d.ts +2 -2
- package/dist/net.js +3 -3
- package/dist/{particle-sim-CwJ5rI_P.d.ts → particle-sim-B-vZBF5R.d.ts} +1 -1
- package/dist/{pathfinding-DRCe89SI.d.ts → pathfinding-DgOo2KNF.d.ts} +1 -1
- package/dist/{physics-2d-BuyAwsW5.js → physics-2d-DqAclql-.js} +22 -9
- package/dist/{physics-3d-C8Kn_Nyb.js → physics-3d-DxBH4sIF.js} +27 -11
- package/dist/react.d.ts +2 -2
- package/dist/react.js +1 -1
- package/dist/{register-G3edsjJ2.js → register-BFLg0-_i.js} +490 -12
- package/dist/{register-OodmuUMK.js → register-BjbPMA5B.js} +2 -2
- package/dist/{register-BLPC10Mj.js → register-DSmIRAf7.js} +11 -5
- package/dist/{schema-CcoWb32N.d.ts → schema-3ywbdlrv.d.ts} +10 -0
- package/dist/{test-C4B5znap.js → test-9EokzbRd.js} +10 -10
- package/dist/test.d.ts +4 -4
- package/dist/test.js +2 -2
- package/dist/vite.js +1 -1
- package/editor/assets/{agent8-BTODHtdM.js → agent8-D3_GWeuh.js} +1 -1
- package/editor/assets/{debug-CJEz4EwC.js → debug-CX0LDd1r.js} +1 -1
- package/editor/assets/index-CMlKFT0C.js +10773 -0
- package/editor/index.html +1 -1
- package/package.json +1 -1
- package/schemas/scene.schema.json +109 -0
- package/skills/incanto-assets.md +21 -0
- package/skills/incanto-behaviors-and-scripts.md +16 -0
- package/skills/incanto-editor.md +17 -1
- package/skills/incanto-gameplay-behaviors.md +6 -0
- package/skills/incanto-hud.md +16 -0
- package/skills/incanto-localization.md +132 -0
- package/skills/incanto-node-reference.md +33 -18
- package/skills/incanto-save-slots.md +152 -0
- package/templates-app/beacon-isle-3d/package.json +1 -1
- package/templates-app/tps-3d/package.json +1 -1
- package/templates-app/village-quest-3d/PROJECT/Context.md +16 -0
- package/templates-app/village-quest-3d/package.json +1 -1
- package/templates-app/village-quest-3d/src/village.scene.json +25 -3
- package/editor/assets/index-BYCso8Bf.js +0 -10696
package/dist/env.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as Rng, i as SceneJson, n as NodeJson, s as JsonObject } from "./schema-
|
|
1
|
+
import { a as Rng, i as SceneJson, n as NodeJson, s as JsonObject } from "./schema-3ywbdlrv.js";
|
|
2
2
|
|
|
3
3
|
//#region src/env/arena.d.ts
|
|
4
4
|
/** Valid `generateArena` themes — drives the catalog options AND validation. */
|
|
@@ -1,13 +1,157 @@
|
|
|
1
|
-
import { t as registerCoreNodes } from "./register-
|
|
1
|
+
import { t as registerCoreNodes } from "./register-BFLg0-_i.js";
|
|
2
2
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
3
3
|
import { t as Rng } from "./rng-DP-SR7eg.js";
|
|
4
4
|
import { i as getNodeSchema, l as registerNode } from "./registry-CJdGpT2V.js";
|
|
5
5
|
import { t as createNoise2D } from "./noise-CGUMx44x.js";
|
|
6
6
|
import { i as applyParticlePreset, r as PARTICLE_PRESET_NAMES, t as ParticleSim } from "./particle-sim-Bw7hB93B.js";
|
|
7
|
-
import { A as Water3D, F as PhysicsBody3D, H as colliderFootDrop, I as RigidBody3D, L as StaticBody3D, M as WaterCutout3D, N as Area3D, P as CharacterBody3D, R as Node3D } from "./gameplay-
|
|
7
|
+
import { A as Water3D, F as PhysicsBody3D, H as colliderFootDrop, I as RigidBody3D, L as StaticBody3D, M as WaterCutout3D, N as Area3D, P as CharacterBody3D, R as Node3D } from "./gameplay-BvhcQbfJ.js";
|
|
8
8
|
import { n as splatWeights, t as buildHeightmap } from "./heightmap-CRK0M4jT.js";
|
|
9
|
-
import { AdditiveBlending, AnimationClip, AnimationMixer, Box3, BoxGeometry, BufferAttribute, BufferGeometry, CanvasTexture, CapsuleGeometry, Color, ConeGeometry, CylinderGeometry, DataTexture, DirectionalLight, DoubleSide, DynamicDrawUsage, Euler, Group, IcosahedronGeometry, ImageBitmapLoader, InstancedBufferAttribute, InstancedMesh, LinearFilter, LoopOnce, LoopRepeat, Matrix4, Mesh, MeshBasicMaterial, MeshDepthMaterial, MeshPhysicalMaterial, MeshStandardMaterial, NearestFilter, NoBlending, NormalBlending, PerspectiveCamera, PlaneGeometry, PointLight, Points, PointsMaterial, Quaternion, QuaternionKeyframeTrack, RGBADepthPacking, RGBAFormat, RepeatWrapping, SRGBColorSpace, ShaderChunk, ShaderMaterial, SphereGeometry, Texture, TextureLoader, UniformsLib, UniformsUtils, Vector3, Vector4, VectorKeyframeTrack } from "three";
|
|
9
|
+
import { AdditiveBlending, AnimationClip, AnimationMixer, Box3, BoxGeometry, BufferAttribute, BufferGeometry, CanvasTexture, CapsuleGeometry, ClampToEdgeWrapping, Color, ConeGeometry, CylinderGeometry, DataTexture, DirectionalLight, DoubleSide, DynamicDrawUsage, Euler, Group, IcosahedronGeometry, ImageBitmapLoader, InstancedBufferAttribute, InstancedMesh, LinearFilter, LinearMipmapLinearFilter, LoopOnce, LoopRepeat, Matrix4, Mesh, MeshBasicMaterial, MeshDepthMaterial, MeshPhysicalMaterial, MeshStandardMaterial, NearestFilter, NoBlending, NoColorSpace, NormalBlending, PerspectiveCamera, PlaneGeometry, PointLight, Points, PointsMaterial, Quaternion, QuaternionKeyframeTrack, RGBADepthPacking, RGBAFormat, RepeatWrapping, SRGBColorSpace, ShaderChunk, ShaderMaterial, SphereGeometry, Texture, TextureLoader, UniformsLib, UniformsUtils, Vector3, Vector4, VectorKeyframeTrack } from "three";
|
|
10
10
|
import { clone } from "three/addons/utils/SkeletonUtils.js";
|
|
11
|
+
//#region src/3d/textures.ts
|
|
12
|
+
/**
|
|
13
|
+
* One decode per image, however many nodes want it.
|
|
14
|
+
*
|
|
15
|
+
* Four places each built their own `new TextureLoader()` per node — `Sprite3D`,
|
|
16
|
+
* `AnimatedSprite3D`, `MeshInstance3D`, `Terrain3D` — so a hundred sprite mobs
|
|
17
|
+
* sharing one atlas meant a hundred fetches, a hundred decodes and a hundred GPU
|
|
18
|
+
* uploads. `AssetStore3D` knew only `model` and `animation`; textures had no
|
|
19
|
+
* owner at all. The 2D side has solved this since day one (`2d/assets.ts`).
|
|
20
|
+
*
|
|
21
|
+
* `tree-3d.ts` keeps its own map and is deliberately NOT folded in here: it
|
|
22
|
+
* already dedupes, it decodes off-thread through `ImageBitmapLoader`, and its
|
|
23
|
+
* page-session lifetime is load-bearing (the editor builds and disposes three
|
|
24
|
+
* renderers, so store-scoping it would re-decode every bark and leaf on every
|
|
25
|
+
* Play). Nothing to fix there.
|
|
26
|
+
*
|
|
27
|
+
* **`acquire` returns the SHARED texture.** That is the important default and it
|
|
28
|
+
* is deliberately not a clone: `Texture.copy()` ends with `needsUpdate = true`,
|
|
29
|
+
* which bumps `source.version`, which makes the next draw re-upload the whole
|
|
30
|
+
* image. Cloning on every acquire would turn "spawn an enemy per frame" into
|
|
31
|
+
* "re-upload the atlas per frame" — precisely the stall this file exists to
|
|
32
|
+
* remove.
|
|
33
|
+
*
|
|
34
|
+
* `acquireOwn` is for the two nodes that genuinely hold per-node UV state:
|
|
35
|
+
* `AnimatedSprite3D` (a frame window) and `MeshInstance3D` (`repeat`). A clone
|
|
36
|
+
* shares `texture.source`, so three still fetches and decodes once and, when the
|
|
37
|
+
* sampler parameters match, hands out one GL texture for all of them.
|
|
38
|
+
*/
|
|
39
|
+
const defaultLoad = (url, onError) => new TextureLoader().load(url, void 0, void 0, onError);
|
|
40
|
+
function keyOf(url, spec) {
|
|
41
|
+
return [
|
|
42
|
+
url,
|
|
43
|
+
spec?.colorSpace ?? "srgb",
|
|
44
|
+
spec?.filter ?? "linear",
|
|
45
|
+
spec?.wrap ?? "clamp",
|
|
46
|
+
String(spec?.anisotropy ?? 1),
|
|
47
|
+
spec?.process?.id ?? ""
|
|
48
|
+
].join("|");
|
|
49
|
+
}
|
|
50
|
+
function dress(texture, spec) {
|
|
51
|
+
texture.colorSpace = (spec?.colorSpace ?? "srgb") === "srgb" ? SRGBColorSpace : NoColorSpace;
|
|
52
|
+
const nearest = spec?.filter === "nearest";
|
|
53
|
+
texture.magFilter = nearest ? NearestFilter : LinearFilter;
|
|
54
|
+
texture.generateMipmaps = !nearest;
|
|
55
|
+
texture.minFilter = nearest ? NearestFilter : LinearMipmapLinearFilter;
|
|
56
|
+
const wrap = spec?.wrap === "repeat" ? RepeatWrapping : ClampToEdgeWrapping;
|
|
57
|
+
texture.wrapS = wrap;
|
|
58
|
+
texture.wrapT = wrap;
|
|
59
|
+
if (spec?.anisotropy) texture.anisotropy = spec.anisotropy;
|
|
60
|
+
}
|
|
61
|
+
var TextureCache3D = class {
|
|
62
|
+
entries = /* @__PURE__ */ new Map();
|
|
63
|
+
load;
|
|
64
|
+
diagnostics;
|
|
65
|
+
constructor(opts) {
|
|
66
|
+
this.load = opts?.loader ?? defaultLoad;
|
|
67
|
+
this.diagnostics = opts?.diagnostics ?? null;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* The SHARED texture for this url+spec, or null with no DOM to decode in.
|
|
71
|
+
*
|
|
72
|
+
* Callers must NOT mutate `offset`/`repeat`/`center`/`rotation` on it — that
|
|
73
|
+
* is what `acquireOwn` is for — and must not dispose it; the store owns it.
|
|
74
|
+
*/
|
|
75
|
+
acquire(url, spec) {
|
|
76
|
+
if (url === "") return null;
|
|
77
|
+
if (typeof document === "undefined" && this.load === defaultLoad) return null;
|
|
78
|
+
const key = keyOf(url, spec);
|
|
79
|
+
const found = this.entries.get(key);
|
|
80
|
+
if (found) return found.texture;
|
|
81
|
+
const entry = {
|
|
82
|
+
url,
|
|
83
|
+
texture: null,
|
|
84
|
+
error: null
|
|
85
|
+
};
|
|
86
|
+
entry.texture = this.load(url, (error) => {
|
|
87
|
+
entry.error = error instanceof Error ? error.message : String(error);
|
|
88
|
+
this.diagnostics?.warn(`texture failed to load: ${url} — ${entry.error}`);
|
|
89
|
+
});
|
|
90
|
+
dress(entry.texture, spec);
|
|
91
|
+
spec?.process?.run(entry.texture);
|
|
92
|
+
this.entries.set(key, entry);
|
|
93
|
+
return entry.texture;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* A private CLONE, for a node that writes its own UV window.
|
|
97
|
+
*
|
|
98
|
+
* The caller owns it and disposes it in `free()`. That is safe: three
|
|
99
|
+
* refcounts the GPU texture per `source`, so disposing one clone does not
|
|
100
|
+
* pull the image out from under the others.
|
|
101
|
+
*/
|
|
102
|
+
acquireOwn(url, spec) {
|
|
103
|
+
const master = this.acquire(url, spec);
|
|
104
|
+
return master ? master.clone() : null;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* What 404'd, by URL — reported raw, never by cache key, because an agent
|
|
108
|
+
* greps this against the URL it wrote.
|
|
109
|
+
*/
|
|
110
|
+
errors() {
|
|
111
|
+
const out = [];
|
|
112
|
+
for (const entry of this.entries.values()) if (entry.error !== null) out.push({
|
|
113
|
+
url: entry.url,
|
|
114
|
+
error: entry.error
|
|
115
|
+
});
|
|
116
|
+
return out;
|
|
117
|
+
}
|
|
118
|
+
/** How many distinct images this store has decoded — the point, measurable. */
|
|
119
|
+
size() {
|
|
120
|
+
return this.entries.size;
|
|
121
|
+
}
|
|
122
|
+
dispose() {
|
|
123
|
+
for (const entry of this.entries.values()) entry.texture.dispose();
|
|
124
|
+
this.entries.clear();
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
/**
|
|
128
|
+
* The one call a node makes: shared texture through the store, or an uncached
|
|
129
|
+
* load when there is no store (a detached probe, a headless test).
|
|
130
|
+
*
|
|
131
|
+
* The fallback is deliberately silent and deliberately uncached — a node that
|
|
132
|
+
* renders outside a renderer walk is a legitimate case (`Tree3D._trunk()` builds
|
|
133
|
+
* detached), and failing there would be worse than doing the work twice.
|
|
134
|
+
*/
|
|
135
|
+
function acquireTexture(assets, url, spec) {
|
|
136
|
+
if (assets) return assets.textures.acquire(url, spec);
|
|
137
|
+
return uncached().acquire(url, spec);
|
|
138
|
+
}
|
|
139
|
+
/** As `acquireTexture`, but a private clone for a node with its own UV window. */
|
|
140
|
+
function acquireOwnTexture(assets, url, spec) {
|
|
141
|
+
if (assets) return assets.textures.acquireOwn(url, spec);
|
|
142
|
+
return uncached().acquireOwn(url, spec);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* A throwaway cache for the store-less path.
|
|
146
|
+
*
|
|
147
|
+
* Not a module-level shared instance: that is the module-level engine state the
|
|
148
|
+
* repo bans, and it is what `tree-3d.ts` had. One decode per call here is the
|
|
149
|
+
* honest cost of rendering outside a renderer.
|
|
150
|
+
*/
|
|
151
|
+
function uncached() {
|
|
152
|
+
return new TextureCache3D();
|
|
153
|
+
}
|
|
154
|
+
//#endregion
|
|
11
155
|
//#region src/3d/camera-rig.ts
|
|
12
156
|
const QUARTER_PITCH = Math.atan(1 / Math.SQRT2);
|
|
13
157
|
function rigPose(view, player, eyeHeight, yaw, pitch, distance) {
|
|
@@ -227,8 +371,8 @@ var MeshInstance3D = class extends Node3D {
|
|
|
227
371
|
_createObject3D() {
|
|
228
372
|
return new Mesh(new BoxGeometry(1, 1, 1), new MeshPhysicalMaterial());
|
|
229
373
|
}
|
|
230
|
-
_syncObject3D() {
|
|
231
|
-
super._syncObject3D();
|
|
374
|
+
_syncObject3D(alpha = 1, assets = null) {
|
|
375
|
+
super._syncObject3D(alpha, assets);
|
|
232
376
|
const m = this._ensureObject3D();
|
|
233
377
|
const key = `${this.mesh}:${JSON.stringify(this.size)}`;
|
|
234
378
|
if (key !== this.geometryKey) {
|
|
@@ -238,14 +382,14 @@ var MeshInstance3D = class extends Node3D {
|
|
|
238
382
|
}
|
|
239
383
|
const mat = m.material;
|
|
240
384
|
applyMeshMaterial(mat, this.material);
|
|
241
|
-
this.syncTextures(mat);
|
|
385
|
+
this.syncTextures(mat, assets);
|
|
242
386
|
m.castShadow = this.castShadow;
|
|
243
387
|
m.receiveShadow = this.receiveShadow;
|
|
244
388
|
}
|
|
245
389
|
/** Lazy texture dressing — same headless guard as Tree3D bark: without a
|
|
246
390
|
* DOM there is no Image decode, so geometry/colors apply and the maps are
|
|
247
391
|
* skipped. Re-loads only when a texture-shaping key changes. */
|
|
248
|
-
syncTextures(mat) {
|
|
392
|
+
syncTextures(mat, assets) {
|
|
249
393
|
const key = JSON.stringify([
|
|
250
394
|
this.material.map ?? "",
|
|
251
395
|
this.material.normalMap ?? "",
|
|
@@ -258,25 +402,50 @@ var MeshInstance3D = class extends Node3D {
|
|
|
258
402
|
const hadMaps = mat.map !== null || mat.normalMap !== null;
|
|
259
403
|
mat.map = null;
|
|
260
404
|
mat.normalMap = null;
|
|
261
|
-
|
|
262
|
-
if (
|
|
263
|
-
if (loader && this.material.normalMap) mat.normalMap = this.loadTexture(loader, this.material.normalMap, false);
|
|
405
|
+
if (this.material.map) mat.map = this.loadTexture(assets, this.material.map, true);
|
|
406
|
+
if (this.material.normalMap) mat.normalMap = this.loadTexture(assets, this.material.normalMap, false);
|
|
264
407
|
if (hadMaps || mat.map || mat.normalMap) mat.needsUpdate = true;
|
|
265
408
|
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
409
|
+
/**
|
|
410
|
+
* A private CLONE: `repeat` is per-node here (a 1x1 crate and a 8x8 floor
|
|
411
|
+
* share one tile image), and that is the one field a shared master cannot
|
|
412
|
+
* carry. The clone shares `texture.source`, so the fetch and the decode are
|
|
413
|
+
* still done once per url for the whole scene.
|
|
414
|
+
*/
|
|
415
|
+
loadTexture(assets, url, srgb) {
|
|
416
|
+
const texture = acquireOwnTexture(assets, url, {
|
|
417
|
+
wrap: "repeat",
|
|
418
|
+
anisotropy: 4,
|
|
419
|
+
colorSpace: srgb ? "srgb" : "linear"
|
|
420
|
+
});
|
|
421
|
+
if (!texture) return null;
|
|
270
422
|
const [u, v] = this.material.repeat ?? [1, 1];
|
|
271
423
|
texture.repeat.set(u, v);
|
|
272
|
-
texture.anisotropy = 4;
|
|
273
|
-
if (srgb) texture.colorSpace = SRGBColorSpace;
|
|
274
424
|
this.loadedTextures.push(texture);
|
|
275
425
|
return texture;
|
|
276
426
|
}
|
|
427
|
+
/**
|
|
428
|
+
* Give the GPU back everything this node OWNS.
|
|
429
|
+
*
|
|
430
|
+
* It used to dispose textures and nothing else, so every freed mesh leaked its
|
|
431
|
+
* geometry and its material — a wave spawner that kills and respawns fifty
|
|
432
|
+
* enemies a minute leaks fifty of each, forever, and nothing in the game says
|
|
433
|
+
* so. Both are built here (`_createObject3D` news them, `_syncObject3D`
|
|
434
|
+
* rebuilds the geometry on a shape change), so both are ours to release.
|
|
435
|
+
*
|
|
436
|
+
* The textures are NOT: since the shared texture cache they belong to the
|
|
437
|
+
* asset store, except the per-node clones this node asked for, which are what
|
|
438
|
+
* `loadedTextures` holds.
|
|
439
|
+
*/
|
|
277
440
|
free() {
|
|
278
441
|
for (const texture of this.loadedTextures) texture.dispose();
|
|
279
442
|
this.loadedTextures = [];
|
|
443
|
+
const mesh = this._builtObject3D;
|
|
444
|
+
if (mesh) {
|
|
445
|
+
mesh.geometry?.dispose();
|
|
446
|
+
const materials = Array.isArray(mesh.material) ? mesh.material : [mesh.material];
|
|
447
|
+
for (const material of materials) material?.dispose();
|
|
448
|
+
}
|
|
280
449
|
super.free();
|
|
281
450
|
}
|
|
282
451
|
};
|
|
@@ -535,7 +704,10 @@ var Joint3D = class extends Node3D {
|
|
|
535
704
|
"spring"
|
|
536
705
|
]
|
|
537
706
|
},
|
|
538
|
-
target: {
|
|
707
|
+
target: {
|
|
708
|
+
default: "",
|
|
709
|
+
nodePath: true
|
|
710
|
+
},
|
|
539
711
|
anchor: { default: [
|
|
540
712
|
0,
|
|
541
713
|
0,
|
|
@@ -1417,7 +1589,6 @@ var Terrain3D = class extends Node3D {
|
|
|
1417
1589
|
heightmap = null;
|
|
1418
1590
|
heightmapKey = "";
|
|
1419
1591
|
builtKey = "";
|
|
1420
|
-
loadedTextures = [];
|
|
1421
1592
|
_createObject3D() {
|
|
1422
1593
|
const geometry = new BufferGeometry();
|
|
1423
1594
|
geometry.setAttribute("position", new BufferAttribute(new Float32Array(0), 3));
|
|
@@ -1516,9 +1687,9 @@ var Terrain3D = class extends Node3D {
|
|
|
1516
1687
|
if (this.theme === "custom") return this.layers;
|
|
1517
1688
|
return terrainThemeLayers(this.theme, this.textureBase);
|
|
1518
1689
|
}
|
|
1519
|
-
_syncObject3D() {
|
|
1520
|
-
super._syncObject3D();
|
|
1521
|
-
this.rebuildIfNeeded();
|
|
1690
|
+
_syncObject3D(alpha = 1, assets = null) {
|
|
1691
|
+
super._syncObject3D(alpha, assets);
|
|
1692
|
+
this.rebuildIfNeeded(assets);
|
|
1522
1693
|
}
|
|
1523
1694
|
effectiveIslandEdge() {
|
|
1524
1695
|
return this.islandEdge ?? this.theme === "island";
|
|
@@ -1527,7 +1698,7 @@ var Terrain3D = class extends Node3D {
|
|
|
1527
1698
|
return Math.max(2, Math.min(Math.floor(this.resolution), MAX_RESOLUTION));
|
|
1528
1699
|
}
|
|
1529
1700
|
/** Rebuild geometry+material only when a terrain-shaping prop changed. */
|
|
1530
|
-
rebuildIfNeeded() {
|
|
1701
|
+
rebuildIfNeeded(assets) {
|
|
1531
1702
|
const key = JSON.stringify([
|
|
1532
1703
|
this.size,
|
|
1533
1704
|
this.maxHeight,
|
|
@@ -1549,8 +1720,7 @@ var Terrain3D = class extends Node3D {
|
|
|
1549
1720
|
mesh.geometry.dispose();
|
|
1550
1721
|
mesh.geometry = this.buildGeometry();
|
|
1551
1722
|
mesh.material.dispose();
|
|
1552
|
-
this.
|
|
1553
|
-
mesh.material = this.buildMaterial();
|
|
1723
|
+
mesh.material = this.buildMaterial(assets);
|
|
1554
1724
|
mesh.receiveShadow = true;
|
|
1555
1725
|
mesh.castShadow = true;
|
|
1556
1726
|
}
|
|
@@ -1583,20 +1753,14 @@ var Terrain3D = class extends Node3D {
|
|
|
1583
1753
|
geometry.setAttribute("color", new BufferAttribute(colors, 3));
|
|
1584
1754
|
return geometry;
|
|
1585
1755
|
}
|
|
1586
|
-
buildMaterial() {
|
|
1756
|
+
buildMaterial(assets) {
|
|
1587
1757
|
const layers = this.resolvedLayers();
|
|
1588
1758
|
const material = new MeshStandardMaterial({ vertexColors: true });
|
|
1589
|
-
const
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
tex.wrapT = RepeatWrapping;
|
|
1595
|
-
tex.anisotropy = 8;
|
|
1596
|
-
if (srgb) tex.colorSpace = SRGBColorSpace;
|
|
1597
|
-
this.loadedTextures.push(tex);
|
|
1598
|
-
return tex;
|
|
1599
|
-
};
|
|
1759
|
+
const load = (url, srgb) => url ? acquireTexture(assets, url, {
|
|
1760
|
+
wrap: "repeat",
|
|
1761
|
+
anisotropy: 8,
|
|
1762
|
+
colorSpace: srgb ? "srgb" : "linear"
|
|
1763
|
+
}) : null;
|
|
1600
1764
|
const textures = layers.map((l) => load(l.texture, true));
|
|
1601
1765
|
const normalMaps = layers.map((l) => load(l.normalMap, false));
|
|
1602
1766
|
const hasNormalMaps = normalMaps.some((t) => t !== null);
|
|
@@ -1621,15 +1785,10 @@ var Terrain3D = class extends Node3D {
|
|
|
1621
1785
|
material.customProgramCacheKey = () => `incanto-terrain-splat:${hasNormalMaps ? 1 : 0}`;
|
|
1622
1786
|
return material;
|
|
1623
1787
|
}
|
|
1624
|
-
disposeTextures() {
|
|
1625
|
-
for (const tex of this.loadedTextures) tex.dispose();
|
|
1626
|
-
this.loadedTextures = [];
|
|
1627
|
-
}
|
|
1628
1788
|
free() {
|
|
1629
1789
|
const mesh = this._ensureObject3D();
|
|
1630
1790
|
mesh.geometry.dispose();
|
|
1631
1791
|
mesh.material.dispose();
|
|
1632
|
-
this.disposeTextures();
|
|
1633
1792
|
this.heightmap = null;
|
|
1634
1793
|
super.free();
|
|
1635
1794
|
}
|
|
@@ -1776,25 +1935,16 @@ var Sprite3D = class extends Node3D {
|
|
|
1776
1935
|
return this.quadMesh;
|
|
1777
1936
|
}
|
|
1778
1937
|
/** Override point: AnimatedSprite3D substitutes its frame window here. */
|
|
1779
|
-
resolveTexture() {
|
|
1938
|
+
resolveTexture(assets) {
|
|
1780
1939
|
if (!this.texture) return null;
|
|
1781
1940
|
if (this.textureRef !== this.texture) {
|
|
1782
|
-
this.loadedTexture?.dispose();
|
|
1783
|
-
this.loadedTexture = null;
|
|
1784
1941
|
this.textureRef = this.texture;
|
|
1785
|
-
|
|
1786
|
-
const tex = new TextureLoader().load(this.texture);
|
|
1787
|
-
tex.colorSpace = SRGBColorSpace;
|
|
1788
|
-
const filter = this.pixelArt ? NearestFilter : LinearFilter;
|
|
1789
|
-
tex.magFilter = filter;
|
|
1790
|
-
tex.minFilter = filter;
|
|
1791
|
-
this.loadedTexture = tex;
|
|
1792
|
-
}
|
|
1942
|
+
this.loadedTexture = acquireTexture(assets, this.texture, { filter: this.pixelArt ? "nearest" : "linear" });
|
|
1793
1943
|
}
|
|
1794
1944
|
return this.loadedTexture;
|
|
1795
1945
|
}
|
|
1796
|
-
_syncObject3D(alpha = 1) {
|
|
1797
|
-
super._syncObject3D(alpha);
|
|
1946
|
+
_syncObject3D(alpha = 1, assets = null) {
|
|
1947
|
+
super._syncObject3D(alpha, assets);
|
|
1798
1948
|
const quad = this._quad();
|
|
1799
1949
|
const mat = quad.material;
|
|
1800
1950
|
const w = this.size[0] ?? 1;
|
|
@@ -1803,7 +1953,7 @@ var Sprite3D = class extends Node3D {
|
|
|
1803
1953
|
const ax = this.anchor[0] ?? .5;
|
|
1804
1954
|
const ay = this.anchor[1] ?? 0;
|
|
1805
1955
|
quad.position.set((.5 - ax) * w, (.5 - ay) * h, 0);
|
|
1806
|
-
const tex = this.resolveTexture();
|
|
1956
|
+
const tex = this.resolveTexture(assets);
|
|
1807
1957
|
if (mat.map !== tex) {
|
|
1808
1958
|
mat.map = tex;
|
|
1809
1959
|
mat.needsUpdate = true;
|
|
@@ -1999,20 +2149,12 @@ var AnimatedSprite3D = class extends Sprite3D {
|
|
|
1999
2149
|
}
|
|
2000
2150
|
this.currentFrame = this.frameList[this.frameIndex] ?? 0;
|
|
2001
2151
|
}
|
|
2002
|
-
resolveTexture() {
|
|
2152
|
+
resolveTexture(assets) {
|
|
2003
2153
|
if (!this.sheet || this.frameWidth <= 0 || this.frameHeight <= 0) return null;
|
|
2004
2154
|
if (this.loadedSheetRef !== this.sheet) {
|
|
2005
2155
|
this.sheetTexture?.dispose();
|
|
2006
|
-
this.sheetTexture = null;
|
|
2007
2156
|
this.loadedSheetRef = this.sheet;
|
|
2008
|
-
|
|
2009
|
-
const tex = new TextureLoader().load(this.sheet);
|
|
2010
|
-
tex.colorSpace = SRGBColorSpace;
|
|
2011
|
-
const filter = this.pixelArt ? NearestFilter : LinearFilter;
|
|
2012
|
-
tex.magFilter = filter;
|
|
2013
|
-
tex.minFilter = filter;
|
|
2014
|
-
this.sheetTexture = tex;
|
|
2015
|
-
}
|
|
2157
|
+
this.sheetTexture = acquireOwnTexture(assets, this.sheet, { filter: this.pixelArt ? "nearest" : "linear" });
|
|
2016
2158
|
}
|
|
2017
2159
|
const tex = this.sheetTexture;
|
|
2018
2160
|
if (!tex) return null;
|
|
@@ -2141,7 +2283,10 @@ var BoneAttachment3D = class extends Node3D {
|
|
|
2141
2283
|
static typeName = "BoneAttachment3D";
|
|
2142
2284
|
static props = {
|
|
2143
2285
|
/** Node path to the ModelInstance3D whose skeleton to ride. */
|
|
2144
|
-
target: {
|
|
2286
|
+
target: {
|
|
2287
|
+
default: "",
|
|
2288
|
+
nodePath: true
|
|
2289
|
+
},
|
|
2145
2290
|
/** Bone name ("RightHand", "Head", …). Empty = inert. */
|
|
2146
2291
|
bone: { default: "" }
|
|
2147
2292
|
};
|
|
@@ -2205,11 +2350,17 @@ var BoneLookAt3D = class extends Node3D {
|
|
|
2205
2350
|
static typeName = "BoneLookAt3D";
|
|
2206
2351
|
static props = {
|
|
2207
2352
|
/** Node path to the ModelInstance3D whose bone to steer. */
|
|
2208
|
-
target: {
|
|
2353
|
+
target: {
|
|
2354
|
+
default: "",
|
|
2355
|
+
nodePath: true
|
|
2356
|
+
},
|
|
2209
2357
|
/** Bone name ("Head", "Neck", "Spine2" — Mixamo spellings matched). */
|
|
2210
2358
|
bone: { default: "Head" },
|
|
2211
2359
|
/** Node path to LOOK AT ('' = idle). */
|
|
2212
|
-
lookAt: {
|
|
2360
|
+
lookAt: {
|
|
2361
|
+
default: "",
|
|
2362
|
+
nodePath: true
|
|
2363
|
+
},
|
|
2213
2364
|
/** Comfort cone half-angle, degrees — beyond it the head returns to the anim. */
|
|
2214
2365
|
maxAngleDeg: { default: 75 },
|
|
2215
2366
|
/** Blend weight 0..1 (how far toward the target the bone turns). */
|
|
@@ -2400,7 +2551,10 @@ var CharacterController3D = class extends Node3D {
|
|
|
2400
2551
|
moveAction: { default: "move" },
|
|
2401
2552
|
jumpAction: { default: "jump" },
|
|
2402
2553
|
sprintAction: { default: "sprint" },
|
|
2403
|
-
skinPath: {
|
|
2554
|
+
skinPath: {
|
|
2555
|
+
default: "../Skin",
|
|
2556
|
+
nodePath: true
|
|
2557
|
+
},
|
|
2404
2558
|
skinYawOffset: { default: 0 },
|
|
2405
2559
|
animations: { default: {} }
|
|
2406
2560
|
};
|
|
@@ -3319,7 +3473,10 @@ var Flowers3D = class extends Node3D {
|
|
|
3319
3473
|
sway: { default: .5 },
|
|
3320
3474
|
drape: { default: null },
|
|
3321
3475
|
avoidWater: { default: true },
|
|
3322
|
-
terrain: {
|
|
3476
|
+
terrain: {
|
|
3477
|
+
default: "",
|
|
3478
|
+
nodePath: true
|
|
3479
|
+
}
|
|
3323
3480
|
};
|
|
3324
3481
|
/** 'lush' | 'sparse' | 'none' | plants per m² (load-time check + budget). */
|
|
3325
3482
|
density = "sparse";
|
|
@@ -4720,7 +4877,10 @@ var Foliage3D = class Foliage3D extends Node3D {
|
|
|
4720
4877
|
seed: { default: 1 },
|
|
4721
4878
|
drape: { default: null },
|
|
4722
4879
|
avoidWater: { default: true },
|
|
4723
|
-
terrain: {
|
|
4880
|
+
terrain: {
|
|
4881
|
+
default: "",
|
|
4882
|
+
nodePath: true
|
|
4883
|
+
},
|
|
4724
4884
|
renderOrder: { default: 2 }
|
|
4725
4885
|
};
|
|
4726
4886
|
/** Transparent blades draw after water (1) + opaque ground (overrides Node3D's 0). */
|
|
@@ -7984,7 +8144,10 @@ var River3D = class River3D extends Node3D {
|
|
|
7984
8144
|
] },
|
|
7985
8145
|
sunColor: { default: "#fff6e0" },
|
|
7986
8146
|
sunIntensity: { default: 1 },
|
|
7987
|
-
terrain: {
|
|
8147
|
+
terrain: {
|
|
8148
|
+
default: "",
|
|
8149
|
+
nodePath: true
|
|
8150
|
+
},
|
|
7988
8151
|
carve: { default: true },
|
|
7989
8152
|
flowForce: { default: 1 },
|
|
7990
8153
|
spray: { default: 1 }
|
|
@@ -10394,7 +10557,10 @@ var Tree3D = class Tree3D extends Node3D {
|
|
|
10394
10557
|
leafFadeEnd: { default: 0 },
|
|
10395
10558
|
leafShadows: { default: true },
|
|
10396
10559
|
drape: { default: null },
|
|
10397
|
-
terrain: {
|
|
10560
|
+
terrain: {
|
|
10561
|
+
default: "",
|
|
10562
|
+
nodePath: true
|
|
10563
|
+
}
|
|
10398
10564
|
};
|
|
10399
10565
|
/** 'simple' (primitive low-poly) | 'medium' (light ez-trees) | 'high' (full). */
|
|
10400
10566
|
tier = "medium";
|
|
@@ -11909,4 +12075,4 @@ function resolveEnvironmentHdri(env) {
|
|
|
11909
12075
|
return null;
|
|
11910
12076
|
}
|
|
11911
12077
|
//#endregion
|
|
11912
|
-
export { Terrain3D as A, keyboardIntensity as B, resolveFlowerDensity as C, BoneLookAt3D as D, Camera3D as E, InstancedMesh3D as F, rigPose as H, MeshInstance3D as I, buildMeshGeometry as L, TERRAIN_THEMES as M, terrainThemeLayers as N, BoneAttachment3D as O, Joint3D as P, QUARTER_PITCH as R, Flowers3D as S, CharacterController3D as T, movementState as V, LoftMesh3D as _, Tree3D as a, Foliage3D as b, buildRiverRings as c, riverCarveChannels as d, riverStepFor as f, ModelInstance3D as g, Particles3D as h, VoxelGrid3D as i, DEFAULT_TERRAIN_TEXTURE_BASE as j, Billboard3D as k, findRiverCoverageGaps as l, traceDownhillPath as m, registerNodes3D as n, Trail3D as o, smoothCourse as p, VOXEL_PALETTE as r, River3D as s, resolveEnvironmentHdri as t, projectToRiver as u, DirectionalLight3D as v, FLOWER_VARIETIES as w, DENSITY_PRESETS as x, OmniLight3D as y, cameraRelative as z };
|
|
12078
|
+
export { Terrain3D as A, keyboardIntensity as B, resolveFlowerDensity as C, BoneLookAt3D as D, Camera3D as E, InstancedMesh3D as F, acquireTexture as G, rigPose as H, MeshInstance3D as I, buildMeshGeometry as L, TERRAIN_THEMES as M, terrainThemeLayers as N, BoneAttachment3D as O, Joint3D as P, QUARTER_PITCH as R, Flowers3D as S, CharacterController3D as T, TextureCache3D as U, movementState as V, acquireOwnTexture as W, LoftMesh3D as _, Tree3D as a, Foliage3D as b, buildRiverRings as c, riverCarveChannels as d, riverStepFor as f, ModelInstance3D as g, Particles3D as h, VoxelGrid3D as i, DEFAULT_TERRAIN_TEXTURE_BASE as j, Billboard3D as k, findRiverCoverageGaps as l, traceDownhillPath as m, registerNodes3D as n, Trail3D as o, smoothCourse as p, VOXEL_PALETTE as r, River3D as s, resolveEnvironmentHdri as t, projectToRiver as u, DirectionalLight3D as v, FLOWER_VARIETIES as w, DENSITY_PRESETS as x, OmniLight3D as y, cameraRelative as z };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { f as Node, g as Behavior, n as loadScene,
|
|
1
|
+
import { f as Node, g as Behavior, n as loadScene, x as registerBehavior } from "./loader-Mig5fY4n.js";
|
|
2
2
|
import { t as IncantoError } from "./errors-BpWbnbb_.js";
|
|
3
3
|
import { t as jsonClone } from "./json-BLk7H2Qa.js";
|
|
4
|
-
import { r as effectiveOrder, t as duplicateNode } from "./duplicate-
|
|
4
|
+
import { r as effectiveOrder, t as duplicateNode } from "./duplicate-C716f-97.js";
|
|
5
5
|
import { Color, CubeCamera, DepthTexture, DoubleSide, Euler, FloatType, Frustum, HalfFloatType, LinearMipmapLinearFilter, MathUtils, Matrix4, Mesh, MeshDepthMaterial, Object3D, PerspectiveCamera, Plane, PlaneGeometry, Quaternion, ShaderMaterial, Sphere, Vector2, Vector3, Vector4, WebGLCubeRenderTarget, WebGLRenderTarget } from "three";
|
|
6
6
|
//#region src/3d/frustum.ts
|
|
7
7
|
const scratchFrustum = new Frustum();
|
|
@@ -2390,8 +2390,15 @@ var Node3D = class Node3D extends Node {
|
|
|
2390
2390
|
}
|
|
2391
2391
|
/** @internal Push JSON props onto the backing object. Called every frame.
|
|
2392
2392
|
* `alpha` (0..1) interpolates a physics body between its last two fixed-step
|
|
2393
|
-
* positions; non-physics nodes ignore it and render `position` directly.
|
|
2394
|
-
|
|
2393
|
+
* positions; non-physics nodes ignore it and render `position` directly.
|
|
2394
|
+
*
|
|
2395
|
+
* `assets` is the renderer's store, the only route a node has to shared
|
|
2396
|
+
* textures — mirroring `_syncObject2D(assets)`, which has always taken it. It
|
|
2397
|
+
* is a PARAMETER rather than a field so a node that forgets it is a type
|
|
2398
|
+
* error rather than a silent per-node decode; overrides that do not need it
|
|
2399
|
+
* simply keep the one-argument signature. Null in a headless test or a
|
|
2400
|
+
* detached probe, where the node falls back to loading uncached. */
|
|
2401
|
+
_syncObject3D(alpha = 1, _assets = null) {
|
|
2395
2402
|
const o = this._ensureObject3D();
|
|
2396
2403
|
const prev = this._interpPrev;
|
|
2397
2404
|
const curr = this._interpCurr;
|
|
@@ -3973,7 +3980,10 @@ const MIN_DRAFT_REF = .15;
|
|
|
3973
3980
|
var Buoyancy = class extends Behavior {
|
|
3974
3981
|
static props = {
|
|
3975
3982
|
/** Water node path; empty = the first Water3D in the tree. */
|
|
3976
|
-
water: {
|
|
3983
|
+
water: {
|
|
3984
|
+
default: "",
|
|
3985
|
+
nodePath: true
|
|
3986
|
+
},
|
|
3977
3987
|
/** Where the resting WATERLINE sits below the body origin, in meters. A
|
|
3978
3988
|
* hull whose origin is its interior floor wants a draft of ~0.1: the water
|
|
3979
3989
|
* then rests that far under the floor and the boat is dry inside. */
|
|
@@ -4191,7 +4201,10 @@ function smoothingFactor(smoothing, dt) {
|
|
|
4191
4201
|
var Chase = class extends Behavior {
|
|
4192
4202
|
static props = {
|
|
4193
4203
|
/** NodePath of the node to chase (resolved from THIS behavior's node). */
|
|
4194
|
-
target: {
|
|
4204
|
+
target: {
|
|
4205
|
+
default: "",
|
|
4206
|
+
nodePath: true
|
|
4207
|
+
},
|
|
4195
4208
|
/** Units per second toward the target. */
|
|
4196
4209
|
speed: { default: 60 },
|
|
4197
4210
|
/** Stop (and emit reachedTarget) when within this distance. */
|
|
@@ -4362,6 +4375,14 @@ group: { default: "player" } };
|
|
|
4362
4375
|
this.total += value;
|
|
4363
4376
|
this.emit("totalChanged", this.total);
|
|
4364
4377
|
}
|
|
4378
|
+
/** How many have been picked up so far. */
|
|
4379
|
+
serialize() {
|
|
4380
|
+
return { total: this.total };
|
|
4381
|
+
}
|
|
4382
|
+
deserialize(data) {
|
|
4383
|
+
const d = data;
|
|
4384
|
+
if (typeof d.total === "number") this.total = d.total;
|
|
4385
|
+
}
|
|
4365
4386
|
};
|
|
4366
4387
|
//#endregion
|
|
4367
4388
|
//#region src/gameplay/health.ts
|
|
@@ -4455,6 +4476,18 @@ var Health = class extends Behavior {
|
|
|
4455
4476
|
this.emit("died");
|
|
4456
4477
|
if (this.freeOnDeath) this.node.queueFree();
|
|
4457
4478
|
}
|
|
4479
|
+
/** Current HP and whether death already fired — `max` comes back from JSON. */
|
|
4480
|
+
serialize() {
|
|
4481
|
+
return {
|
|
4482
|
+
current: this.current,
|
|
4483
|
+
dead: this.dead
|
|
4484
|
+
};
|
|
4485
|
+
}
|
|
4486
|
+
deserialize(data) {
|
|
4487
|
+
const d = data;
|
|
4488
|
+
if (typeof d.current === "number") this.current = Math.min(this.max, Math.max(0, d.current));
|
|
4489
|
+
if (typeof d.dead === "boolean") this.dead = d.dead;
|
|
4490
|
+
}
|
|
4458
4491
|
};
|
|
4459
4492
|
//#endregion
|
|
4460
4493
|
//#region src/gameplay/trigger.ts
|
|
@@ -4686,7 +4719,10 @@ function phaseOf(hour) {
|
|
|
4686
4719
|
var FollowCamera = class extends Behavior {
|
|
4687
4720
|
static props = {
|
|
4688
4721
|
/** NodePath of the node to follow (relative to this node, or absolute). */
|
|
4689
|
-
target: {
|
|
4722
|
+
target: {
|
|
4723
|
+
default: "",
|
|
4724
|
+
nodePath: true
|
|
4725
|
+
},
|
|
4690
4726
|
/** Constant offset added to the target's position ([x,y] or [x,y,z]). */
|
|
4691
4727
|
offset: { default: [] },
|
|
4692
4728
|
/** 0..1 retention factor: 0 = snap, higher = smoother chase. */
|
|
@@ -4802,7 +4838,10 @@ var GameFlow = class extends Behavior {
|
|
|
4802
4838
|
static props = {
|
|
4803
4839
|
restartAction: { default: "restart" },
|
|
4804
4840
|
freezeOnEnd: { default: true },
|
|
4805
|
-
bannerPath: {
|
|
4841
|
+
bannerPath: {
|
|
4842
|
+
default: "%Banner",
|
|
4843
|
+
nodePath: true
|
|
4844
|
+
}
|
|
4806
4845
|
};
|
|
4807
4846
|
/** Input action that restarts from gameover/won (declare it in `input{}`). */
|
|
4808
4847
|
restartAction = "restart";
|
|
@@ -5603,6 +5642,22 @@ var ScoreKeeper = class extends Behavior {
|
|
|
5603
5642
|
this.emit("lost");
|
|
5604
5643
|
}
|
|
5605
5644
|
}
|
|
5645
|
+
/** The run's progress. `scoreToWin` is balance and comes back from JSON. */
|
|
5646
|
+
serialize() {
|
|
5647
|
+
return {
|
|
5648
|
+
score: this.score,
|
|
5649
|
+
lives: this.lives,
|
|
5650
|
+
hasWon: this.hasWon,
|
|
5651
|
+
hasLost: this.hasLost
|
|
5652
|
+
};
|
|
5653
|
+
}
|
|
5654
|
+
deserialize(data) {
|
|
5655
|
+
const d = data;
|
|
5656
|
+
if (typeof d.score === "number") this.score = d.score;
|
|
5657
|
+
if (typeof d.lives === "number") this.lives = d.lives;
|
|
5658
|
+
if (typeof d.hasWon === "boolean") this.hasWon = d.hasWon;
|
|
5659
|
+
if (typeof d.hasLost === "boolean") this.hasLost = d.hasLost;
|
|
5660
|
+
}
|
|
5606
5661
|
};
|
|
5607
5662
|
//#endregion
|
|
5608
5663
|
//#region src/gameplay/spawn-source.ts
|
|
@@ -5686,7 +5741,10 @@ var SpawnSource = class {
|
|
|
5686
5741
|
var Spawner = class extends Behavior {
|
|
5687
5742
|
static props = {
|
|
5688
5743
|
/** Node path of the template to clone. */
|
|
5689
|
-
prefab: {
|
|
5744
|
+
prefab: {
|
|
5745
|
+
default: "",
|
|
5746
|
+
nodePath: true
|
|
5747
|
+
},
|
|
5690
5748
|
/** Seconds between spawns. */
|
|
5691
5749
|
interval: { default: 1 },
|
|
5692
5750
|
/** Max LIVE instances (0 = unlimited). */
|
|
@@ -5964,7 +6022,10 @@ var WaveSpawner = class extends Behavior {
|
|
|
5964
6022
|
var ZombieAI = class extends Behavior {
|
|
5965
6023
|
static props = {
|
|
5966
6024
|
/** NodePath of the node to charge once near (usually the player). */
|
|
5967
|
-
aggroTarget: {
|
|
6025
|
+
aggroTarget: {
|
|
6026
|
+
default: "",
|
|
6027
|
+
nodePath: true
|
|
6028
|
+
},
|
|
5968
6029
|
/** Start charging when the target is within this distance. */
|
|
5969
6030
|
aggroRange: { default: 12 },
|
|
5970
6031
|
/** Give up the charge past this distance (0 = aggroRange × 1.5). */
|
|
@@ -5978,7 +6039,10 @@ var ZombieAI = class extends Behavior {
|
|
|
5978
6039
|
/** Seconds before forcibly choosing a new roam goal. */
|
|
5979
6040
|
wanderChangeEvery: { default: 3 },
|
|
5980
6041
|
/** Optional NodePath to DRIFT toward while roaming (e.g. the objective). */
|
|
5981
|
-
goalTarget: {
|
|
6042
|
+
goalTarget: {
|
|
6043
|
+
default: "",
|
|
6044
|
+
nodePath: true
|
|
6045
|
+
},
|
|
5982
6046
|
/** Stop (and idle) this close to the active target. */
|
|
5983
6047
|
stopRange: { default: 1.2 },
|
|
5984
6048
|
/** Move the parent node instead of this one (AI-on-a-child pattern). */
|