@adatechnology/game-weapons-three 0.16.0 → 0.17.1
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/{chunk-KWJQO6JS.js → chunk-BDYIF7JD.js} +218 -53
- package/dist/chunk-BDYIF7JD.js.map +1 -0
- package/dist/index.d.ts +45 -3
- package/dist/index.global.js +322 -92
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/{testing-CEcZ-zzz.d.ts → testing-BKDGK6cq.d.ts} +15 -0
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -1
- package/package.json +9 -9
- package/dist/chunk-KWJQO6JS.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/test-area/area.ts
|
|
2
2
|
import { markKitOrigin as markKitOrigin6 } from "@adatechnology/game-contracts";
|
|
3
|
-
import { createArsenal, genericWeapons } from "@adatechnology/game-weapons";
|
|
3
|
+
import { createArsenal, genericWeapons, roundsToWarningOf } from "@adatechnology/game-weapons";
|
|
4
4
|
import { furnitureSpec } from "@adatechnology/game-floorplan-three";
|
|
5
5
|
import { isLightBudget, isRenderPools } from "@adatechnology/game-render-three";
|
|
6
6
|
|
|
@@ -183,6 +183,9 @@ function createAccessoryBench(options) {
|
|
|
183
183
|
signature = "";
|
|
184
184
|
});
|
|
185
185
|
return {
|
|
186
|
+
get aimProgress() {
|
|
187
|
+
return aimProgress;
|
|
188
|
+
},
|
|
186
189
|
handleChange(change) {
|
|
187
190
|
if (change.kind === "action") return act(change.id);
|
|
188
191
|
if (change.kind === "control" && change.id === SUPPORTED_CONTROL_ID && typeof change.value === "boolean") {
|
|
@@ -2460,6 +2463,7 @@ function createWeaponAudio(volume = 0.6, options = {}) {
|
|
|
2460
2463
|
}
|
|
2461
2464
|
|
|
2462
2465
|
// src/box-fx.ts
|
|
2466
|
+
import { FIRST_PERSON_LAYER } from "@adatechnology/game-contracts";
|
|
2463
2467
|
import { createRng, muzzleEnergy as muzzleEnergy3 } from "@adatechnology/game-weapons";
|
|
2464
2468
|
|
|
2465
2469
|
// src/fx/layers.ts
|
|
@@ -2521,6 +2525,8 @@ var BODY_HOLD = {
|
|
|
2521
2525
|
shoulderGripTo: 0.34,
|
|
2522
2526
|
/** The farthest apart two hands hold a long gun (a support hand past it slides back along the gun, toward the grip). */
|
|
2523
2527
|
supportSpan: 0.5,
|
|
2528
|
+
/** A gun carried at the hip (`carry: 'hip'`): its rear grip low at the right hip, a little ahead of it. */
|
|
2529
|
+
hipGrip: [0.25, -0.5, -0.24],
|
|
2524
2530
|
/** How much of the aim's pitch a tool held low in one hand follows. */
|
|
2525
2531
|
toolPitch: 0.5
|
|
2526
2532
|
};
|
|
@@ -2532,6 +2538,7 @@ var placeOnBody = (placement) => {
|
|
|
2532
2538
|
holder.scale.setScalar(1);
|
|
2533
2539
|
hand.position.set(...frame.position);
|
|
2534
2540
|
hand.quaternion.set(...frame.quaternion);
|
|
2541
|
+
if (placement.hip) return placeAtHip(placement);
|
|
2535
2542
|
const shouldered = !placement.handgun && placement.left !== null && placement.lengthMetres >= BODY_HOLD.shoulderedFrom;
|
|
2536
2543
|
if (shouldered) {
|
|
2537
2544
|
holder.position.set(0, BODY_HOLD.boreAbove, placement.rear);
|
|
@@ -2555,6 +2562,21 @@ var placeOnBody = (placement) => {
|
|
|
2555
2562
|
hand.position.add(want.sub(now));
|
|
2556
2563
|
hand.updateMatrixWorld(true);
|
|
2557
2564
|
};
|
|
2565
|
+
var placeAtHip = (placement) => {
|
|
2566
|
+
const { THREE, hand, holder } = placement;
|
|
2567
|
+
scratch.a ?? (scratch.a = new THREE.Vector3());
|
|
2568
|
+
scratch.b ?? (scratch.b = new THREE.Vector3());
|
|
2569
|
+
scratch.euler ?? (scratch.euler = new THREE.Euler());
|
|
2570
|
+
const turn2 = scratch.euler.setFromQuaternion(hand.quaternion, "YXZ");
|
|
2571
|
+
hand.quaternion.setFromEuler(turn2.set(turn2.x * BODY_HOLD.toolPitch, turn2.y, 0, "YXZ"));
|
|
2572
|
+
holder.position.set(0, 0, 0);
|
|
2573
|
+
hand.updateMatrixWorld(true);
|
|
2574
|
+
if (!placement.right) return;
|
|
2575
|
+
const want = scratch.a.set(...BODY_HOLD.hipGrip).applyQuaternion(hand.quaternion).add(hand.position);
|
|
2576
|
+
const now = placement.right.part.localToWorld(scratch.b.copy(placement.right.offset));
|
|
2577
|
+
hand.position.add(want.sub(now));
|
|
2578
|
+
hand.updateMatrixWorld(true);
|
|
2579
|
+
};
|
|
2558
2580
|
var limitSupportSpan = (targets) => {
|
|
2559
2581
|
const right = targets.R?.position;
|
|
2560
2582
|
const left = targets.L?.position;
|
|
@@ -2578,6 +2600,57 @@ var createEyeFrame = (THREE, camera) => {
|
|
|
2578
2600
|
};
|
|
2579
2601
|
};
|
|
2580
2602
|
|
|
2603
|
+
// src/fx/view-hold.ts
|
|
2604
|
+
var VIEW_HOLD = {
|
|
2605
|
+
long: { grip: [0.2, -0.28, -0.38], fov: 84, sights: { distance: 0.34, fromRear: 0.3 } },
|
|
2606
|
+
handgun: { grip: [0.13, -0.15, -0.33], fov: 76, sights: { distance: 0.42, fromRear: 0.02 } },
|
|
2607
|
+
launcher: { grip: [0.2, -0.14, -0.3], fov: 84, sights: { distance: 0.18, fromRear: 0.25 } },
|
|
2608
|
+
tool: { grip: [0.21, -0.31, -0.36], fov: 84, sights: { distance: 0.3, fromRear: 0.1 }, tilt: 0.3 },
|
|
2609
|
+
// the gun at the hip, its rear grip low and to the right, the barrels ahead of the body; it has no sights to bring to the eye
|
|
2610
|
+
hip: { grip: [0.44, -0.32, -0.42], fov: 84, sights: { distance: 0.6, fromRear: 0.1 } }
|
|
2611
|
+
};
|
|
2612
|
+
var NO_GRIP_REAR = [0.2, -0.24, -0.12];
|
|
2613
|
+
var SIGHT_UNDER_EYE = 0.02;
|
|
2614
|
+
var scratch2 = { grip: null, hip: null, aimed: null, tilt: null };
|
|
2615
|
+
var ease = (k) => k * k * (3 - 2 * k);
|
|
2616
|
+
function placeInView(placement) {
|
|
2617
|
+
const { THREE, hand, holder, camera, right, box: box2, kind } = placement;
|
|
2618
|
+
const hold = VIEW_HOLD[kind];
|
|
2619
|
+
holder.scale.setScalar(1);
|
|
2620
|
+
hand.position.copy(camera.position);
|
|
2621
|
+
hand.quaternion.copy(camera.quaternion);
|
|
2622
|
+
if (hold.tilt) {
|
|
2623
|
+
scratch2.tilt ?? (scratch2.tilt = new THREE.Quaternion());
|
|
2624
|
+
hand.quaternion.multiply(scratch2.tilt.setFromAxisAngle(new THREE.Vector3(1, 0, 0), hold.tilt));
|
|
2625
|
+
}
|
|
2626
|
+
hand.scale.setScalar(1);
|
|
2627
|
+
holder.position.set(0, 0, 0);
|
|
2628
|
+
hand.updateMatrixWorld(true);
|
|
2629
|
+
scratch2.hip ?? (scratch2.hip = new THREE.Vector3());
|
|
2630
|
+
const hip = scratch2.hip;
|
|
2631
|
+
if (right) {
|
|
2632
|
+
scratch2.grip ?? (scratch2.grip = new THREE.Vector3());
|
|
2633
|
+
const grip = hand.worldToLocal(right.part.localToWorld(scratch2.grip.copy(right.offset)));
|
|
2634
|
+
hip.set(hold.grip[0] - grip.x, hold.grip[1] - grip.y, hold.grip[2] - grip.z);
|
|
2635
|
+
} else hip.set(NO_GRIP_REAR[0], NO_GRIP_REAR[1], NO_GRIP_REAR[2] + box2.min.x);
|
|
2636
|
+
const k = ease(Math.max(0, Math.min(1, placement.aim)));
|
|
2637
|
+
if (k > 0) {
|
|
2638
|
+
const along = box2.min.x + hold.sights.fromRear;
|
|
2639
|
+
scratch2.aimed ?? (scratch2.aimed = new THREE.Vector3());
|
|
2640
|
+
hip.lerp(scratch2.aimed.set(0, -SIGHT_UNDER_EYE - box2.max.y, along - hold.sights.distance), k);
|
|
2641
|
+
}
|
|
2642
|
+
holder.position.copy(hip).add(placement.offset);
|
|
2643
|
+
hand.updateMatrixWorld(true);
|
|
2644
|
+
}
|
|
2645
|
+
function toWorldLens(camera, point, worldFov, lensFov) {
|
|
2646
|
+
const k = Math.tan(worldFov * Math.PI / 360) / Math.tan(lensFov * Math.PI / 360);
|
|
2647
|
+
camera.updateMatrixWorld();
|
|
2648
|
+
camera.worldToLocal(point);
|
|
2649
|
+
point.x *= k;
|
|
2650
|
+
point.y *= k;
|
|
2651
|
+
return camera.localToWorld(point);
|
|
2652
|
+
}
|
|
2653
|
+
|
|
2581
2654
|
// src/fx/hand-hold.ts
|
|
2582
2655
|
var HAND_HOLD = {
|
|
2583
2656
|
/** Half the width of a pistol grip, the palm sits this far (plus the palm) off its middle. */
|
|
@@ -2656,6 +2729,7 @@ function holdOfModel(THREE, model, holderScale) {
|
|
|
2656
2729
|
const toRoot = (x, y, z) => V(THREE, inner.position.x + x * inner.scale.x, y, z);
|
|
2657
2730
|
const handgun = parts.family === "pistol" || parts.family === "revolver";
|
|
2658
2731
|
root.updateWorldMatrix(true, true);
|
|
2732
|
+
if (parts.holdRight || parts.holdLeft) return namedHold(THREE, model, holderScale);
|
|
2659
2733
|
let gripAt;
|
|
2660
2734
|
let up;
|
|
2661
2735
|
if (parts.grip) {
|
|
@@ -2702,6 +2776,18 @@ function holdOfModel(THREE, model, holderScale) {
|
|
|
2702
2776
|
gripLeft: HAND_HOLD.forend
|
|
2703
2777
|
};
|
|
2704
2778
|
}
|
|
2779
|
+
function namedHold(THREE, model, holderScale) {
|
|
2780
|
+
const { parts } = model;
|
|
2781
|
+
const on = (mark, fingers) => mark ? { part: mark, offset: V(THREE, 0, HAND_HOLD.palm, 0), quaternion: handFrame(THREE, fingers, V(THREE, 0, 1, 0)) } : null;
|
|
2782
|
+
return {
|
|
2783
|
+
right: on(parts.holdRight, V(THREE, 1, 0, 0)),
|
|
2784
|
+
left: on(parts.holdLeft, V(THREE, 0, 0, 1)),
|
|
2785
|
+
leftMagazine: null,
|
|
2786
|
+
scale: holderScale,
|
|
2787
|
+
grip: HAND_HOLD.closed,
|
|
2788
|
+
gripLeft: HAND_HOLD.closed
|
|
2789
|
+
};
|
|
2790
|
+
}
|
|
2705
2791
|
function holdOfProp(THREE, group, category, scale) {
|
|
2706
2792
|
const handle = group.getObjectByName("handle") ?? group.getObjectByName("body") ?? group;
|
|
2707
2793
|
const head = group.getObjectByName("head");
|
|
@@ -3210,6 +3296,15 @@ function createBoxFx(options) {
|
|
|
3210
3296
|
const q2 = new THREE.Quaternion();
|
|
3211
3297
|
const pointForward = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI / 2);
|
|
3212
3298
|
const frontOf = new THREE.Vector3();
|
|
3299
|
+
const restBox = new THREE.Box3();
|
|
3300
|
+
const noMotion = new THREE.Vector3();
|
|
3301
|
+
let inLens = false;
|
|
3302
|
+
const setLens = (on) => {
|
|
3303
|
+
if (on !== inLens) options.viewmodelFov?.(on ? VIEW_HOLD.tool.fov : null);
|
|
3304
|
+
inLens = on;
|
|
3305
|
+
const layer = on ? FIRST_PERSON_LAYER : 0;
|
|
3306
|
+
hand.traverse((node) => node.layers.set(layer));
|
|
3307
|
+
};
|
|
3213
3308
|
const equip = (weapon) => {
|
|
3214
3309
|
if (model) hand.remove(model);
|
|
3215
3310
|
model = null;
|
|
@@ -3217,6 +3312,8 @@ function createBoxFx(options) {
|
|
|
3217
3312
|
def = arsenal.weapons.get(weapon) ?? null;
|
|
3218
3313
|
if (!def || BODY_ACTIONS.has(def.id)) return;
|
|
3219
3314
|
model = buildWeaponModel(THREE, def, options.items);
|
|
3315
|
+
restBox.setFromObject(model);
|
|
3316
|
+
inLens = false;
|
|
3220
3317
|
const length = new THREE.Box3().setFromObject(model).getSize(v).x;
|
|
3221
3318
|
rear = new THREE.Box3().setFromObject(model).min.x;
|
|
3222
3319
|
lengthMetres = length;
|
|
@@ -3317,6 +3414,7 @@ function createBoxFx(options) {
|
|
|
3317
3414
|
return {
|
|
3318
3415
|
unequip() {
|
|
3319
3416
|
if (model) hand.remove(model);
|
|
3417
|
+
if (inLens) setLens(false);
|
|
3320
3418
|
model = null;
|
|
3321
3419
|
inHand = null;
|
|
3322
3420
|
hold = null;
|
|
@@ -3325,6 +3423,7 @@ function createBoxFx(options) {
|
|
|
3325
3423
|
if (!model || !def || !SPOUTS.has(def.action.kind)) return null;
|
|
3326
3424
|
hand.updateMatrixWorld(true);
|
|
3327
3425
|
const at = model.localToWorld(v.copy(frontOf));
|
|
3426
|
+
if (inLens) toWorldLens(camera, at, camera.fov ?? 72, VIEW_HOLD.tool.fov);
|
|
3328
3427
|
const along = v2.set(1, 0, 0).applyQuaternion(model.getWorldQuaternion(q2)).normalize();
|
|
3329
3428
|
return { position: [at.x, at.y, at.z], direction: [along.x, along.y, along.z], drawsFlash: false };
|
|
3330
3429
|
},
|
|
@@ -3347,7 +3446,13 @@ function createBoxFx(options) {
|
|
|
3347
3446
|
update(dt) {
|
|
3348
3447
|
kick *= Math.exp(-dt * 14);
|
|
3349
3448
|
dip += ((reloading ? 1 : 0) - dip) * Math.min(1, dt * 8);
|
|
3350
|
-
if (inHand && model) {
|
|
3449
|
+
if (inHand && model && options.firstPerson?.()) {
|
|
3450
|
+
setLens(true);
|
|
3451
|
+
placeInView({ THREE, hand, holder: model, camera, right: hold?.right ?? null, box: restBox, kind: "tool", aim: 0, offset: noMotion });
|
|
3452
|
+
hand.position.add(v.set(0, -0.12 * dip, 0.05 * kick).applyQuaternion(camera.quaternion));
|
|
3453
|
+
hand.updateMatrixWorld(true);
|
|
3454
|
+
} else if (inHand && model) {
|
|
3455
|
+
if (inLens) setLens(false);
|
|
3351
3456
|
const handgun = def?.category === "pistol" || def?.category === "revolver";
|
|
3352
3457
|
placeOnBody({ THREE, hand, holder: model, frame: options.bodyHold?.() ?? eyeFrame(), rear, lengthMetres, handgun, right: hold?.right ?? null, left: hold?.left ?? null });
|
|
3353
3458
|
hand.position.add(v.set(0, -0.12 * dip, 0.05 * kick).applyQuaternion(camera.quaternion));
|
|
@@ -5892,6 +5997,9 @@ function buildHousing(kit, parts, group) {
|
|
|
5892
5997
|
cylinderZ(group, 0.016, 0.07, M.poly, 0.06, -0.01, side * 0.2, 14);
|
|
5893
5998
|
}
|
|
5894
5999
|
parts.trigger = box2(group, 0.012, 0.02, 0.016, M.dark, 0.1, 0.085, 0.14, 0.3);
|
|
6000
|
+
parts.holdRight = kit.mark(group, 0.06, 6e-3, 0.2);
|
|
6001
|
+
parts.holdLeft = kit.mark(group, 0.22, 0.164, 0);
|
|
6002
|
+
parts.carry = "hip";
|
|
5895
6003
|
parts.safety = box2(group, 0.014, 6e-3, 0.01, M.dark, 0.2, 0.073, -0.076, 0.4);
|
|
5896
6004
|
}
|
|
5897
6005
|
function buildFeed(kit, parts, group) {
|
|
@@ -6319,7 +6427,7 @@ function buildWeaponModelById(THREE, id) {
|
|
|
6319
6427
|
}
|
|
6320
6428
|
|
|
6321
6429
|
// src/fx/viewmodel.ts
|
|
6322
|
-
import { createToolClipPlayer, toolAnimationStep, warnOnce as warnOnce2 } from "@adatechnology/game-contracts";
|
|
6430
|
+
import { createToolClipPlayer, FIRST_PERSON_LAYER as FIRST_PERSON_LAYER2, toolAnimationStep, warnOnce as warnOnce2 } from "@adatechnology/game-contracts";
|
|
6323
6431
|
import { discardObject3D as discardObject3D3 } from "@adatechnology/game-shapes-three";
|
|
6324
6432
|
import { createRng as createRng2, muzzleEnergy as muzzleEnergy4 } from "@adatechnology/game-weapons";
|
|
6325
6433
|
|
|
@@ -6329,7 +6437,7 @@ var RELOAD_SAMPLE_HITS2 = reload_sample_hits_default.hits;
|
|
|
6329
6437
|
var ROOT = "root";
|
|
6330
6438
|
var AXIS_INDEX = { x: 0, y: 1, z: 2 };
|
|
6331
6439
|
var EASE_STEPS = 10;
|
|
6332
|
-
var
|
|
6440
|
+
var ease2 = (progress) => progress < 0.5 ? 2 * progress * progress : 1 - (-2 * progress + 2) ** 2 / 2;
|
|
6333
6441
|
var move = (part, axis, start, duration, from, to) => ({ part, channel: "position", axis, start, duration, from, to });
|
|
6334
6442
|
var turn = (part, axis, start, duration, from, to) => ({ part, channel: "rotation", axis, start, duration, from, to });
|
|
6335
6443
|
var cue = (t, type, data) => ({ t, type, ...data ? { data } : {} });
|
|
@@ -6343,7 +6451,7 @@ var valueAt = (tweens, t, includeInstants) => {
|
|
|
6343
6451
|
for (const tween of tweens) {
|
|
6344
6452
|
if (tween.start > t || tween.duration === 0 && (tween.start === t ? !includeInstants : false)) continue;
|
|
6345
6453
|
if (tween.duration === 0 || t >= tween.start + tween.duration) value = tween.to;
|
|
6346
|
-
else value = tween.from + (tween.to - tween.from) *
|
|
6454
|
+
else value = tween.from + (tween.to - tween.from) * ease2((t - tween.start) / tween.duration);
|
|
6347
6455
|
}
|
|
6348
6456
|
return value;
|
|
6349
6457
|
};
|
|
@@ -7425,38 +7533,6 @@ function createEffects(THREE, sink, random) {
|
|
|
7425
7533
|
};
|
|
7426
7534
|
}
|
|
7427
7535
|
|
|
7428
|
-
// src/fx/view-hold.ts
|
|
7429
|
-
var VIEW_HOLD = {
|
|
7430
|
-
/** The right hand's grip, from the eye. */
|
|
7431
|
-
grip: [0.2, -0.2, -0.3],
|
|
7432
|
-
/** A handgun's grip: higher and nearer the middle, the arms out in front. */
|
|
7433
|
-
handgunGrip: [0.13, -0.15, -0.33],
|
|
7434
|
-
/** A rocket launcher's grip: its tube rides on the shoulder, so the hands are higher. */
|
|
7435
|
-
launcherGrip: [0.2, -0.14, -0.3],
|
|
7436
|
-
/** A gun with no grip anchor: the rear of its bore, from the eye. */
|
|
7437
|
-
rear: [0.2, -0.24, -0.12]
|
|
7438
|
-
};
|
|
7439
|
-
var scratch2 = { grip: null };
|
|
7440
|
-
function placeInView(placement) {
|
|
7441
|
-
const { THREE, hand, holder, camera, right } = placement;
|
|
7442
|
-
holder.scale.setScalar(1);
|
|
7443
|
-
hand.position.copy(camera.position);
|
|
7444
|
-
hand.quaternion.copy(camera.quaternion);
|
|
7445
|
-
hand.scale.setScalar(1);
|
|
7446
|
-
holder.position.set(0, 0, 0);
|
|
7447
|
-
hand.updateMatrixWorld(true);
|
|
7448
|
-
if (!right) {
|
|
7449
|
-
holder.position.set(VIEW_HOLD.rear[0], VIEW_HOLD.rear[1], VIEW_HOLD.rear[2] + placement.rear);
|
|
7450
|
-
hand.updateMatrixWorld(true);
|
|
7451
|
-
return;
|
|
7452
|
-
}
|
|
7453
|
-
scratch2.grip ?? (scratch2.grip = new THREE.Vector3());
|
|
7454
|
-
const grip = hand.worldToLocal(right.part.localToWorld(scratch2.grip.copy(right.offset)));
|
|
7455
|
-
const [x, y, z] = placement.kind === "handgun" ? VIEW_HOLD.handgunGrip : placement.kind === "launcher" ? VIEW_HOLD.launcherGrip : VIEW_HOLD.grip;
|
|
7456
|
-
holder.position.set(x - grip.x, y - grip.y, z - grip.z);
|
|
7457
|
-
hand.updateMatrixWorld(true);
|
|
7458
|
-
}
|
|
7459
|
-
|
|
7460
7536
|
// src/fx/heavy.ts
|
|
7461
7537
|
import { LIGHT_PRIORITY as LIGHT_PRIORITY2, geometryKey, materialKey } from "@adatechnology/game-render-three";
|
|
7462
7538
|
import { discardObject3D } from "@adatechnology/game-shapes-three";
|
|
@@ -7845,11 +7921,12 @@ function createClipEventHandler(world, session) {
|
|
|
7845
7921
|
switch (event.type) {
|
|
7846
7922
|
case "muzzle_flash":
|
|
7847
7923
|
if (data.at === "ugl") {
|
|
7848
|
-
if (parts.uglMuzzle && world.layers.muzzleFlash) effects.muzzleFlash(positionOf(parts.uglMuzzle), root.getWorldQuaternion(new THREE.Quaternion()), UGL_FLASH);
|
|
7924
|
+
if (parts.uglMuzzle && world.layers.muzzleFlash) world.afterPose(() => parts.uglMuzzle && effects.muzzleFlash(positionOf(parts.uglMuzzle), root.getWorldQuaternion(new THREE.Quaternion()), UGL_FLASH));
|
|
7849
7925
|
} else if (parts.muzzle && world.layers.muzzleFlash && (session.def.action.kind === "firearm" || session.def.action.kind === "launcher")) {
|
|
7850
7926
|
const profile = muzzleSmokeOf({ caliber: session.caliber, weapon: session.def, suppressed: session.suppressed });
|
|
7851
7927
|
const size = session.def.action.kind === "launcher" ? 2.2 : FLASH_BY_CASE[session.caseType];
|
|
7852
|
-
|
|
7928
|
+
const muzzle = parts.muzzle;
|
|
7929
|
+
world.afterPose(() => effects.muzzleFlash(positionOf(muzzle), root.getWorldQuaternion(new THREE.Quaternion()), size, profile));
|
|
7853
7930
|
}
|
|
7854
7931
|
break;
|
|
7855
7932
|
case "eject_casing":
|
|
@@ -8390,7 +8467,9 @@ function workWeights(works, running) {
|
|
|
8390
8467
|
|
|
8391
8468
|
// src/fx/viewmodel.ts
|
|
8392
8469
|
var PI14 = Math.PI;
|
|
8393
|
-
var HEAT_DISPLAY_MAX_FALLBACK =
|
|
8470
|
+
var HEAT_DISPLAY_MAX_FALLBACK = 750;
|
|
8471
|
+
var SMOKE_WISPS_PER_SECOND = 10;
|
|
8472
|
+
var SMOKE_THICKNESS_GAIN = 1.7;
|
|
8394
8473
|
var WALL_PULL = { margin: 0.03, max: 1.2, rate: 14, probe: 3 };
|
|
8395
8474
|
var HAND_IN_VIEW = { floor: -0.88, max: 0.3, rate: 10 };
|
|
8396
8475
|
var LAUNCH_VOLUME = 0.6;
|
|
@@ -8409,6 +8488,7 @@ var indexCurl = (turn2, sinceShot) => {
|
|
|
8409
8488
|
const held = sinceShot < TRIGGER_FINGER.burstSeconds ? TRIGGER_FINGER.pulled - TRIGGER_FINGER.tremor * (0.5 + 0.5 * Math.sin(sinceShot * 220)) : 0;
|
|
8410
8489
|
return Math.max(ready + (TRIGGER_FINGER.pulled - ready) * pull, held);
|
|
8411
8490
|
};
|
|
8491
|
+
var VIEW_MOTION = { sway: 6e-3, swayMax: 0.02, swayRate: 9, bobX: 6e-3, bobY: 8e-3, run: 1.6, fullSpeed: 4, frequency: 3.2 };
|
|
8412
8492
|
function createViewmodel(options) {
|
|
8413
8493
|
const { THREE, scene, camera, arsenal, groundAt, audio } = options;
|
|
8414
8494
|
const kit = modelKit(THREE);
|
|
@@ -8416,6 +8496,11 @@ function createViewmodel(options) {
|
|
|
8416
8496
|
const layers = options.layers ?? createLayers();
|
|
8417
8497
|
const distance = () => options.soundDistance?.() ?? 0;
|
|
8418
8498
|
const particles = createParticles(THREE, scene, groundAt, options.particleLimit);
|
|
8499
|
+
const spawnParticle = particles.spawn.bind(particles);
|
|
8500
|
+
particles.spawn = (object, velocity, particleOptions) => {
|
|
8501
|
+
if (lens) toWorldLens(camera, object.position, worldFovOf(), lens.fov);
|
|
8502
|
+
spawnParticle(object, velocity, particleOptions);
|
|
8503
|
+
};
|
|
8419
8504
|
particles.onBounce = (kind, hit) => {
|
|
8420
8505
|
if (!audio || kind !== "casing" && kind !== "magazine") return;
|
|
8421
8506
|
const surface = hit ? options.surfaceAt?.(hit.object.position.x, hit.object.position.z) : void 0;
|
|
@@ -8428,7 +8513,16 @@ function createViewmodel(options) {
|
|
|
8428
8513
|
};
|
|
8429
8514
|
if (!options.effects) warnOnce2("game-weapons-three.own-effects-world", "game-weapons-three made an effects world of its own because the host lent none (options.effects); pass the host effects so the effects share one budget");
|
|
8430
8515
|
const ownVfx = options.effects ? void 0 : createVfxRenderer(THREE, { scene, camera, vfx: { profile: "medium" }, ...options.lights ? { lights: options.lights } : {} });
|
|
8431
|
-
const
|
|
8516
|
+
const worldSink = options.effects ?? ownVfx;
|
|
8517
|
+
const lensSink = worldSink ? {
|
|
8518
|
+
play: (request) => {
|
|
8519
|
+
if (!lens || !request.point) return worldSink.play(request);
|
|
8520
|
+
const at = toWorldLens(camera, lensPoint.set(...request.point), worldFovOf(), lens.fov);
|
|
8521
|
+
return worldSink.play({ ...request, point: [at.x, at.y, at.z] });
|
|
8522
|
+
},
|
|
8523
|
+
stop: (handle) => worldSink.stop(handle)
|
|
8524
|
+
} : void 0;
|
|
8525
|
+
const effects = createEffects(THREE, lensSink, random);
|
|
8432
8526
|
const hand = new THREE.Group();
|
|
8433
8527
|
hand.name = VIEWMODEL_NODE_NAME;
|
|
8434
8528
|
scene.add(hand);
|
|
@@ -8454,6 +8548,7 @@ function createViewmodel(options) {
|
|
|
8454
8548
|
const rootQuaternion = new THREE.Quaternion();
|
|
8455
8549
|
const muzzleAt = new THREE.Vector3();
|
|
8456
8550
|
const muzzleAlong = new THREE.Vector3();
|
|
8551
|
+
const posed = [];
|
|
8457
8552
|
const world = {
|
|
8458
8553
|
kit,
|
|
8459
8554
|
scene,
|
|
@@ -8467,13 +8562,17 @@ function createViewmodel(options) {
|
|
|
8467
8562
|
const played = audio?.cue(cue2, profile, lead);
|
|
8468
8563
|
options.onSound?.({ weapon, cue: cue2, profile, ...played ? { played } : {} });
|
|
8469
8564
|
},
|
|
8470
|
-
|
|
8565
|
+
afterPose: (emit) => void posed.push(emit),
|
|
8566
|
+
schedule: (delay, seconds, step, done) => void tasks.push({ delay, seconds, elapsed: 0, step: (progress) => step(ease2(progress)), done })
|
|
8471
8567
|
};
|
|
8472
8568
|
const heatMax = arsenal.rules.heat.displayMax || HEAT_DISPLAY_MAX_FALLBACK;
|
|
8473
8569
|
const visual = arsenal.rules.heat.visual;
|
|
8474
8570
|
const hasSuppressor = (parts) => parts.some((part) => arsenal.attachments.get(part.id)?.kind === "suppressor");
|
|
8475
8571
|
const release = () => {
|
|
8476
8572
|
if (!session) return;
|
|
8573
|
+
if (lens) options.viewmodelFov?.(null);
|
|
8574
|
+
lens = null;
|
|
8575
|
+
lensLayer = -1;
|
|
8477
8576
|
session.attachments?.dispose();
|
|
8478
8577
|
discardObject3D3(session.model.root);
|
|
8479
8578
|
player = null;
|
|
@@ -8513,6 +8612,9 @@ function createViewmodel(options) {
|
|
|
8513
8612
|
const modelBox = new THREE.Box3().setFromObject(model.root);
|
|
8514
8613
|
const length = modelBox.getSize(new THREE.Vector3()).x;
|
|
8515
8614
|
modelRear = modelBox.min.x;
|
|
8615
|
+
restBox.copy(modelBox);
|
|
8616
|
+
lens = null;
|
|
8617
|
+
lensLayer = -1;
|
|
8516
8618
|
holder.add(model.root);
|
|
8517
8619
|
const caliber = caliberOf(arsenal, def);
|
|
8518
8620
|
const dims = caliber?.cartridge;
|
|
@@ -8575,6 +8677,42 @@ function createViewmodel(options) {
|
|
|
8575
8677
|
let reach = 0;
|
|
8576
8678
|
let pull = 0;
|
|
8577
8679
|
let lift = 0;
|
|
8680
|
+
const restBox = new THREE.Box3();
|
|
8681
|
+
let lens = null;
|
|
8682
|
+
let lensLayer = -1;
|
|
8683
|
+
const lensPoint = new THREE.Vector3();
|
|
8684
|
+
const worldFovOf = () => camera.fov ?? 72;
|
|
8685
|
+
const setLens = (kind) => {
|
|
8686
|
+
const fov = kind ? VIEW_HOLD[kind].fov : null;
|
|
8687
|
+
if ((lens?.fov ?? null) !== fov) options.viewmodelFov?.(fov);
|
|
8688
|
+
lens = kind && fov !== null ? { kind, fov } : null;
|
|
8689
|
+
const layer = lens ? FIRST_PERSON_LAYER2 : 0;
|
|
8690
|
+
if (layer === lensLayer && !lens) return;
|
|
8691
|
+
lensLayer = layer;
|
|
8692
|
+
hand.traverse((node) => node.layers.set(layer));
|
|
8693
|
+
};
|
|
8694
|
+
const motion = { phase: 0, swayX: 0, swayY: 0, lastYaw: Number.NaN, lastPitch: Number.NaN };
|
|
8695
|
+
const motionEuler = new THREE.Euler(0, 0, 0, "YXZ");
|
|
8696
|
+
const motionOffset = new THREE.Vector3();
|
|
8697
|
+
const viewMotion = (dt, aim) => {
|
|
8698
|
+
const moving = options.motion?.() ?? { speed: 0, running: false };
|
|
8699
|
+
const calm = 1 - 0.8 * Math.max(0, Math.min(1, aim));
|
|
8700
|
+
motionEuler.setFromQuaternion(camera.quaternion, "YXZ");
|
|
8701
|
+
const turnYaw = Number.isNaN(motion.lastYaw) || dt <= 0 ? 0 : Math.atan2(Math.sin(motionEuler.y - motion.lastYaw), Math.cos(motionEuler.y - motion.lastYaw)) / dt;
|
|
8702
|
+
const turnPitch = Number.isNaN(motion.lastPitch) || dt <= 0 ? 0 : (motionEuler.x - motion.lastPitch) / dt;
|
|
8703
|
+
motion.lastYaw = motionEuler.y;
|
|
8704
|
+
motion.lastPitch = motionEuler.x;
|
|
8705
|
+
const follow = Math.min(1, dt * VIEW_MOTION.swayRate);
|
|
8706
|
+
motion.swayX += (Math.max(-VIEW_MOTION.swayMax, Math.min(VIEW_MOTION.swayMax, turnYaw * VIEW_MOTION.sway)) - motion.swayX) * follow;
|
|
8707
|
+
motion.swayY += (Math.max(-VIEW_MOTION.swayMax, Math.min(VIEW_MOTION.swayMax, -turnPitch * VIEW_MOTION.sway)) - motion.swayY) * follow;
|
|
8708
|
+
const stride = Math.min(1, moving.speed / VIEW_MOTION.fullSpeed) * (moving.running ? VIEW_MOTION.run : 1);
|
|
8709
|
+
motion.phase += dt * moving.speed * VIEW_MOTION.frequency;
|
|
8710
|
+
return motionOffset.set(
|
|
8711
|
+
(motion.swayX + Math.sin(motion.phase) * VIEW_MOTION.bobX * stride) * calm,
|
|
8712
|
+
(motion.swayY - Math.abs(Math.cos(motion.phase)) * VIEW_MOTION.bobY * stride) * calm,
|
|
8713
|
+
0
|
|
8714
|
+
);
|
|
8715
|
+
};
|
|
8578
8716
|
const ahead = new THREE.Vector3();
|
|
8579
8717
|
const up = new THREE.Vector3();
|
|
8580
8718
|
const seen = new THREE.Vector3();
|
|
@@ -8607,13 +8745,17 @@ function createViewmodel(options) {
|
|
|
8607
8745
|
const family = session.model.parts.family;
|
|
8608
8746
|
session.holderScale = 1;
|
|
8609
8747
|
if (options.firstPerson?.()) {
|
|
8610
|
-
|
|
8748
|
+
const kind = session.model.parts.carry === "hip" ? "hip" : family === "pistol" || family === "revolver" ? "handgun" : family === "rocket" ? "launcher" : "long";
|
|
8749
|
+
const aim = kind === "hip" ? 0 : options.aim?.() ?? 0;
|
|
8750
|
+
placeInView({ THREE, hand, holder, camera, right: hold?.right ?? null, box: restBox, kind, aim, offset: viewMotion(dt, aim) });
|
|
8751
|
+
setLens(kind);
|
|
8611
8752
|
lift = 0;
|
|
8612
|
-
|
|
8753
|
+
pull = 0;
|
|
8613
8754
|
return;
|
|
8614
8755
|
}
|
|
8756
|
+
setLens(null);
|
|
8615
8757
|
hand.scale.set(1, 1, 1);
|
|
8616
|
-
placeOnBody({ THREE, hand, holder, frame: options.bodyHold?.() ?? eyeFrame(), rear: modelRear, lengthMetres: session.lengthMetres, handgun: family === "pistol" || family === "revolver", right: hold?.right ?? null, left: hold?.left ?? null });
|
|
8758
|
+
placeOnBody({ THREE, hand, holder, frame: options.bodyHold?.() ?? eyeFrame(), rear: modelRear, lengthMetres: session.lengthMetres, handgun: family === "pistol" || family === "revolver", hip: session.model.parts.carry === "hip", right: hold?.right ?? null, left: hold?.left ?? null });
|
|
8617
8759
|
hand.updateMatrixWorld(true);
|
|
8618
8760
|
lift += (liftToKeepInView() - lift) * Math.min(1, dt * HAND_IN_VIEW.rate);
|
|
8619
8761
|
if (lift > 1e-4) hand.position.addScaledVector(up.set(0, 1, 0).applyQuaternion(camera.quaternion), lift);
|
|
@@ -8689,6 +8831,10 @@ function createViewmodel(options) {
|
|
|
8689
8831
|
if (session) {
|
|
8690
8832
|
place(dt);
|
|
8691
8833
|
player?.update(dt);
|
|
8834
|
+
if (posed.length) {
|
|
8835
|
+
hand.updateMatrixWorld(true);
|
|
8836
|
+
for (const emit of posed.splice(0)) emit();
|
|
8837
|
+
}
|
|
8692
8838
|
const wantsMagazine = reloading || options.tool?.().reloading === true;
|
|
8693
8839
|
magazineHand += ((wantsMagazine ? 1 : 0) - magazineHand) * Math.min(1, dt * HAND_HOLD.magRate);
|
|
8694
8840
|
const tool = options.tool?.();
|
|
@@ -8704,10 +8850,11 @@ function createViewmodel(options) {
|
|
|
8704
8850
|
}
|
|
8705
8851
|
secondsSinceShot += dt;
|
|
8706
8852
|
if (tool && tool.heat !== void 0 && tool.heat * heatMax > visual.smokeFrom && secondsSinceShot < visual.smokeSeconds && session.model.parts.muzzle) {
|
|
8707
|
-
|
|
8853
|
+
const smokeLevel = Math.min(1, (tool.heat * heatMax - visual.smokeFrom) / visual.smokeSpan);
|
|
8854
|
+
smokeDebt += dt * smokeLevel * SMOKE_WISPS_PER_SECOND;
|
|
8708
8855
|
while (smokeDebt > 1) {
|
|
8709
8856
|
smokeDebt -= 1;
|
|
8710
|
-
const k = 0.5 +
|
|
8857
|
+
const k = 0.5 + smokeLevel * SMOKE_THICKNESS_GAIN;
|
|
8711
8858
|
effects.smoke(worldPositionOf(session, session.model.parts.muzzle, new THREE.Vector3()), new THREE.Vector3((random() - 0.5) * 0.015, 0.07 + random() * 0.08, (random() - 0.5) * 0.015), 4e-3 * k, 1.2 + random() * 0.6, Math.min(0.18, 0.06 + k * 0.04));
|
|
8712
8859
|
}
|
|
8713
8860
|
}
|
|
@@ -8734,6 +8881,7 @@ function createViewmodel(options) {
|
|
|
8734
8881
|
if (!session || !mark) return null;
|
|
8735
8882
|
hand.updateMatrixWorld(true);
|
|
8736
8883
|
const at = worldPositionOf(session, mark, muzzleAt);
|
|
8884
|
+
if (lens) toWorldLens(camera, at, worldFovOf(), lens.fov);
|
|
8737
8885
|
const along = muzzleAlong.set(1, 0, 0).applyQuaternion(session.model.root.getWorldQuaternion(rootQuaternion)).normalize();
|
|
8738
8886
|
const kind = session.def.action.kind;
|
|
8739
8887
|
return { position: [at.x, at.y, at.z], direction: [along.x, along.y, along.z], drawsFlash: kind === "firearm" || kind === "launcher" };
|
|
@@ -8743,7 +8891,8 @@ function createViewmodel(options) {
|
|
|
8743
8891
|
hand.updateMatrixWorld(true);
|
|
8744
8892
|
const targets = targetsOf(THREE, hold, session.model.root.getWorldQuaternion(rootQuaternion), magazineHand, hold.works ? workWeights(hold.works, player?.running ?? []) : void 0);
|
|
8745
8893
|
const trigger = session.model.parts.trigger;
|
|
8746
|
-
if (
|
|
8894
|
+
if (session.model.parts.carry === "hip") targets.fingers = { index: 1 };
|
|
8895
|
+
else if (trigger) targets.fingers = { index: indexCurl(trigger.rotation.z - triggerRest, clock - lastShot) };
|
|
8747
8896
|
return limitSupportSpan(targets);
|
|
8748
8897
|
},
|
|
8749
8898
|
get inHand() {
|
|
@@ -8793,6 +8942,9 @@ function createWeaponFx(options) {
|
|
|
8793
8942
|
...options.contact ? { contact: options.contact } : {},
|
|
8794
8943
|
...options.bodyHold ? { bodyHold: options.bodyHold } : {},
|
|
8795
8944
|
...options.firstPerson ? { firstPerson: options.firstPerson } : {},
|
|
8945
|
+
...options.viewmodelFov ? { viewmodelFov: options.viewmodelFov } : {},
|
|
8946
|
+
...options.aim ? { aim: options.aim } : {},
|
|
8947
|
+
...options.motion ? { motion: options.motion } : {},
|
|
8796
8948
|
...options.effects ? { effects: options.effects } : {},
|
|
8797
8949
|
...options.flyRocket === void 0 ? {} : { flyRocket: options.flyRocket },
|
|
8798
8950
|
...options.particleLimit ? { particleLimit: options.particleLimit } : {},
|
|
@@ -9910,7 +10062,7 @@ var TEXT = {
|
|
|
9910
10062
|
fuseLength: "Dynamite fuse length",
|
|
9911
10063
|
fuseLengthHint: "Metres of safety fuse (131 s per metre): a long one is set down lit, for a delayed trap",
|
|
9912
10064
|
layers: { muzzle_flash: "Muzzle flash", casings: "Ejected casings", magazines: "Dropped magazines" },
|
|
9913
|
-
metrics: { casings_live: "Casings in the scene", magazines_live: "Magazines in the scene", heat: "Barrel heat" }
|
|
10065
|
+
metrics: { casings_live: "Casings in the scene", magazines_live: "Magazines in the scene", heat: "Barrel temperature above ambient", rounds_to_warning: "Rounds to the heat warning (cyclic rate, from cold)" }
|
|
9914
10066
|
},
|
|
9915
10067
|
"pt-BR": {
|
|
9916
10068
|
group: "Armas",
|
|
@@ -9946,7 +10098,7 @@ var TEXT = {
|
|
|
9946
10098
|
fuseLength: "Pavio da dinamite",
|
|
9947
10099
|
fuseLengthHint: "Metros de pavio de seguran\xE7a (131 s por metro): um longo \xE9 posto no ch\xE3o aceso, para armadilha com atraso",
|
|
9948
10100
|
layers: { muzzle_flash: "Clar\xE3o do cano", casings: "C\xE1psulas ejetadas", magazines: "Pentes que caem" },
|
|
9949
|
-
metrics: { casings_live: "C\xE1psulas na cena", magazines_live: "Pentes na cena", heat: "
|
|
10101
|
+
metrics: { casings_live: "C\xE1psulas na cena", magazines_live: "Pentes na cena", heat: "Temperatura do cano acima do ambiente", rounds_to_warning: "Tiros at\xE9 o aviso de calor (cad\xEAncia, a frio)" }
|
|
9950
10102
|
}
|
|
9951
10103
|
};
|
|
9952
10104
|
var textOf = (locale) => TEXT[locale] ?? TEXT.en;
|
|
@@ -10070,7 +10222,12 @@ function createWeaponsTestModule(options = {}) {
|
|
|
10070
10222
|
let host = null;
|
|
10071
10223
|
let soundDistance = 0;
|
|
10072
10224
|
let soundIndoors = false;
|
|
10073
|
-
const
|
|
10225
|
+
const barrelCelsius = () => (host?.tool().heat ?? 0) * arsenal.rules.heat.displayMax;
|
|
10226
|
+
const roundsToWarning = () => {
|
|
10227
|
+
const weaponId = host?.tool().weapon;
|
|
10228
|
+
const rounds = weaponId ? roundsToWarningOf(arsenal, weaponId) : Infinity;
|
|
10229
|
+
return Number.isFinite(rounds) ? rounds : "-";
|
|
10230
|
+
};
|
|
10074
10231
|
return {
|
|
10075
10232
|
id: "weapons_area",
|
|
10076
10233
|
name: text.name,
|
|
@@ -10123,7 +10280,8 @@ function createWeaponsTestModule(options = {}) {
|
|
|
10123
10280
|
metrics: () => [
|
|
10124
10281
|
{ id: "casings_live", name: text.metrics.casings_live, read: () => fx?.casings ?? 0 },
|
|
10125
10282
|
{ id: "magazines_live", name: text.metrics.magazines_live, read: () => fx?.magazines ?? 0 },
|
|
10126
|
-
{ id: "heat", name: text.metrics.heat, unit: "
|
|
10283
|
+
{ id: "heat", name: text.metrics.heat, unit: "\xB0C", max: arsenal.rules.heat.displayMax, digits: 0, read: barrelCelsius },
|
|
10284
|
+
{ id: "rounds_to_warning", name: text.metrics.rounds_to_warning, read: roundsToWarning },
|
|
10127
10285
|
...accessoryMetrics(accessoryText, () => host?.tool() ?? EMPTY_TOOL)
|
|
10128
10286
|
],
|
|
10129
10287
|
attach(lent) {
|
|
@@ -10166,6 +10324,10 @@ function createWeaponsTestModule(options = {}) {
|
|
|
10166
10324
|
contact: createLaserRaycast(lent.THREE, lent.scene, lent.camera, { now: () => simulatedMs }),
|
|
10167
10325
|
...lent.holdFrame ? { bodyHold: () => lent.holdFrame?.() ?? null } : {},
|
|
10168
10326
|
firstPerson: () => lent.player().cameraMode === "first",
|
|
10327
|
+
// the lens of the gun in first person, how far it is brought to the eye (the right button) and how the body moves (the bob and the sway follow it)
|
|
10328
|
+
...lent.setViewmodelFov ? { viewmodelFov: (degrees) => lent.setViewmodelFov?.(degrees) } : {},
|
|
10329
|
+
aim: () => accessories.aimProgress,
|
|
10330
|
+
motion: () => ({ speed: lent.player().speed, running: lent.player().running }),
|
|
10169
10331
|
...lent.effects ? { effects: lent.effects } : {},
|
|
10170
10332
|
...lent.particleLimit ? { particleLimit: lent.particleLimit } : {},
|
|
10171
10333
|
...isLightBudget(lent.lights) ? { lights: lent.lights } : {},
|
|
@@ -11268,6 +11430,8 @@ export {
|
|
|
11268
11430
|
weaponSampleDefaults,
|
|
11269
11431
|
weaponSampleBank,
|
|
11270
11432
|
createWeaponAudio,
|
|
11433
|
+
VIEW_HOLD,
|
|
11434
|
+
toWorldLens,
|
|
11271
11435
|
BODY_ACTIONS,
|
|
11272
11436
|
weaponProp,
|
|
11273
11437
|
buildProp,
|
|
@@ -11302,6 +11466,7 @@ export {
|
|
|
11302
11466
|
buildCartridge,
|
|
11303
11467
|
buildCasing,
|
|
11304
11468
|
buildRound,
|
|
11469
|
+
VIEW_MOTION,
|
|
11305
11470
|
createWeaponFx,
|
|
11306
11471
|
buildModeledProp,
|
|
11307
11472
|
buildTripodMountedProp,
|
|
@@ -11329,4 +11494,4 @@ export {
|
|
|
11329
11494
|
DEFAULT_EXPLOSIVES_SCENE,
|
|
11330
11495
|
createExplosivesTestModule
|
|
11331
11496
|
};
|
|
11332
|
-
//# sourceMappingURL=chunk-
|
|
11497
|
+
//# sourceMappingURL=chunk-BDYIF7JD.js.map
|