@adatechnology/game-test-room 0.12.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +13 -0
- package/dist/index.global.js +250 -45
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +161 -34
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -1706,6 +1706,9 @@ function createNarrator(c) {
|
|
|
1706
1706
|
var EYE = 1.7;
|
|
1707
1707
|
var PLAYER_RADIUS = 0.3;
|
|
1708
1708
|
var WALK = 3.4;
|
|
1709
|
+
var CROUCH_DROP = 0.55;
|
|
1710
|
+
var CROUCH_WALK = 1.7;
|
|
1711
|
+
var CROUCH_RATE = 9;
|
|
1709
1712
|
var RUN = 6.2;
|
|
1710
1713
|
var JUMP = 4.6;
|
|
1711
1714
|
var GRAVITY = 13;
|
|
@@ -1716,17 +1719,20 @@ function createPlayer(THREE, o) {
|
|
|
1716
1719
|
let pitch = 0;
|
|
1717
1720
|
let y = 0;
|
|
1718
1721
|
let eye = EYE;
|
|
1722
|
+
let crouch = 0;
|
|
1719
1723
|
let vy = 0;
|
|
1720
1724
|
let walked = 0;
|
|
1721
1725
|
let running = false;
|
|
1722
1726
|
const px = { x: o.start[0], z: o.start[2] };
|
|
1723
1727
|
let locked = false;
|
|
1724
1728
|
const keys = /* @__PURE__ */ new Set();
|
|
1729
|
+
const crouchKeys = o.crouchKeys ?? ["KeyC"];
|
|
1730
|
+
const isCrouchHeld = () => crouchKeys.some((code) => keys.has(code));
|
|
1725
1731
|
const euler = new THREE.Euler(0, 0, 0, "YXZ");
|
|
1726
1732
|
const apply = () => {
|
|
1727
1733
|
euler.set(pitch, yaw, 0, "YXZ");
|
|
1728
1734
|
cam.quaternion.setFromEuler(euler);
|
|
1729
|
-
cam.position.set(px.x, eye + y, px.z);
|
|
1735
|
+
cam.position.set(px.x, eye + y - CROUCH_DROP * crouch, px.z);
|
|
1730
1736
|
cam.updateMatrixWorld(true);
|
|
1731
1737
|
};
|
|
1732
1738
|
apply();
|
|
@@ -1753,6 +1759,20 @@ function createPlayer(THREE, o) {
|
|
|
1753
1759
|
};
|
|
1754
1760
|
const onLockChange = () => {
|
|
1755
1761
|
locked = document.pointerLockElement === o.dom;
|
|
1762
|
+
if (locked) {
|
|
1763
|
+
try {
|
|
1764
|
+
const nav = typeof navigator !== "undefined" ? navigator : null;
|
|
1765
|
+
nav?.keyboard?.lock?.().catch(() => {
|
|
1766
|
+
});
|
|
1767
|
+
} catch {
|
|
1768
|
+
}
|
|
1769
|
+
} else {
|
|
1770
|
+
try {
|
|
1771
|
+
const nav = typeof navigator !== "undefined" ? navigator : null;
|
|
1772
|
+
nav?.keyboard?.unlock?.();
|
|
1773
|
+
} catch {
|
|
1774
|
+
}
|
|
1775
|
+
}
|
|
1756
1776
|
};
|
|
1757
1777
|
const onMouseDown = (e) => {
|
|
1758
1778
|
o.dom.focus?.();
|
|
@@ -1822,6 +1842,10 @@ function createPlayer(THREE, o) {
|
|
|
1822
1842
|
const onKeyDown = (e) => {
|
|
1823
1843
|
if (typing(e)) return;
|
|
1824
1844
|
if (e.code === "Space" || e.code === "Tab") e.preventDefault();
|
|
1845
|
+
const isControlHeld = e.ctrlKey || e.metaKey || keys.has("ControlLeft") || keys.has("ControlRight");
|
|
1846
|
+
if (isControlHeld || e.altKey && locked) {
|
|
1847
|
+
if (!/^F\d+$/.test(e.code)) e.preventDefault();
|
|
1848
|
+
}
|
|
1825
1849
|
if (!e.repeat) keys.add(e.code);
|
|
1826
1850
|
o.hooks.key(e.code, true, e);
|
|
1827
1851
|
};
|
|
@@ -1832,6 +1856,11 @@ function createPlayer(THREE, o) {
|
|
|
1832
1856
|
};
|
|
1833
1857
|
const onContext = (e) => e.preventDefault();
|
|
1834
1858
|
const onBlur = () => keys.clear();
|
|
1859
|
+
const onBeforeUnload = (e) => {
|
|
1860
|
+
if (!locked && !keys.has("ControlLeft") && !keys.has("ControlRight")) return;
|
|
1861
|
+
e.preventDefault();
|
|
1862
|
+
e.returnValue = "";
|
|
1863
|
+
};
|
|
1835
1864
|
o.dom.addEventListener("mousedown", onMouseDown);
|
|
1836
1865
|
window.addEventListener("mouseup", onMouseUp);
|
|
1837
1866
|
window.addEventListener("mousemove", onMouseMove);
|
|
@@ -1841,6 +1870,7 @@ function createPlayer(THREE, o) {
|
|
|
1841
1870
|
window.addEventListener("keydown", onKeyDown);
|
|
1842
1871
|
window.addEventListener("keyup", onKeyUp);
|
|
1843
1872
|
window.addEventListener("blur", onBlur);
|
|
1873
|
+
window.addEventListener("beforeunload", onBeforeUnload);
|
|
1844
1874
|
return {
|
|
1845
1875
|
get yaw() {
|
|
1846
1876
|
return yaw;
|
|
@@ -1869,12 +1899,18 @@ function createPlayer(THREE, o) {
|
|
|
1869
1899
|
get running() {
|
|
1870
1900
|
return running;
|
|
1871
1901
|
},
|
|
1902
|
+
get crouching() {
|
|
1903
|
+
return isCrouchHeld();
|
|
1904
|
+
},
|
|
1872
1905
|
keys,
|
|
1873
1906
|
update(dt) {
|
|
1874
|
-
const
|
|
1907
|
+
const crouched = isCrouchHeld();
|
|
1908
|
+
crouch += ((crouched ? 1 : 0) - crouch) * Math.min(1, dt * CROUCH_RATE);
|
|
1909
|
+
if (!crouched && crouch < 1e-3) crouch = 0;
|
|
1910
|
+
const run = !crouched && (keys.has("ShiftLeft") || keys.has("ShiftRight"));
|
|
1875
1911
|
const fromX = px.x;
|
|
1876
1912
|
const fromZ = px.z;
|
|
1877
|
-
const speed = run ? RUN : WALK;
|
|
1913
|
+
const speed = crouched ? CROUCH_WALK : run ? RUN : WALK;
|
|
1878
1914
|
let f = 0;
|
|
1879
1915
|
let r = 0;
|
|
1880
1916
|
if (keys.has("KeyW") || keys.has("ArrowUp")) f += 1;
|
|
@@ -1950,13 +1986,14 @@ function createPlayer(THREE, o) {
|
|
|
1950
1986
|
window.removeEventListener("keydown", onKeyDown);
|
|
1951
1987
|
window.removeEventListener("keyup", onKeyUp);
|
|
1952
1988
|
window.removeEventListener("blur", onBlur);
|
|
1989
|
+
window.removeEventListener("beforeunload", onBeforeUnload);
|
|
1953
1990
|
if (document.pointerLockElement === o.dom) document.exitPointerLock?.();
|
|
1954
1991
|
}
|
|
1955
1992
|
};
|
|
1956
1993
|
}
|
|
1957
1994
|
|
|
1958
1995
|
// src/avatar.ts
|
|
1959
|
-
var DEFAULT_STRIKE_CLIPS = { fists: "punch_right", shove: "shove_two_hands", kick: "front_kick" };
|
|
1996
|
+
var DEFAULT_STRIKE_CLIPS = { hand: "punch_right", fists: "punch_right", shove: "shove_two_hands", kick: "front_kick" };
|
|
1960
1997
|
var DEFAULT_HAND_STANCES = { fists: "fists" };
|
|
1961
1998
|
var THIRD_PERSON_DEFAULTS = {
|
|
1962
1999
|
back: 3.8,
|
|
@@ -2197,7 +2234,7 @@ var en = {
|
|
|
2197
2234
|
"hud.throw": "throw",
|
|
2198
2235
|
"hud.tilt": "tilt (hold)",
|
|
2199
2236
|
"hud.equip": "equip {weapon}",
|
|
2200
|
-
"ui.help": "Click: look \xB7 WASD: walk \xB7 Shift: run \xB7 Space: jump \xB7 1-0 / wheel: tool \xB7 LMB: use \xB7 E: grab/drop \xB7 G or RMB: throw \xB7 R: reload \xB7 Q: fire mode \xB7 X: clear a jam \xB7 B: safety \xB7 Y: detonate charges set down \xB7 Tab: panels \xB7 Esc: free the mouse",
|
|
2237
|
+
"ui.help": "Click: look \xB7 WASD: walk \xB7 Shift: run \xB7 C: crouch \xB7 Space: jump \xB7 1-0 / wheel: tool \xB7 LMB: use \xB7 E: grab/drop \xB7 G or RMB: throw \xB7 R: reload \xB7 Q: fire mode \xB7 X: clear a jam \xB7 B: safety \xB7 Y: detonate charges set down \xB7 Tab: panels \xB7 Esc: free the mouse",
|
|
2201
2238
|
"ui.help.camera": "V: 1st/3rd person (Shift+V: kick)",
|
|
2202
2239
|
"camera.first": "1st person",
|
|
2203
2240
|
"camera.third": "3rd person",
|
|
@@ -2218,6 +2255,8 @@ var en = {
|
|
|
2218
2255
|
"ui.slow": "Slow motion 0.25\xD7",
|
|
2219
2256
|
"ui.fast": "Time \xD710",
|
|
2220
2257
|
"ui.tap": "Tap",
|
|
2258
|
+
"ui.fullscreen": "Full screen",
|
|
2259
|
+
"ui.fullscreen.hint": "Full screen opened from here keeps the whole keyboard in the game, Ctrl+W included (F11 does not)",
|
|
2221
2260
|
"ui.blast.shelter": "Shelter",
|
|
2222
2261
|
"ui.blast.fragmentHits": "Fragments",
|
|
2223
2262
|
"ui.blast.confinement": "Confinement",
|
|
@@ -2476,7 +2515,7 @@ var ptBR = {
|
|
|
2476
2515
|
"hud.throw": "arremessar",
|
|
2477
2516
|
"hud.tilt": "inclinar (segurar)",
|
|
2478
2517
|
"hud.equip": "equipar {weapon}",
|
|
2479
|
-
"ui.help": "Clique: olhar \xB7 WASD: andar \xB7 Shift: correr \xB7 Espa\xE7o: pular \xB7 1-0 / roda: ferramenta \xB7 bot\xE3o esquerdo: usar \xB7 E: pegar/soltar \xB7 G ou bot\xE3o direito: arremessar \xB7 R: recarregar \xB7 Q: modo de tiro \xB7 X: destravar \xB7 B: trava \xB7 Y: detonar cargas postas \xB7 Tab: pain\xE9is \xB7 Esc: soltar o mouse",
|
|
2518
|
+
"ui.help": "Clique: olhar \xB7 WASD: andar \xB7 Shift: correr \xB7 C: agachar \xB7 Espa\xE7o: pular \xB7 1-0 / roda: ferramenta \xB7 bot\xE3o esquerdo: usar \xB7 E: pegar/soltar \xB7 G ou bot\xE3o direito: arremessar \xB7 R: recarregar \xB7 Q: modo de tiro \xB7 X: destravar \xB7 B: trava \xB7 Y: detonar cargas postas \xB7 Tab: pain\xE9is \xB7 Esc: soltar o mouse",
|
|
2480
2519
|
"ui.help.camera": "V: 1\xAA/3\xAA pessoa (Shift+V: chute)",
|
|
2481
2520
|
"camera.first": "1\xAA pessoa",
|
|
2482
2521
|
"camera.third": "3\xAA pessoa",
|
|
@@ -2497,6 +2536,8 @@ var ptBR = {
|
|
|
2497
2536
|
"ui.slow": "C\xE2mera lenta 0,25\xD7",
|
|
2498
2537
|
"ui.fast": "Tempo \xD710",
|
|
2499
2538
|
"ui.tap": "Torneira",
|
|
2539
|
+
"ui.fullscreen": "Tela cheia",
|
|
2540
|
+
"ui.fullscreen.hint": "A tela cheia aberta por aqui segura o teclado todo no jogo, inclusive Ctrl+W (o F11 n\xE3o)",
|
|
2500
2541
|
"ui.blast.shelter": "Abrigo",
|
|
2501
2542
|
"ui.blast.fragmentHits": "Estilha\xE7os",
|
|
2502
2543
|
"ui.blast.confinement": "Confinamento",
|
|
@@ -2924,6 +2965,19 @@ var thumb = (thumbnail, credit) => {
|
|
|
2924
2965
|
e.style.setProperty("--tr-thumb", `url("${thumbSource(thumbnail)}")`);
|
|
2925
2966
|
return e;
|
|
2926
2967
|
};
|
|
2968
|
+
async function toggleFullscreen() {
|
|
2969
|
+
const keyboard = navigator.keyboard;
|
|
2970
|
+
try {
|
|
2971
|
+
if (document.fullscreenElement) {
|
|
2972
|
+
keyboard?.unlock?.();
|
|
2973
|
+
await document.exitFullscreen();
|
|
2974
|
+
return;
|
|
2975
|
+
}
|
|
2976
|
+
await document.documentElement.requestFullscreen();
|
|
2977
|
+
await keyboard?.lock?.();
|
|
2978
|
+
} catch {
|
|
2979
|
+
}
|
|
2980
|
+
}
|
|
2927
2981
|
function createUi(o) {
|
|
2928
2982
|
const { t } = o;
|
|
2929
2983
|
const style = mk2("style");
|
|
@@ -3135,6 +3189,8 @@ function createUi(o) {
|
|
|
3135
3189
|
o.onFast(fast);
|
|
3136
3190
|
});
|
|
3137
3191
|
const tapBtn = ctl(t("ui.tap"), () => o.onTap());
|
|
3192
|
+
const fullscreenBtn = ctl(t("ui.fullscreen"), () => void toggleFullscreen());
|
|
3193
|
+
fullscreenBtn.title = t("ui.fullscreen.hint");
|
|
3138
3194
|
const blastBtns = ["shelter", "fragmentHits", "confinement"].map((key) => ({ key, b: ctl(t(`ui.blast.${key}`), () => o.onBlast(key)) }));
|
|
3139
3195
|
for (const { key, b } of blastBtns) b.title = t(`ui.blast.${key}.hint`);
|
|
3140
3196
|
const qSel = mk2("select");
|
|
@@ -3688,6 +3744,7 @@ function createTestRoom(options) {
|
|
|
3688
3744
|
blockers,
|
|
3689
3745
|
limit: arenaSize,
|
|
3690
3746
|
start: arena.playerStart,
|
|
3747
|
+
crouchKeys: options.crouch?.keys,
|
|
3691
3748
|
hooks: {
|
|
3692
3749
|
primaryDown: () => {
|
|
3693
3750
|
useHeld = true;
|
|
@@ -3940,6 +3997,7 @@ function createTestRoom(options) {
|
|
|
3940
3997
|
const third = { ...THIRD_PERSON_DEFAULTS, ...options.thirdPerson };
|
|
3941
3998
|
let avatar = null;
|
|
3942
3999
|
let cameraMode = options.cameraMode ?? "first";
|
|
4000
|
+
let crouchForced = false;
|
|
3943
4001
|
const avatarState = { speed: 0, running: false, crouch: false, down: false, armed: false, pitch: 0 };
|
|
3944
4002
|
let feetPrev = null;
|
|
3945
4003
|
let armedForced = null;
|
|
@@ -3993,9 +4051,12 @@ function createTestRoom(options) {
|
|
|
3993
4051
|
if (avatarState.speed < 0.02) avatarState.speed = 0;
|
|
3994
4052
|
}
|
|
3995
4053
|
feetPrev = [x, z];
|
|
3996
|
-
avatarState.running = player.keys.has("ShiftLeft") || player.keys.has("ShiftRight");
|
|
4054
|
+
avatarState.running = !player.crouching && (player.keys.has("ShiftLeft") || player.keys.has("ShiftRight"));
|
|
4055
|
+
avatarState.crouch = crouchForced || player.crouching;
|
|
3997
4056
|
avatarState.armed = armedForced ?? tool.def.action.kind === "firearm";
|
|
3998
4057
|
avatarState.pitch = player.pitch;
|
|
4058
|
+
avatarState.holding = heldPiece !== null;
|
|
4059
|
+
avatarState.itemUse = useItemPlayer ? { id: useItemName, ...useItemPlayer.pose() } : heldPiece && heldTilt > 0.01 ? { id: "tilt", position: [0.2, -0.1, -0.38], rotation: [-heldTilt, 0, 0] } : null;
|
|
3999
4060
|
avatar.root.position.set(x, player.feet, z);
|
|
4000
4061
|
avatar.root.rotation.set(0, player.yaw + Math.PI, 0);
|
|
4001
4062
|
avatar.update(dt, avatarState);
|
|
@@ -4451,7 +4512,11 @@ function createTestRoom(options) {
|
|
|
4451
4512
|
const useTool = (dt, held) => {
|
|
4452
4513
|
aim();
|
|
4453
4514
|
const cat = tool.def.category;
|
|
4454
|
-
if (cat === "hand")
|
|
4515
|
+
if (cat === "hand") {
|
|
4516
|
+
if (strikes.some((strike) => strike.key === "hand" || strike.key === "fists")) return;
|
|
4517
|
+
strikeUse({ kind: "melee", damage: "blunt", energy: 25, radius: 0.1, reach: 0.8, origin: [aimO[0], aimO[1], aimO[2]], direction: [aimD[0], aimD[1], aimD[2]] }, "hand");
|
|
4518
|
+
return;
|
|
4519
|
+
}
|
|
4455
4520
|
if (strikes.some((strike) => strike.key === toolId)) return;
|
|
4456
4521
|
const res = tool.trigger([aimO[0], aimO[1], aimO[2]], [aimD[0], aimD[1], aimD[2]], dt, held, "player");
|
|
4457
4522
|
flushEvents(toolId, tool, res.recoil);
|
|
@@ -4544,6 +4609,7 @@ function createTestRoom(options) {
|
|
|
4544
4609
|
let heldTilt = 0;
|
|
4545
4610
|
let tiltKey = 0;
|
|
4546
4611
|
const heldLocal = new THREE.Vector3();
|
|
4612
|
+
const heldSize = new THREE.Vector3(0.2, 0.2, 0.2);
|
|
4547
4613
|
let heldRadius = 0.2;
|
|
4548
4614
|
const heldVel = [0, 0, 0];
|
|
4549
4615
|
let useItemPlayer = null;
|
|
@@ -4589,12 +4655,15 @@ function createTestRoom(options) {
|
|
|
4589
4655
|
heldName = nameOf(r.object);
|
|
4590
4656
|
piece.held = true;
|
|
4591
4657
|
piece.sleeping = false;
|
|
4658
|
+
const savedQ = piece.root.quaternion.clone();
|
|
4659
|
+
piece.root.quaternion.identity();
|
|
4660
|
+
piece.root.updateMatrixWorld(true);
|
|
4592
4661
|
const box2 = new THREE.Box3().setFromObject(piece.root);
|
|
4593
|
-
|
|
4662
|
+
box2.getCenter(heldLocal).sub(piece.root.position);
|
|
4663
|
+
box2.getSize(heldSize);
|
|
4664
|
+
piece.root.quaternion.copy(savedQ);
|
|
4594
4665
|
piece.root.updateMatrixWorld(true);
|
|
4595
|
-
|
|
4596
|
-
heldLocal.applyQuaternion(piece.root.quaternion.clone().invert());
|
|
4597
|
-
heldRadius = box2.getSize(new THREE.Vector3()).length() / 3;
|
|
4666
|
+
heldRadius = heldSize.length() / 3;
|
|
4598
4667
|
heldYaw = 0;
|
|
4599
4668
|
heldTilt = 0;
|
|
4600
4669
|
heldVel[0] = heldVel[1] = heldVel[2] = 0;
|
|
@@ -4615,18 +4684,43 @@ function createTestRoom(options) {
|
|
|
4615
4684
|
fire("throw", { objectId: id, speed });
|
|
4616
4685
|
return true;
|
|
4617
4686
|
};
|
|
4618
|
-
const carriedTargets = (root) => {
|
|
4687
|
+
const carriedTargets = (root, gripQ) => {
|
|
4688
|
+
const width2 = Math.max(heldSize.x, heldSize.z);
|
|
4689
|
+
const sideGrip = heldSize.y > width2 * 1.04 && width2 <= 0.22;
|
|
4690
|
+
if (sideGrip) {
|
|
4691
|
+
const center2 = heldLocal.clone().applyQuaternion(root.quaternion).add(root.position);
|
|
4692
|
+
const radius = Math.min(heldSize.x, heldSize.z) * 0.5;
|
|
4693
|
+
const handX = new THREE.Vector3(-0.35, 0, -0.94).normalize().applyQuaternion(gripQ);
|
|
4694
|
+
const handY = new THREE.Vector3(0.94, 0, -0.35).normalize().applyQuaternion(gripQ);
|
|
4695
|
+
const handZ = new THREE.Vector3().crossVectors(handX, handY).normalize();
|
|
4696
|
+
const q2 = new THREE.Quaternion().setFromRotationMatrix(new THREE.Matrix4().makeBasis(handX, handY, handZ));
|
|
4697
|
+
const up = new THREE.Vector3(0, 1, 0).applyQuaternion(gripQ);
|
|
4698
|
+
const palm = center2.clone().addScaledVector(handY, radius + CARRY_PALM).addScaledVector(handX, -0.022).addScaledVector(up, heldSize.y > 0.16 ? -heldSize.y * 0.08 : -5e-3);
|
|
4699
|
+
if (useItemName === "open" || useItemName === "close") {
|
|
4700
|
+
const leftX = new THREE.Vector3(0.35, 0, -0.94).normalize().applyQuaternion(gripQ);
|
|
4701
|
+
const leftY = new THREE.Vector3(-0.94, 0, -0.35).normalize().applyQuaternion(gripQ);
|
|
4702
|
+
const leftZ = new THREE.Vector3().crossVectors(leftX, leftY).normalize();
|
|
4703
|
+
const lq = new THREE.Quaternion().setFromRotationMatrix(new THREE.Matrix4().makeBasis(leftX, leftY, leftZ));
|
|
4704
|
+
const leftPalm = center2.clone().addScaledVector(up, heldSize.y * 0.45).addScaledVector(leftY, radius * 0.65 + CARRY_PALM).addScaledVector(leftX, -0.018);
|
|
4705
|
+
return {
|
|
4706
|
+
R: { position: [palm.x, palm.y, palm.z], quaternion: [q2.x, q2.y, q2.z, q2.w] },
|
|
4707
|
+
L: { position: [leftPalm.x, leftPalm.y, leftPalm.z], quaternion: [lq.x, lq.y, lq.z, lq.w] },
|
|
4708
|
+
grip: 0.85,
|
|
4709
|
+
gripL: 0.8
|
|
4710
|
+
};
|
|
4711
|
+
}
|
|
4712
|
+
return { R: { position: [palm.x, palm.y, palm.z], quaternion: [q2.x, q2.y, q2.z, q2.w] }, grip: 0.85 };
|
|
4713
|
+
}
|
|
4619
4714
|
const box2 = new THREE.Box3().setFromObject(root);
|
|
4620
4715
|
const center = box2.getCenter(new THREE.Vector3());
|
|
4621
|
-
const forward =
|
|
4622
|
-
|
|
4623
|
-
|
|
4624
|
-
forward.normalize();
|
|
4625
|
-
const
|
|
4626
|
-
const z = forward.clone().cross(back).normalize();
|
|
4627
|
-
const q = new THREE.Quaternion().setFromRotationMatrix(new THREE.Matrix4().makeBasis(forward, back, z));
|
|
4716
|
+
const forward = new THREE.Vector3(0, 0, -1).applyQuaternion(gripQ).normalize();
|
|
4717
|
+
const back = new THREE.Vector3(0, -1, 0).applyQuaternion(gripQ).normalize();
|
|
4718
|
+
const z = new THREE.Vector3().crossVectors(forward, back).normalize();
|
|
4719
|
+
const y = new THREE.Vector3().crossVectors(z, forward).normalize();
|
|
4720
|
+
const q = new THREE.Quaternion().setFromRotationMatrix(new THREE.Matrix4().makeBasis(forward, y, z));
|
|
4628
4721
|
return { R: { position: [center.x, box2.min.y - CARRY_PALM, center.z], quaternion: [q.x, q.y, q.z, q.w] }, grip: CARRY_GRIP };
|
|
4629
4722
|
};
|
|
4723
|
+
const gripQuat = new THREE.Quaternion();
|
|
4630
4724
|
const followHeld = (dt) => {
|
|
4631
4725
|
const piece = heldPiece;
|
|
4632
4726
|
carriedHand = null;
|
|
@@ -4636,21 +4730,47 @@ function createTestRoom(options) {
|
|
|
4636
4730
|
let pos;
|
|
4637
4731
|
const targetQ = tmpQ;
|
|
4638
4732
|
const hand = thirdActive() ? avatar?.hand?.("R") : void 0;
|
|
4733
|
+
const isDrink = useItemName === "drink" || useItemName === "sip" || useItemName === "chug";
|
|
4639
4734
|
if (hand) {
|
|
4640
|
-
|
|
4641
|
-
|
|
4642
|
-
|
|
4735
|
+
const handWorld = hand.getWorldPosition(tmpHand);
|
|
4736
|
+
const yawQ = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), player.yaw);
|
|
4737
|
+
const pose = useItemPlayer?.pose();
|
|
4738
|
+
const rx = pose ? isDrink ? Math.abs(pose.rotation[0]) * 0.9 : pose.rotation[0] : -heldTilt;
|
|
4739
|
+
const ry = pose ? pose.rotation[1] : 0;
|
|
4740
|
+
const rz = pose ? pose.rotation[2] : 0;
|
|
4741
|
+
gripQuat.copy(yawQ).multiply(new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.max(-1.35, Math.min(1.25, rx)), ry, rz, "XYZ")));
|
|
4742
|
+
targetQ.copy(yawQ).multiply(new THREE.Quaternion().setFromEuler(new THREE.Euler(rx, ry, rz, "XYZ")));
|
|
4743
|
+
targetQ.multiply(new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), heldYaw));
|
|
4744
|
+
const gripOffset = new THREE.Vector3(-0.02, 0.015, -0.04).applyQuaternion(gripQuat);
|
|
4745
|
+
pos = tmpV.copy(handWorld).add(gripOffset);
|
|
4643
4746
|
} else if (useItemPlayer) {
|
|
4644
4747
|
const pose = useItemPlayer.pose();
|
|
4645
|
-
const
|
|
4646
|
-
|
|
4647
|
-
const
|
|
4648
|
-
|
|
4748
|
+
const frameQ = avatar?.firstPerson ? camera.quaternion : new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), player.yaw);
|
|
4749
|
+
const raise = isDrink ? Math.max(0, Math.min(1, (pose.position[1] + 0.2) / 0.22)) : 0;
|
|
4750
|
+
const px2 = pose.position[0] + (isDrink ? 0.02 * raise : 0);
|
|
4751
|
+
const py2 = pose.position[1] - (isDrink ? 0.08 * raise : 0);
|
|
4752
|
+
const pz2 = pose.position[2] - (isDrink ? 0.05 * raise : 0);
|
|
4753
|
+
pos = tmpV.set(px2, py2, pz2).applyQuaternion(frameQ).add(camera.position);
|
|
4754
|
+
const rx = isDrink ? Math.abs(pose.rotation[0]) * 0.85 : pose.rotation[0];
|
|
4755
|
+
const eq = new THREE.Quaternion().setFromEuler(new THREE.Euler(rx, pose.rotation[1], pose.rotation[2], "XYZ"));
|
|
4756
|
+
const wristEq = new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.max(-1.35, Math.min(1.25, rx)), pose.rotation[1], pose.rotation[2], "XYZ"));
|
|
4757
|
+
gripQuat.copy(frameQ).multiply(wristEq);
|
|
4758
|
+
targetQ.copy(frameQ).multiply(eq);
|
|
4649
4759
|
targetQ.multiply(new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), heldYaw));
|
|
4650
4760
|
} else {
|
|
4651
|
-
|
|
4761
|
+
const small = heldRadius < 0.22;
|
|
4762
|
+
const holdX = avatar?.firstPerson ? small ? 0.22 : 0.08 : 0.05;
|
|
4763
|
+
const holdY = avatar?.firstPerson ? small ? -0.2 : -0.26 : -0.28;
|
|
4764
|
+
const holdZ = avatar?.firstPerson ? small ? -0.42 : -Math.min(1.15, CARRY_NEAR + heldRadius) : -1.15;
|
|
4765
|
+
pos = tmpV.set(holdX, holdY, holdZ).applyMatrix4(camera.matrixWorld);
|
|
4766
|
+
const baseQ = avatar?.firstPerson && small ? camera.quaternion : new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), player.yaw);
|
|
4767
|
+
gripQuat.copy(baseQ).multiply(new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1, 0, 0), Math.max(-1.35, -heldTilt)));
|
|
4652
4768
|
targetQ.setFromAxisAngle(new THREE.Vector3(0, 1, 0), player.yaw + heldYaw);
|
|
4653
|
-
|
|
4769
|
+
if (avatar?.firstPerson && small && heldTilt <= 1e-4) {
|
|
4770
|
+
targetQ.copy(camera.quaternion).multiply(new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), heldYaw));
|
|
4771
|
+
} else {
|
|
4772
|
+
targetQ.multiply(new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1, 0, 0), -heldTilt));
|
|
4773
|
+
}
|
|
4654
4774
|
}
|
|
4655
4775
|
const k = Math.min(1, (useItemPlayer ? 30 : 16) * dt);
|
|
4656
4776
|
const px = root.position.x;
|
|
@@ -4665,7 +4785,7 @@ function createTestRoom(options) {
|
|
|
4665
4785
|
heldVel[2] = (root.position.z - pz) / dt;
|
|
4666
4786
|
}
|
|
4667
4787
|
root.updateMatrixWorld(true);
|
|
4668
|
-
if (avatar?.firstPerson && cameraMode === "first") carriedHand = carriedTargets(root);
|
|
4788
|
+
if (avatar?.firstPerson && cameraMode === "first") carriedHand = carriedTargets(root, gripQuat);
|
|
4669
4789
|
};
|
|
4670
4790
|
const useItem = (useId) => {
|
|
4671
4791
|
const e = heldEntry;
|
|
@@ -4675,11 +4795,13 @@ function createTestRoom(options) {
|
|
|
4675
4795
|
const c = fluids.container(e.containerId);
|
|
4676
4796
|
if (!c) return false;
|
|
4677
4797
|
if (def.liquids && def.liquids.length > 0 && (!c.liquid || !def.liquids.includes(c.liquid))) return false;
|
|
4678
|
-
|
|
4798
|
+
const consuming = useId === "drink" || useId === "sip" || useId === "chug" || useId === "pour" || useId === "pour_out";
|
|
4799
|
+
if (consuming && c.liters <= 1e-6) {
|
|
4679
4800
|
say(t("hud.empty_container", { name: e.name }));
|
|
4680
4801
|
return false;
|
|
4681
4802
|
}
|
|
4682
4803
|
if (useItemPlayer && !useItemPlayer.done) return false;
|
|
4804
|
+
if (consuming && c.closed) fluids.open(e.containerId);
|
|
4683
4805
|
useItemPlayer = createItemUse(fluids, e.containerId, def);
|
|
4684
4806
|
useItemName = def.id;
|
|
4685
4807
|
action("use_item", t("act.use_item", { name: e.name, use: S.text[`use.${def.id}`] ?? def.id }), { objectId: e.so.objectId, itemId: e.so.itemId, data: { use: def.id } });
|
|
@@ -4801,7 +4923,7 @@ function createTestRoom(options) {
|
|
|
4801
4923
|
if (heldEntry?.uses[0]) useItem(heldEntry.uses[0]);
|
|
4802
4924
|
break;
|
|
4803
4925
|
case "KeyC":
|
|
4804
|
-
if (heldEntry?.uses[1]) useItem(heldEntry.uses[1]);
|
|
4926
|
+
if (heldEntry?.uses[1] && !(options.crouch?.keys ?? ["KeyC"]).includes("KeyC")) useItem(heldEntry.uses[1]);
|
|
4805
4927
|
break;
|
|
4806
4928
|
case "KeyV":
|
|
4807
4929
|
if (heldEntry?.uses[2]) useItem(heldEntry.uses[2]);
|
|
@@ -4893,6 +5015,7 @@ function createTestRoom(options) {
|
|
|
4893
5015
|
const roomMetrics = createRoomMetrics({ gl, destruction: renderer, fluids: fluidView, effects: vfx.world, ids: roomMetricIds, blast: () => lastBlast });
|
|
4894
5016
|
let qualityName = quality;
|
|
4895
5017
|
const syncContainers = (sdt) => {
|
|
5018
|
+
const drinkingHeld = useItemPlayer !== null && (useItemName === "drink" || useItemName === "sip" || useItemName === "chug");
|
|
4896
5019
|
for (const e of entries.values()) {
|
|
4897
5020
|
if (!e.containerId) continue;
|
|
4898
5021
|
const host2 = hostOf(e);
|
|
@@ -4901,7 +5024,8 @@ function createTestRoom(options) {
|
|
|
4901
5024
|
const p = tmpV.set(e.fluidOffset[0], e.fluidOffset[1], e.fluidOffset[2]).applyMatrix4(host2.root.matrixWorld);
|
|
4902
5025
|
const vel = sdt > 0 ? [(p.x - e.last[0]) / sdt, (p.y - e.last[1]) / sdt, (p.z - e.last[2]) / sdt] : void 0;
|
|
4903
5026
|
e.last = [p.x, p.y, p.z];
|
|
4904
|
-
|
|
5027
|
+
const rot = drinkingHeld && e === heldEntry ? [0, 0, 0, 1] : [q.x, q.y, q.z, q.w];
|
|
5028
|
+
fluids.setTransform(e.containerId, [p.x, p.y, p.z], rot, vel);
|
|
4905
5029
|
}
|
|
4906
5030
|
};
|
|
4907
5031
|
const syncLiters = () => {
|
|
@@ -5652,7 +5776,10 @@ function createTestRoom(options) {
|
|
|
5652
5776
|
return avatar;
|
|
5653
5777
|
},
|
|
5654
5778
|
setAvatarState(state) {
|
|
5655
|
-
if (state.crouch !== void 0)
|
|
5779
|
+
if (state.crouch !== void 0) {
|
|
5780
|
+
crouchForced = state.crouch;
|
|
5781
|
+
avatarState.crouch = state.crouch || player.crouching;
|
|
5782
|
+
}
|
|
5656
5783
|
if (state.down !== void 0) avatarState.down = state.down;
|
|
5657
5784
|
if (state.armed !== void 0) armedForced = state.armed;
|
|
5658
5785
|
},
|