@adatechnology/game-weapons-three 0.10.4 → 0.11.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/README.md +2 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.global.js +828 -206
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +153 -46
- package/dist/index.js.map +1 -1
- package/package.json +12 -13
package/dist/index.js
CHANGED
|
@@ -1511,6 +1511,83 @@ var createLaserRaycast = (THREE, scene, camera, options = {}) => {
|
|
|
1511
1511
|
};
|
|
1512
1512
|
};
|
|
1513
1513
|
|
|
1514
|
+
// src/fx/body-hold.ts
|
|
1515
|
+
var BODY_HOLD = {
|
|
1516
|
+
/** With no body to lend the frame: the pocket of the right shoulder from the eye, in the eye's yaw frame (right, up, back). */
|
|
1517
|
+
eyeToPocket: [0.2, -0.275, 0.17],
|
|
1518
|
+
/** A shouldered gun's bore runs this far above the shoulder pocket (the cheek on the comb). */
|
|
1519
|
+
boreAbove: 0.05,
|
|
1520
|
+
/** A handgun's (or a short two-hand gun's) grip: toward the middle of the chest, a little low, at the reach of bent arms. */
|
|
1521
|
+
handgunGrip: [-0.15, -0.04, -0.42],
|
|
1522
|
+
/** A one-hand tool's grip: low in front of the body, the elbow bent. */
|
|
1523
|
+
toolGrip: [0.02, -0.34, -0.3],
|
|
1524
|
+
/** A tool at least this long, held by two hands, is shouldered (its stock in the pocket). */
|
|
1525
|
+
shoulderedFrom: 0.55,
|
|
1526
|
+
/** The farthest a shouldered gun's grip sits ahead of the pocket; a launcher whose grip is farther slides back, its tube behind the shoulder. */
|
|
1527
|
+
shoulderGripMax: 0.42,
|
|
1528
|
+
/** The nearest a shouldered gun's grip sits ahead of the pocket; a gun with no stock (a pistol grip at its rear) slides forward, its grip not behind the eye. */
|
|
1529
|
+
shoulderGripMin: 0.25,
|
|
1530
|
+
/** Where such a grip is brought to, ahead of the pocket. */
|
|
1531
|
+
shoulderGripTo: 0.34,
|
|
1532
|
+
/** The farthest apart two hands hold a long gun (a support hand past it slides back along the gun, toward the grip). */
|
|
1533
|
+
supportSpan: 0.5,
|
|
1534
|
+
/** How much of the aim's pitch a tool held low in one hand follows. */
|
|
1535
|
+
toolPitch: 0.5
|
|
1536
|
+
};
|
|
1537
|
+
var scratch = { a: null, b: null, euler: null };
|
|
1538
|
+
var placeOnBody = (placement) => {
|
|
1539
|
+
const { THREE, hand, holder, frame } = placement;
|
|
1540
|
+
scratch.a ?? (scratch.a = new THREE.Vector3());
|
|
1541
|
+
scratch.b ?? (scratch.b = new THREE.Vector3());
|
|
1542
|
+
holder.scale.setScalar(1);
|
|
1543
|
+
hand.position.set(...frame.position);
|
|
1544
|
+
hand.quaternion.set(...frame.quaternion);
|
|
1545
|
+
const shouldered = !placement.handgun && placement.left !== null && placement.lengthMetres >= BODY_HOLD.shoulderedFrom;
|
|
1546
|
+
if (shouldered) {
|
|
1547
|
+
holder.position.set(0, BODY_HOLD.boreAbove, placement.rear);
|
|
1548
|
+
hand.updateMatrixWorld(true);
|
|
1549
|
+
if (!placement.right) return;
|
|
1550
|
+
const grip2 = hand.worldToLocal(placement.right.part.localToWorld(scratch.a.copy(placement.right.offset)));
|
|
1551
|
+
if (-grip2.z <= BODY_HOLD.shoulderGripMax && -grip2.z >= BODY_HOLD.shoulderGripMin) return;
|
|
1552
|
+
holder.position.z += -grip2.z - BODY_HOLD.shoulderGripTo;
|
|
1553
|
+
hand.updateMatrixWorld(true);
|
|
1554
|
+
return;
|
|
1555
|
+
}
|
|
1556
|
+
scratch.euler ?? (scratch.euler = new THREE.Euler());
|
|
1557
|
+
const turn2 = scratch.euler.setFromQuaternion(hand.quaternion, "YXZ");
|
|
1558
|
+
hand.quaternion.setFromEuler(turn2.set(turn2.x * BODY_HOLD.toolPitch, turn2.y, 0, "YXZ"));
|
|
1559
|
+
holder.position.set(0, 0, 0);
|
|
1560
|
+
hand.updateMatrixWorld(true);
|
|
1561
|
+
if (!placement.right) return;
|
|
1562
|
+
const grip = placement.handgun || placement.left ? BODY_HOLD.handgunGrip : BODY_HOLD.toolGrip;
|
|
1563
|
+
const want = scratch.a.set(grip[0], grip[1], grip[2]).applyQuaternion(hand.quaternion).add(hand.position);
|
|
1564
|
+
const now = placement.right.part.localToWorld(scratch.b.copy(placement.right.offset));
|
|
1565
|
+
hand.position.add(want.sub(now));
|
|
1566
|
+
hand.updateMatrixWorld(true);
|
|
1567
|
+
};
|
|
1568
|
+
var limitSupportSpan = (targets) => {
|
|
1569
|
+
const right = targets.R?.position;
|
|
1570
|
+
const left = targets.L?.position;
|
|
1571
|
+
if (!right || !left || !targets.L) return targets;
|
|
1572
|
+
const span = Math.hypot(left[0] - right[0], left[1] - right[1], left[2] - right[2]);
|
|
1573
|
+
if (span <= BODY_HOLD.supportSpan) return targets;
|
|
1574
|
+
const k = BODY_HOLD.supportSpan / span;
|
|
1575
|
+
const position = [right[0] + (left[0] - right[0]) * k, right[1] + (left[1] - right[1]) * k, right[2] + (left[2] - right[2]) * k];
|
|
1576
|
+
return { ...targets, L: { ...targets.L, position } };
|
|
1577
|
+
};
|
|
1578
|
+
var createEyeFrame = (THREE, camera) => {
|
|
1579
|
+
const frame = { position: [0, 0, 0], quaternion: [0, 0, 0, 1] };
|
|
1580
|
+
const turn2 = new THREE.Euler(0, 0, 0, "YXZ");
|
|
1581
|
+
const pocket = new THREE.Vector3();
|
|
1582
|
+
return () => {
|
|
1583
|
+
turn2.setFromQuaternion(camera.quaternion, "YXZ");
|
|
1584
|
+
pocket.set(...BODY_HOLD.eyeToPocket).applyEuler(turn2.set(0, turn2.y, 0)).add(camera.position);
|
|
1585
|
+
frame.position = [pocket.x, pocket.y, pocket.z];
|
|
1586
|
+
frame.quaternion = [camera.quaternion.x, camera.quaternion.y, camera.quaternion.z, camera.quaternion.w];
|
|
1587
|
+
return frame;
|
|
1588
|
+
};
|
|
1589
|
+
};
|
|
1590
|
+
|
|
1514
1591
|
// src/fx/hand-hold.ts
|
|
1515
1592
|
var HAND_HOLD = {
|
|
1516
1593
|
/** Half the width of a pistol grip, the palm sits this far (plus the palm) off its middle. */
|
|
@@ -4943,7 +5020,6 @@ var FALLBACK_ENERGY = 300;
|
|
|
4943
5020
|
var MAX_CASINGS = 120;
|
|
4944
5021
|
var MAX_MAGAZINES = 12;
|
|
4945
5022
|
var LIFETIME_S = 25;
|
|
4946
|
-
var HAND_OFFSET = [0.2, -0.2, -0.42];
|
|
4947
5023
|
var GRAVITY = 9.81;
|
|
4948
5024
|
function createBoxFx(options) {
|
|
4949
5025
|
const { THREE, scene, camera, arsenal, groundAt } = options;
|
|
@@ -4965,6 +5041,10 @@ function createBoxFx(options) {
|
|
|
4965
5041
|
let dip = 0;
|
|
4966
5042
|
let reloading = false;
|
|
4967
5043
|
const v = new THREE.Vector3();
|
|
5044
|
+
const v2 = new THREE.Vector3();
|
|
5045
|
+
const eyeFrame = createEyeFrame(THREE, camera);
|
|
5046
|
+
let rear = 0;
|
|
5047
|
+
let lengthMetres = 0;
|
|
4968
5048
|
const q = new THREE.Quaternion();
|
|
4969
5049
|
const q2 = new THREE.Quaternion();
|
|
4970
5050
|
const pointForward = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI / 2);
|
|
@@ -4976,13 +5056,17 @@ function createBoxFx(options) {
|
|
|
4976
5056
|
if (!def || BODY_ACTIONS.has(def.id)) return;
|
|
4977
5057
|
model = buildWeaponModel(THREE, def);
|
|
4978
5058
|
const length = new THREE.Box3().setFromObject(model).getSize(v).x;
|
|
4979
|
-
|
|
5059
|
+
rear = new THREE.Box3().setFromObject(model).min.x;
|
|
5060
|
+
lengthMetres = length;
|
|
4980
5061
|
model.quaternion.copy(pointForward);
|
|
4981
5062
|
hand.add(model);
|
|
4982
5063
|
inHand = def.id;
|
|
4983
|
-
hold = holdOfProp(THREE, model, def.category,
|
|
5064
|
+
hold = holdOfProp(THREE, model, def.category, 1);
|
|
5065
|
+
};
|
|
5066
|
+
const handPoint = (x, y, z, out) => {
|
|
5067
|
+
if (!model) return out.set(x, y, z).applyQuaternion(camera.quaternion).add(camera.position);
|
|
5068
|
+
return out.set(x, y, z).applyQuaternion(camera.quaternion).add(model.getWorldPosition(v2));
|
|
4984
5069
|
};
|
|
4985
|
-
const handPoint = (x, y, z, out) => out.set(HAND_OFFSET[0] + x, HAND_OFFSET[1] + y, HAND_OFFSET[2] + z).applyQuaternion(camera.quaternion).add(camera.position);
|
|
4986
5070
|
const throwBody = (kind, mesh, from, velocity, radius) => {
|
|
4987
5071
|
if (!(kind === "casing" ? layers.casings : layers.magazines)) {
|
|
4988
5072
|
mesh.geometry.dispose();
|
|
@@ -5093,10 +5177,12 @@ function createBoxFx(options) {
|
|
|
5093
5177
|
update(dt) {
|
|
5094
5178
|
kick *= Math.exp(-dt * 14);
|
|
5095
5179
|
dip += ((reloading ? 1 : 0) - dip) * Math.min(1, dt * 8);
|
|
5096
|
-
if (inHand) {
|
|
5097
|
-
|
|
5180
|
+
if (inHand && model) {
|
|
5181
|
+
const handgun = def?.category === "pistol" || def?.category === "revolver";
|
|
5182
|
+
placeOnBody({ THREE, hand, holder: model, frame: options.bodyHold?.() ?? eyeFrame(), rear, lengthMetres, handgun, right: hold?.right ?? null, left: hold?.left ?? null });
|
|
5183
|
+
hand.position.add(v.set(0, -0.12 * dip, 0.05 * kick).applyQuaternion(camera.quaternion));
|
|
5098
5184
|
q.setFromEuler(new THREE.Euler(0.14 * kick - 0.25 * dip, 0, 0.6 * dip));
|
|
5099
|
-
hand.quaternion.
|
|
5185
|
+
hand.quaternion.multiply(q);
|
|
5100
5186
|
}
|
|
5101
5187
|
for (const body of [...bodies]) {
|
|
5102
5188
|
stepBody(body, dt);
|
|
@@ -6181,6 +6267,14 @@ function createEffects(THREE, sink, random) {
|
|
|
6181
6267
|
|
|
6182
6268
|
// src/fx/heavy.ts
|
|
6183
6269
|
var PI12 = Math.PI;
|
|
6270
|
+
var ROCKET_LIGHT_NAME = "rocket-light";
|
|
6271
|
+
var rocketsInFlight = /* @__PURE__ */ new WeakMap();
|
|
6272
|
+
function createRocketLight(THREE) {
|
|
6273
|
+
const light = new THREE.PointLight(16751168, 0, 2.5);
|
|
6274
|
+
light.name = ROCKET_LIGHT_NAME;
|
|
6275
|
+
light.position.set(0, -50, 0);
|
|
6276
|
+
return light;
|
|
6277
|
+
}
|
|
6184
6278
|
var flameMaterials = (kit) => {
|
|
6185
6279
|
const { THREE } = kit;
|
|
6186
6280
|
return [
|
|
@@ -6210,8 +6304,9 @@ function launchRocket(context, flyRound = true) {
|
|
|
6210
6304
|
exhaust.rotation.z = PI12 / 2;
|
|
6211
6305
|
exhaust.position.x = -0.08;
|
|
6212
6306
|
rocket.add(exhaust);
|
|
6213
|
-
const light =
|
|
6214
|
-
|
|
6307
|
+
const light = context.rocketLight;
|
|
6308
|
+
light.intensity = 3;
|
|
6309
|
+
rocketsInFlight.set(light, (rocketsInFlight.get(light) ?? 0) + 1);
|
|
6215
6310
|
context.every(
|
|
6216
6311
|
1.6,
|
|
6217
6312
|
(progress, dt) => {
|
|
@@ -6219,6 +6314,7 @@ function launchRocket(context, flyRound = true) {
|
|
|
6219
6314
|
const distance = 1.2 * flight + (flight > 0.25 ? 9 * (flight - 0.25) ** 2 : 0);
|
|
6220
6315
|
rocket.position.copy(muzzle).addScaledVector(forward, distance);
|
|
6221
6316
|
rocket.rotation.x += 0.25 * dt * 60;
|
|
6317
|
+
light.position.copy(rocket.position);
|
|
6222
6318
|
exhaust.scale.set(1, 0.6 + random() * 0.8, 1);
|
|
6223
6319
|
if (random() < 0.9) context.effects.smoke(rocket.position.clone().addScaledVector(forward, -0.12), new THREE.Vector3((random() - 0.5) * 0.1, 0.05, (random() - 0.5) * 0.1), 0.02 + random() * 0.015, 2.2, 0.5);
|
|
6224
6320
|
},
|
|
@@ -6226,7 +6322,11 @@ function launchRocket(context, flyRound = true) {
|
|
|
6226
6322
|
rocket.removeFromParent();
|
|
6227
6323
|
exhaust.geometry.dispose();
|
|
6228
6324
|
exhaust.material.dispose();
|
|
6229
|
-
|
|
6325
|
+
const remaining = (rocketsInFlight.get(light) ?? 1) - 1;
|
|
6326
|
+
rocketsInFlight.set(light, remaining);
|
|
6327
|
+
if (remaining > 0) return;
|
|
6328
|
+
light.intensity = 0;
|
|
6329
|
+
light.position.set(0, -50, 0);
|
|
6230
6330
|
}
|
|
6231
6331
|
);
|
|
6232
6332
|
}
|
|
@@ -7045,11 +7145,9 @@ function workWeights(works, running) {
|
|
|
7045
7145
|
|
|
7046
7146
|
// src/fx/viewmodel.ts
|
|
7047
7147
|
var PI14 = Math.PI;
|
|
7048
|
-
var HAND_OFFSET2 = [0.2, -0.2, -0.42];
|
|
7049
|
-
var HANDGUN_OFFSET = [0.1, -0.12, -0.44];
|
|
7050
7148
|
var HEAT_DISPLAY_MAX_FALLBACK = 120;
|
|
7051
|
-
var WALL_PULL = { margin: 0.03, max:
|
|
7052
|
-
var HAND_IN_VIEW = { floor: -0.88, max: 0.
|
|
7149
|
+
var WALL_PULL = { margin: 0.03, max: 1.2, rate: 14, probe: 3 };
|
|
7150
|
+
var HAND_IN_VIEW = { floor: -0.88, max: 0.3, rate: 10 };
|
|
7053
7151
|
var LAUNCH_VOLUME = 0.6;
|
|
7054
7152
|
var fittedOf2 = (parts) => parts.map((part) => ({ id: part.id, mount: part.mount, ...part.integral ? { integral: true } : {}, ...part.on === void 0 ? {} : { on: part.on } }));
|
|
7055
7153
|
var collapsedStockPose = (move2) => {
|
|
@@ -7079,6 +7177,8 @@ function createViewmodel(options) {
|
|
|
7079
7177
|
const hand = new THREE.Group();
|
|
7080
7178
|
hand.name = VIEWMODEL_NODE_NAME;
|
|
7081
7179
|
scene.add(hand);
|
|
7180
|
+
const rocketLight = createRocketLight(THREE);
|
|
7181
|
+
scene.add(rocketLight);
|
|
7082
7182
|
const holder = new THREE.Group();
|
|
7083
7183
|
holder.quaternion.setFromAxisAngle(new THREE.Vector3(0, 1, 0), PI14 / 2);
|
|
7084
7184
|
hand.add(holder);
|
|
@@ -7135,7 +7235,8 @@ function createViewmodel(options) {
|
|
|
7135
7235
|
positionOf: (part) => worldPositionOf(current, part, new THREE.Vector3()),
|
|
7136
7236
|
orientation: () => current.model.root.getWorldQuaternion(new THREE.Quaternion()),
|
|
7137
7237
|
every: (seconds, step, done) => void tasks.push({ delay: 0, seconds, elapsed: 0, step, done }),
|
|
7138
|
-
groundAt
|
|
7238
|
+
groundAt,
|
|
7239
|
+
rocketLight
|
|
7139
7240
|
});
|
|
7140
7241
|
const equip = (weapon) => {
|
|
7141
7242
|
const def = arsenal.weapons.get(weapon);
|
|
@@ -7148,14 +7249,11 @@ function createViewmodel(options) {
|
|
|
7148
7249
|
reach = 0;
|
|
7149
7250
|
pull = 0;
|
|
7150
7251
|
lift = 0;
|
|
7151
|
-
handHeight = 0;
|
|
7152
|
-
handDepth = 0;
|
|
7153
7252
|
rigStock(THREE, model, def);
|
|
7154
7253
|
rigUnderbarrel(THREE, model, def);
|
|
7155
|
-
const
|
|
7156
|
-
const
|
|
7157
|
-
|
|
7158
|
-
holder.position.set(0, 0, Math.min(0.25, 0.25 * length * scale));
|
|
7254
|
+
const modelBox = new THREE.Box3().setFromObject(model.root);
|
|
7255
|
+
const length = modelBox.getSize(new THREE.Vector3()).x;
|
|
7256
|
+
modelRear = modelBox.min.x;
|
|
7159
7257
|
holder.add(model.root);
|
|
7160
7258
|
const caliber = caliberOf(arsenal, def);
|
|
7161
7259
|
const dims = caliber?.cartridge;
|
|
@@ -7167,7 +7265,7 @@ function createViewmodel(options) {
|
|
|
7167
7265
|
def,
|
|
7168
7266
|
caliber,
|
|
7169
7267
|
model,
|
|
7170
|
-
holderScale:
|
|
7268
|
+
holderScale: 1,
|
|
7171
7269
|
lengthMetres: length,
|
|
7172
7270
|
caseType: caliber?.caseType ?? "rifle",
|
|
7173
7271
|
soundProfile: soundProfileOf(weapon, model.parts.family),
|
|
@@ -7197,7 +7295,7 @@ function createViewmodel(options) {
|
|
|
7197
7295
|
applyCondition(kit, model, condition);
|
|
7198
7296
|
lastAmmo = options.tool?.().ammo ?? 0;
|
|
7199
7297
|
hand.updateMatrixWorld(true);
|
|
7200
|
-
hold = holdOfModel(THREE, model,
|
|
7298
|
+
hold = holdOfModel(THREE, model, 1);
|
|
7201
7299
|
hold = { ...hold, works: handWorkOf(THREE, model, weapon, hold.right) };
|
|
7202
7300
|
triggerRest = model.parts.trigger?.rotation.z ?? 0;
|
|
7203
7301
|
lastShot = -Infinity;
|
|
@@ -7217,8 +7315,6 @@ function createViewmodel(options) {
|
|
|
7217
7315
|
let reach = 0;
|
|
7218
7316
|
let pull = 0;
|
|
7219
7317
|
let lift = 0;
|
|
7220
|
-
let handHeight = 0;
|
|
7221
|
-
let handDepth = 0;
|
|
7222
7318
|
const ahead = new THREE.Vector3();
|
|
7223
7319
|
const up = new THREE.Vector3();
|
|
7224
7320
|
const seen = new THREE.Vector3();
|
|
@@ -7231,19 +7327,31 @@ function createViewmodel(options) {
|
|
|
7231
7327
|
for (const x of [bounds.min.x, bounds.max.x]) for (const y of [bounds.min.y, bounds.max.y]) for (const z of [bounds.min.z, bounds.max.z]) farthest = Math.max(farthest, corner.set(x, y, z).sub(camera.position).dot(ahead));
|
|
7232
7328
|
return farthest;
|
|
7233
7329
|
};
|
|
7330
|
+
let modelRear = 0;
|
|
7331
|
+
const eyeFrame = createEyeFrame(THREE, camera);
|
|
7332
|
+
const liftToKeepInView = () => {
|
|
7333
|
+
if (!hold || !session || !("fov" in camera)) return 0;
|
|
7334
|
+
const tanHalf = Math.tan((camera.fov ?? 70) * PI14 / 360);
|
|
7335
|
+
eyeTurn.copy(camera.quaternion).invert();
|
|
7336
|
+
const rest = targetsOf(THREE, hold, session.model.root.getWorldQuaternion(rootQuaternion), 0);
|
|
7337
|
+
let needed = 0;
|
|
7338
|
+
for (const [anchor, pose] of [[hold.right, rest.R], [hold.left, rest.L]]) {
|
|
7339
|
+
if (!anchor || !pose || anchor.part !== session.model.root) continue;
|
|
7340
|
+
seen.set(...pose.position).sub(camera.position).applyQuaternion(eyeTurn);
|
|
7341
|
+
if (-seen.z > 0.05) needed = Math.max(needed, HAND_IN_VIEW.floor * -seen.z * tanHalf - seen.y);
|
|
7342
|
+
}
|
|
7343
|
+
return Math.max(0, Math.min(HAND_IN_VIEW.max, needed));
|
|
7344
|
+
};
|
|
7234
7345
|
const place = (dt = 0) => {
|
|
7235
|
-
|
|
7236
|
-
const
|
|
7237
|
-
|
|
7238
|
-
hand.
|
|
7239
|
-
if (session && handDepth > 0.05 && "fov" in camera) {
|
|
7240
|
-
const tanHalf = Math.tan((camera.fov ?? 70) * PI14 / 360);
|
|
7241
|
-
const want2 = Math.max(0, Math.min(HAND_IN_VIEW.max, lift + (HAND_IN_VIEW.floor - handHeight) * tanHalf * handDepth));
|
|
7242
|
-
lift += (want2 - lift) * Math.min(1, dt * HAND_IN_VIEW.rate);
|
|
7243
|
-
if (lift > 1e-4) hand.position.addScaledVector(up.set(0, 1, 0).applyQuaternion(camera.quaternion), lift);
|
|
7244
|
-
}
|
|
7346
|
+
if (!session) return;
|
|
7347
|
+
const family = session.model.parts.family;
|
|
7348
|
+
session.holderScale = 1;
|
|
7349
|
+
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 });
|
|
7245
7350
|
hand.updateMatrixWorld(true);
|
|
7246
|
-
|
|
7351
|
+
lift += (liftToKeepInView() - lift) * Math.min(1, dt * HAND_IN_VIEW.rate);
|
|
7352
|
+
if (lift > 1e-4) hand.position.addScaledVector(up.set(0, 1, 0).applyQuaternion(camera.quaternion), lift);
|
|
7353
|
+
hand.updateMatrixWorld(true);
|
|
7354
|
+
if (!options.contact) return;
|
|
7247
7355
|
ahead.set(0, 0, -1).applyQuaternion(camera.quaternion);
|
|
7248
7356
|
if (reach === 0) reach = Math.max(0.01, measureReach(session));
|
|
7249
7357
|
const free = options.contact(camera.position, ahead, WALL_PULL.probe);
|
|
@@ -7357,12 +7465,7 @@ function createViewmodel(options) {
|
|
|
7357
7465
|
const targets = targetsOf(THREE, hold, session.model.root.getWorldQuaternion(rootQuaternion), magazineHand, hold.works ? workWeights(hold.works, player?.running ?? []) : void 0);
|
|
7358
7466
|
const trigger = session.model.parts.trigger;
|
|
7359
7467
|
if (trigger) targets.fingers = { index: indexCurl(trigger.rotation.z - triggerRest, clock - lastShot) };
|
|
7360
|
-
|
|
7361
|
-
seen.set(...targets.R.position).sub(camera.position).applyQuaternion(eyeTurn.copy(camera.quaternion).invert());
|
|
7362
|
-
handDepth = -seen.z;
|
|
7363
|
-
handHeight = handDepth > 0.05 ? seen.y / handDepth / Math.tan((camera.fov ?? 70) * PI14 / 360) : 0;
|
|
7364
|
-
}
|
|
7365
|
-
return targets;
|
|
7468
|
+
return limitSupportSpan(targets);
|
|
7366
7469
|
},
|
|
7367
7470
|
get inHand() {
|
|
7368
7471
|
return session?.id ?? null;
|
|
@@ -7381,6 +7484,8 @@ function createViewmodel(options) {
|
|
|
7381
7484
|
particles.dispose();
|
|
7382
7485
|
ownVfx?.dispose();
|
|
7383
7486
|
hand.removeFromParent();
|
|
7487
|
+
rocketLight.removeFromParent();
|
|
7488
|
+
rocketLight.dispose();
|
|
7384
7489
|
}
|
|
7385
7490
|
};
|
|
7386
7491
|
}
|
|
@@ -7405,6 +7510,7 @@ function createWeaponFx(options) {
|
|
|
7405
7510
|
...options.attachmentModels ? { attachmentModels: options.attachmentModels } : {},
|
|
7406
7511
|
...options.raycast ? { raycast: options.raycast } : {},
|
|
7407
7512
|
...options.contact ? { contact: options.contact } : {},
|
|
7513
|
+
...options.bodyHold ? { bodyHold: options.bodyHold } : {},
|
|
7408
7514
|
...options.effects ? { effects: options.effects } : {},
|
|
7409
7515
|
...options.flyRocket === void 0 ? {} : { flyRocket: options.flyRocket }
|
|
7410
7516
|
});
|
|
@@ -8686,6 +8792,7 @@ function createWeaponsTestModule(options = {}) {
|
|
|
8686
8792
|
raycast: createLaserRaycast(lent.THREE, lent.scene, lent.camera),
|
|
8687
8793
|
// the weapon against a wall asks as often as the laser, on the clock of the simulation (so a fast-forwarded room measures as often per frame)
|
|
8688
8794
|
contact: createLaserRaycast(lent.THREE, lent.scene, lent.camera, { now: () => simulatedMs }),
|
|
8795
|
+
...lent.holdFrame ? { bodyHold: () => lent.holdFrame?.() ?? null } : {},
|
|
8689
8796
|
...lent.effects ? { effects: lent.effects } : {},
|
|
8690
8797
|
...options.attachmentModels ? { attachmentModels: options.attachmentModels } : {},
|
|
8691
8798
|
...options.condition ? { condition: options.condition } : {},
|
|
@@ -9505,7 +9612,7 @@ function pushScenario(all, bench, mode) {
|
|
|
9505
9612
|
};
|
|
9506
9613
|
for (const { kind, item } of PUSH_KINDS) PUSH_LAYOUT[kind].forEach(([distance, degrees]) => lay(kind, item, bearing(centre, distance, degrees)));
|
|
9507
9614
|
if (mode === "grenade") {
|
|
9508
|
-
lay("zombie", "zombie_walker", bearing(centre, 3.4, -
|
|
9615
|
+
lay("zombie", "zombie_walker", bearing(centre, 3.4, -130));
|
|
9509
9616
|
lay("survivor", "person_police_officer", bearing(centre, 7.5, 78));
|
|
9510
9617
|
lay("camp_table", "camp_table", bearing(centre, 3, 90));
|
|
9511
9618
|
}
|
|
@@ -9548,7 +9655,7 @@ function pushScenario(all, bench, mode) {
|
|
|
9548
9655
|
const outward = ((now[0] - from[0]) * (from[0] - blast.point[0]) + (now[2] - from[2]) * (from[2] - blast.point[2])) / away;
|
|
9549
9656
|
return { ...body, distance, outward, moved: flat(now, from) };
|
|
9550
9657
|
});
|
|
9551
|
-
const torn = (row) => PUSH_KINDS.some((entry) => entry.kind === row.kind) && partsOf(row.objectId) < (partsBefore.get(row.objectId) ?? 0);
|
|
9658
|
+
const torn = (row) => (PUSH_KINDS.some((entry) => entry.kind === row.kind) || HEAVY_ITEMS.includes(row.kind)) && partsOf(row.objectId) < (partsBefore.get(row.objectId) ?? 0);
|
|
9552
9659
|
const reached = rows.filter((row) => row.distance < blast.radius * 0.85 && !torn(row));
|
|
9553
9660
|
const movedAway = reached.filter((row) => row.outward >= MOVED);
|
|
9554
9661
|
const least = reached.length === 0 ? 0 : Math.min(...reached.map((row) => row.outward));
|
|
@@ -9561,9 +9668,9 @@ function pushScenario(all, bench, mode) {
|
|
|
9561
9668
|
expect(near.outward > far.outward, fillText2(text.push_falloff, { what: things[kind] ?? kind, near: near.outward.toFixed(2), nearDistance: near.distance.toFixed(1), far: far.outward.toFixed(2), farDistance: far.distance.toFixed(1) }), { near: near.outward, far: far.outward });
|
|
9562
9669
|
}
|
|
9563
9670
|
for (const row of reached.filter((entry) => entry.kind === "zombie" || entry.kind === "survivor")) {
|
|
9564
|
-
expect(row.outward >= MOVED, fillText2(text.push_person, { who: things[row.kind] ?? row.kind, distance: row.distance.toFixed(1), moved: row.outward.toFixed(2) }), { row });
|
|
9671
|
+
expect(row.outward >= MOVED, fillText2(text.push_person, { who: things[row.kind] ?? row.kind, distance: row.distance.toFixed(1), moved: row.outward.toFixed(2) }), { row: { kind: row.kind, distance: row.distance, outward: row.outward } });
|
|
9565
9672
|
}
|
|
9566
|
-
const table =
|
|
9673
|
+
const table = rows.find((row) => HEAVY_ITEMS.includes(row.kind) && row.distance < blast.radius * 0.85);
|
|
9567
9674
|
if (table) expect(table.moved >= MOVED, fillText2(text.push_heavy, { what: things[table.itemId] ?? table.itemId, moved: table.moved.toFixed(2) }), { table });
|
|
9568
9675
|
}
|
|
9569
9676
|
};
|