@adatechnology/game-weapons-three 0.10.4 → 0.11.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/README.md +2 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.global.js +833 -212
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +158 -52
- 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. */
|
|
@@ -1539,9 +1616,7 @@ var HAND_HOLD = {
|
|
|
1539
1616
|
/** How far the shooting hand slides on its grip so the thumb reaches the safety lever. */
|
|
1540
1617
|
thumbReach: 0.02,
|
|
1541
1618
|
/** How fast the supporting hand goes to the magazine and back, per second. */
|
|
1542
|
-
magRate: 7
|
|
1543
|
-
/** The hands shrink with the tool: a tool drawn at scale `s` takes hands at `s ** handScaleExponent`. */
|
|
1544
|
-
handScaleExponent: 0.55
|
|
1619
|
+
magRate: 7
|
|
1545
1620
|
};
|
|
1546
1621
|
var handFrame = (THREE, x, y) => {
|
|
1547
1622
|
const ax = x.clone().normalize();
|
|
@@ -1631,7 +1706,8 @@ function holdOfModel(THREE, model, holderScale) {
|
|
|
1631
1706
|
right,
|
|
1632
1707
|
left,
|
|
1633
1708
|
leftMagazine,
|
|
1634
|
-
scale:
|
|
1709
|
+
// the hands at the tool's scale: a tool drawn smaller than the hands looks like a toy in them
|
|
1710
|
+
scale: holderScale,
|
|
1635
1711
|
grip: HAND_HOLD.closed,
|
|
1636
1712
|
gripLeft: HAND_HOLD.forend
|
|
1637
1713
|
};
|
|
@@ -1646,7 +1722,7 @@ function holdOfProp(THREE, group, category, scale) {
|
|
|
1646
1722
|
const long = head && ["smg", "carbine", "rifle", "sniper", "shotgun", "crossbow", "flame"].includes(category);
|
|
1647
1723
|
const headSize = head ? size(head) : null;
|
|
1648
1724
|
const left = long && head && headSize ? { part: group, offset: head.position.clone().add(V(THREE, -headSize.x * 0.15, -headSize.y / 2 - HAND_HOLD.palm, 0)), quaternion: forendFrame(THREE) } : null;
|
|
1649
|
-
return { right, left, leftMagazine: null, scale
|
|
1725
|
+
return { right, left, leftMagazine: null, scale, grip: HAND_HOLD.closed, gripLeft: HAND_HOLD.forend };
|
|
1650
1726
|
}
|
|
1651
1727
|
|
|
1652
1728
|
// src/props.ts
|
|
@@ -4943,7 +5019,6 @@ var FALLBACK_ENERGY = 300;
|
|
|
4943
5019
|
var MAX_CASINGS = 120;
|
|
4944
5020
|
var MAX_MAGAZINES = 12;
|
|
4945
5021
|
var LIFETIME_S = 25;
|
|
4946
|
-
var HAND_OFFSET = [0.2, -0.2, -0.42];
|
|
4947
5022
|
var GRAVITY = 9.81;
|
|
4948
5023
|
function createBoxFx(options) {
|
|
4949
5024
|
const { THREE, scene, camera, arsenal, groundAt } = options;
|
|
@@ -4965,6 +5040,10 @@ function createBoxFx(options) {
|
|
|
4965
5040
|
let dip = 0;
|
|
4966
5041
|
let reloading = false;
|
|
4967
5042
|
const v = new THREE.Vector3();
|
|
5043
|
+
const v2 = new THREE.Vector3();
|
|
5044
|
+
const eyeFrame = createEyeFrame(THREE, camera);
|
|
5045
|
+
let rear = 0;
|
|
5046
|
+
let lengthMetres = 0;
|
|
4968
5047
|
const q = new THREE.Quaternion();
|
|
4969
5048
|
const q2 = new THREE.Quaternion();
|
|
4970
5049
|
const pointForward = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI / 2);
|
|
@@ -4976,13 +5055,17 @@ function createBoxFx(options) {
|
|
|
4976
5055
|
if (!def || BODY_ACTIONS.has(def.id)) return;
|
|
4977
5056
|
model = buildWeaponModel(THREE, def);
|
|
4978
5057
|
const length = new THREE.Box3().setFromObject(model).getSize(v).x;
|
|
4979
|
-
|
|
5058
|
+
rear = new THREE.Box3().setFromObject(model).min.x;
|
|
5059
|
+
lengthMetres = length;
|
|
4980
5060
|
model.quaternion.copy(pointForward);
|
|
4981
5061
|
hand.add(model);
|
|
4982
5062
|
inHand = def.id;
|
|
4983
|
-
hold = holdOfProp(THREE, model, def.category,
|
|
5063
|
+
hold = holdOfProp(THREE, model, def.category, 1);
|
|
5064
|
+
};
|
|
5065
|
+
const handPoint = (x, y, z, out) => {
|
|
5066
|
+
if (!model) return out.set(x, y, z).applyQuaternion(camera.quaternion).add(camera.position);
|
|
5067
|
+
return out.set(x, y, z).applyQuaternion(camera.quaternion).add(model.getWorldPosition(v2));
|
|
4984
5068
|
};
|
|
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
5069
|
const throwBody = (kind, mesh, from, velocity, radius) => {
|
|
4987
5070
|
if (!(kind === "casing" ? layers.casings : layers.magazines)) {
|
|
4988
5071
|
mesh.geometry.dispose();
|
|
@@ -5093,10 +5176,12 @@ function createBoxFx(options) {
|
|
|
5093
5176
|
update(dt) {
|
|
5094
5177
|
kick *= Math.exp(-dt * 14);
|
|
5095
5178
|
dip += ((reloading ? 1 : 0) - dip) * Math.min(1, dt * 8);
|
|
5096
|
-
if (inHand) {
|
|
5097
|
-
|
|
5179
|
+
if (inHand && model) {
|
|
5180
|
+
const handgun = def?.category === "pistol" || def?.category === "revolver";
|
|
5181
|
+
placeOnBody({ THREE, hand, holder: model, frame: options.bodyHold?.() ?? eyeFrame(), rear, lengthMetres, handgun, right: hold?.right ?? null, left: hold?.left ?? null });
|
|
5182
|
+
hand.position.add(v.set(0, -0.12 * dip, 0.05 * kick).applyQuaternion(camera.quaternion));
|
|
5098
5183
|
q.setFromEuler(new THREE.Euler(0.14 * kick - 0.25 * dip, 0, 0.6 * dip));
|
|
5099
|
-
hand.quaternion.
|
|
5184
|
+
hand.quaternion.multiply(q);
|
|
5100
5185
|
}
|
|
5101
5186
|
for (const body of [...bodies]) {
|
|
5102
5187
|
stepBody(body, dt);
|
|
@@ -6181,6 +6266,14 @@ function createEffects(THREE, sink, random) {
|
|
|
6181
6266
|
|
|
6182
6267
|
// src/fx/heavy.ts
|
|
6183
6268
|
var PI12 = Math.PI;
|
|
6269
|
+
var ROCKET_LIGHT_NAME = "rocket-light";
|
|
6270
|
+
var rocketsInFlight = /* @__PURE__ */ new WeakMap();
|
|
6271
|
+
function createRocketLight(THREE) {
|
|
6272
|
+
const light = new THREE.PointLight(16751168, 0, 2.5);
|
|
6273
|
+
light.name = ROCKET_LIGHT_NAME;
|
|
6274
|
+
light.position.set(0, -50, 0);
|
|
6275
|
+
return light;
|
|
6276
|
+
}
|
|
6184
6277
|
var flameMaterials = (kit) => {
|
|
6185
6278
|
const { THREE } = kit;
|
|
6186
6279
|
return [
|
|
@@ -6210,8 +6303,9 @@ function launchRocket(context, flyRound = true) {
|
|
|
6210
6303
|
exhaust.rotation.z = PI12 / 2;
|
|
6211
6304
|
exhaust.position.x = -0.08;
|
|
6212
6305
|
rocket.add(exhaust);
|
|
6213
|
-
const light =
|
|
6214
|
-
|
|
6306
|
+
const light = context.rocketLight;
|
|
6307
|
+
light.intensity = 3;
|
|
6308
|
+
rocketsInFlight.set(light, (rocketsInFlight.get(light) ?? 0) + 1);
|
|
6215
6309
|
context.every(
|
|
6216
6310
|
1.6,
|
|
6217
6311
|
(progress, dt) => {
|
|
@@ -6219,6 +6313,7 @@ function launchRocket(context, flyRound = true) {
|
|
|
6219
6313
|
const distance = 1.2 * flight + (flight > 0.25 ? 9 * (flight - 0.25) ** 2 : 0);
|
|
6220
6314
|
rocket.position.copy(muzzle).addScaledVector(forward, distance);
|
|
6221
6315
|
rocket.rotation.x += 0.25 * dt * 60;
|
|
6316
|
+
light.position.copy(rocket.position);
|
|
6222
6317
|
exhaust.scale.set(1, 0.6 + random() * 0.8, 1);
|
|
6223
6318
|
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
6319
|
},
|
|
@@ -6226,7 +6321,11 @@ function launchRocket(context, flyRound = true) {
|
|
|
6226
6321
|
rocket.removeFromParent();
|
|
6227
6322
|
exhaust.geometry.dispose();
|
|
6228
6323
|
exhaust.material.dispose();
|
|
6229
|
-
|
|
6324
|
+
const remaining = (rocketsInFlight.get(light) ?? 1) - 1;
|
|
6325
|
+
rocketsInFlight.set(light, remaining);
|
|
6326
|
+
if (remaining > 0) return;
|
|
6327
|
+
light.intensity = 0;
|
|
6328
|
+
light.position.set(0, -50, 0);
|
|
6230
6329
|
}
|
|
6231
6330
|
);
|
|
6232
6331
|
}
|
|
@@ -7045,11 +7144,9 @@ function workWeights(works, running) {
|
|
|
7045
7144
|
|
|
7046
7145
|
// src/fx/viewmodel.ts
|
|
7047
7146
|
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
7147
|
var HEAT_DISPLAY_MAX_FALLBACK = 120;
|
|
7051
|
-
var WALL_PULL = { margin: 0.03, max:
|
|
7052
|
-
var HAND_IN_VIEW = { floor: -0.88, max: 0.
|
|
7148
|
+
var WALL_PULL = { margin: 0.03, max: 1.2, rate: 14, probe: 3 };
|
|
7149
|
+
var HAND_IN_VIEW = { floor: -0.88, max: 0.3, rate: 10 };
|
|
7053
7150
|
var LAUNCH_VOLUME = 0.6;
|
|
7054
7151
|
var fittedOf2 = (parts) => parts.map((part) => ({ id: part.id, mount: part.mount, ...part.integral ? { integral: true } : {}, ...part.on === void 0 ? {} : { on: part.on } }));
|
|
7055
7152
|
var collapsedStockPose = (move2) => {
|
|
@@ -7079,6 +7176,8 @@ function createViewmodel(options) {
|
|
|
7079
7176
|
const hand = new THREE.Group();
|
|
7080
7177
|
hand.name = VIEWMODEL_NODE_NAME;
|
|
7081
7178
|
scene.add(hand);
|
|
7179
|
+
const rocketLight = createRocketLight(THREE);
|
|
7180
|
+
scene.add(rocketLight);
|
|
7082
7181
|
const holder = new THREE.Group();
|
|
7083
7182
|
holder.quaternion.setFromAxisAngle(new THREE.Vector3(0, 1, 0), PI14 / 2);
|
|
7084
7183
|
hand.add(holder);
|
|
@@ -7135,7 +7234,8 @@ function createViewmodel(options) {
|
|
|
7135
7234
|
positionOf: (part) => worldPositionOf(current, part, new THREE.Vector3()),
|
|
7136
7235
|
orientation: () => current.model.root.getWorldQuaternion(new THREE.Quaternion()),
|
|
7137
7236
|
every: (seconds, step, done) => void tasks.push({ delay: 0, seconds, elapsed: 0, step, done }),
|
|
7138
|
-
groundAt
|
|
7237
|
+
groundAt,
|
|
7238
|
+
rocketLight
|
|
7139
7239
|
});
|
|
7140
7240
|
const equip = (weapon) => {
|
|
7141
7241
|
const def = arsenal.weapons.get(weapon);
|
|
@@ -7148,14 +7248,11 @@ function createViewmodel(options) {
|
|
|
7148
7248
|
reach = 0;
|
|
7149
7249
|
pull = 0;
|
|
7150
7250
|
lift = 0;
|
|
7151
|
-
handHeight = 0;
|
|
7152
|
-
handDepth = 0;
|
|
7153
7251
|
rigStock(THREE, model, def);
|
|
7154
7252
|
rigUnderbarrel(THREE, model, def);
|
|
7155
|
-
const
|
|
7156
|
-
const
|
|
7157
|
-
|
|
7158
|
-
holder.position.set(0, 0, Math.min(0.25, 0.25 * length * scale));
|
|
7253
|
+
const modelBox = new THREE.Box3().setFromObject(model.root);
|
|
7254
|
+
const length = modelBox.getSize(new THREE.Vector3()).x;
|
|
7255
|
+
modelRear = modelBox.min.x;
|
|
7159
7256
|
holder.add(model.root);
|
|
7160
7257
|
const caliber = caliberOf(arsenal, def);
|
|
7161
7258
|
const dims = caliber?.cartridge;
|
|
@@ -7167,7 +7264,7 @@ function createViewmodel(options) {
|
|
|
7167
7264
|
def,
|
|
7168
7265
|
caliber,
|
|
7169
7266
|
model,
|
|
7170
|
-
holderScale:
|
|
7267
|
+
holderScale: 1,
|
|
7171
7268
|
lengthMetres: length,
|
|
7172
7269
|
caseType: caliber?.caseType ?? "rifle",
|
|
7173
7270
|
soundProfile: soundProfileOf(weapon, model.parts.family),
|
|
@@ -7197,7 +7294,7 @@ function createViewmodel(options) {
|
|
|
7197
7294
|
applyCondition(kit, model, condition);
|
|
7198
7295
|
lastAmmo = options.tool?.().ammo ?? 0;
|
|
7199
7296
|
hand.updateMatrixWorld(true);
|
|
7200
|
-
hold = holdOfModel(THREE, model,
|
|
7297
|
+
hold = holdOfModel(THREE, model, 1);
|
|
7201
7298
|
hold = { ...hold, works: handWorkOf(THREE, model, weapon, hold.right) };
|
|
7202
7299
|
triggerRest = model.parts.trigger?.rotation.z ?? 0;
|
|
7203
7300
|
lastShot = -Infinity;
|
|
@@ -7217,8 +7314,6 @@ function createViewmodel(options) {
|
|
|
7217
7314
|
let reach = 0;
|
|
7218
7315
|
let pull = 0;
|
|
7219
7316
|
let lift = 0;
|
|
7220
|
-
let handHeight = 0;
|
|
7221
|
-
let handDepth = 0;
|
|
7222
7317
|
const ahead = new THREE.Vector3();
|
|
7223
7318
|
const up = new THREE.Vector3();
|
|
7224
7319
|
const seen = new THREE.Vector3();
|
|
@@ -7231,23 +7326,35 @@ function createViewmodel(options) {
|
|
|
7231
7326
|
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
7327
|
return farthest;
|
|
7233
7328
|
};
|
|
7329
|
+
let modelRear = 0;
|
|
7330
|
+
const eyeFrame = createEyeFrame(THREE, camera);
|
|
7331
|
+
const liftToKeepInView = () => {
|
|
7332
|
+
if (!hold || !session || !("fov" in camera)) return 0;
|
|
7333
|
+
const tanHalf = Math.tan((camera.fov ?? 70) * PI14 / 360);
|
|
7334
|
+
eyeTurn.copy(camera.quaternion).invert();
|
|
7335
|
+
const rest = targetsOf(THREE, hold, session.model.root.getWorldQuaternion(rootQuaternion), 0);
|
|
7336
|
+
let needed = 0;
|
|
7337
|
+
for (const [anchor, pose] of [[hold.right, rest.R], [hold.left, rest.L]]) {
|
|
7338
|
+
if (!anchor || !pose || anchor.part !== session.model.root) continue;
|
|
7339
|
+
seen.set(...pose.position).sub(camera.position).applyQuaternion(eyeTurn);
|
|
7340
|
+
if (-seen.z > 0.05) needed = Math.max(needed, HAND_IN_VIEW.floor * -seen.z * tanHalf - seen.y);
|
|
7341
|
+
}
|
|
7342
|
+
return Math.max(0, Math.min(HAND_IN_VIEW.max, needed));
|
|
7343
|
+
};
|
|
7234
7344
|
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
|
-
}
|
|
7345
|
+
if (!session) return;
|
|
7346
|
+
const family = session.model.parts.family;
|
|
7347
|
+
session.holderScale = 1;
|
|
7348
|
+
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
7349
|
hand.updateMatrixWorld(true);
|
|
7246
|
-
|
|
7350
|
+
lift += (liftToKeepInView() - lift) * Math.min(1, dt * HAND_IN_VIEW.rate);
|
|
7351
|
+
if (lift > 1e-4) hand.position.addScaledVector(up.set(0, 1, 0).applyQuaternion(camera.quaternion), lift);
|
|
7352
|
+
hand.updateMatrixWorld(true);
|
|
7353
|
+
if (!options.contact) return;
|
|
7247
7354
|
ahead.set(0, 0, -1).applyQuaternion(camera.quaternion);
|
|
7248
7355
|
if (reach === 0) reach = Math.max(0.01, measureReach(session));
|
|
7249
7356
|
const free = options.contact(camera.position, ahead, WALL_PULL.probe);
|
|
7250
|
-
const want = free === null ? 0 : Math.max(0, Math.min(WALL_PULL.max, reach + WALL_PULL.margin - free));
|
|
7357
|
+
const want = free === null ? 0 : Math.max(0, Math.min(Math.max(WALL_PULL.max, session.lengthMetres * session.holderScale), reach + WALL_PULL.margin - free));
|
|
7251
7358
|
pull += (want - pull) * Math.min(1, dt * WALL_PULL.rate);
|
|
7252
7359
|
if (pull < 1e-4) return;
|
|
7253
7360
|
hand.position.addScaledVector(ahead, -pull);
|
|
@@ -7357,12 +7464,7 @@ function createViewmodel(options) {
|
|
|
7357
7464
|
const targets = targetsOf(THREE, hold, session.model.root.getWorldQuaternion(rootQuaternion), magazineHand, hold.works ? workWeights(hold.works, player?.running ?? []) : void 0);
|
|
7358
7465
|
const trigger = session.model.parts.trigger;
|
|
7359
7466
|
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;
|
|
7467
|
+
return limitSupportSpan(targets);
|
|
7366
7468
|
},
|
|
7367
7469
|
get inHand() {
|
|
7368
7470
|
return session?.id ?? null;
|
|
@@ -7381,6 +7483,8 @@ function createViewmodel(options) {
|
|
|
7381
7483
|
particles.dispose();
|
|
7382
7484
|
ownVfx?.dispose();
|
|
7383
7485
|
hand.removeFromParent();
|
|
7486
|
+
rocketLight.removeFromParent();
|
|
7487
|
+
rocketLight.dispose();
|
|
7384
7488
|
}
|
|
7385
7489
|
};
|
|
7386
7490
|
}
|
|
@@ -7405,6 +7509,7 @@ function createWeaponFx(options) {
|
|
|
7405
7509
|
...options.attachmentModels ? { attachmentModels: options.attachmentModels } : {},
|
|
7406
7510
|
...options.raycast ? { raycast: options.raycast } : {},
|
|
7407
7511
|
...options.contact ? { contact: options.contact } : {},
|
|
7512
|
+
...options.bodyHold ? { bodyHold: options.bodyHold } : {},
|
|
7408
7513
|
...options.effects ? { effects: options.effects } : {},
|
|
7409
7514
|
...options.flyRocket === void 0 ? {} : { flyRocket: options.flyRocket }
|
|
7410
7515
|
});
|
|
@@ -8686,6 +8791,7 @@ function createWeaponsTestModule(options = {}) {
|
|
|
8686
8791
|
raycast: createLaserRaycast(lent.THREE, lent.scene, lent.camera),
|
|
8687
8792
|
// 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
8793
|
contact: createLaserRaycast(lent.THREE, lent.scene, lent.camera, { now: () => simulatedMs }),
|
|
8794
|
+
...lent.holdFrame ? { bodyHold: () => lent.holdFrame?.() ?? null } : {},
|
|
8689
8795
|
...lent.effects ? { effects: lent.effects } : {},
|
|
8690
8796
|
...options.attachmentModels ? { attachmentModels: options.attachmentModels } : {},
|
|
8691
8797
|
...options.condition ? { condition: options.condition } : {},
|
|
@@ -9505,7 +9611,7 @@ function pushScenario(all, bench, mode) {
|
|
|
9505
9611
|
};
|
|
9506
9612
|
for (const { kind, item } of PUSH_KINDS) PUSH_LAYOUT[kind].forEach(([distance, degrees]) => lay(kind, item, bearing(centre, distance, degrees)));
|
|
9507
9613
|
if (mode === "grenade") {
|
|
9508
|
-
lay("zombie", "zombie_walker", bearing(centre, 3.4, -
|
|
9614
|
+
lay("zombie", "zombie_walker", bearing(centre, 3.4, -130));
|
|
9509
9615
|
lay("survivor", "person_police_officer", bearing(centre, 7.5, 78));
|
|
9510
9616
|
lay("camp_table", "camp_table", bearing(centre, 3, 90));
|
|
9511
9617
|
}
|
|
@@ -9548,7 +9654,7 @@ function pushScenario(all, bench, mode) {
|
|
|
9548
9654
|
const outward = ((now[0] - from[0]) * (from[0] - blast.point[0]) + (now[2] - from[2]) * (from[2] - blast.point[2])) / away;
|
|
9549
9655
|
return { ...body, distance, outward, moved: flat(now, from) };
|
|
9550
9656
|
});
|
|
9551
|
-
const torn = (row) => PUSH_KINDS.some((entry) => entry.kind === row.kind) && partsOf(row.objectId) < (partsBefore.get(row.objectId) ?? 0);
|
|
9657
|
+
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
9658
|
const reached = rows.filter((row) => row.distance < blast.radius * 0.85 && !torn(row));
|
|
9553
9659
|
const movedAway = reached.filter((row) => row.outward >= MOVED);
|
|
9554
9660
|
const least = reached.length === 0 ? 0 : Math.min(...reached.map((row) => row.outward));
|
|
@@ -9561,9 +9667,9 @@ function pushScenario(all, bench, mode) {
|
|
|
9561
9667
|
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
9668
|
}
|
|
9563
9669
|
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 });
|
|
9670
|
+
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
9671
|
}
|
|
9566
|
-
const table =
|
|
9672
|
+
const table = rows.find((row) => HEAVY_ITEMS.includes(row.kind) && row.distance < blast.radius * 0.85);
|
|
9567
9673
|
if (table) expect(table.moved >= MOVED, fillText2(text.push_heavy, { what: things[table.itemId] ?? table.itemId, moved: table.moved.toFixed(2) }), { table });
|
|
9568
9674
|
}
|
|
9569
9675
|
};
|