@bitefoundry/retrieviewer 0.0.2 → 0.0.4
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/ASSET-PROVENANCE.md +6 -0
- package/ASSETS-LICENSE.md +2 -1
- package/ATTRIBUTION.md +6 -1
- package/COMFORT-ART.md +65 -0
- package/DESKTOP-PLATFORMS.md +75 -0
- package/INSTALLING.md +8 -5
- package/PLUGIN.md +13 -10
- package/PREREQUISITES.md +95 -0
- package/PUPPY-MEMORY.md +102 -1
- package/README.ko.md +110 -0
- package/README.md +119 -58
- package/RELEASING.md +27 -14
- package/THIRD-PARTY-NOTICES.md +5 -3
- package/braille.mjs +35 -9
- package/examples/live.mjs +2 -2
- package/integrations/desktop/platform.mjs +27 -0
- package/integrations/linux-overlay/README.md +83 -0
- package/integrations/linux-overlay/overlay.py +1094 -0
- package/integrations/macos-overlay/README.md +83 -0
- package/integrations/macos-overlay/overlay.jxa +639 -0
- package/integrations/opencode/runtime.mjs +4 -4
- package/integrations/opencode/tui.tsx +1 -1
- package/integrations/windows-overlay/Overlay.cs +4 -4
- package/integrations/windows-overlay/desktop.mjs +40 -8
- package/integrations/windows-overlay/protocol.mjs +11 -7
- package/integrations/windows-overlay/worker.mjs +13 -7
- package/package.json +41 -14
- package/puppy-comfort-sprites.mjs +25 -0
- package/puppy-companion-comfort-q5.bin.gz +0 -0
- package/puppy-companion-comfort.json +77 -0
- package/puppy-companion-life.mjs +49 -16
- package/puppy-companion-objects.mjs +12 -0
- package/puppy-frame-predictive.mjs +15 -9
- package/puppy-frame-store.mjs +2 -2
- package/puppy-paper-world.mjs +14 -0
- package/puppy-paper.mjs +65 -14
- package/retrieviewer-cli.mjs +10 -3
- package/retrieviewer-plugin.d.mts +1 -1
- package/retrieviewer-plugin.mjs +1 -1
- package/retrieviewer.d.mts +10 -4
- package/retrieviewer.mjs +20 -14
- package/locomotion-core.mjs +0 -21
- package/locomotion-puppy.animal +0 -0
- package/vendor/procedural-animals/package.json +0 -40
- package/vendor/procedural-animals/src/animal.js +0 -146
- package/vendor/procedural-animals/src/bake.js +0 -51
- package/vendor/procedural-animals/src/build.js +0 -81
- package/vendor/procedural-animals/src/core/build/coatKit.js +0 -121
- package/vendor/procedural-animals/src/core/build/featherCards.js +0 -189
- package/vendor/procedural-animals/src/core/build/finEdges.js +0 -85
- package/vendor/procedural-animals/src/core/build/furSlope.js +0 -115
- package/vendor/procedural-animals/src/core/build/mesh.js +0 -67
- package/vendor/procedural-animals/src/core/build/pipeline.js +0 -272
- package/vendor/procedural-animals/src/core/build/seams.js +0 -183
- package/vendor/procedural-animals/src/core/build/warp.js +0 -112
- package/vendor/procedural-animals/src/core/build/weights.js +0 -393
- package/vendor/procedural-animals/src/core/math/vec.js +0 -81
- package/vendor/procedural-animals/src/core/motion/actions.js +0 -800
- package/vendor/procedural-animals/src/core/motion/bird.js +0 -3063
- package/vendor/procedural-animals/src/core/motion/birdActions.js +0 -1059
- package/vendor/procedural-animals/src/core/motion/common.js +0 -158
- package/vendor/procedural-animals/src/core/motion/index.js +0 -22
- package/vendor/procedural-animals/src/core/motion/quadruped.js +0 -2875
- package/vendor/procedural-animals/src/core/motion/snake.js +0 -1594
- package/vendor/procedural-animals/src/core/motion/spider.js +0 -1810
- package/vendor/procedural-animals/src/core/motion/swimmer.js +0 -1047
- package/vendor/procedural-animals/src/core/motion/swimmerActions.js +0 -613
- package/vendor/procedural-animals/src/core/render/animalObject.js +0 -262
- package/vendor/procedural-animals/src/core/render/coatMaterial.js +0 -1301
- package/vendor/procedural-animals/src/core/render/dqs.js +0 -159
- package/vendor/procedural-animals/src/core/render/eyes.js +0 -676
- package/vendor/procedural-animals/src/core/render/membranes.js +0 -77
- package/vendor/procedural-animals/src/core/render/skeleton.js +0 -41
- package/vendor/procedural-animals/src/core/rig/bird.js +0 -327
- package/vendor/procedural-animals/src/core/rig/quadruped.js +0 -76
- package/vendor/procedural-animals/src/core/rig/rig.js +0 -79
- package/vendor/procedural-animals/src/core/rig/snake.js +0 -76
- package/vendor/procedural-animals/src/core/rig/spider.js +0 -110
- package/vendor/procedural-animals/src/core/rig/swimmer.js +0 -181
- package/vendor/procedural-animals/src/core/sdf/eyeSocket.js +0 -53
- package/vendor/procedural-animals/src/core/sdf/mesher.js +0 -238
- package/vendor/procedural-animals/src/core/sdf/sdf.js +0 -263
- package/vendor/procedural-animals/src/index.d.ts +0 -98
- package/vendor/procedural-animals/src/index.js +0 -29
- package/vendor/procedural-animals/src/registry.js +0 -48
- package/vendor/procedural-animals/src/species/bear/behaviour.js +0 -463
- package/vendor/procedural-animals/src/species/bear/claws.js +0 -147
- package/vendor/procedural-animals/src/species/bear/coat.js +0 -726
- package/vendor/procedural-animals/src/species/bear/index.js +0 -139
- package/vendor/procedural-animals/src/species/bear/motion.js +0 -112
- package/vendor/procedural-animals/src/species/bear/regions.js +0 -78
- package/vendor/procedural-animals/src/species/bear/rig.js +0 -112
- package/vendor/procedural-animals/src/species/bear/sculpt.js +0 -272
- package/vendor/procedural-animals/src/species/boar/behaviour.js +0 -335
- package/vendor/procedural-animals/src/species/boar/coat.js +0 -372
- package/vendor/procedural-animals/src/species/boar/index.js +0 -110
- package/vendor/procedural-animals/src/species/boar/motion.js +0 -85
- package/vendor/procedural-animals/src/species/boar/regions.js +0 -88
- package/vendor/procedural-animals/src/species/boar/rig.js +0 -111
- package/vendor/procedural-animals/src/species/boar/sculpt.js +0 -285
- package/vendor/procedural-animals/src/species/cat/behaviour.js +0 -559
- package/vendor/procedural-animals/src/species/cat/coat.js +0 -841
- package/vendor/procedural-animals/src/species/cat/index.js +0 -211
- package/vendor/procedural-animals/src/species/cat/motion.js +0 -101
- package/vendor/procedural-animals/src/species/cat/regions.js +0 -82
- package/vendor/procedural-animals/src/species/cat/rig.js +0 -100
- package/vendor/procedural-animals/src/species/cat/sculpt.js +0 -266
- package/vendor/procedural-animals/src/species/cat/whiskers.js +0 -110
- package/vendor/procedural-animals/src/species/cheetah/coat.js +0 -427
- package/vendor/procedural-animals/src/species/cheetah/index.js +0 -51
- package/vendor/procedural-animals/src/species/cheetah/joints.js +0 -3
- package/vendor/procedural-animals/src/species/cheetah/motion.js +0 -77
- package/vendor/procedural-animals/src/species/cheetah/regions.js +0 -95
- package/vendor/procedural-animals/src/species/cheetah/rig.js +0 -66
- package/vendor/procedural-animals/src/species/cheetah/sculpt.js +0 -158
- package/vendor/procedural-animals/src/species/chicken/coat.js +0 -313
- package/vendor/procedural-animals/src/species/chicken/coverts.js +0 -320
- package/vendor/procedural-animals/src/species/chicken/index.js +0 -110
- package/vendor/procedural-animals/src/species/chicken/motion.js +0 -177
- package/vendor/procedural-animals/src/species/chicken/regions.js +0 -66
- package/vendor/procedural-animals/src/species/chicken/rig.js +0 -144
- package/vendor/procedural-animals/src/species/chicken/sculpt.js +0 -389
- package/vendor/procedural-animals/src/species/chicken/wingLook.js +0 -66
- package/vendor/procedural-animals/src/species/chicken/wingStack.js +0 -124
- package/vendor/procedural-animals/src/species/cow/behaviour.js +0 -521
- package/vendor/procedural-animals/src/species/cow/coat.js +0 -465
- package/vendor/procedural-animals/src/species/cow/index.js +0 -118
- package/vendor/procedural-animals/src/species/cow/motion.js +0 -81
- package/vendor/procedural-animals/src/species/cow/regions.js +0 -98
- package/vendor/procedural-animals/src/species/cow/rig.js +0 -116
- package/vendor/procedural-animals/src/species/cow/sculpt.js +0 -339
- package/vendor/procedural-animals/src/species/crow/coat.js +0 -145
- package/vendor/procedural-animals/src/species/crow/index.js +0 -70
- package/vendor/procedural-animals/src/species/crow/joints.js +0 -3
- package/vendor/procedural-animals/src/species/crow/motion.js +0 -101
- package/vendor/procedural-animals/src/species/crow/regions.js +0 -50
- package/vendor/procedural-animals/src/species/crow/rig.js +0 -83
- package/vendor/procedural-animals/src/species/crow/sculpt.js +0 -118
- package/vendor/procedural-animals/src/species/deer/behaviour.js +0 -513
- package/vendor/procedural-animals/src/species/deer/coat.js +0 -391
- package/vendor/procedural-animals/src/species/deer/index.js +0 -106
- package/vendor/procedural-animals/src/species/deer/motion.js +0 -97
- package/vendor/procedural-animals/src/species/deer/regions.js +0 -60
- package/vendor/procedural-animals/src/species/deer/rig.js +0 -124
- package/vendor/procedural-animals/src/species/deer/sculpt.js +0 -297
- package/vendor/procedural-animals/src/species/dog/behaviour.js +0 -521
- package/vendor/procedural-animals/src/species/dog/coat.js +0 -495
- package/vendor/procedural-animals/src/species/dog/index.js +0 -144
- package/vendor/procedural-animals/src/species/dog/motion.js +0 -118
- package/vendor/procedural-animals/src/species/dog/regions.js +0 -61
- package/vendor/procedural-animals/src/species/dog/rig.js +0 -129
- package/vendor/procedural-animals/src/species/dog/sculpt.js +0 -246
- package/vendor/procedural-animals/src/species/eagle/coat.js +0 -250
- package/vendor/procedural-animals/src/species/eagle/index.js +0 -76
- package/vendor/procedural-animals/src/species/eagle/joints.js +0 -3
- package/vendor/procedural-animals/src/species/eagle/motion.js +0 -137
- package/vendor/procedural-animals/src/species/eagle/regions.js +0 -57
- package/vendor/procedural-animals/src/species/eagle/rig.js +0 -107
- package/vendor/procedural-animals/src/species/eagle/sculpt.js +0 -137
- package/vendor/procedural-animals/src/species/fish/coat.js +0 -271
- package/vendor/procedural-animals/src/species/fish/index.js +0 -88
- package/vendor/procedural-animals/src/species/fish/motion.js +0 -92
- package/vendor/procedural-animals/src/species/fish/regions.js +0 -27
- package/vendor/procedural-animals/src/species/fish/rig.js +0 -143
- package/vendor/procedural-animals/src/species/fish/sculpt.js +0 -214
- package/vendor/procedural-animals/src/species/fish/variants.js +0 -126
- package/vendor/procedural-animals/src/species/fox/behaviour.js +0 -314
- package/vendor/procedural-animals/src/species/fox/coat.js +0 -444
- package/vendor/procedural-animals/src/species/fox/index.js +0 -120
- package/vendor/procedural-animals/src/species/fox/motion.js +0 -81
- package/vendor/procedural-animals/src/species/fox/regions.js +0 -59
- package/vendor/procedural-animals/src/species/fox/rig.js +0 -91
- package/vendor/procedural-animals/src/species/fox/sculpt.js +0 -202
- package/vendor/procedural-animals/src/species/frog/behaviour.js +0 -590
- package/vendor/procedural-animals/src/species/frog/coat.js +0 -305
- package/vendor/procedural-animals/src/species/frog/index.js +0 -97
- package/vendor/procedural-animals/src/species/frog/motion.js +0 -69
- package/vendor/procedural-animals/src/species/frog/regions.js +0 -46
- package/vendor/procedural-animals/src/species/frog/rig.js +0 -156
- package/vendor/procedural-animals/src/species/frog/sculpt.js +0 -240
- package/vendor/procedural-animals/src/species/goat/behaviour.js +0 -509
- package/vendor/procedural-animals/src/species/goat/coat.js +0 -590
- package/vendor/procedural-animals/src/species/goat/index.js +0 -149
- package/vendor/procedural-animals/src/species/goat/motion.js +0 -95
- package/vendor/procedural-animals/src/species/goat/regions.js +0 -98
- package/vendor/procedural-animals/src/species/goat/rig.js +0 -181
- package/vendor/procedural-animals/src/species/goat/sculpt.js +0 -547
- package/vendor/procedural-animals/src/species/horse/coat.js +0 -361
- package/vendor/procedural-animals/src/species/horse/coatSeam.js +0 -122
- package/vendor/procedural-animals/src/species/horse/index.js +0 -80
- package/vendor/procedural-animals/src/species/horse/motion.js +0 -245
- package/vendor/procedural-animals/src/species/horse/regions.js +0 -60
- package/vendor/procedural-animals/src/species/horse/rig.js +0 -117
- package/vendor/procedural-animals/src/species/horse/sculpt.js +0 -316
- package/vendor/procedural-animals/src/species/horse/seamWeights.js +0 -272
- package/vendor/procedural-animals/src/species/lion/behaviour.js +0 -509
- package/vendor/procedural-animals/src/species/lion/coat.js +0 -1016
- package/vendor/procedural-animals/src/species/lion/index.js +0 -111
- package/vendor/procedural-animals/src/species/lion/motion.js +0 -87
- package/vendor/procedural-animals/src/species/lion/regions.js +0 -106
- package/vendor/procedural-animals/src/species/lion/rig.js +0 -110
- package/vendor/procedural-animals/src/species/lion/sculpt.js +0 -384
- package/vendor/procedural-animals/src/species/lion/whiskers.js +0 -132
- package/vendor/procedural-animals/src/species/pig/behaviour.js +0 -575
- package/vendor/procedural-animals/src/species/pig/coat.js +0 -730
- package/vendor/procedural-animals/src/species/pig/ears.js +0 -242
- package/vendor/procedural-animals/src/species/pig/index.js +0 -161
- package/vendor/procedural-animals/src/species/pig/motion.js +0 -105
- package/vendor/procedural-animals/src/species/pig/regions.js +0 -100
- package/vendor/procedural-animals/src/species/pig/rig.js +0 -152
- package/vendor/procedural-animals/src/species/pig/sculpt.js +0 -382
- package/vendor/procedural-animals/src/species/rabbit/behaviour.js +0 -605
- package/vendor/procedural-animals/src/species/rabbit/coat.js +0 -285
- package/vendor/procedural-animals/src/species/rabbit/index.js +0 -85
- package/vendor/procedural-animals/src/species/rabbit/motion.js +0 -85
- package/vendor/procedural-animals/src/species/rabbit/regions.js +0 -48
- package/vendor/procedural-animals/src/species/rabbit/rig.js +0 -99
- package/vendor/procedural-animals/src/species/rabbit/sculpt.js +0 -148
- package/vendor/procedural-animals/src/species/rat/behaviour.js +0 -539
- package/vendor/procedural-animals/src/species/rat/coat.js +0 -341
- package/vendor/procedural-animals/src/species/rat/index.js +0 -111
- package/vendor/procedural-animals/src/species/rat/motion.js +0 -90
- package/vendor/procedural-animals/src/species/rat/regions.js +0 -92
- package/vendor/procedural-animals/src/species/rat/rig.js +0 -112
- package/vendor/procedural-animals/src/species/rat/sculpt.js +0 -163
- package/vendor/procedural-animals/src/species/rat/whiskers.js +0 -119
- package/vendor/procedural-animals/src/species/shark/coat.js +0 -383
- package/vendor/procedural-animals/src/species/shark/index.js +0 -104
- package/vendor/procedural-animals/src/species/shark/motion.js +0 -69
- package/vendor/procedural-animals/src/species/shark/regions.js +0 -34
- package/vendor/procedural-animals/src/species/shark/rig.js +0 -194
- package/vendor/procedural-animals/src/species/shark/sculpt.js +0 -343
- package/vendor/procedural-animals/src/species/shark/variants.js +0 -105
- package/vendor/procedural-animals/src/species/sheep/behaviour.js +0 -522
- package/vendor/procedural-animals/src/species/sheep/coat.js +0 -529
- package/vendor/procedural-animals/src/species/sheep/index.js +0 -152
- package/vendor/procedural-animals/src/species/sheep/motion.js +0 -86
- package/vendor/procedural-animals/src/species/sheep/neck.js +0 -41
- package/vendor/procedural-animals/src/species/sheep/regions.js +0 -62
- package/vendor/procedural-animals/src/species/sheep/rig.js +0 -163
- package/vendor/procedural-animals/src/species/sheep/sculpt.js +0 -542
- package/vendor/procedural-animals/src/species/snake/coat.js +0 -315
- package/vendor/procedural-animals/src/species/snake/index.js +0 -73
- package/vendor/procedural-animals/src/species/snake/motion.js +0 -51
- package/vendor/procedural-animals/src/species/snake/regions.js +0 -51
- package/vendor/procedural-animals/src/species/snake/rig.js +0 -108
- package/vendor/procedural-animals/src/species/snake/sculpt.js +0 -122
- package/vendor/procedural-animals/src/species/spider/coat.js +0 -279
- package/vendor/procedural-animals/src/species/spider/index.js +0 -78
- package/vendor/procedural-animals/src/species/spider/motion.js +0 -72
- package/vendor/procedural-animals/src/species/spider/regions.js +0 -87
- package/vendor/procedural-animals/src/species/spider/rig.js +0 -118
- package/vendor/procedural-animals/src/species/spider/sculpt.js +0 -182
- package/vendor/procedural-animals/src/species/wolf/behaviour.js +0 -160
- package/vendor/procedural-animals/src/species/wolf/coat.js +0 -749
- package/vendor/procedural-animals/src/species/wolf/index.js +0 -107
- package/vendor/procedural-animals/src/species/wolf/motion.js +0 -80
- package/vendor/procedural-animals/src/species/wolf/regions.js +0 -57
- package/vendor/procedural-animals/src/species/wolf/rig.js +0 -87
- package/vendor/procedural-animals/src/species/wolf/sculpt.js +0 -339
- package/vendor/procedural-animals/src/worker.js +0 -29
|
@@ -1,513 +0,0 @@
|
|
|
1
|
-
// White-tailed deer behaviour layer for the quadruped engine (species.motion.hooks, see
|
|
2
|
-
// core/motion/actions.js):
|
|
3
|
-
//
|
|
4
|
-
// pose(engine, dt) after the engine's solve: the ears swivel on their own, constantly (each
|
|
5
|
-
// pinna turns toward a new "sound" every 0.6-3 s, faster when alarmed); the
|
|
6
|
-
// tail flag (raised vertically, white underside showing, waving a little from
|
|
7
|
-
// side to side) blended over the engine's tail chain
|
|
8
|
-
// update(P, dt, layer) every frame over the action layer: alarm level (fleeing, hit, stomping,
|
|
9
|
-
// jumping) -> tail flag; the walk's head nod; grazing with frequent head-up
|
|
10
|
-
// alert checks (chewing, ears pricked, looking round); zig-zag escape
|
|
11
|
-
// steering; idle variants (the suspicious foot stomp with head bob, the alert
|
|
12
|
-
// stare, tail swishes); sternal sleep with the head laid back
|
|
13
|
-
// actions stomp, alert, flee, attack (buck: antler thrust; doe / fawn: rears and
|
|
14
|
-
// flails with the forefeet), hit (engine stagger + tail flag), jump (slower
|
|
15
|
-
// tuck, forelegs reaching for the landing; opts.height / distance), death
|
|
16
|
-
// (hooves planted while the legs buckle), lie / sleep (staged kneel, rise hind
|
|
17
|
-
// first), sit (sternal bedding, head up and alert)
|
|
18
|
-
//
|
|
19
|
-
// Distances are deer metres at the reference size (x cfg.s); posture offsets the engine multiplies
|
|
20
|
-
// by cfg.k (fwd, side, headRaise, neckReach) are divided by cfg.unit.
|
|
21
|
-
import * as THREE from 'three';
|
|
22
|
-
import { clamp, lerp, smooth, TAU, tv, tqa } from '../../core/motion/common.js';
|
|
23
|
-
import { mx, mxLeg, ONESHOTS, POSTURES } from '../../core/motion/actions.js';
|
|
24
|
-
import { antlerCurves } from './sculpt.js';
|
|
25
|
-
import { deerJoints } from './rig.js';
|
|
26
|
-
|
|
27
|
-
const _q = new THREE.Quaternion(), _s = new THREE.Vector3(1, 1, 1);
|
|
28
|
-
const sm = (w) => w * w * (3 - 2 * w);
|
|
29
|
-
|
|
30
|
-
// per-engine behaviour state
|
|
31
|
-
function B(e) {
|
|
32
|
-
if (!e._deer) {
|
|
33
|
-
e._deer = {
|
|
34
|
-
ear: [{ sw: 0, v: 0, target: 0, tNext: 0.4 }, { sw: 0, v: 0, target: 0, tNext: 1.1 }],
|
|
35
|
-
alarm: 0, flag: 0, flagV: 0, flagT: 0,
|
|
36
|
-
idleT: 6 + e.rand() * 6, graze: { checkIn: 2 + e.rand() * 3, t: -1, dur: 2, look: new THREE.Vector3() },
|
|
37
|
-
flee: null, dirs: null,
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
return e._deer;
|
|
41
|
-
}
|
|
42
|
-
const busy = (L) => L.postures.length > 0 || L.oneshots.some((a) => !a.stopping);
|
|
43
|
-
|
|
44
|
-
// antler sample points (beam and tine tips) relative to the occiput, bind pose, reference size
|
|
45
|
-
const _AJ = deerJoints();
|
|
46
|
-
function antlerSamples(A) {
|
|
47
|
-
const o = _AJ.occiput, out = [];
|
|
48
|
-
for (const side of antlerCurves(A)) {
|
|
49
|
-
for (let i = 2; i < side.beam.length; i += 2) out.push(side.beam[i]);
|
|
50
|
-
out.push(side.beam[side.beam.length - 1]);
|
|
51
|
-
for (const t of side.tines) out.push(t.pts[t.pts.length - 1], t.pts[Math.floor(t.pts.length / 2)]);
|
|
52
|
-
}
|
|
53
|
-
return out.map((p) => new THREE.Vector3(p[0] - o[0], p[1] - o[1], p[2] - o[2]));
|
|
54
|
-
}
|
|
55
|
-
const _qa = new THREE.Quaternion(), _qb = new THREE.Quaternion(), _m = new THREE.Matrix4();
|
|
56
|
-
|
|
57
|
-
// antlers never enter the ground (a buck lying dead, sleeping, grazing on a bank): the skull (with
|
|
58
|
-
// the jaw and ears) turns about the occiput just enough to lift the lowest antler point, smoothly
|
|
59
|
-
function antlerClear(e, b, dt) {
|
|
60
|
-
const A = e.params.antlers;
|
|
61
|
-
if (!A) return;
|
|
62
|
-
const cfg = e.cfg, head = e.bone.head;
|
|
63
|
-
if (!head || !e.bindQ || !e.bindQ.head) return;
|
|
64
|
-
if (e.lod >= 2 && e.P.groundW < 0.01 && !(b.aLift > 0)) return; // (crowd: only resting on the ground)
|
|
65
|
-
if (!b.aPts) { b.aPts = antlerSamples(A); b.aLift = 0; b.aReach = Math.max(...b.aPts.map((v) => v.length())); }
|
|
66
|
-
const occ = tv().setFromMatrixPosition(head.matrixWorld);
|
|
67
|
-
const s = cfg.s;
|
|
68
|
-
if (occ.y - e.terrainH(occ.x, occ.z) > b.aReach * s + 0.05 && b.aLift < 1e-4) return;
|
|
69
|
-
_qa.setFromRotationMatrix(head.matrixWorld).multiply(_qb.copy(e.bindQ.head).invert());
|
|
70
|
-
let need = 0, ax = null, deep = 0;
|
|
71
|
-
const clr = (A.base * 0.8 + 0.01) * s;
|
|
72
|
-
for (const v of b.aPts) {
|
|
73
|
-
const r = tv().copy(v).multiplyScalar(s).applyQuaternion(_qa);
|
|
74
|
-
const p = tv().copy(occ).add(r);
|
|
75
|
-
const depth = e.terrainH(p.x, p.z) + clr - p.y;
|
|
76
|
-
if (depth <= deep) continue;
|
|
77
|
-
const hor = Math.hypot(r.x, r.z);
|
|
78
|
-
if (hor < 1e-3) continue;
|
|
79
|
-
deep = depth; ax = tv().crossVectors(r, tv(0, 1, 0)).normalize();
|
|
80
|
-
need = Math.asin(clamp(depth / Math.max(hor, depth + 1e-3), 0, 1)) * 1.05;
|
|
81
|
-
}
|
|
82
|
-
// (rises at once when needed, relaxes slowly)
|
|
83
|
-
b.aLift = need > b.aLift ? need : Math.max(need, b.aLift - dt * 1.2);
|
|
84
|
-
if (!ax) { if (b.aLift < 1e-4) return; ax = b.aAx || tv(1, 0, 0); } else { b.aAx = (b.aAx || new THREE.Vector3()).copy(ax); }
|
|
85
|
-
if (b.aLift < 1e-4) return;
|
|
86
|
-
const R = tqa(b.aAx, b.aLift);
|
|
87
|
-
for (const name of ['head', 'jaw', 'earL', 'earR']) {
|
|
88
|
-
const bn = e.bone[name];
|
|
89
|
-
if (!bn) continue;
|
|
90
|
-
const p = tv().setFromMatrixPosition(bn.matrixWorld).sub(occ).applyQuaternion(R).add(occ);
|
|
91
|
-
_q.setFromRotationMatrix(bn.matrixWorld).premultiply(R);
|
|
92
|
-
bn.matrixWorld.compose(p, _q, _s);
|
|
93
|
-
}
|
|
94
|
-
void _m;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// ------------------------------------------------------------------------------------------------
|
|
98
|
-
// pose: antler ground clearance, ear swivels and the tail flag
|
|
99
|
-
function pose(e, dt) {
|
|
100
|
-
const b = B(e), P = e.P, cfg = e.cfg;
|
|
101
|
-
antlerClear(e, b, dt);
|
|
102
|
-
const awake = 1 - P.eyelid;
|
|
103
|
-
// ---- ears
|
|
104
|
-
if (cfg.hasEars && e.lod < 2) {
|
|
105
|
-
const alert = clamp(b.alarm + (P.lookW > 0 && P.look ? 0.3 : 0), 0, 1);
|
|
106
|
-
for (let k = 0; k < 2; k++) {
|
|
107
|
-
const E = b.ear[k], s = k === 0 ? 1 : -1;
|
|
108
|
-
const bone = k === 0 ? e.bone.earL : e.bone.earR;
|
|
109
|
-
if (!bone) continue;
|
|
110
|
-
E.tNext -= dt * (1 + 1.5 * alert);
|
|
111
|
-
if (E.tNext <= 0) {
|
|
112
|
-
E.tNext = 0.6 + e.rand() * 2.4;
|
|
113
|
-
// mostly out to the side and back (sounds behind), sometimes forward; independent per ear
|
|
114
|
-
const r = e.rand();
|
|
115
|
-
E.target = r < 0.25 ? -0.25 * s : r < 0.5 ? 0 : (0.3 + 0.9 * e.rand()) * s;
|
|
116
|
-
}
|
|
117
|
-
const want = E.target * awake * (1 - clamp(P.earFlat, 0, 1));
|
|
118
|
-
const om = 14; // quick, critically damped swivel
|
|
119
|
-
E.v += (om * om * (want - E.sw) - 2 * om * E.v) * dt;
|
|
120
|
-
E.sw += E.v * dt;
|
|
121
|
-
if (Math.abs(E.sw) < 1e-4) continue;
|
|
122
|
-
const base = tv().setFromMatrixPosition(bone.matrixWorld);
|
|
123
|
-
_q.setFromRotationMatrix(bone.matrixWorld);
|
|
124
|
-
const ax = tv(0, 1, 0).applyQuaternion(_q);
|
|
125
|
-
_q.premultiply(tqa(ax, E.sw));
|
|
126
|
-
bone.matrixWorld.compose(base, _q, _s);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
// ---- tail flag: each segment turned toward vertical (a little back at the root, the tip
|
|
130
|
-
// leaning forward over the rump), with a slow side-to-side wave
|
|
131
|
-
const f = b.flag;
|
|
132
|
-
if (f < 1e-3) return;
|
|
133
|
-
const tl = e.tail, n = tl.n, fr = e.fr;
|
|
134
|
-
const up = tv(0, 1, 0).applyQuaternion(fr.qPel), back = tv(0, 0, -1).applyQuaternion(fr.qPel), latP = tv(1, 0, 0).applyQuaternion(fr.qPel);
|
|
135
|
-
// (the bone roll is parallel-transported along the chain exactly as the engine does it, so the
|
|
136
|
-
// flag blends in without a twist)
|
|
137
|
-
const latRef = tv().copy(latP);
|
|
138
|
-
const p = tv().copy(tl.p[0]);
|
|
139
|
-
const wave = e.lod >= 2 ? 0 : Math.sin(e.time * TAU * 1.3) * 0.35;
|
|
140
|
-
for (let i = 0; i < n; i++) {
|
|
141
|
-
const r = i / Math.max(1, n - 1);
|
|
142
|
-
const a = lerp(0.95, 1.75, Math.pow(r, 0.8)); // target angle from "back" toward "up" (rad)
|
|
143
|
-
// the segment swings up through the horizontal behind the rump (an angle blend in the
|
|
144
|
-
// back / up plane: the hanging tail and the flag point in nearly opposite directions)
|
|
145
|
-
const cur = tv().subVectors(tl.p[i + 1], tl.p[i]).normalize();
|
|
146
|
-
const cb = cur.dot(back), cu = cur.dot(up), cl = cur.dot(latP);
|
|
147
|
-
const th0 = Math.atan2(cu, cb), th = th0 + (a - th0) * f;
|
|
148
|
-
const lt = cl * (1 - f) + wave * r * 0.5 * f;
|
|
149
|
-
const h = Math.sqrt(Math.max(0, 1 - lt * lt));
|
|
150
|
-
const d = tv().copy(back).multiplyScalar(Math.cos(th) * h).addScaledVector(up, Math.sin(th) * h).addScaledVector(latP, lt).normalize();
|
|
151
|
-
const q0 = tv().copy(p);
|
|
152
|
-
p.addScaledVector(d, tl.len[i]);
|
|
153
|
-
latRef.addScaledVector(d, -latRef.dot(d)).normalize();
|
|
154
|
-
e.setBoneF(e.tailNames[i], q0, d, latRef);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// ------------------------------------------------------------------------------------------------
|
|
159
|
-
// update: alarm / flag, walk nod, grazing alert checks, idle variants, escape steering
|
|
160
|
-
function update(P, dt, L) {
|
|
161
|
-
const e = L.engine, b = B(e), cfg = e.cfg, u = 1 / cfg.unit;
|
|
162
|
-
const vn = e.speed / cfg.sq;
|
|
163
|
-
// ---- alarm: fleeing at a gallop, hit, stomping, jumping, an attack
|
|
164
|
-
let alarmT = smooth(4.2, 6.5, vn) * P.gaitW;
|
|
165
|
-
for (const a of L.oneshots) {
|
|
166
|
-
if (a.stopping && a.w < 0.3) continue;
|
|
167
|
-
if (a.name === 'hit' || a.name === 'flee' || a.name === 'jump') alarmT = 1;
|
|
168
|
-
else if (a.name === 'stomp') alarmT = Math.max(alarmT, smooth(0.6, 1.2, a.t) * 0.9);
|
|
169
|
-
else if (a.name === 'attack') alarmT = Math.max(alarmT, 0.6);
|
|
170
|
-
}
|
|
171
|
-
if (e.air.active) alarmT = 1;
|
|
172
|
-
if (e.input.alarm) alarmT = 1; // (games: motion.input.alarm = true keeps the flag up)
|
|
173
|
-
// the flag stays up for a moment after the danger (the tail comes down while slowing)
|
|
174
|
-
b.alarm = alarmT > b.alarm ? alarmT : Math.max(alarmT, b.alarm - dt * 0.5);
|
|
175
|
-
// lying / dead: tail down
|
|
176
|
-
const down = L.postures.reduce((m, p) => Math.max(m, p.w), 0);
|
|
177
|
-
const flagT = clamp(b.alarm, 0, 1) * (1 - down);
|
|
178
|
-
// critically damped spring (fast up, slower down)
|
|
179
|
-
const om = flagT > b.flag ? 9 : 5;
|
|
180
|
-
b.flagV += (om * om * (flagT - b.flag) - 2 * om * b.flagV) * dt;
|
|
181
|
-
b.flag = clamp(b.flag + b.flagV * dt, 0, 1);
|
|
182
|
-
if (b.flag > 0.3) { mx(P, 'earFlat', 0.25, smooth(5, 9, vn) * b.flag); mx(P, 'tailIdle', 0, b.flag); }
|
|
183
|
-
|
|
184
|
-
// ---- walk: the head and neck nod once per forelimb stance
|
|
185
|
-
const g = e.gait;
|
|
186
|
-
const walkW = smooth(0.12, 0.6, vn) * (1 - smooth(1.4, 1.9, vn)) * P.gaitW;
|
|
187
|
-
if (walkW > 0.001) {
|
|
188
|
-
const ph = e.phase - g.off[0];
|
|
189
|
-
const c = 0.5 + 0.5 * Math.cos(4 * Math.PI * (ph - 0.1));
|
|
190
|
-
P.headRaise -= 0.03 * u * walkW * c;
|
|
191
|
-
P.headPitch += 0.05 * walkW * (c - 0.5);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
// ---- grazing: frequent head-up alert checks (chewing, ears pricked, looking round)
|
|
195
|
-
const eat = L.oneshots.find((a) => a.name === 'eat' || a.name === 'drink');
|
|
196
|
-
const gz = b.graze;
|
|
197
|
-
if (eat && !eat.stopping && eat.w > 0.9) {
|
|
198
|
-
if (gz.t < 0) {
|
|
199
|
-
gz.checkIn -= dt;
|
|
200
|
-
if (gz.checkIn <= 0) {
|
|
201
|
-
gz.t = 0; gz.dur = 1.4 + e.rand() * 1.8;
|
|
202
|
-
const a = e.heading + (e.rand() - 0.5) * 2.6, d = 10 * cfg.k;
|
|
203
|
-
gz.look.set(e.pos.x + Math.sin(a) * d, e.pos.y + 0.8 * cfg.s, e.pos.z + Math.cos(a) * d);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
} else if (!eat) { gz.t = -1; gz.checkIn = 1.5 + e.rand() * 2; }
|
|
207
|
-
if (gz.t >= 0) {
|
|
208
|
-
// (a check under way runs to its end, also while the grazing fades out)
|
|
209
|
-
gz.t += dt;
|
|
210
|
-
if (gz.t > gz.dur) { gz.t = -1; gz.checkIn = (eat && eat.name === 'drink' ? 3 : 2.2) + e.rand() * 4; }
|
|
211
|
-
}
|
|
212
|
-
if (gz.t >= 0 && eat) {
|
|
213
|
-
const c = sm(smooth(0, 0.35, gz.t) * (1 - smooth(gz.dur - 0.45, gz.dur, gz.t))) * sm(eat.w);
|
|
214
|
-
mx(P, 'headW', 0, c); mx(P, 'headReach', 0, c); mx(P, 'headPitch', -0.05, c); mx(P, 'headYaw', 0, c);
|
|
215
|
-
mx(P, 'headOmega', 1.4, c);
|
|
216
|
-
mx(P, 'headRaise', 0.02 * u, c);
|
|
217
|
-
P.look = gz.look; mx(P, 'lookW', 1, c);
|
|
218
|
-
mx(P, 'earFlat', -0.12, c); mx(P, 'earTwitch', 0.3, c);
|
|
219
|
-
if (eat.name === 'eat') { mx(P, 'jaw', 0.05 + 0.05 * Math.max(0, Math.sin(gz.t * 7.5)), c); }
|
|
220
|
-
else mx(P, 'jaw', 0.02, c);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// ---- escape steering (flee): zig-zags at speed
|
|
224
|
-
const f = b.flee;
|
|
225
|
-
if (f) {
|
|
226
|
-
f.t += dt;
|
|
227
|
-
if (f.t >= f.dur) b.flee = null;
|
|
228
|
-
else {
|
|
229
|
-
f.next -= dt;
|
|
230
|
-
if (f.next <= 0) { f.side = -f.side; f.next = 0.9 + e.rand() * 0.7; }
|
|
231
|
-
e.wantSpeed = Math.max(e.wantSpeed, f.speed * cfg.sq * smooth(0, 0.4, f.t));
|
|
232
|
-
e.wantHeading = f.h0 + f.side * f.amp * smooth(0.5, 1.2, f.t);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// ---- sleep (sternal, curled): the body stays upright, the head is laid back along the flank
|
|
237
|
-
for (const p of L.postures) {
|
|
238
|
-
if (p.name !== 'sleep') continue;
|
|
239
|
-
const c = sm(clamp(p.w, 0, 1)) * smooth(1.0, 3.0, p.t);
|
|
240
|
-
mx(P, 'roll', p.side * 0.1, c); mx(P, 'bend', p.side * 0.45, c);
|
|
241
|
-
mx(P, 'tailCurl', 0, c); mx(P, 'tailSide', p.side * 0.3, c);
|
|
242
|
-
mx(P, 'earFlat', 0.6, c);
|
|
243
|
-
}
|
|
244
|
-
// dying / dead: ears laid back; a buck's head stays upright on its chin, the antlers clear of
|
|
245
|
-
// the ground (a head on its cheek would drive the lower beam into the ground)
|
|
246
|
-
for (const p of L.postures) {
|
|
247
|
-
if (p.name !== 'death') continue;
|
|
248
|
-
const w = sm(clamp(p.w, 0, 1)) * smooth(0.3, 1.0, p.t);
|
|
249
|
-
mx(P, 'earFlat', 1, w); mx(P, 'earTwitch', 0, w);
|
|
250
|
-
if (!e.params.antlers) P.headPos.y += 0.018 * cfg.s * w; // (the broad pinnae lie on the ground, not in it)
|
|
251
|
-
else {
|
|
252
|
-
mx(P, 'headRoll', 0, w); mx(P, 'headPitch', 0.05, w);
|
|
253
|
-
P.headPos.y += 0.09 * cfg.s * w;
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// any other action interrupts grazing / drinking
|
|
258
|
-
if (L.oneshots.some((a) => !a.stopping && a.name !== 'eat' && a.name !== 'drink' && a.name !== 'hit')) for (const a of L.oneshots) if (a.name === 'eat' || a.name === 'drink') a.stopping = true;
|
|
259
|
-
|
|
260
|
-
// ---- idle variants (standing still, nothing else running, nobody steering the gaze)
|
|
261
|
-
if (e.idleVariants !== false && L.idle.w > 0.98 && !busy(L) && !e.input.look && !e.input.follow) {
|
|
262
|
-
b.idleT -= dt;
|
|
263
|
-
if (b.idleT <= 0) {
|
|
264
|
-
b.idleT = 7 + e.rand() * 9;
|
|
265
|
-
const r = e.rand();
|
|
266
|
-
if (r < 0.35) L.play('stomp');
|
|
267
|
-
else if (r < 0.7) L.play('alert');
|
|
268
|
-
}
|
|
269
|
-
} else if (busy(L)) b.idleT = Math.max(b.idleT, 4);
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
// ------------------------------------------------------------------------------------------------
|
|
273
|
-
// stomp: suspicious. Head up and ears forward, a head bob (a feint: the head dips as if to feed
|
|
274
|
-
// and snaps back up), then 2-3 hard stomps with one forefoot; tail half raised.
|
|
275
|
-
const stomp = {
|
|
276
|
-
kind: 'oneshot', fade: 0.25,
|
|
277
|
-
start(inst, L) {
|
|
278
|
-
const e = L.engine;
|
|
279
|
-
inst.leg = inst.opts.leg ?? (e.rand() < 0.5 ? 0 : 1);
|
|
280
|
-
const n = inst.opts.count ?? (e.rand() < 0.5 ? 2 : 3);
|
|
281
|
-
inst.hits = Array.from({ length: n }, (_, i) => 1.15 + i * 0.42);
|
|
282
|
-
inst.done = inst.hits.map(() => false);
|
|
283
|
-
inst.dur = inst.hits[n - 1] + 0.75;
|
|
284
|
-
const a = e.heading + (e.rand() - 0.5) * 1.2, d = 8 * e.cfg.k;
|
|
285
|
-
inst.look = inst.opts.target ? inst.opts.target.clone() : new THREE.Vector3(e.pos.x + Math.sin(a) * d, e.pos.y + 0.6 * e.cfg.s, e.pos.z + Math.cos(a) * d);
|
|
286
|
-
},
|
|
287
|
-
update(inst, dt, L) {
|
|
288
|
-
const e = L.engine;
|
|
289
|
-
inst.hits.forEach((tt, j) => {
|
|
290
|
-
if (!inst.done[j] && inst.t >= tt) {
|
|
291
|
-
inst.done[j] = true;
|
|
292
|
-
const leg = e.legs[inst.leg];
|
|
293
|
-
e.emit('footstep', { foot: leg.def.key, position: leg.plant.clone(), speed: 0, strength: 1, stomp: true });
|
|
294
|
-
}
|
|
295
|
-
});
|
|
296
|
-
return inst.t >= inst.dur;
|
|
297
|
-
},
|
|
298
|
-
apply(P, w, inst, L) {
|
|
299
|
-
const e = L.engine, s = e.cfg.s, u = 1 / e.cfg.unit, t = inst.t;
|
|
300
|
-
mx(P, 'gaitW', 0, w); mx(P, 'legGait', 0, w);
|
|
301
|
-
P.look = inst.look; mx(P, 'lookW', 1, w);
|
|
302
|
-
mx(P, 'earFlat', -0.15, w); mx(P, 'earTwitch', 0.2, w);
|
|
303
|
-
mx(P, 'headRaise', 0.035 * u, w);
|
|
304
|
-
// head bob: dips toward the ground and snaps back up
|
|
305
|
-
const bob = Math.sin(Math.PI * clamp((t - 0.25) / 0.6, 0, 1));
|
|
306
|
-
mx(P, 'headRaise', -0.22 * u, w * bob * bob); mx(P, 'headPitch', 0.35, w * bob);
|
|
307
|
-
mx(P, 'lookW', 0, w * bob);
|
|
308
|
-
// stomps: the foot is lifted (knee flexed) and slammed down on its own spot
|
|
309
|
-
let lift = 0;
|
|
310
|
-
for (const tt of inst.hits) lift = Math.max(lift, smooth(tt - 0.3, tt - 0.1, t) * (1 - smooth(tt - 0.07, tt, t)));
|
|
311
|
-
const leg = e.legs[inst.leg];
|
|
312
|
-
const k = w * smooth(0.8, 0.95, t) * (1 - smooth(inst.hits[inst.hits.length - 1], inst.hits[inst.hits.length - 1] + 0.3, t));
|
|
313
|
-
const tp = tv().copy(leg.plant);
|
|
314
|
-
tp.y += 0.13 * s * lift;
|
|
315
|
-
tp.addScaledVector(e.forward(e.heading, tv()), 0.02 * s * lift);
|
|
316
|
-
P.legs[inst.leg].target.copy(tp);
|
|
317
|
-
mxLeg(P, inst.leg, 'reach', 1, k);
|
|
318
|
-
// the body leans back a little onto the other legs, the forehand drops at each strike
|
|
319
|
-
mx(P, 'dropF', 0.04 + 0.05 * (1 - lift), k);
|
|
320
|
-
},
|
|
321
|
-
};
|
|
322
|
-
|
|
323
|
-
// alert: stands tall and stares, ears forward, neck stretched up, tail twitching half-raised
|
|
324
|
-
const alert = {
|
|
325
|
-
kind: 'oneshot', fade: 0.35,
|
|
326
|
-
start(inst, L) {
|
|
327
|
-
const e = L.engine;
|
|
328
|
-
inst.dur = inst.opts.duration ?? 2.5 + e.rand() * 2;
|
|
329
|
-
const a = e.heading + (e.rand() - 0.5) * 2.0, d = 12 * e.cfg.k;
|
|
330
|
-
inst.look = inst.opts.target ? inst.opts.target.clone() : new THREE.Vector3(e.pos.x + Math.sin(a) * d, e.pos.y + 0.5 * e.cfg.s, e.pos.z + Math.cos(a) * d);
|
|
331
|
-
},
|
|
332
|
-
update(inst) { return inst.t >= inst.dur; },
|
|
333
|
-
apply(P, w, inst, L) {
|
|
334
|
-
const u = 1 / L.engine.cfg.unit;
|
|
335
|
-
const k = w * smooth(0, 0.3, inst.t);
|
|
336
|
-
mx(P, 'headRaise', 0.07 * u, k); mx(P, 'neckReach', -0.02 * u, k); mx(P, 'headPitch', -0.12, k);
|
|
337
|
-
P.look = inst.look; mx(P, 'lookW', 1, k);
|
|
338
|
-
mx(P, 'earFlat', -0.2, k); mx(P, 'earTwitch', 0.2, k);
|
|
339
|
-
mx(P, 'tailLift', 0.35, k); mx(P, 'breathRate', 1.4, k);
|
|
340
|
-
},
|
|
341
|
-
};
|
|
342
|
-
|
|
343
|
-
// flee: bounds away with long zig-zags, tail flagged, ears back
|
|
344
|
-
const flee = {
|
|
345
|
-
kind: 'oneshot', fade: 0.25,
|
|
346
|
-
start(inst, L) {
|
|
347
|
-
const e = L.engine, b = B(e);
|
|
348
|
-
inst.dur = inst.opts.duration ?? 4;
|
|
349
|
-
let h0 = e.heading;
|
|
350
|
-
if (inst.opts.from) h0 = Math.atan2(e.pos.x - inst.opts.from.x, e.pos.z - inst.opts.from.z);
|
|
351
|
-
if (inst.opts.heading !== undefined) h0 = inst.opts.heading;
|
|
352
|
-
b.flee = { t: 0, dur: inst.dur, h0, side: e.rand() < 0.5 ? -1 : 1, next: 1.0, amp: 0.35, speed: inst.opts.speed ?? (e.cfg.gears.bound || 11 * e.cfg.sq) / e.cfg.sq };
|
|
353
|
-
},
|
|
354
|
-
update(inst, dt, L) { if (inst.t >= inst.dur) { B(L.engine).flee = null; return true; } return false; },
|
|
355
|
-
apply(P, w) { mx(P, 'earFlat', 0.5, w); },
|
|
356
|
-
};
|
|
357
|
-
|
|
358
|
-
// attack: bucks lower the head and thrust the antlers (with a twist); does and fawns rear up on the
|
|
359
|
-
// hind legs and flail with the forefeet, striking down alternately, then come down on their own
|
|
360
|
-
// hoofprints (running, they butt with the head instead). play('attack', { style: 'strike' |
|
|
361
|
-
// 'antler' }) picks one.
|
|
362
|
-
const STRIKES = [0.5, 0.66, 0.82, 0.98];
|
|
363
|
-
const attack = {
|
|
364
|
-
...ONESHOTS.attack,
|
|
365
|
-
kind: 'oneshot', needsStand: true,
|
|
366
|
-
start(inst, L) {
|
|
367
|
-
const e = L.engine;
|
|
368
|
-
const run = smooth(1.5, 4, e.speed / e.cfg.sk);
|
|
369
|
-
const want = inst.opts.style || (e.params.antlers ? 'antler' : 'strike');
|
|
370
|
-
inst.strikeMode = want !== 'antler' && run < 0.3;
|
|
371
|
-
if (inst.strikeMode) {
|
|
372
|
-
inst.style = 'strike'; inst.dur = 1.72; inst.run = run; inst.hits = STRIKES.map(() => false);
|
|
373
|
-
inst.target = inst.opts.target ? inst.opts.target.clone() : null;
|
|
374
|
-
return;
|
|
375
|
-
}
|
|
376
|
-
inst.tune = { ...inst.tune, style: 'headbutt' };
|
|
377
|
-
ONESHOTS.attack.start.call(this, inst, L);
|
|
378
|
-
},
|
|
379
|
-
update(inst, dt, L) {
|
|
380
|
-
if (!inst.strikeMode) return ONESHOTS.attack.update.call(this, inst, dt, L);
|
|
381
|
-
const e = L.engine;
|
|
382
|
-
STRIKES.forEach((t0, j) => {
|
|
383
|
-
if (!inst.hits[j] && inst.t >= t0 + 0.08) {
|
|
384
|
-
inst.hits[j] = true;
|
|
385
|
-
const leg = e.legs[j & 1];
|
|
386
|
-
const p = new THREE.Vector3().setFromMatrixPosition(e.bone['fhoof' + leg.def.S].matrixWorld);
|
|
387
|
-
const dir = inst.target ? inst.target.clone().sub(e.pos).setY(0).normalize() : e.forward(e.heading, new THREE.Vector3());
|
|
388
|
-
e.emit('attackHit', { position: p, direction: dir, style: 'strike' });
|
|
389
|
-
}
|
|
390
|
-
});
|
|
391
|
-
return inst.t >= inst.dur;
|
|
392
|
-
},
|
|
393
|
-
apply(P, w, inst, L) {
|
|
394
|
-
const t = inst.t;
|
|
395
|
-
if (!inst.strikeMode) {
|
|
396
|
-
ONESHOTS.attack.apply.call(this, P, w, inst, L);
|
|
397
|
-
// antler thrust: the head goes low, antlers forward; a twisting shove at contact
|
|
398
|
-
const low = smooth(0, 0.35, t) * (1 - smooth(0.75, 1.1, t));
|
|
399
|
-
const thrust = smooth(0.35, 0.55, t) * (1 - smooth(0.65, 1.0, t));
|
|
400
|
-
mx(P, 'headPitch', 0.95, low * w);
|
|
401
|
-
mx(P, 'headRoll', 0.2 * Math.sin((t - 0.4) * 8), thrust * w);
|
|
402
|
-
mx(P, 'earFlat', 1, w);
|
|
403
|
-
// (a shorter lunge than the engine's charge: the planted hooves stay within reach)
|
|
404
|
-
P.fwd *= 1 - 0.65 * w;
|
|
405
|
-
return;
|
|
406
|
-
}
|
|
407
|
-
const e = L.engine, cfg = e.cfg;
|
|
408
|
-
if (inst.target) { P.look = inst.target; mx(P, 'lookW', 1, w); }
|
|
409
|
-
mx(P, 'earFlat', 1, w * smooth(0, 0.15, t)); mx(P, 'earTwitch', 0, w);
|
|
410
|
-
// up on the hind legs, forehand raised; the gait is held until the forefeet are down again
|
|
411
|
-
const up = smooth(0.05, 0.42, t) * (1 - smooth(1.05, 1.42, t));
|
|
412
|
-
const hold = Math.min(1, smooth(0.0, 0.2, t) * (1 - smooth(1.5, 1.7, t)));
|
|
413
|
-
mx(P, 'gaitW', 0, hold * w); mx(P, 'legGait', 0, hold * w);
|
|
414
|
-
mx(P, 'dropF', -1.0, up * w); mx(P, 'dropH', 0.22, up * w); mx(P, 'headRaise', 0.03 / cfg.unit, up * w);
|
|
415
|
-
const fwd = e.forward(e.heading, tv()), lat = e.left(e.heading, tv());
|
|
416
|
-
for (let i = 0; i < 2; i++) {
|
|
417
|
-
const leg = e.legs[i], Ld = leg.def;
|
|
418
|
-
// between strikes the forelegs are folded; each strike reaches forward and down
|
|
419
|
-
let k = 0;
|
|
420
|
-
for (let j = i; j < STRIKES.length; j += 2) k = Math.max(k, Math.pow(Math.sin(Math.PI * clamp((t - STRIKES[j] + 0.06) / 0.22, 0, 1)), 2));
|
|
421
|
-
mxLeg(P, i, 'tuck', 1, up * (1 - k) * w); P.legs[i].extend = 0.2;
|
|
422
|
-
const tp = tv().copy(e.fr.shC).addScaledVector(fwd, 0.42 * Ld.len).addScaledVector(lat, Ld.s * Ld.cx);
|
|
423
|
-
tp.y -= 0.55 * Ld.len;
|
|
424
|
-
const ks = k * up * w;
|
|
425
|
-
// coming down: each forefoot is set back on the hoofprint it rose from
|
|
426
|
-
const down = (1 - up) * hold * w;
|
|
427
|
-
P.legs[i].target.copy(leg.plant).lerp(tp, ks / Math.max(1e-3, ks + down));
|
|
428
|
-
mxLeg(P, i, 'reach', 1, Math.max(ks, down));
|
|
429
|
-
}
|
|
430
|
-
},
|
|
431
|
-
};
|
|
432
|
-
|
|
433
|
-
// jump: the engine's leap (the species' everyday obstacle jump; play('jump', { height, distance })
|
|
434
|
-
// picks another one: { height: 2 } is the record escape leap). The legs fold up a little more slowly
|
|
435
|
-
// after take-off (the long slender forelegs tucked in 0.12 s snapped at the elbow), and the forelegs
|
|
436
|
-
// unfold and reach for the ground over the last part of the flight (they were still folded under the
|
|
437
|
-
// chest at touchdown)
|
|
438
|
-
const jump = {
|
|
439
|
-
...ONESHOTS.jump, kind: 'oneshot', airborne: true,
|
|
440
|
-
start(inst, L) {
|
|
441
|
-
const o = inst.opts, t = inst.tune || {};
|
|
442
|
-
if (o.height || o.distance) {
|
|
443
|
-
const h = o.height ?? t.height, k = t.height ? h / t.height : 1;
|
|
444
|
-
inst.tune = { ...t, height: h, distance: o.distance ?? (t.distance ?? 3.8) * Math.sqrt(k) * (k > 1 ? 1.3 : 1) };
|
|
445
|
-
}
|
|
446
|
-
ONESHOTS.jump.start.call(this, inst, L);
|
|
447
|
-
},
|
|
448
|
-
apply(P, w, inst, L) {
|
|
449
|
-
ONESHOTS.jump.apply.call(this, P, w, inst, L);
|
|
450
|
-
if (inst.phase === 'air') {
|
|
451
|
-
const k = smooth(0, 0.26, inst.t - inst.tAir);
|
|
452
|
-
const T = (2 * inst.vy) / 9.81, x = clamp((inst.t - inst.tAir) / T, 0, 1);
|
|
453
|
-
const reach = smooth(0.62, 0.92, x);
|
|
454
|
-
P.legs.forEach((l, i) => { l.tuck = Math.min(l.tuck, k) * (1 - (i < 2 ? 0.75 : 0.35) * reach); });
|
|
455
|
-
}
|
|
456
|
-
},
|
|
457
|
-
};
|
|
458
|
-
|
|
459
|
-
// hit: the engine's stagger, the tail flags
|
|
460
|
-
const hit = { ...ONESHOTS.hit, kind: 'oneshot' };
|
|
461
|
-
|
|
462
|
-
// lie / sleep: the engine's kneeling sequence (down forelegs first, up hind end first). Getting up,
|
|
463
|
-
// the sequence runs on a weight that reaches zero a little before the posture ends, so the springs
|
|
464
|
-
// that stagger the two ends have settled when the posture is removed (no snap of the forelegs).
|
|
465
|
-
function staged(def) {
|
|
466
|
-
return {
|
|
467
|
-
...def, kind: 'posture',
|
|
468
|
-
apply(P, w, inst, L) {
|
|
469
|
-
const dt = clamp(inst.t - (inst.ts ?? inst.t), 0, 0.1);
|
|
470
|
-
inst.ts = inst.t;
|
|
471
|
-
inst.shift = inst.target > 0 ? 0 : Math.min(0.3, (inst.shift || 0) + dt * 0.8);
|
|
472
|
-
const we = clamp((w - inst.shift) / (1 - inst.shift), 0, 1);
|
|
473
|
-
def.apply(P, we, inst, L);
|
|
474
|
-
},
|
|
475
|
-
};
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
// death: the engine's collapse, at its own pace. The legs buckle under the load: the hooves stay
|
|
479
|
-
// planted while the carpi and hocks give and the body sinks, and fold up only as the body goes over
|
|
480
|
-
// onto its side (the engine folds them from the start: on the deer's long legs all four hooves hung
|
|
481
|
-
// 6-8 cm in the air while the body was still near standing height, as if it floated)
|
|
482
|
-
const death = {
|
|
483
|
-
...POSTURES.death, kind: 'posture',
|
|
484
|
-
apply(P, w, inst, L) {
|
|
485
|
-
POSTURES.death.apply(P, w, inst, L);
|
|
486
|
-
// (the legs swing out to the side only once the body is well down: moving the feet to the side
|
|
487
|
-
// pose lifts them in a small step)
|
|
488
|
-
const t = inst.t, fall = clamp((t - 0.3) / 0.55, 0, 1), fallE = fall * fall;
|
|
489
|
-
for (let i = 0; i < 4; i++) { mxLeg(P, i, 'fold', 0, w * (1 - fallE)); P.legs[i].side *= smooth(0.6, 1.15, t); }
|
|
490
|
-
},
|
|
491
|
-
};
|
|
492
|
-
|
|
493
|
-
// sit: a deer beds down sternally with the head up, ears forward and alert (a dog-like sit reads as
|
|
494
|
-
// an injured deer); lie is the same bed, relaxed, the head lower
|
|
495
|
-
function alertBed(def) {
|
|
496
|
-
const base = staged(def);
|
|
497
|
-
return {
|
|
498
|
-
...base,
|
|
499
|
-
apply(P, w, inst, L) {
|
|
500
|
-
base.apply(P, w, inst, L);
|
|
501
|
-
const u = 1 / L.engine.cfg.unit;
|
|
502
|
-
const k = sm(clamp(w, 0, 1)) * smooth(0.6, 1.6, inst.t);
|
|
503
|
-
mx(P, 'headRaise', 0.06 * u, k); mx(P, 'headPitch', -0.1, k);
|
|
504
|
-
mx(P, 'earFlat', -0.15, k); mx(P, 'earTwitch', 0.6, k); mx(P, 'tailIdle', 0.4, k);
|
|
505
|
-
},
|
|
506
|
-
};
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
export const hooks = {
|
|
510
|
-
pose,
|
|
511
|
-
update,
|
|
512
|
-
actions: { stomp, alert, flee, attack, hit, jump, death, lie: staged(POSTURES.lie), sit: alertBed(POSTURES.lie), sleep: staged(POSTURES.sleep) },
|
|
513
|
-
};
|