@adatechnology/game-weapons-three 0.14.2 → 0.15.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/assets/weapon-svg/generated/m79.svg +1 -1
- package/dist/{chunk-XMVSA7UT.js → chunk-GBO6L7CQ.js} +1638 -1406
- package/dist/chunk-GBO6L7CQ.js.map +1 -0
- package/dist/index.d.ts +31 -6
- package/dist/index.global.js +2078 -1037
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +23 -2
- package/dist/index.js.map +1 -1
- package/dist/{testing-DnPjEPC5.d.ts → testing-Cf1M1sWN.d.ts} +27 -25
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -1
- package/package.json +9 -9
- package/dist/chunk-XMVSA7UT.js.map +0 -1
package/dist/index.global.js
CHANGED
|
@@ -32,6 +32,7 @@ var GameWeaponsThree = (() => {
|
|
|
32
32
|
DEFAULT_THUMBNAIL_BASE: () => DEFAULT_THUMBNAIL_BASE,
|
|
33
33
|
EXPLOSIVES_AREA_ID: () => EXPLOSIVES_AREA_ID,
|
|
34
34
|
EXPLOSIVES_TEXT: () => EXPLOSIVES_TEXT,
|
|
35
|
+
EXPLOSIVE_MODEL_IDS: () => EXPLOSIVE_MODEL_IDS,
|
|
35
36
|
GAME_DISTANCE_CURVE: () => GAME_DISTANCE_CURVE,
|
|
36
37
|
GAME_SOUND_CLASSES: () => GAME_SOUND_CLASSES,
|
|
37
38
|
GUNSHOT_PROFILES: () => GUNSHOT_PROFILES,
|
|
@@ -52,10 +53,12 @@ var GameWeaponsThree = (() => {
|
|
|
52
53
|
applyCondition: () => applyCondition,
|
|
53
54
|
buildCartridge: () => buildCartridge,
|
|
54
55
|
buildCasing: () => buildCasing,
|
|
56
|
+
buildExplosiveModel: () => buildExplosiveModel,
|
|
55
57
|
buildItemWeaponModel: () => buildItemWeaponModel,
|
|
56
58
|
buildModeledProp: () => buildModeledProp,
|
|
57
59
|
buildProp: () => buildProp,
|
|
58
60
|
buildRound: () => buildRound,
|
|
61
|
+
buildThrowableModel: () => buildThrowableModel,
|
|
59
62
|
buildToolClips: () => buildToolClips,
|
|
60
63
|
buildTripodMountedProp: () => buildTripodMountedProp,
|
|
61
64
|
buildWeaponModel: () => buildWeaponModel,
|
|
@@ -75,6 +78,8 @@ var GameWeaponsThree = (() => {
|
|
|
75
78
|
deriveFrames: () => deriveFrames,
|
|
76
79
|
explosivesTextOf: () => explosivesTextOf,
|
|
77
80
|
fitAttachmentModels: () => fitAttachmentModels,
|
|
81
|
+
hasExplosiveModel: () => hasExplosiveModel,
|
|
82
|
+
hasThrowableModel: () => hasThrowableModel,
|
|
78
83
|
hasWeaponModel: () => hasWeaponModel,
|
|
79
84
|
itemModelOfWeapon: () => itemModelOfWeapon,
|
|
80
85
|
mechanicalSoundOf: () => mechanicalSoundOf,
|
|
@@ -5951,7 +5956,10 @@ var GameWeaponsThree = (() => {
|
|
|
5951
5956
|
]
|
|
5952
5957
|
}
|
|
5953
5958
|
],
|
|
5954
|
-
fitted: []
|
|
5959
|
+
fitted: [],
|
|
5960
|
+
tags: [
|
|
5961
|
+
"pdw"
|
|
5962
|
+
]
|
|
5955
5963
|
},
|
|
5956
5964
|
{
|
|
5957
5965
|
id: "kriss_vector",
|
|
@@ -10410,7 +10418,9 @@ var GameWeaponsThree = (() => {
|
|
|
10410
10418
|
"arsenal",
|
|
10411
10419
|
"reference",
|
|
10412
10420
|
"derived"
|
|
10413
|
-
]
|
|
10421
|
+
],
|
|
10422
|
+
mounts: [],
|
|
10423
|
+
fitted: []
|
|
10414
10424
|
},
|
|
10415
10425
|
{
|
|
10416
10426
|
id: "hk_mp5sd3",
|
|
@@ -11169,7 +11179,10 @@ var GameWeaponsThree = (() => {
|
|
|
11169
11179
|
fitted: [],
|
|
11170
11180
|
stock: {
|
|
11171
11181
|
kind: "retract"
|
|
11172
|
-
}
|
|
11182
|
+
},
|
|
11183
|
+
tags: [
|
|
11184
|
+
"pdw"
|
|
11185
|
+
]
|
|
11173
11186
|
},
|
|
11174
11187
|
{
|
|
11175
11188
|
id: "hk_g36",
|
|
@@ -12870,7 +12883,8 @@ var GameWeaponsThree = (() => {
|
|
|
12870
12883
|
dmr: "marksman rifle",
|
|
12871
12884
|
hunting: "hunting rifle",
|
|
12872
12885
|
machine_gun: "machine gun",
|
|
12873
|
-
launcher: "launcher"
|
|
12886
|
+
launcher: "launcher",
|
|
12887
|
+
pdw: "PDW (personal defence weapon)"
|
|
12874
12888
|
};
|
|
12875
12889
|
var faultsEn = { misfire: "misfire", stovepipe: "stovepipe", double_feed: "double feed", failure_to_extract: "failure to extract" };
|
|
12876
12890
|
var conditionsEn = { new: "new", used: "used", worn: "worn", rusty: "rusty" };
|
|
@@ -12923,7 +12937,27 @@ var GameWeaponsThree = (() => {
|
|
|
12923
12937
|
hunting_rifle_30_06: ".30-06 hunting rifle",
|
|
12924
12938
|
m2_flamethrower: "M2 flamethrower",
|
|
12925
12939
|
improvised_flamethrower: "Improvised flamethrower",
|
|
12926
|
-
m79: "M79 grenade launcher"
|
|
12940
|
+
m79: "M79 grenade launcher",
|
|
12941
|
+
m203: "M203 grenade launcher",
|
|
12942
|
+
gp_25: "GP-25 grenade launcher",
|
|
12943
|
+
ag36: "AG36 grenade launcher",
|
|
12944
|
+
flashbang: "Flashbang",
|
|
12945
|
+
dynamite: "Dynamite",
|
|
12946
|
+
c4: "C4 charge",
|
|
12947
|
+
claymore: "Claymore mine",
|
|
12948
|
+
tactical_knife: "Tactical knife",
|
|
12949
|
+
meat_cleaver: "Meat cleaver",
|
|
12950
|
+
hatchet: "Hatchet",
|
|
12951
|
+
nail_bat: "Nail bat",
|
|
12952
|
+
iron_pipe: "Iron pipe",
|
|
12953
|
+
pickaxe: "Pickaxe",
|
|
12954
|
+
sickle: "Sickle",
|
|
12955
|
+
police_baton: "Police baton",
|
|
12956
|
+
cast_iron_skillet: "Cast iron skillet",
|
|
12957
|
+
improvised_spear: "Improvised spear",
|
|
12958
|
+
chainsaw: "Chainsaw",
|
|
12959
|
+
recurve_bow: "Recurve bow",
|
|
12960
|
+
m134: "M134 Minigun"
|
|
12927
12961
|
},
|
|
12928
12962
|
modes: modesEn,
|
|
12929
12963
|
categories: categoriesEn,
|
|
@@ -12997,7 +13031,27 @@ var GameWeaponsThree = (() => {
|
|
|
12997
13031
|
hunting_rifle_30_06: "Rifle de ca\xE7a .30-06",
|
|
12998
13032
|
m2_flamethrower: "Lan\xE7a-chamas M2",
|
|
12999
13033
|
improvised_flamethrower: "Lan\xE7a-chamas caseiro",
|
|
13000
|
-
m79: "Lan\xE7a-granadas M79"
|
|
13034
|
+
m79: "Lan\xE7a-granadas M79",
|
|
13035
|
+
m203: "Lan\xE7a-granadas M203",
|
|
13036
|
+
gp_25: "Lan\xE7a-granadas GP-25",
|
|
13037
|
+
ag36: "Lan\xE7a-granadas AG36",
|
|
13038
|
+
flashbang: "granada de luz",
|
|
13039
|
+
dynamite: "dinamite",
|
|
13040
|
+
c4: "C4 com detonador",
|
|
13041
|
+
claymore: "mina Claymore",
|
|
13042
|
+
tactical_knife: "faca t\xE1tica",
|
|
13043
|
+
meat_cleaver: "cutelo",
|
|
13044
|
+
hatchet: "machadinha",
|
|
13045
|
+
nail_bat: "taco com pregos",
|
|
13046
|
+
iron_pipe: "cano de ferro",
|
|
13047
|
+
pickaxe: "picareta",
|
|
13048
|
+
sickle: "foice",
|
|
13049
|
+
police_baton: "cassetete",
|
|
13050
|
+
cast_iron_skillet: "frigideira de ferro",
|
|
13051
|
+
improvised_spear: "lan\xE7a improvisada",
|
|
13052
|
+
chainsaw: "motosserra",
|
|
13053
|
+
recurve_bow: "arco recurvo",
|
|
13054
|
+
m134: "Minigun M134"
|
|
13001
13055
|
},
|
|
13002
13056
|
modes: { single: "tiro \xFAnico", semi: "semiautom\xE1tico", burst: "rajada", auto: "autom\xE1tico", pump: "repeti\xE7\xE3o", bolt: "ferrolho", lever: "alavanca", break: "basculante", volley: "salva" },
|
|
13003
13057
|
categories: {
|
|
@@ -13021,7 +13075,8 @@ var GameWeaponsThree = (() => {
|
|
|
13021
13075
|
dmr: "fuzil de precis\xE3o semiautom\xE1tico",
|
|
13022
13076
|
hunting: "arma de ca\xE7a",
|
|
13023
13077
|
machine_gun: "metralhadora",
|
|
13024
|
-
launcher: "lan\xE7ador"
|
|
13078
|
+
launcher: "lan\xE7ador",
|
|
13079
|
+
pdw: "PDW (arma de defesa pessoal)"
|
|
13025
13080
|
},
|
|
13026
13081
|
explosives: {
|
|
13027
13082
|
m67: "Granada M67",
|
|
@@ -13114,7 +13169,13 @@ var GameWeaponsThree = (() => {
|
|
|
13114
13169
|
// Arsenal §11: montar e desmontar exige chave de fenda ou bancada; 2/15/30 s e a troca do lança-granadas (0,8 s) são padrões aprovados pelo dono (2026-10-24)
|
|
13115
13170
|
attachments: { fitSeconds: { field: 2, tool: 15, bench: 30 }, switchSeconds: 0.8, speedOfSound: 343 },
|
|
13116
13171
|
// Arsenal §08: tempo de mira = 0,15 s + 0,05 s por kg. O quadril do Arsenal é ×6 (o ZombiAdA liga isso por configuração); o SDK é neutro (1)
|
|
13117
|
-
aim: {
|
|
13172
|
+
aim: {
|
|
13173
|
+
base: 0.15,
|
|
13174
|
+
perKg: 0.05,
|
|
13175
|
+
hipSpread: 1,
|
|
13176
|
+
// the iron sights close the view in a little: more for a long gun, whose sights sit farther from the eye, than for a handgun
|
|
13177
|
+
ironSightZoom: { pistol: 1.1, revolver: 1.1, smg: 1.2, carbine: 1.25, shotgun: 1.15, rifle: 1.3, hunting: 1.35, dmr: 1.4, sniper: 1.4, machine_gun: 1.2, launcher: 1.15, bow: 1.15, crossbow: 1.25 }
|
|
13178
|
+
},
|
|
13118
13179
|
// Arsenal §08/§11: coronha retrátil saca mais rápido, mais recuo; os números são padrões aprovados pelo dono (2026-10-24)
|
|
13119
13180
|
stock: {
|
|
13120
13181
|
seconds: 0.6,
|
|
@@ -14713,6 +14774,26 @@ ${problems.map((problem) => ` - ${problem}`).join("\n")}`);
|
|
|
14713
14774
|
const id = caliber?.propellant === "black_powder" ? "black_powder" : caliber?.propellant === "none" ? "none" : "smokeless";
|
|
14714
14775
|
return MUZZLE_SMOKE[id];
|
|
14715
14776
|
}
|
|
14777
|
+
function aimZoomOf(arsenal, weaponId, attachments = arsenal.weapons.get(weaponId)?.fitted?.map((part) => part.id) ?? []) {
|
|
14778
|
+
const def = arsenal.weapons.get(weaponId);
|
|
14779
|
+
if (!def) return 1;
|
|
14780
|
+
const optic = attachments.map((id) => arsenal.attachments.get(id)?.optic).find((entry2) => entry2 !== void 0);
|
|
14781
|
+
if (optic) return optic.zoom[0];
|
|
14782
|
+
return arsenal.rules.aim.ironSightZoom[def.category] ?? 1;
|
|
14783
|
+
}
|
|
14784
|
+
var isGenericKind = (kind, category) => kind === "firearm" && category !== "bow" && category !== "crossbow" || kind === "flame";
|
|
14785
|
+
function genericWeapons(arsenal) {
|
|
14786
|
+
const archetypes = new Set(ARCHETYPE_IDS);
|
|
14787
|
+
const generics = /* @__PURE__ */ new Map();
|
|
14788
|
+
for (const def of arsenal.weapons.values()) if (archetypes.has(def.id) && isGenericKind(def.action.kind, def.category) && !def.maker) generics.set(def.id, void 0);
|
|
14789
|
+
for (const def of [...arsenal.weapons.values()].sort((a, b) => a.id < b.id ? -1 : 1)) {
|
|
14790
|
+
const { archetype } = def;
|
|
14791
|
+
if (!archetype || archetypes.has(def.id) || !generics.has(archetype) || generics.get(archetype)) continue;
|
|
14792
|
+
if (arsenal.weapons.get(archetype)?.action.kind === def.action.kind) generics.set(archetype, def.id);
|
|
14793
|
+
}
|
|
14794
|
+
for (const [id, brand] of generics) if (!brand && arsenal.weapons.get(id)?.action.kind === "flame") generics.delete(id);
|
|
14795
|
+
return generics;
|
|
14796
|
+
}
|
|
14716
14797
|
|
|
14717
14798
|
// ../game-render-three/dist/index.js
|
|
14718
14799
|
var DEFAULT_ANGLE = Math.PI / 3;
|
|
@@ -15964,8 +16045,8 @@ ${problems.map((problem) => ` - ${problem}`).join("\n")}`);
|
|
|
15964
16045
|
const face = faces[i];
|
|
15965
16046
|
f3(face[2] + offset, face[1] + offset, face[0] + offset);
|
|
15966
16047
|
}
|
|
15967
|
-
const
|
|
15968
|
-
offset = vlen *
|
|
16048
|
+
const layer3 = steps + bevelSegments * 2;
|
|
16049
|
+
offset = vlen * layer3;
|
|
15969
16050
|
for (let i = 0; i < flen; i++) {
|
|
15970
16051
|
const face = faces[i];
|
|
15971
16052
|
f3(face[0] + offset, face[1] + offset, face[2] + offset);
|
|
@@ -17392,11 +17473,11 @@ ${problems.map((problem) => ` - ${problem}`).join("\n")}`);
|
|
|
17392
17473
|
B.open_suitcases = (M, a) => {
|
|
17393
17474
|
const K = kit(M, a), cs = [K.main(11549236), 2767450], rs = [13156520, 4876938, 14736592, 11028538];
|
|
17394
17475
|
const suitcase = (x, z, ww, dd, c, ry, al) => {
|
|
17395
|
-
const lx = x,
|
|
17476
|
+
const lx = x, hz2 = z - dd / 2;
|
|
17396
17477
|
K.box("plain", lx, 0, z, ww, 0.16, dd, c, ry);
|
|
17397
17478
|
K.box("fabric", lx, 0.12, z, ww - 0.06, 0.05, dd - 0.06, 14209216, ry);
|
|
17398
17479
|
for (let i = 0; i < 5; i++) K.box("fabric", lx + (K.rnd() - 0.5) * (ww - 0.2), 0.16, z + (K.rnd() - 0.5) * (dd - 0.2), 0.14 + K.rnd() * 0.1, 0.04 + K.rnd() * 0.04, 0.12 + K.rnd() * 0.1, rs[i % 4], K.rnd() * 3);
|
|
17399
|
-
K.ramp("plain", lx, 0.16,
|
|
17480
|
+
K.ramp("plain", lx, 0.16, hz2, ww, 0.07, dd, c, al);
|
|
17400
17481
|
K.box("metal", lx + ww * 0.3, 0.1, z + dd / 2, 0.04, 0.03, 0.01, 12632256);
|
|
17401
17482
|
};
|
|
17402
17483
|
suitcase(-0.4, 0, 0.75, 0.5, cs[0], 0.15, 1.35);
|
|
@@ -19582,26 +19663,26 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19582
19663
|
for (const e of planned.items) if (e.type === "wall_switch") e.lit = (e.connections.controls || []).some((id) => planned.items.find((x) => x.id === id)?.lit === true);
|
|
19583
19664
|
}
|
|
19584
19665
|
for (const e of planned.items) if (e.type === "lantern_lamp") e.item.on = !!e.lit;
|
|
19585
|
-
let
|
|
19666
|
+
let scratch3 = null;
|
|
19586
19667
|
function probe(e, hinge, setback, blockedAt) {
|
|
19587
|
-
if (!
|
|
19668
|
+
if (!scratch3) scratch3 = GI.createWorld({ locale, strings: hh.strings, items: hh.items, loot: hh.loot, grid: false });
|
|
19588
19669
|
const it = at(e.item);
|
|
19589
19670
|
const x = it.x + Math.sin(it.ry) * setback;
|
|
19590
19671
|
const z = it.z + Math.cos(it.ry) * setback;
|
|
19591
19672
|
const spec = hh.build(e.type, Object.assign({}, e.item, { hinge }), recorderApi());
|
|
19592
|
-
|
|
19673
|
+
scratch3.add("__probe", spec, { x, y: e.floorY, z, ry: it.ry });
|
|
19593
19674
|
const blocks = (px, pz) => blockedAt(px, pz, e.floor);
|
|
19594
19675
|
let sum2 = 0;
|
|
19595
19676
|
let min2 = 1;
|
|
19596
19677
|
let n = 0;
|
|
19597
19678
|
for (const p of spec.parts || []) {
|
|
19598
19679
|
if (!p.motion || p.motion.kind !== "hinge" || !(p.bounds || p.sweep)) continue;
|
|
19599
|
-
const t =
|
|
19680
|
+
const t = scratch3.fitSweep("__probe", p.id, blocks);
|
|
19600
19681
|
sum2 += t;
|
|
19601
19682
|
min2 = Math.min(min2, t);
|
|
19602
19683
|
n++;
|
|
19603
19684
|
}
|
|
19604
|
-
|
|
19685
|
+
scratch3.remove("__probe");
|
|
19605
19686
|
return { sum: sum2, min: min2, n };
|
|
19606
19687
|
}
|
|
19607
19688
|
const better = (a, b) => a.sum > b.sum + 1e-9 || Math.abs(a.sum - b.sum) <= 1e-9 && a.min > b.min + 1e-9;
|
|
@@ -19926,26 +20007,26 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19926
20007
|
return { point: [p[0], sign2 * hh, p[2]], normal: [0, sign2, 0] };
|
|
19927
20008
|
};
|
|
19928
20009
|
var aabbOf = (s, center, q) => {
|
|
19929
|
-
let hx, hy,
|
|
20010
|
+
let hx, hy, hz2;
|
|
19930
20011
|
if (s.kind === "sphere") {
|
|
19931
|
-
hx = hy =
|
|
20012
|
+
hx = hy = hz2 = s.radius;
|
|
19932
20013
|
} else {
|
|
19933
20014
|
const m = quat.toMatrix(q);
|
|
19934
20015
|
if (s.kind === "box") {
|
|
19935
20016
|
const a = s.size[0] / 2, b = s.size[1] / 2, c = s.size[2] / 2;
|
|
19936
20017
|
hx = Math.abs(m[0]) * a + Math.abs(m[1]) * b + Math.abs(m[2]) * c;
|
|
19937
20018
|
hy = Math.abs(m[3]) * a + Math.abs(m[4]) * b + Math.abs(m[5]) * c;
|
|
19938
|
-
|
|
20019
|
+
hz2 = Math.abs(m[6]) * a + Math.abs(m[7]) * b + Math.abs(m[8]) * c;
|
|
19939
20020
|
} else {
|
|
19940
20021
|
const ax = [m[1], m[4], m[7]];
|
|
19941
20022
|
const hh = s.height / 2;
|
|
19942
20023
|
const e = (i) => s.radius * Math.sqrt(Math.max(0, 1 - ax[i] * ax[i])) + hh * Math.abs(ax[i]);
|
|
19943
20024
|
hx = e(0);
|
|
19944
20025
|
hy = e(1);
|
|
19945
|
-
|
|
20026
|
+
hz2 = e(2);
|
|
19946
20027
|
}
|
|
19947
20028
|
}
|
|
19948
|
-
return { min: [center[0] - hx, center[1] - hy, center[2] -
|
|
20029
|
+
return { min: [center[0] - hx, center[1] - hy, center[2] - hz2], max: [center[0] + hx, center[1] + hy, center[2] + hz2] };
|
|
19949
20030
|
};
|
|
19950
20031
|
var createRng2 = (seed) => {
|
|
19951
20032
|
let s = seed | 0;
|
|
@@ -20001,6 +20082,22 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20001
20082
|
return angle === 0 ? q : quat.mul(q, quat.fromAxisAngle([0, 0, 1], angle));
|
|
20002
20083
|
};
|
|
20003
20084
|
var clamp = (v, a, b) => Math.max(a, Math.min(b, v));
|
|
20085
|
+
var splitAlong = (box5, count, axis2, rnd2) => {
|
|
20086
|
+
const shares = Array.from({ length: count }, () => 0.25 + 1.5 * rnd2());
|
|
20087
|
+
const total = shares.reduce((sum2, share) => sum2 + share, 0);
|
|
20088
|
+
const out = [];
|
|
20089
|
+
let from = box5.c[axis2] - box5.s[axis2] / 2;
|
|
20090
|
+
for (const share of shares) {
|
|
20091
|
+
const length2 = box5.s[axis2] * share / total;
|
|
20092
|
+
const c = [box5.c[0], box5.c[1], box5.c[2]];
|
|
20093
|
+
const size = [box5.s[0], box5.s[1], box5.s[2]];
|
|
20094
|
+
c[axis2] = from + length2 / 2;
|
|
20095
|
+
size[axis2] = length2;
|
|
20096
|
+
out.push({ c, s: size });
|
|
20097
|
+
from += length2;
|
|
20098
|
+
}
|
|
20099
|
+
return out;
|
|
20100
|
+
};
|
|
20004
20101
|
var splinterBox = (inp, box5, limit = inp.maxFragments) => {
|
|
20005
20102
|
const { rnd: rnd2 } = inp;
|
|
20006
20103
|
const dims = box5.s;
|
|
@@ -20010,35 +20107,81 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20010
20107
|
const w = Math.max(fmin * 1.5, 0.01);
|
|
20011
20108
|
const c = clamp(Math.round(dims[a] * dims[b] / (w * w)), 3, Math.max(3, Math.floor(limit / 2)));
|
|
20012
20109
|
const maxLen = fmax * 4;
|
|
20013
|
-
const cells =
|
|
20110
|
+
const cells = [];
|
|
20111
|
+
for (const cell of bsp(box5, c, [a, b], rnd2)) {
|
|
20112
|
+
const wide2 = cell.s[a] >= cell.s[b] ? a : b;
|
|
20113
|
+
if (rnd2() < 0.4 && cell.s[wide2] > fmin * 0.5) for (const part of splitAlong(cell, 2, wide2, rnd2)) cells.push(part);
|
|
20114
|
+
else cells.push(cell);
|
|
20115
|
+
}
|
|
20014
20116
|
const pieces = [];
|
|
20015
20117
|
for (const cell of cells) {
|
|
20016
|
-
const extra = rnd2()
|
|
20118
|
+
const extra = Math.floor(rnd2() * 3);
|
|
20017
20119
|
const k = Math.max(1, Math.ceil(dims[g] / maxLen)) + extra;
|
|
20018
|
-
for (const p of
|
|
20120
|
+
for (const p of splitAlong(cell, k, g, rnd2)) pieces.push(p);
|
|
20019
20121
|
}
|
|
20020
20122
|
return pieces.slice(0, limit).map((p) => ({ center: p.c, size: [p.s[g], p.s[a], p.s[b]], q: frame(g, a, b), shape: "splinter", weight: p.s[0] * p.s[1] * p.s[2] }));
|
|
20021
20123
|
};
|
|
20124
|
+
var PLY = 3e-3;
|
|
20125
|
+
var PLY_GAP = 0.6;
|
|
20126
|
+
var PLY_SHEET = 0.012;
|
|
20127
|
+
var plyBreak = (inp, root, limit) => {
|
|
20128
|
+
const { rnd: rnd2 } = inp;
|
|
20129
|
+
const dims = root.s;
|
|
20130
|
+
const sorted = [0, 1, 2].sort((x, y) => dims[x] - dims[y]);
|
|
20131
|
+
const t = sorted[0];
|
|
20132
|
+
const [u, v] = [sorted[1], sorted[2]].sort((x, y) => x - y);
|
|
20133
|
+
const along = dims[u] >= dims[v] ? u : v;
|
|
20134
|
+
const across2 = along === u ? v : u;
|
|
20135
|
+
const layers = clamp(Math.round(dims[t] / PLY / 2), 2, 3);
|
|
20136
|
+
const pitch = dims[t] / layers;
|
|
20137
|
+
const th = Math.min(pitch, PLY_SHEET);
|
|
20138
|
+
const per = Math.max(2, Math.floor(limit / layers));
|
|
20139
|
+
const out = [];
|
|
20140
|
+
for (let k = 0; k < layers; k++) {
|
|
20141
|
+
const layer3 = { c: [root.c[0], root.c[1], root.c[2]], s: [dims[0], dims[1], dims[2]] };
|
|
20142
|
+
layer3.c[t] = root.c[t] + (-dims[t] / 2 + (k + 0.5) * pitch) * (pitch > PLY_SHEET ? 1 : 1 + PLY_GAP);
|
|
20143
|
+
layer3.s[t] = th;
|
|
20144
|
+
for (const cell of bsp(layer3, per, [u, v], rnd2)) {
|
|
20145
|
+
if (out.length >= limit) return out;
|
|
20146
|
+
if (rnd2() < 0.35) {
|
|
20147
|
+
const strand = cell.s[across2] * (0.15 + 0.2 * rnd2());
|
|
20148
|
+
out.push({ center: cell.c, size: [cell.s[along], strand, th * 0.7], q: frame(along, across2, t), shape: "splinter", weight: cell.s[along] * strand * th });
|
|
20149
|
+
} else {
|
|
20150
|
+
out.push({ center: cell.c, size: [cell.s[u], cell.s[v], th], q: frame(u, v, t, (rnd2() - 0.5) * 0.5), shape: "scrap", weight: cell.s[u] * cell.s[v] * th });
|
|
20151
|
+
}
|
|
20152
|
+
}
|
|
20153
|
+
}
|
|
20154
|
+
return out;
|
|
20155
|
+
};
|
|
20156
|
+
var granules = (inp, box5, count) => bsp(box5, count, [0, 1, 2], inp.rnd).map((b) => ({ center: b.c, size: b.s, q: quat.identity(), shape: "chunk", weight: b.s[0] * b.s[1] * b.s[2] }));
|
|
20157
|
+
var CRUMBS = 6;
|
|
20022
20158
|
var severAt = (inp, root, at3, gap) => {
|
|
20023
20159
|
const dims = root.s;
|
|
20024
20160
|
const L = [0, 1, 2].sort((x, y) => dims[y] - dims[x])[0];
|
|
20025
20161
|
const half = dims[L] / 2;
|
|
20026
20162
|
const lo = clamp(at3 - gap / 2, -half, half), hi = clamp(at3 + gap / 2, -half, half);
|
|
20027
20163
|
const out = [];
|
|
20028
|
-
const
|
|
20164
|
+
const fibrous = inp.form === "slivers" || inp.form === "plies";
|
|
20165
|
+
const [a, b] = [0, 1, 2].filter((i) => i !== L);
|
|
20166
|
+
const stub = (from, to, breakAtEnd) => {
|
|
20029
20167
|
if (to - from < 0.02) return;
|
|
20030
20168
|
const c = [root.c[0], root.c[1], root.c[2]], sz = [dims[0], dims[1], dims[2]];
|
|
20031
20169
|
c[L] = (from + to) / 2;
|
|
20032
20170
|
sz[L] = to - from;
|
|
20033
|
-
|
|
20171
|
+
const weight = sz[0] * sz[1] * sz[2];
|
|
20172
|
+
if (fibrous) out.push({ center: c, size: [sz[L], sz[a], sz[b]], q: frame(L, a, b, breakAtEnd ? 0 : Math.PI), shape: "slab", weight });
|
|
20173
|
+
else out.push({ center: c, size: sz, q: quat.identity(), shape: "slab", weight });
|
|
20034
20174
|
};
|
|
20035
|
-
stub(-half, lo);
|
|
20036
|
-
stub(hi, half);
|
|
20175
|
+
stub(-half, lo, true);
|
|
20176
|
+
stub(hi, half, false);
|
|
20037
20177
|
const band = { c: [root.c[0], root.c[1], root.c[2]], s: [dims[0], dims[1], dims[2]] };
|
|
20038
20178
|
band.c[L] = (lo + hi) / 2;
|
|
20039
20179
|
band.s[L] = Math.max(hi - lo, 0.01);
|
|
20040
|
-
|
|
20041
|
-
|
|
20180
|
+
const room = inp.maxFragments - out.length;
|
|
20181
|
+
if (inp.style === "snap" && inp.form === "plies") for (const p of plyBreak(inp, band, Math.max(3, room))) out.push(p);
|
|
20182
|
+
else if (inp.style === "snap" && inp.form === "granules") for (const p of granules(inp, band, clamp(room, 3, 12))) out.push(p);
|
|
20183
|
+
else if (inp.style === "snap") {
|
|
20184
|
+
for (const b2 of bsp(band, Math.max(3, Math.min(6, room)), [0, 1, 2], inp.rnd)) out.push({ center: b2.c, size: b2.s, q: quat.identity(), shape: "chunk", weight: b2.s[0] * b2.s[1] * b2.s[2] });
|
|
20042
20185
|
} else for (const p of splinterBox(inp, band, Math.max(3, inp.maxFragments - out.length))) out.push(p);
|
|
20043
20186
|
return out;
|
|
20044
20187
|
};
|
|
@@ -20071,8 +20214,18 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20071
20214
|
const [u, v] = [sorted[1], sorted[2]].sort((a, b) => a - b);
|
|
20072
20215
|
if (style === "snap") {
|
|
20073
20216
|
if (inp.cut) return severAt(inp, root, inp.cut.at, inp.cut.gap);
|
|
20217
|
+
if (inp.form === "plies") return plyBreak(inp, root, maxFragments);
|
|
20074
20218
|
const n2 = Math.min(maxFragments, 2 + Math.floor(rnd2() * 3));
|
|
20075
20219
|
for (const b of bsp(root, n2, [0, 1, 2], rnd2)) out.push({ center: b.c, size: b.s, q: idq, shape: "slab", weight: b.s[0] * b.s[1] * b.s[2] });
|
|
20220
|
+
if (inp.form !== "granules") return out;
|
|
20221
|
+
const crumbs = Math.min(CRUMBS, maxFragments - out.length);
|
|
20222
|
+
if (crumbs <= 0) return out;
|
|
20223
|
+
const band = { c: [0, 0, 0], s: [0, 0, 0] };
|
|
20224
|
+
for (let i = 0; i < 3; i++) {
|
|
20225
|
+
band.s[i] = Math.min(dims[i], Math.max(fmin, dims[i] * 0.2));
|
|
20226
|
+
band.c[i] = clamp(inp.hit[i], -dims[i] / 2 + band.s[i] / 2, dims[i] / 2 - band.s[i] / 2);
|
|
20227
|
+
}
|
|
20228
|
+
for (const p of granules(inp, band, crumbs)) out.push({ ...p, weight: p.weight * 0.5 });
|
|
20076
20229
|
return out;
|
|
20077
20230
|
}
|
|
20078
20231
|
if (style === "crumble" || style === "none") {
|
|
@@ -20179,13 +20332,95 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20179
20332
|
}
|
|
20180
20333
|
return marks;
|
|
20181
20334
|
};
|
|
20335
|
+
var JOINT_GAP = 1e-4;
|
|
20336
|
+
var MIN_BEARING_SHARE = 0.25;
|
|
20337
|
+
var unsupportedCells = (cells, thin, dims, standing) => {
|
|
20338
|
+
if (thin === 1) return [];
|
|
20339
|
+
const [u, v] = planeAxes(thin);
|
|
20340
|
+
const bottom = -dims[v] / 2;
|
|
20341
|
+
const rowOf = (y) => Math.round((y - bottom) * 1e4);
|
|
20342
|
+
const rows = /* @__PURE__ */ new Map();
|
|
20343
|
+
for (let i = 0; i < cells.length; i++) {
|
|
20344
|
+
if (!standing(i)) continue;
|
|
20345
|
+
const cell = cells[i];
|
|
20346
|
+
const key2 = rowOf(cell.center[v] - cell.size[v] / 2);
|
|
20347
|
+
const row = rows.get(key2);
|
|
20348
|
+
if (row) row.push(i);
|
|
20349
|
+
else rows.set(key2, [i]);
|
|
20350
|
+
}
|
|
20351
|
+
const held = /* @__PURE__ */ new Set();
|
|
20352
|
+
const queue = [];
|
|
20353
|
+
for (const i of rows.get(0) ?? []) {
|
|
20354
|
+
held.add(i);
|
|
20355
|
+
queue.push(i);
|
|
20356
|
+
}
|
|
20357
|
+
const overlap = (a, b) => Math.min(a.center[u] + a.size[u] / 2, b.center[u] + b.size[u] / 2) - Math.max(a.center[u] - a.size[u] / 2, b.center[u] - b.size[u] / 2);
|
|
20358
|
+
const climb = () => {
|
|
20359
|
+
while (queue.length > 0) {
|
|
20360
|
+
const cell = cells[queue.pop()];
|
|
20361
|
+
for (const j of rows.get(rowOf(cell.center[v] + cell.size[v] / 2)) ?? []) {
|
|
20362
|
+
const other = cells[j];
|
|
20363
|
+
if (held.has(j) || overlap(cell, other) <= Math.max(JOINT_GAP, MIN_BEARING_SHARE * Math.min(cell.size[u], other.size[u]))) continue;
|
|
20364
|
+
held.add(j);
|
|
20365
|
+
queue.push(j);
|
|
20366
|
+
}
|
|
20367
|
+
}
|
|
20368
|
+
};
|
|
20369
|
+
for (const row of rows.values()) row.sort((a, b) => cells[a].center[u] - cells[b].center[u]);
|
|
20370
|
+
const touching = (a, b) => Math.abs(a.center[u] + a.size[u] / 2 - (b.center[u] - b.size[u] / 2)) <= 1e-3;
|
|
20371
|
+
for (let wedged = true; wedged; ) {
|
|
20372
|
+
climb();
|
|
20373
|
+
wedged = false;
|
|
20374
|
+
for (const row of rows.values()) {
|
|
20375
|
+
for (let k = 1; k < row.length - 1; k++) {
|
|
20376
|
+
const i = row[k];
|
|
20377
|
+
if (held.has(i) || !held.has(row[k - 1]) || !held.has(row[k + 1])) continue;
|
|
20378
|
+
if (!touching(cells[row[k - 1]], cells[i]) || !touching(cells[i], cells[row[k + 1]])) continue;
|
|
20379
|
+
held.add(i);
|
|
20380
|
+
queue.push(i);
|
|
20381
|
+
wedged = true;
|
|
20382
|
+
}
|
|
20383
|
+
}
|
|
20384
|
+
}
|
|
20385
|
+
const loose = [];
|
|
20386
|
+
for (const row of rows.values()) for (const i of row) if (!held.has(i)) loose.push(i);
|
|
20387
|
+
return loose;
|
|
20388
|
+
};
|
|
20389
|
+
var clumpCells = (cells, thin, cap) => {
|
|
20390
|
+
if (cells.length <= cap) return [...cells];
|
|
20391
|
+
const [u, v] = planeAxes(thin);
|
|
20392
|
+
let lo0 = Infinity, lo1 = Infinity, hi0 = -Infinity, hi1 = -Infinity;
|
|
20393
|
+
for (const cell of cells) {
|
|
20394
|
+
lo0 = Math.min(lo0, cell.center[u] - cell.size[u] / 2);
|
|
20395
|
+
hi0 = Math.max(hi0, cell.center[u] + cell.size[u] / 2);
|
|
20396
|
+
lo1 = Math.min(lo1, cell.center[v] - cell.size[v] / 2);
|
|
20397
|
+
hi1 = Math.max(hi1, cell.center[v] + cell.size[v] / 2);
|
|
20398
|
+
}
|
|
20399
|
+
let side = Math.sqrt((hi0 - lo0) * (hi1 - lo1) / cap);
|
|
20400
|
+
for (; ; ) {
|
|
20401
|
+
const bins = /* @__PURE__ */ new Map();
|
|
20402
|
+
for (const cell of cells) {
|
|
20403
|
+
const key2 = `${Math.floor((cell.center[u] - lo0) / side)}:${Math.floor((cell.center[v] - lo1) / side)}`;
|
|
20404
|
+
const bin = bins.get(key2) ?? { lo: [Infinity, Infinity, Infinity], hi: [-Infinity, -Infinity, -Infinity] };
|
|
20405
|
+
for (let k = 0; k < 3; k++) {
|
|
20406
|
+
bin.lo[k] = Math.min(bin.lo[k], cell.center[k] - cell.size[k] / 2);
|
|
20407
|
+
bin.hi[k] = Math.max(bin.hi[k], cell.center[k] + cell.size[k] / 2);
|
|
20408
|
+
}
|
|
20409
|
+
bins.set(key2, bin);
|
|
20410
|
+
}
|
|
20411
|
+
if (bins.size <= cap) {
|
|
20412
|
+
return [...bins.values()].map(({ lo, hi }) => ({ center: [(lo[0] + hi[0]) / 2, (lo[1] + hi[1]) / 2, (lo[2] + hi[2]) / 2], size: [hi[0] - lo[0], hi[1] - lo[1], hi[2] - lo[2]] }));
|
|
20413
|
+
}
|
|
20414
|
+
side *= 1.25;
|
|
20415
|
+
}
|
|
20416
|
+
};
|
|
20182
20417
|
var MAX_SPALLS = 64;
|
|
20183
20418
|
var thinAxisOf = (dims) => dims[0] <= dims[1] && dims[0] <= dims[2] ? 0 : dims[1] <= dims[2] ? 1 : 2;
|
|
20184
20419
|
var resolveLayer = (def, index, mat) => ({ index, def, mat, energy: mat.penetration * def.thickness * 1e3 });
|
|
20185
|
-
var onFace = (
|
|
20186
|
-
var isSpalled = (spalls,
|
|
20420
|
+
var onFace = (layer3, face) => layer3.def.faces === "both" || layer3.def.faces === (face > 0 ? "+" : "-");
|
|
20421
|
+
var isSpalled = (spalls, layer3, face, point) => {
|
|
20187
20422
|
for (const s of spalls ?? []) {
|
|
20188
|
-
if (s[0] !==
|
|
20423
|
+
if (s[0] !== layer3 || s[1] !== face) continue;
|
|
20189
20424
|
const dx = s[2] - point[0], dy = s[3] - point[1], dz = s[4] - point[2];
|
|
20190
20425
|
if (dx * dx + dy * dy + dz * dz <= s[5] * s[5]) return true;
|
|
20191
20426
|
}
|
|
@@ -20771,12 +21006,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20771
21006
|
const [dx, dz] = c.direction;
|
|
20772
21007
|
const along = (p) => {
|
|
20773
21008
|
const cx = (p.min[0] + p.max[0]) / 2, cz = (p.min[2] + p.max[2]) / 2;
|
|
20774
|
-
const hx = (p.max[0] - p.min[0]) / 2,
|
|
21009
|
+
const hx = (p.max[0] - p.min[0]) / 2, hz2 = (p.max[2] - p.min[2]) / 2;
|
|
20775
21010
|
return {
|
|
20776
21011
|
u: cx * dx + cz * dz,
|
|
20777
21012
|
v: -cx * dz + cz * dx,
|
|
20778
|
-
du: 2 * (Math.abs(dx) * hx + Math.abs(dz) *
|
|
20779
|
-
dv: 2 * (Math.abs(dz) * hx + Math.abs(dx) *
|
|
21013
|
+
du: 2 * (Math.abs(dx) * hx + Math.abs(dz) * hz2),
|
|
21014
|
+
dv: 2 * (Math.abs(dz) * hx + Math.abs(dx) * hz2)
|
|
20780
21015
|
};
|
|
20781
21016
|
};
|
|
20782
21017
|
const g = parts.map(along);
|
|
@@ -20871,9 +21106,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20871
21106
|
for (const b of p.beams ?? []) {
|
|
20872
21107
|
const q = parts[b];
|
|
20873
21108
|
if (!q?.elasticPa) continue;
|
|
20874
|
-
const hx = q.max[0] - q.min[0],
|
|
20875
|
-
const long = Math.max(hx,
|
|
20876
|
-
const cos2 = hx >=
|
|
21109
|
+
const hx = q.max[0] - q.min[0], hz2 = q.max[2] - q.min[2];
|
|
21110
|
+
const long = Math.max(hx, hz2), short = Math.min(hx, hz2);
|
|
21111
|
+
const cos2 = hx >= hz2 ? Math.abs(dx) : Math.abs(dz);
|
|
20877
21112
|
const depth = q.max[1] - q.min[1];
|
|
20878
21113
|
const inertia = tBeamInertia(short, depth, short + 2 * c.flange * long, q.slab ?? 0);
|
|
20879
21114
|
beams += cos2 * cos2 * q.elasticPa * c.beamFactor * inertia / Math.max(long, 1e-6);
|
|
@@ -21158,6 +21393,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21158
21393
|
},
|
|
21159
21394
|
{
|
|
21160
21395
|
id: "wood_soft",
|
|
21396
|
+
splitForm: "slivers",
|
|
21161
21397
|
density: 500,
|
|
21162
21398
|
hpPerKg: 90,
|
|
21163
21399
|
penetration: 9,
|
|
@@ -21203,6 +21439,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21203
21439
|
},
|
|
21204
21440
|
{
|
|
21205
21441
|
id: "wood_hard",
|
|
21442
|
+
splitForm: "slivers",
|
|
21206
21443
|
density: 750,
|
|
21207
21444
|
hpPerKg: 140,
|
|
21208
21445
|
penetration: 14,
|
|
@@ -21247,6 +21484,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21247
21484
|
},
|
|
21248
21485
|
{
|
|
21249
21486
|
id: "plywood",
|
|
21487
|
+
splitForm: "plies",
|
|
21250
21488
|
density: 600,
|
|
21251
21489
|
hpPerKg: 70,
|
|
21252
21490
|
penetration: 7,
|
|
@@ -21294,6 +21532,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21294
21532
|
},
|
|
21295
21533
|
{
|
|
21296
21534
|
id: "mdf",
|
|
21535
|
+
splitForm: "granules",
|
|
21297
21536
|
density: 750,
|
|
21298
21537
|
hpPerKg: 45,
|
|
21299
21538
|
penetration: 6,
|
|
@@ -21805,6 +22044,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21805
22044
|
},
|
|
21806
22045
|
{
|
|
21807
22046
|
id: "green_wood",
|
|
22047
|
+
splitForm: "slivers",
|
|
21808
22048
|
density: 650,
|
|
21809
22049
|
hpPerKg: 5,
|
|
21810
22050
|
penetration: 10,
|
|
@@ -22085,6 +22325,125 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22085
22325
|
"brittle"
|
|
22086
22326
|
],
|
|
22087
22327
|
compressive: 1e5
|
|
22328
|
+
},
|
|
22329
|
+
{
|
|
22330
|
+
id: "mud",
|
|
22331
|
+
density: 1700,
|
|
22332
|
+
hpPerKg: 1,
|
|
22333
|
+
penetration: 5,
|
|
22334
|
+
ductility: 0.8,
|
|
22335
|
+
fracture: "crumble",
|
|
22336
|
+
fragmentSize: [
|
|
22337
|
+
0.02,
|
|
22338
|
+
0.08
|
|
22339
|
+
],
|
|
22340
|
+
hitDebris: "dust",
|
|
22341
|
+
breakDebris: "dust",
|
|
22342
|
+
thermal: {
|
|
22343
|
+
conductivity: 0.5,
|
|
22344
|
+
heatCapacity: 3.2
|
|
22345
|
+
},
|
|
22346
|
+
tags: [
|
|
22347
|
+
"soil",
|
|
22348
|
+
"wet"
|
|
22349
|
+
],
|
|
22350
|
+
compressive: 5e3
|
|
22351
|
+
},
|
|
22352
|
+
{
|
|
22353
|
+
id: "clay",
|
|
22354
|
+
density: 1800,
|
|
22355
|
+
hpPerKg: 5,
|
|
22356
|
+
penetration: 7,
|
|
22357
|
+
ductility: 0.05,
|
|
22358
|
+
fracture: "crumble",
|
|
22359
|
+
fragmentSize: [
|
|
22360
|
+
0.02,
|
|
22361
|
+
0.1
|
|
22362
|
+
],
|
|
22363
|
+
hitDebris: "chips",
|
|
22364
|
+
breakDebris: "dust",
|
|
22365
|
+
thermal: {
|
|
22366
|
+
conductivity: 0.15,
|
|
22367
|
+
heatCapacity: 2.2
|
|
22368
|
+
},
|
|
22369
|
+
tags: [
|
|
22370
|
+
"soil",
|
|
22371
|
+
"brittle"
|
|
22372
|
+
],
|
|
22373
|
+
compressive: 6e4
|
|
22374
|
+
},
|
|
22375
|
+
{
|
|
22376
|
+
id: "snow",
|
|
22377
|
+
density: 300,
|
|
22378
|
+
hpPerKg: 1,
|
|
22379
|
+
penetration: 3,
|
|
22380
|
+
ductility: 0.6,
|
|
22381
|
+
fracture: "crumble",
|
|
22382
|
+
fragmentSize: [
|
|
22383
|
+
0.01,
|
|
22384
|
+
0.05
|
|
22385
|
+
],
|
|
22386
|
+
hitDebris: "dust",
|
|
22387
|
+
breakDebris: "dust",
|
|
22388
|
+
thermal: {
|
|
22389
|
+
conductivity: 0.1,
|
|
22390
|
+
heatCapacity: 2.1
|
|
22391
|
+
},
|
|
22392
|
+
tags: [
|
|
22393
|
+
"soil",
|
|
22394
|
+
"frozen"
|
|
22395
|
+
],
|
|
22396
|
+
compressive: 1e3
|
|
22397
|
+
},
|
|
22398
|
+
{
|
|
22399
|
+
id: "cobble",
|
|
22400
|
+
density: 2650,
|
|
22401
|
+
hpPerKg: 25,
|
|
22402
|
+
penetration: 25,
|
|
22403
|
+
penetrationClass: "concrete",
|
|
22404
|
+
penetrationScale: 0.9,
|
|
22405
|
+
ductility: 0.03,
|
|
22406
|
+
fracture: "crumble",
|
|
22407
|
+
fragmentSize: [
|
|
22408
|
+
0.05,
|
|
22409
|
+
0.15
|
|
22410
|
+
],
|
|
22411
|
+
hitDebris: "chips",
|
|
22412
|
+
breakDebris: "chips",
|
|
22413
|
+
thermal: {
|
|
22414
|
+
conductivity: 0.2,
|
|
22415
|
+
heatCapacity: 2.5
|
|
22416
|
+
},
|
|
22417
|
+
tags: [
|
|
22418
|
+
"masonry",
|
|
22419
|
+
"brittle"
|
|
22420
|
+
],
|
|
22421
|
+
compressive: 3e5
|
|
22422
|
+
},
|
|
22423
|
+
{
|
|
22424
|
+
id: "paver",
|
|
22425
|
+
density: 2300,
|
|
22426
|
+
hpPerKg: 14,
|
|
22427
|
+
penetration: 18,
|
|
22428
|
+
penetrationClass: "concrete",
|
|
22429
|
+
penetrationScale: 1,
|
|
22430
|
+
ductility: 0.03,
|
|
22431
|
+
fracture: "crumble",
|
|
22432
|
+
fragmentSize: [
|
|
22433
|
+
0.04,
|
|
22434
|
+
0.12
|
|
22435
|
+
],
|
|
22436
|
+
hitDebris: "chips",
|
|
22437
|
+
breakDebris: "chips",
|
|
22438
|
+
thermal: {
|
|
22439
|
+
conductivity: 0.15,
|
|
22440
|
+
heatCapacity: 2.5
|
|
22441
|
+
},
|
|
22442
|
+
tags: [
|
|
22443
|
+
"masonry",
|
|
22444
|
+
"brittle"
|
|
22445
|
+
],
|
|
22446
|
+
compressive: 35e4
|
|
22088
22447
|
}
|
|
22089
22448
|
];
|
|
22090
22449
|
var material_hints_default = {
|
|
@@ -22297,6 +22656,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22297
22656
|
var BREACH_BLAST_FACTOR = 6;
|
|
22298
22657
|
var BREACH_AREA = 0.25;
|
|
22299
22658
|
var BREACH_BLAST_REACH = 0.12;
|
|
22659
|
+
var MEMBER_CUT_REACH = 0.5;
|
|
22660
|
+
var BLAST_REFERENCE_RESISTANCE = 200 * 1900 * 0.13;
|
|
22661
|
+
var BLAST_EDGE_RAGGED = 0.3;
|
|
22662
|
+
var BLAST_EDGE_LOOSE = 1.35;
|
|
22663
|
+
var BLAST_EDGE_WEAR = 0.6;
|
|
22300
22664
|
var RESIDUAL_CAPACITY = 0.15;
|
|
22301
22665
|
var SEVER_BAND = 0.1;
|
|
22302
22666
|
var SEVER_ASPECT = 3;
|
|
@@ -23549,7 +23913,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23549
23913
|
if (j.st.open) continue;
|
|
23550
23914
|
if (j.spec.kind === "rebar" && (isReinforced(o.parts[j.ia].spec) || isReinforced(o.parts[j.ib].spec))) continue;
|
|
23551
23915
|
if (near && jointReach(o, j, near) > Math.max(radius, jointReachLimit(o, j))) continue;
|
|
23552
|
-
j.st.hp -= span === void 0 ? amount : amount * Math.min(1, span / Math.max(jointLength(o, j), 1e-6));
|
|
23916
|
+
j.st.hp -= span === void 0 ? amount : Math.min(amount, j.st.maxHp) * Math.min(1, span / Math.max(jointLength(o, j), 1e-6));
|
|
23553
23917
|
if (j.st.hp <= 0) {
|
|
23554
23918
|
j.st.hp = 0;
|
|
23555
23919
|
j.st.open = true;
|
|
@@ -23571,14 +23935,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23571
23935
|
var _a;
|
|
23572
23936
|
if (p.layers.length === 0) return;
|
|
23573
23937
|
const lp = objLocal(o, wp);
|
|
23574
|
-
const
|
|
23575
|
-
if (!
|
|
23938
|
+
const layer3 = outerLayer(p.layers, p.rt.spalls, face, lp);
|
|
23939
|
+
if (!layer3) return;
|
|
23576
23940
|
const spalls = (_a = p.rt).spalls ?? (_a.spalls = []);
|
|
23577
|
-
spalls.push([
|
|
23941
|
+
spalls.push([layer3.index, face, lp[0], lp[1], lp[2], radius]);
|
|
23578
23942
|
if (spalls.length > MAX_SPALLS) spalls.shift();
|
|
23579
23943
|
markDamaged(p);
|
|
23580
|
-
emit2({ ...base(o, src), type: "spall", part: p.spec.id, layer:
|
|
23581
|
-
debris2(o, p,
|
|
23944
|
+
emit2({ ...base(o, src), type: "spall", part: p.spec.id, layer: layer3.index, point: wp, area: Math.PI * radius * radius });
|
|
23945
|
+
debris2(o, p, layer3.mat.hitDebris, wp, normal, 5, 2, src, layer3.mat.id);
|
|
23582
23946
|
setStage(o, p, 1, {}, src);
|
|
23583
23947
|
};
|
|
23584
23948
|
const crater = (o, p, wp, normal, radius, src) => {
|
|
@@ -23677,6 +24041,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23677
24041
|
const worn = (_a = p.rt).chips ?? (_a.chips = {});
|
|
23678
24042
|
const cut = (_b = p.rt).craters ?? (_b.craters = {});
|
|
23679
24043
|
const out = [];
|
|
24044
|
+
const wholeBefore = Object.values(worn).filter((w) => w === -1).length;
|
|
23680
24045
|
const shot = kind === "ballistic";
|
|
23681
24046
|
for (let i = 0; i < grid.length; i++) {
|
|
23682
24047
|
const cell = grid[i];
|
|
@@ -23735,6 +24100,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23735
24100
|
emit2({ ...base(o, src), type: "chip", part: p.spec.id, center, size: [cell.size[0], cell.size[1], cell.size[2]], rotation: q, fragments });
|
|
23736
24101
|
debris2(o, p, p.mat.breakDebris, center, vec.scale(dir ?? [0, 1, 0], -1), 6, 2, src);
|
|
23737
24102
|
}
|
|
24103
|
+
if (Object.values(worn).filter((w) => w === -1).length > wholeBefore) dropUnsupported(o, p, src);
|
|
23738
24104
|
if (p.spec.reinforcement) exposeRebar(o, p, src);
|
|
23739
24105
|
for (const cell of out) addBreach(o, p, toWorld(c, q, cell.center), cell.size[u] * cell.size[v], energy, dir, src);
|
|
23740
24106
|
if (p.structural && !isLost(p)) {
|
|
@@ -23838,10 +24204,122 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23838
24204
|
setStage(o, p, 1, {}, src);
|
|
23839
24205
|
setStage(o, p, 2, { opening: { center: worldCenter, radius }, fragments }, src);
|
|
23840
24206
|
debris2(o, p, p.mat.breakDebris, worldCenter, vec.scale(dir ?? [0, 1, 0], -1), 14, 3, src);
|
|
24207
|
+
dropUnsupported(o, p, src);
|
|
23841
24208
|
const reinforcement = p.spec.reinforcement;
|
|
23842
24209
|
if (reinforcement) exposeRebar(o, p, src);
|
|
23843
24210
|
if (p.structural) solveStructure(o);
|
|
23844
24211
|
};
|
|
24212
|
+
const blastReachOf = (p, energy) => {
|
|
24213
|
+
const perKg = p.mat.hits?.blunt?.unitJoules ?? chipEnergy;
|
|
24214
|
+
const resistance = Math.max(1, perKg * p.mat.density * p.thickness);
|
|
24215
|
+
return BREACH_BLAST_REACH * Math.cbrt(Math.max(0, energy) / 1e3) * clamp2(Math.cbrt(BLAST_REFERENCE_RESISTANCE / resistance), 0.3, 2);
|
|
24216
|
+
};
|
|
24217
|
+
const blastUnits = (o, p, wp, energy, dist2, src) => {
|
|
24218
|
+
var _a, _b;
|
|
24219
|
+
if (!p.staged || p.st.stripped || isLost(p) || chipEnergy <= 0) return false;
|
|
24220
|
+
const reach = blastReachOf(p, energy);
|
|
24221
|
+
if (dist2 >= reach) return false;
|
|
24222
|
+
const radius = Math.sqrt(reach * reach - dist2 * dist2);
|
|
24223
|
+
const [u, v] = planeAxes(p.thin);
|
|
24224
|
+
const lp = toLocal(p.pos, p.q, objLocal(o, wp));
|
|
24225
|
+
const op = p.st.opening ? toLocal(p.pos, p.q, p.st.opening.center) : null;
|
|
24226
|
+
const grid = gridOf(p);
|
|
24227
|
+
const worn = (_a = p.rt).chips ?? (_a.chips = {});
|
|
24228
|
+
const perKg = p.mat.hits?.blunt?.unitJoules ?? chipEnergy;
|
|
24229
|
+
const lobes = [rnd2() * 2 * Math.PI, rnd2() * 2 * Math.PI];
|
|
24230
|
+
const out = [];
|
|
24231
|
+
for (let i = 0; i < grid.length; i++) {
|
|
24232
|
+
const cell = grid[i];
|
|
24233
|
+
if (worn[i] === -1) continue;
|
|
24234
|
+
if (op && p.st.opening && Math.hypot(cell.center[u] - op[u], cell.center[v] - op[v]) <= p.st.opening.radius) continue;
|
|
24235
|
+
const du = cell.center[u] - lp[u], dv = cell.center[v] - lp[v];
|
|
24236
|
+
const angle = Math.atan2(dv, du);
|
|
24237
|
+
const edge = radius * (1 + BLAST_EDGE_RAGGED * (0.5 * Math.sin(3 * angle + lobes[0]) + 0.3 * Math.sin(5 * angle + lobes[1]) + 0.4 * (rnd2() - 0.5)));
|
|
24238
|
+
const d = Math.hypot(du, dv);
|
|
24239
|
+
if (d <= edge) {
|
|
24240
|
+
worn[i] = -1;
|
|
24241
|
+
out.push(i);
|
|
24242
|
+
} else if (d <= edge * BLAST_EDGE_LOOSE) {
|
|
24243
|
+
const mass = p.mat.density * cell.size[0] * cell.size[1] * cell.size[2];
|
|
24244
|
+
worn[i] = Math.max(worn[i] ?? 0, perKg * mass * BLAST_EDGE_WEAR);
|
|
24245
|
+
}
|
|
24246
|
+
}
|
|
24247
|
+
if (out.length === 0) return false;
|
|
24248
|
+
const loose = unsupportedCells(grid, p.thin, p.dims, (i) => worn[i] !== -1 && !(op && p.st.opening && Math.hypot(grid[i].center[u] - op[u], grid[i].center[v] - op[v]) <= p.st.opening.radius));
|
|
24249
|
+
for (const i of loose) worn[i] = -1;
|
|
24250
|
+
const blown = out.map((i) => grid[i]), fallen = loose.map((i) => grid[i]);
|
|
24251
|
+
const volume = (cells2) => cells2.reduce((sum2, cell) => sum2 + cell.size[0] * cell.size[1] * cell.size[2], 0);
|
|
24252
|
+
const blownMass = Math.min(p.st.mass, p.mat.density * volume(blown));
|
|
24253
|
+
const fallenMass = Math.min(p.st.mass - blownMass, p.mat.density * volume(fallen));
|
|
24254
|
+
const speed = clamp2(Math.sqrt(2 * energy * 0.02 / Math.max(blownMass, 0.05)), 1, 12);
|
|
24255
|
+
const { c, q } = partXf(o, p);
|
|
24256
|
+
const chipped = (_b = p.st).chipped ?? (_b.chipped = []);
|
|
24257
|
+
const tag = `x${chipped.length}_`;
|
|
24258
|
+
const fragments = [
|
|
24259
|
+
...cellFragments(o, p, clumpCells(blown, p.thin, maxFragments), wp, null, speed, blownMass, tag, true),
|
|
24260
|
+
...fallen.length > 0 ? cellFragments(o, p, clumpCells(fallen, p.thin, Math.max(2, Math.round(maxFragments / 4))), wp, null, 0.3, fallenMass, `${tag}f`, true) : []
|
|
24261
|
+
];
|
|
24262
|
+
const cells = [...blown, ...fallen];
|
|
24263
|
+
const holes = localHolesOf(p);
|
|
24264
|
+
p.st.holes = p.st.holes.filter((_, k) => !cells.some((cell) => marksInBox(cell.center, cell.size, void 0, [holes[k]]).length > 0));
|
|
24265
|
+
const lo = [Infinity, Infinity, Infinity], hi = [-Infinity, -Infinity, -Infinity];
|
|
24266
|
+
for (const cell of cells) {
|
|
24267
|
+
chipped.push({ center: [cell.center[0], cell.center[1], cell.center[2]], size: [cell.size[0], cell.size[1], cell.size[2]] });
|
|
24268
|
+
for (let k = 0; k < 3; k++) {
|
|
24269
|
+
lo[k] = Math.min(lo[k], cell.center[k] - cell.size[k] / 2);
|
|
24270
|
+
hi[k] = Math.max(hi[k], cell.center[k] + cell.size[k] / 2);
|
|
24271
|
+
}
|
|
24272
|
+
}
|
|
24273
|
+
p.st.mass = Math.max(0, p.st.mass - blownMass - fallenMass);
|
|
24274
|
+
p.rt.removed = (p.rt.removed ?? 0) + blownMass + fallenMass;
|
|
24275
|
+
markDamaged(p);
|
|
24276
|
+
setStage(o, p, 1, {}, src);
|
|
24277
|
+
const center = toWorld(c, q, [(lo[0] + hi[0]) / 2, (lo[1] + hi[1]) / 2, (lo[2] + hi[2]) / 2]);
|
|
24278
|
+
const units = cells.map((cell) => ({ center: toWorld(c, q, cell.center), size: [cell.size[0], cell.size[1], cell.size[2]] }));
|
|
24279
|
+
emit2({ ...base(o, src), type: "chip", part: p.spec.id, center, size: [hi[0] - lo[0], hi[1] - lo[1], hi[2] - lo[2]], rotation: q, fragments, units });
|
|
24280
|
+
debris2(o, p, p.mat.breakDebris, center, vec.normalize(vec.sub(center, wp), [0, 1, 0]), 14, 3, src);
|
|
24281
|
+
if (p.spec.reinforcement) exposeRebar(o, p, src);
|
|
24282
|
+
if (p.structural && !isLost(p)) {
|
|
24283
|
+
solveStructure(o);
|
|
24284
|
+
collapseCheck(o, src);
|
|
24285
|
+
}
|
|
24286
|
+
return true;
|
|
24287
|
+
};
|
|
24288
|
+
const dropUnsupported = (o, p, src) => {
|
|
24289
|
+
var _a, _b;
|
|
24290
|
+
if (!p.spec.units || p.spec.units.mortar === p.spec.material || p.st.stripped || isLost(p)) return 0;
|
|
24291
|
+
const [u, v] = planeAxes(p.thin);
|
|
24292
|
+
const grid = gridOf(p);
|
|
24293
|
+
const worn = (_a = p.rt).chips ?? (_a.chips = {});
|
|
24294
|
+
const op = p.st.opening ? toLocal(p.pos, p.q, p.st.opening.center) : null;
|
|
24295
|
+
const opened = (cell) => !!op && !!p.st.opening && Math.hypot(cell.center[u] - op[u], cell.center[v] - op[v]) <= p.st.opening.radius;
|
|
24296
|
+
const loose = unsupportedCells(grid, p.thin, p.dims, (i) => worn[i] !== -1 && !opened(grid[i]));
|
|
24297
|
+
if (loose.length === 0) return 0;
|
|
24298
|
+
for (const i of loose) worn[i] = -1;
|
|
24299
|
+
const fallen = loose.map((i) => grid[i]);
|
|
24300
|
+
const mass = Math.min(p.st.mass, p.mat.density * fallen.reduce((sum2, cell) => sum2 + cell.size[0] * cell.size[1] * cell.size[2], 0));
|
|
24301
|
+
const { c, q } = partXf(o, p);
|
|
24302
|
+
const chipped = (_b = p.st).chipped ?? (_b.chipped = []);
|
|
24303
|
+
const lo = [Infinity, Infinity, Infinity], hi = [-Infinity, -Infinity, -Infinity];
|
|
24304
|
+
for (const cell of fallen) {
|
|
24305
|
+
for (let k = 0; k < 3; k++) {
|
|
24306
|
+
lo[k] = Math.min(lo[k], cell.center[k] - cell.size[k] / 2);
|
|
24307
|
+
hi[k] = Math.max(hi[k], cell.center[k] + cell.size[k] / 2);
|
|
24308
|
+
}
|
|
24309
|
+
}
|
|
24310
|
+
const center = toWorld(c, q, [(lo[0] + hi[0]) / 2, (lo[1] + hi[1]) / 2, (lo[2] + hi[2]) / 2]);
|
|
24311
|
+
const fragments = cellFragments(o, p, clumpCells(fallen, p.thin, Math.max(2, Math.round(maxFragments / 4))), vec.add(center, [0, 1, 0]), null, 0.3, mass, `u${chipped.length}_`, true);
|
|
24312
|
+
const holes = localHolesOf(p);
|
|
24313
|
+
p.st.holes = p.st.holes.filter((_, k) => !fallen.some((cell) => marksInBox(cell.center, cell.size, void 0, [holes[k]]).length > 0));
|
|
24314
|
+
for (const cell of fallen) chipped.push({ center: [cell.center[0], cell.center[1], cell.center[2]], size: [cell.size[0], cell.size[1], cell.size[2]] });
|
|
24315
|
+
p.st.mass = Math.max(0, p.st.mass - mass);
|
|
24316
|
+
p.rt.removed = (p.rt.removed ?? 0) + mass;
|
|
24317
|
+
markDamaged(p);
|
|
24318
|
+
const units = fallen.map((cell) => ({ center: toWorld(c, q, cell.center), size: [cell.size[0], cell.size[1], cell.size[2]] }));
|
|
24319
|
+
emit2({ ...base(o, src), type: "chip", part: p.spec.id, center, size: [hi[0] - lo[0], hi[1] - lo[1], hi[2] - lo[2]], rotation: q, fragments, units });
|
|
24320
|
+
debris2(o, p, p.mat.breakDebris, center, [0, -1, 0], 6, 1, src);
|
|
24321
|
+
return loose.length;
|
|
24322
|
+
};
|
|
23845
24323
|
const stripPart = (o, p, reinforcement, src) => {
|
|
23846
24324
|
const bars = rebarBars(p.dims, p.thin, reinforcement.spacing);
|
|
23847
24325
|
p.st.stripped = true;
|
|
@@ -23908,6 +24386,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23908
24386
|
const unitPlan = p.spec.units ? unitFragmentPlan(p, maxFragments * UNIT_FRAGMENT_FACTOR) : [];
|
|
23909
24387
|
const axis2 = style === "splinter" || style === "snap" ? severAxis(p) : -1;
|
|
23910
24388
|
const cutAt2 = axis2 < 0 ? void 0 : p.rt.cutAt ?? (origin ? hitLocal[axis2] : void 0);
|
|
24389
|
+
const planRnd = p.mat.splitForm ? splitStream(o.id, p.spec.id, hitLocal) : rnd2;
|
|
23911
24390
|
const plan = unitPlan.length > 0 ? unitPlan : planFragments({
|
|
23912
24391
|
style,
|
|
23913
24392
|
dims: p.dims,
|
|
@@ -23916,8 +24395,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23916
24395
|
hit: hitLocal,
|
|
23917
24396
|
fragmentSize: p.mat.fragmentSize ?? [0.04, 0.2],
|
|
23918
24397
|
maxFragments,
|
|
23919
|
-
rnd:
|
|
24398
|
+
rnd: planRnd,
|
|
23920
24399
|
sheet: p.mat.sheet,
|
|
24400
|
+
...p.mat.splitForm ? { form: p.mat.splitForm } : {},
|
|
23921
24401
|
...cutAt2 !== void 0 ? { cut: { at: cutAt2, gap: SEVER_BAND } } : {}
|
|
23922
24402
|
});
|
|
23923
24403
|
const holes = p.st.holes.length > 0 ? localHolesOf(p) : [];
|
|
@@ -24056,7 +24536,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
24056
24536
|
const fragments = [];
|
|
24057
24537
|
for (let i = 0; i < n; i++) {
|
|
24058
24538
|
const back = !exit || i % 3 === 2;
|
|
24059
|
-
const
|
|
24539
|
+
const plies = p.mat.splitForm === "plies";
|
|
24540
|
+
const len = scale * (fibre ? 1.2 + 1.2 * rnd2() : 3 + 4 * rnd2()), w = scale * (0.8 + 0.8 * rnd2()), t = scale * (fibre ? 0.7 + 0.6 * rnd2() : plies ? 0.15 + 0.15 * rnd2() : 0.4 + 0.4 * rnd2());
|
|
24060
24541
|
const size = [w, w, w];
|
|
24061
24542
|
size[along] = len;
|
|
24062
24543
|
size[(along + 1) % 3] = w;
|
|
@@ -24217,7 +24698,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
24217
24698
|
checkIgnite(o, p, src);
|
|
24218
24699
|
}
|
|
24219
24700
|
}
|
|
24220
|
-
wearJoints(o, p, Ein * 0.5, void 0, 0, src);
|
|
24701
|
+
wearJoints(o, p, Ein * 0.5, void 0, 0, src, false, 2 * BREACH_BLAST_REACH * Math.cbrt(Math.max(0, energy) / 1e3));
|
|
24221
24702
|
const amount = Ein * DMG_PER_J * (mat.damageScale?.explosive ?? 1);
|
|
24222
24703
|
if (blastFrontSpeed > 0 && dist2 > 0 && mat.tags?.includes("glass")) {
|
|
24223
24704
|
frontQueue.push({ o, p, due: time + dist2 / blastFrontSpeed, amount, fragEnergy: Ein * 0.3, point, ...src !== void 0 ? { src } : {} });
|
|
@@ -24227,7 +24708,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
24227
24708
|
const dealt = applyDamage(o, p, amount, "explosive", point, null, Ein * 0.3, 40, src);
|
|
24228
24709
|
res.damage += dealt;
|
|
24229
24710
|
if (p.bend && flexure.enabled) bendByBlast(o, p, point, energy, radius, reach, src);
|
|
24230
|
-
|
|
24711
|
+
const breachReach = BREACH_BLAST_REACH * Math.cbrt(Math.max(0, energy) / 1e3);
|
|
24712
|
+
if (p.spec.units && p.spec.units.mortar !== p.spec.material) blastUnits(o, p, wp, energy, dist2, src);
|
|
24713
|
+
else if (p.spec.reinforcement && p.spec.units && dist2 > MEMBER_CUT_REACH * breachReach) blastUnits(o, p, wp, energy, dist2, src);
|
|
24714
|
+
else if (dist2 <= breachReach) addBreach(o, p, wp, breachAreaOf(p, dealt, true), Ein, null, src);
|
|
24231
24715
|
return reach;
|
|
24232
24716
|
};
|
|
24233
24717
|
const blastProbe = { partsTested: 0, partsNear: 0 };
|
|
@@ -24473,6 +24957,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
24473
24957
|
}
|
|
24474
24958
|
return h | 0;
|
|
24475
24959
|
};
|
|
24960
|
+
const splitStream = (objectId, partId, hit) => {
|
|
24961
|
+
const codes = Array.from(`${objectId}|${partId}`, (char) => char.charCodeAt(0) / 1e3);
|
|
24962
|
+
const stream = createRng2(seedOf2(rng2.state() / 1e3, ...codes, hit[0], hit[1], hit[2]));
|
|
24963
|
+
return () => stream.next();
|
|
24964
|
+
};
|
|
24476
24965
|
const throwFragment = (frag, objectId, from, g, centre, index, src, shields, results, reports, mult) => {
|
|
24477
24966
|
const v = frag.velocity;
|
|
24478
24967
|
const speed = Math.hypot(v[0], v[1], v[2]);
|
|
@@ -25420,7 +25909,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
25420
25909
|
var defaultSet;
|
|
25421
25910
|
var defaultAssemblies = () => defaultSet ?? (defaultSet = assembliesOver(ASSEMBLIES));
|
|
25422
25911
|
var getAssembly = (id) => defaultAssemblies().get(id);
|
|
25423
|
-
var faceCount = (
|
|
25912
|
+
var faceCount = (layer3) => layer3.faces === "both" ? 2 : 1;
|
|
25424
25913
|
var assemblyDepth = (def) => def.depth ?? def.core.thickness + (def.layers ?? []).reduce((sum2, l) => sum2 + l.thickness * faceCount(l), 0);
|
|
25425
25914
|
var buildAssemblyPart = (def, assemblyId, options) => {
|
|
25426
25915
|
if (!def) throw new Error(`unknown assembly "${assemblyId}"`);
|
|
@@ -25768,7 +26257,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
25768
26257
|
var DEFAULT_DENSITY = 500;
|
|
25769
26258
|
var densityOf = (material) => DENSITY[material] ?? DEFAULT_DENSITY;
|
|
25770
26259
|
var OPEN_ROOM_TYPES = ["balcony", "terrace", "porch"];
|
|
26260
|
+
var WALL_PILLAR_SIDE = 0.2;
|
|
26261
|
+
var HALF = WALL_PILLAR_SIDE / 2;
|
|
25771
26262
|
var CLOSED_ONLY = [...OPEN_ROOM_TYPES, "void"];
|
|
26263
|
+
var HALF_PILLAR = WALL_PILLAR_SIDE / 2;
|
|
25772
26264
|
var entry = (itemId, min2, max2, group, pickable, weight) => ({ itemId, min: min2, max: max2, group, pickable, weight });
|
|
25773
26265
|
var FRIDGE = [
|
|
25774
26266
|
entry("water_bottle", 1, 3, "water", true, 3),
|
|
@@ -26503,6 +26995,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
26503
26995
|
}
|
|
26504
26996
|
var LINTEL_DEPTH2 = 0.2;
|
|
26505
26997
|
var LINTEL_BEARING2 = 0.2;
|
|
26998
|
+
var SILL_BEAM_DEPTH = 0.1;
|
|
26999
|
+
var LINTEL_SPAN_RATIO = 10;
|
|
26506
27000
|
var MIN_PIECE = 0.05;
|
|
26507
27001
|
var frameOf = (wall) => {
|
|
26508
27002
|
const alongU = wall.aabb[2] - wall.aabb[0] >= wall.aabb[3] - wall.aabb[1];
|
|
@@ -26516,6 +27010,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
26516
27010
|
const drafts = [];
|
|
26517
27011
|
const piers = [];
|
|
26518
27012
|
const lintels = [];
|
|
27013
|
+
const sillBeams = [];
|
|
26519
27014
|
const spandrels = [];
|
|
26520
27015
|
const height = wall.y1 - wall.y0;
|
|
26521
27016
|
let cursor = frame2.from;
|
|
@@ -26526,23 +27021,26 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
26526
27021
|
};
|
|
26527
27022
|
own.forEach((opening2, k) => {
|
|
26528
27023
|
addPier(Math.max(cursor, opening2.from));
|
|
26529
|
-
const
|
|
27024
|
+
const span = opening2.to - opening2.from;
|
|
27025
|
+
const lintelTop = Math.min(wall.y1, opening2.y1 + Math.max(LINTEL_DEPTH2, style.lintelDepth?.(span) ?? 0, (span + LINTEL_BEARING2) / LINTEL_SPAN_RATIO));
|
|
26530
27026
|
const lintelFrom = Math.max(frame2.from, opening2.from - LINTEL_BEARING2);
|
|
26531
27027
|
const lintelTo = Math.min(frame2.to, opening2.to + LINTEL_BEARING2);
|
|
26532
27028
|
const lintelHeight = lintelTop - opening2.y1;
|
|
26533
|
-
|
|
27029
|
+
const sillTop = style.sillBeam && opening2.y0 - wall.y0 > SILL_BEAM_DEPTH + MIN_PIECE ? opening2.y0 - SILL_BEAM_DEPTH : opening2.y0;
|
|
27030
|
+
if (sillTop - wall.y0 > MIN_PIECE) drafts.push({ id: `${wall.id}_sill_${k}`, role: "partition", material: wall.material, from: opening2.from, to: opening2.to, y0: wall.y0, y1: sillTop, volume: (opening2.to - opening2.from) * (sillTop - wall.y0) });
|
|
27031
|
+
if (sillTop < opening2.y0) sillBeams.push({ id: `${wall.id}_sillbeam_${k}`, role: "beam", material: style.lintelMaterial, from: lintelFrom, to: lintelTo, y0: sillTop, y1: opening2.y0, volume: (lintelTo - lintelFrom) * SILL_BEAM_DEPTH });
|
|
26534
27032
|
lintels.push({ id: `${wall.id}_lintel_${k}`, role: "beam", material: style.lintelMaterial, from: lintelFrom, to: lintelTo, y0: opening2.y1, y1: lintelTop, volume: (lintelTo - lintelFrom) * lintelHeight });
|
|
26535
27033
|
spandrels.push(wall.y1 - lintelTop > MIN_PIECE ? { id: `${wall.id}_spandrel_${k}`, role: roleOf2, material: wall.material, from: opening2.from, to: opening2.to, y0: lintelTop, y1: wall.y1, volume: (opening2.to - opening2.from) * (wall.y1 - lintelTop) } : void 0);
|
|
26536
27034
|
cursor = opening2.to;
|
|
26537
27035
|
});
|
|
26538
27036
|
addPier(frame2.to);
|
|
26539
27037
|
for (const pier of piers) {
|
|
26540
|
-
for (const lintel of lintels) {
|
|
27038
|
+
for (const lintel of [...lintels, ...sillBeams]) {
|
|
26541
27039
|
const overlap = Math.max(0, Math.min(pier.to, lintel.to) - Math.max(pier.from, lintel.from));
|
|
26542
27040
|
pier.volume -= overlap * (lintel.y1 - lintel.y0);
|
|
26543
27041
|
}
|
|
26544
27042
|
}
|
|
26545
|
-
const all = [...piers, ...drafts, ...lintels, ...spandrels.filter((d) => d !== void 0)];
|
|
27043
|
+
const all = [...piers, ...drafts, ...sillBeams, ...lintels, ...spandrels.filter((d) => d !== void 0)];
|
|
26546
27044
|
const total = all.reduce((sum2, d) => sum2 + d.volume, 0);
|
|
26547
27045
|
const pieces = all.map((d) => ({
|
|
26548
27046
|
id: d.id,
|
|
@@ -26557,6 +27055,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
26557
27055
|
...d.role === "beam" ? style.lintelAssembly ? { assembly: style.lintelAssembly } : {} : wall.assembly ? { assembly: wall.assembly } : {}
|
|
26558
27056
|
}));
|
|
26559
27057
|
const internal = [];
|
|
27058
|
+
for (const beam of sillBeams) {
|
|
27059
|
+
const sill = drafts.find((d) => d.id === beam.id.replace("_sillbeam_", "_sill_"));
|
|
27060
|
+
if (sill) internal.push({ part: beam.id, on: sill.id, joint: style.lintelJoint });
|
|
27061
|
+
for (const pier of piers) if (Math.min(pier.to, beam.to) - Math.max(pier.from, beam.from) > 0) internal.push({ part: beam.id, on: pier.id, joint: style.lintelJoint });
|
|
27062
|
+
}
|
|
26560
27063
|
lintels.forEach((lintel, k) => {
|
|
26561
27064
|
for (const pier of piers) if (Math.min(pier.to, lintel.to) - Math.max(pier.from, lintel.from) > 0) internal.push({ part: lintel.id, on: pier.id, joint: style.lintelJoint });
|
|
26562
27065
|
const spandrel = spandrels[k];
|
|
@@ -26586,7 +27089,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
26586
27089
|
...system.timber ? {} : { lintelAssembly: "reinforced_concrete" },
|
|
26587
27090
|
lintelJoint: system.joints.beam,
|
|
26588
27091
|
wallJoint: system.joints.wall,
|
|
26589
|
-
...lintelDepth && !system.timber ? { lintelDepth } : {}
|
|
27092
|
+
...lintelDepth && !system.timber ? { lintelDepth } : {},
|
|
27093
|
+
...construction.system === "masonry" ? { sillBeam: true } : {}
|
|
26590
27094
|
});
|
|
26591
27095
|
if (split.pieces.length > 1) splits.set(part.id, split);
|
|
26592
27096
|
}
|
|
@@ -26594,7 +27098,18 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
26594
27098
|
}
|
|
26595
27099
|
function applyPanels(input, structure, detail, lintelDepth) {
|
|
26596
27100
|
if (detail === "coarse") return input;
|
|
26597
|
-
return applySplits(input, panelSplits(input, structure, lintelDepth));
|
|
27101
|
+
return onJambPillars(applySplits(input, panelSplits(input, structure, lintelDepth)));
|
|
27102
|
+
}
|
|
27103
|
+
var OPENING_BEAM = /_(lintel|sillbeam)_\d+$/;
|
|
27104
|
+
var overlaps2 = (a, b) => a[0] < b[2] && a[2] > b[0] && a[1] < b[3] && a[3] > b[1];
|
|
27105
|
+
function onJambPillars(split) {
|
|
27106
|
+
const pillars = split.parts.filter((part) => part.role === "column" && part.material === "concrete");
|
|
27107
|
+
const extra = [];
|
|
27108
|
+
for (const beam of split.parts) {
|
|
27109
|
+
if (beam.role !== "beam" || !OPENING_BEAM.test(beam.id)) continue;
|
|
27110
|
+
for (const pillar of pillars) if (pillar.floor === beam.floor && overlaps2(pillar.aabb, beam.aabb) && pillar.y0 <= beam.y0 && pillar.y1 >= beam.y1 - 0.01) extra.push({ part: beam.id, on: pillar.id, joint: "rebar" });
|
|
27111
|
+
}
|
|
27112
|
+
return extra.length ? { parts: split.parts, supports: [...split.supports, ...extra] } : split;
|
|
26598
27113
|
}
|
|
26599
27114
|
function applyUnits(input, structure) {
|
|
26600
27115
|
const splits = /* @__PURE__ */ new Map();
|
|
@@ -26656,21 +27171,35 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
26656
27171
|
};
|
|
26657
27172
|
var MEMBER_CAGE = { spacing: 0.1, diameter: 8e-3, unit: 0.1 };
|
|
26658
27173
|
var CAGED_ROLES = /* @__PURE__ */ new Set(["beam", "column"]);
|
|
27174
|
+
var CAGE_COVER = 0.03;
|
|
27175
|
+
var CAGE_BUCKLING_SHARE = 0.5;
|
|
27176
|
+
var DEFAULT_RESIDUAL = 0.15;
|
|
27177
|
+
function cageResidualCapacity(size, reinforcement, capacity) {
|
|
27178
|
+
const [a = 0, b = 0] = [...size].sort((x, y) => x - y);
|
|
27179
|
+
const perSide = (w) => Math.max(2, Math.floor(Math.max(0, w - 2 * CAGE_COVER) / reinforcement.spacing) + 1);
|
|
27180
|
+
const bars = 2 * perSide(a) + 2 * perSide(b) - 4;
|
|
27181
|
+
const steel = MATERIALS2.find((m) => m.id === reinforcement.material)?.compressive ?? 0;
|
|
27182
|
+
const carries2 = bars * Math.PI * (reinforcement.diameter / 2) ** 2 * steel * CAGE_BUCKLING_SHARE;
|
|
27183
|
+
if (!capacity || capacity <= 0 || carries2 <= 0) return DEFAULT_RESIDUAL;
|
|
27184
|
+
return Math.min(1, Math.max(DEFAULT_RESIDUAL, carries2 / capacity));
|
|
27185
|
+
}
|
|
26659
27186
|
var caged = (spec, part, rebar2) => {
|
|
26660
27187
|
if (!rebar2 || part.material !== "concrete" || !CAGED_ROLES.has(part.role) || spec.reinforcement) return spec;
|
|
26661
27188
|
const size = spec.shape.kind === "box" ? spec.shape.size : null;
|
|
26662
27189
|
if (!size) return spec;
|
|
26663
27190
|
const thin = Math.min(...size);
|
|
27191
|
+
const reinforcement = { material: rebar2, spacing: MEMBER_CAGE.spacing, diameter: MEMBER_CAGE.diameter };
|
|
26664
27192
|
return {
|
|
26665
27193
|
...spec,
|
|
26666
|
-
reinforcement: {
|
|
27194
|
+
reinforcement: part.role === "column" ? { ...reinforcement, residualCapacity: cageResidualCapacity(size, reinforcement, spec.structure?.capacity) } : reinforcement,
|
|
26667
27195
|
units: { size: [MEMBER_CAGE.unit, MEMBER_CAGE.unit, thin], bond: "stack", mortar: "concrete" }
|
|
26668
27196
|
};
|
|
26669
27197
|
};
|
|
26670
27198
|
var partSpecOf = (part, capacity, detailed, rebar2) => {
|
|
26671
27199
|
if (detailed && part.assembly) return assemblySpec(part, capacity);
|
|
26672
27200
|
const spec = boxSpec(part, capacity);
|
|
26673
|
-
|
|
27201
|
+
const out = detailed ? caged(spec, part, rebar2) : spec;
|
|
27202
|
+
return part.beamKind === "ground_beam" ? { ...out, anchored: true, structure: { role: "foundation" } } : out;
|
|
26674
27203
|
};
|
|
26675
27204
|
function toDestructibleSpec(structure, options = {}) {
|
|
26676
27205
|
const { safety = 0.65, redundancy = 0.97, safetyOthers = 0.45 } = options;
|
|
@@ -26686,7 +27215,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
26686
27215
|
const walled = applyPanels(slabbed, structure, detail, slabOptions && structure.construction.frame.rebar ? (span) => beamDepthFor(span, slabOptions) : void 0);
|
|
26687
27216
|
const panels = slabOptions && detail !== "coarse" ? deepenBondBeams(walled, structure, slabOptions) : walled;
|
|
26688
27217
|
const sizing = { safety, redundancy, safetyOthers };
|
|
26689
|
-
const
|
|
27218
|
+
const foundation = new Set(panels.parts.filter((part) => part.beamKind === "ground_beam").map((part) => part.id));
|
|
27219
|
+
const onFoundation = foundation.size ? panels.supports.filter((s) => !foundation.has(s.part)).map((s) => foundation.has(s.on) ? { ...s, on: GROUND } : s) : panels.supports;
|
|
27220
|
+
const sized = { ...panels, capacities: options.sized === false ? /* @__PURE__ */ new Map() : sizeCapacities(panels.parts.filter((part) => !foundation.has(part.id)), onFoundation, sizing) };
|
|
26690
27221
|
const { parts, supports, capacities } = detail === "units" ? applyUnits(sized, structure) : sized;
|
|
26691
27222
|
const specs = parts.map((part) => partSpecOf(part, capacities.get(part.id), detail !== "coarse", structure.construction.frame.rebar));
|
|
26692
27223
|
const margin = options.terrainMargin ?? TERRAIN_MARGIN;
|
|
@@ -26751,6 +27282,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
26751
27282
|
out.parts = out.parts.map((p, i) => i === ground ? raft2 : p);
|
|
26752
27283
|
return out;
|
|
26753
27284
|
}
|
|
27285
|
+
var LOW_WINDOW = SILL_BEAM_DEPTH + 0.05;
|
|
26754
27286
|
var slabId = (g, f) => f === g.floors - 1 && g.roof ? "roof" : `slab_${f}`;
|
|
26755
27287
|
var storeyBase = (g, f) => f * (g.height + g.slab);
|
|
26756
27288
|
var slabHalf = (g) => [(g.spanX + g.columnSize + 0.2) / 2, (g.spanZ + g.columnSize + 0.2) / 2];
|
|
@@ -26856,13 +27388,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
26856
27388
|
const c = { ...CURTAIN_DEFAULTS, ...options };
|
|
26857
27389
|
const parts = [...spec.parts];
|
|
26858
27390
|
const joints = [...spec.joints ?? []];
|
|
26859
|
-
const [hx,
|
|
27391
|
+
const [hx, hz2] = slabHalf(g);
|
|
26860
27392
|
const h = g.height + g.slab;
|
|
26861
27393
|
const sides = [
|
|
26862
|
-
{ name: "n", along: 0, length: 2 * hx, fixed:
|
|
26863
|
-
{ name: "s", along: 0, length: 2 * hx, fixed: -
|
|
26864
|
-
{ name: "e", along: 2, length: 2 *
|
|
26865
|
-
{ name: "w", along: 2, length: 2 *
|
|
27394
|
+
{ name: "n", along: 0, length: 2 * hx, fixed: hz2 + c.offset, axis: 2 },
|
|
27395
|
+
{ name: "s", along: 0, length: 2 * hx, fixed: -hz2 - c.offset, axis: 2 },
|
|
27396
|
+
{ name: "e", along: 2, length: 2 * hz2, fixed: hx + c.offset, axis: 0 },
|
|
27397
|
+
{ name: "w", along: 2, length: 2 * hz2, fixed: -hx - c.offset, axis: 0 }
|
|
26866
27398
|
];
|
|
26867
27399
|
for (let f = 0; f < g.floors; f++) {
|
|
26868
27400
|
if (c.skip?.(f)) continue;
|
|
@@ -26909,7 +27441,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
26909
27441
|
parts.push({ id, material: c.material, shape: box2(size), position, structure: { role: "partition" }, tags: ["infill"] });
|
|
26910
27442
|
for (const o of on) rests(joints, id, o, "mortar");
|
|
26911
27443
|
};
|
|
26912
|
-
const bay = (side, k, along,
|
|
27444
|
+
const bay = (side, k, along, centre2, fixed2, length2, c1, c2) => {
|
|
26913
27445
|
const clear = length2 - g.columnSize;
|
|
26914
27446
|
const win = clear * c.window;
|
|
26915
27447
|
const pier = (clear - win) / 2;
|
|
@@ -26920,11 +27452,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
26920
27452
|
wall(`infill_${f}_${side}_${k}_${name}`, size(u, h), [p[0], y, p[2]], on);
|
|
26921
27453
|
};
|
|
26922
27454
|
const id = (name) => `infill_${f}_${side}_${k}_${name}`;
|
|
26923
|
-
put("sill", clear, sill, yb + sill / 2,
|
|
26924
|
-
put("pl", pier, head - sill, yb + sill + (head - sill) / 2,
|
|
26925
|
-
put("pr", pier, head - sill, yb + sill + (head - sill) / 2,
|
|
26926
|
-
put("head", clear, room - head, yb + head + (room - head) / 2,
|
|
26927
|
-
const gp = at23(
|
|
27455
|
+
put("sill", clear, sill, yb + sill / 2, centre2, [c1, c2]);
|
|
27456
|
+
put("pl", pier, head - sill, yb + sill + (head - sill) / 2, centre2 - clear / 2 + pier / 2, [c1, id("sill")]);
|
|
27457
|
+
put("pr", pier, head - sill, yb + sill + (head - sill) / 2, centre2 + clear / 2 - pier / 2, [c2, id("sill")]);
|
|
27458
|
+
put("head", clear, room - head, yb + head + (room - head) / 2, centre2, [c1, c2]);
|
|
27459
|
+
const gp = at23(centre2);
|
|
26928
27460
|
const gid = `glass_${f}_${side}_${k}`;
|
|
26929
27461
|
parts.push({
|
|
26930
27462
|
id: gid,
|
|
@@ -27391,7 +27923,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
27391
27923
|
}
|
|
27392
27924
|
var towerLocales = { en: { labels: en_default.labels }, "pt-BR": { labels: pt_BR_default.labels } };
|
|
27393
27925
|
|
|
27394
|
-
// ../game-floorplan-three/dist/chunk-
|
|
27926
|
+
// ../game-floorplan-three/dist/chunk-7XVCZF6H.js
|
|
27395
27927
|
var en2 = {
|
|
27396
27928
|
"prompt.open": "E: open {what}",
|
|
27397
27929
|
"prompt.close": "E: close {what}",
|
|
@@ -28133,6 +28665,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
28133
28665
|
}
|
|
28134
28666
|
function installHouseWalls(K, shared2) {
|
|
28135
28667
|
const { EPS: EPS6, Y0, boxC, bx, cursor, effectiveHeight, pieceRecord, structurePiece, wallColor } = K;
|
|
28668
|
+
const sh = (color2, factor) => K.sh(color2, factor);
|
|
28136
28669
|
function wallBox(alongU, L, a, b, ya, yb, th, cL, cH, mL, mH) {
|
|
28137
28670
|
if (yb - ya < 1e-4 || b - a < 1e-4) return;
|
|
28138
28671
|
if (alongU) {
|
|
@@ -28176,6 +28709,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
28176
28709
|
function walls() {
|
|
28177
28710
|
const R = shared2.ctx.r, cut = shared2.ctx.cut, nA = R.floors.length, vMin = Math.min(...R.walls.map((w) => w.axis === "u" ? w.v0 : Math.min(w.v0, w.v1)));
|
|
28178
28711
|
const corners = /* @__PURE__ */ new Map();
|
|
28712
|
+
const looks = /* @__PURE__ */ new Map();
|
|
28179
28713
|
for (const w of R.walls) {
|
|
28180
28714
|
const f = w.floor;
|
|
28181
28715
|
cursor.group = "f" + f;
|
|
@@ -28185,6 +28719,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
28185
28719
|
const hh = cut ? Math.min(h, 1.2) : h, L = alongU ? w.v0 : w.u0, s0 = Math.min(alongU ? w.u0 : w.v0, alongU ? w.u1 : w.v1), s1 = Math.max(alongU ? w.u0 : w.v0, alongU ? w.u1 : w.v1);
|
|
28186
28720
|
const front = alongU && Math.abs(L - vMin) < 0.05;
|
|
28187
28721
|
const sideL = sideOf(w.sides[0], front), sideH = sideOf(w.sides[1], front);
|
|
28722
|
+
if (w.id) {
|
|
28723
|
+
const face = sideL.exterior ? sideL : sideH;
|
|
28724
|
+
looks.set(w.id, { mat: face.mat, color: face.color, top: y0 + hh });
|
|
28725
|
+
}
|
|
28188
28726
|
shared2.ctx.colliders.push({ type: "wall", piece: w.id, f, x0: alongU ? s0 : L - th / 2, z0: alongU ? L - th / 2 : s0, x1: alongU ? s1 : L + th / 2, z1: alongU ? L + th / 2 : s1 });
|
|
28189
28727
|
if (w.type === "railing") {
|
|
28190
28728
|
const c0 = shared2.ctx.colors.metal != null ? shared2.ctx.colors.metal : 9080466;
|
|
@@ -28231,8 +28769,27 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
28231
28769
|
cursor.group = "f" + e.f;
|
|
28232
28770
|
bx(e.color.mat, e.pu - e.th / 2, e.y0, e.pv - e.th / 2, e.pu + e.th / 2, e.y0 + e.hh, e.pv + e.th / 2, e.color.color);
|
|
28233
28771
|
}
|
|
28772
|
+
if (shared2.ctx.showPillars) wallPillars(looks);
|
|
28773
|
+
}
|
|
28774
|
+
const PILLAR_IN_WALL = /^(wall_column_|column_\d|jamb_column_)/;
|
|
28775
|
+
const wallOf = (pillar, parts) => {
|
|
28776
|
+
const u = (pillar.aabb[0] + pillar.aabb[2]) / 2, v = (pillar.aabb[1] + pillar.aabb[3]) / 2;
|
|
28777
|
+
return parts.find((q) => (q.role === "wall" || q.role === "partition") && q.assembly !== void 0 && q.floor === pillar.floor && u >= q.aabb[0] - 1e-3 && u <= q.aabb[2] + 1e-3 && v >= q.aabb[1] - 1e-3 && v <= q.aabb[3] + 1e-3);
|
|
28778
|
+
};
|
|
28779
|
+
function wallPillars(looks) {
|
|
28780
|
+
const parts = Object.values(shared2.ctx.structureIndex);
|
|
28781
|
+
for (const e of parts) {
|
|
28782
|
+
if (e.role !== "column" || !PILLAR_IN_WALL.test(e.id)) continue;
|
|
28783
|
+
const host = wallOf(e, parts);
|
|
28784
|
+
const look = host && looks.get(host.id);
|
|
28785
|
+
if (!host || !look) continue;
|
|
28786
|
+
cursor.group = "f" + e.floor;
|
|
28787
|
+
cursor.pc = structurePiece(host.id);
|
|
28788
|
+
bx(look.mat, e.aabb[0], e.y0, e.aabb[1], e.aabb[2], Math.min(e.y1, look.top), e.aabb[3], sh(look.color != null ? look.color : 15262420, 0.93));
|
|
28789
|
+
}
|
|
28790
|
+
cursor.pc = null;
|
|
28234
28791
|
}
|
|
28235
|
-
Object.assign(K, { wallBox, sideOf, pieceOf, nearestWall, walls });
|
|
28792
|
+
Object.assign(K, { wallBox, sideOf, pieceOf, nearestWall, walls, wallPillars });
|
|
28236
28793
|
}
|
|
28237
28794
|
function installHouseDoors(K, shared2) {
|
|
28238
28795
|
const seedKey = (id) => K.seedKey(id);
|
|
@@ -33604,7 +34161,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
33604
34161
|
if (!pc || pc.unit) return sp;
|
|
33605
34162
|
if (pc.role !== "wall" && pc.role !== "partition") {
|
|
33606
34163
|
const def = getAssembly(pc.assembly || (pc.material === "concrete" && ["slab", "beam", "column", "stair"].includes(pc.role) ? "reinforced_concrete" : ""));
|
|
33607
|
-
const
|
|
34164
|
+
const cage = def && def.reinforcement ? pc.role === "column" && sp.shape.kind === "box" ? { ...def.reinforcement, residualCapacity: cageResidualCapacity(sp.shape.size, def.reinforcement, sp.structure?.capacity) } : { ...def.reinforcement } : null;
|
|
34165
|
+
const out = cage && !sp.reinforcement ? { ...sp, reinforcement: cage } : sp;
|
|
33608
34166
|
if (out.reinforcement && !out.units && pc.material === "concrete" && (pc.role === "beam" || pc.role === "column") && sp.shape.kind === "box") {
|
|
33609
34167
|
return { ...out, units: { size: [MEMBER_CAGE.unit, MEMBER_CAGE.unit, Math.min(...sp.shape.size)], bond: "stack", mortar: "concrete" } };
|
|
33610
34168
|
}
|
|
@@ -33630,6 +34188,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
33630
34188
|
const a = pos.array;
|
|
33631
34189
|
const u = mesh3.userData;
|
|
33632
34190
|
if (!u._p0) u._p0 = a.slice();
|
|
34191
|
+
if (!u.plainPositions) Object.defineProperty(u, "plainPositions", { value: u._p0, enumerable: false, configurable: true, writable: true });
|
|
33633
34192
|
const list2 = u.collapsedRanges ?? (u.collapsedRanges = []);
|
|
33634
34193
|
if (!list2.some((r) => r[0] === v0 && r[1] === v1)) list2.push([v0, v1]);
|
|
33635
34194
|
const saved = a.slice(v0 * 3, v1 * 3);
|
|
@@ -33713,10 +34272,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
33713
34272
|
const v = house.worldToLocal(tmp.p.set(p[0], p[1], p[2]));
|
|
33714
34273
|
return [v.x, v.y, v.z];
|
|
33715
34274
|
};
|
|
33716
|
-
function cells(part, units) {
|
|
34275
|
+
function cells(part, units, mask) {
|
|
33717
34276
|
const [u0, v0, u1, v1] = part.aabb;
|
|
33718
|
-
const alongU =
|
|
34277
|
+
const alongU = mask.alongU;
|
|
33719
34278
|
const len = alongU ? u1 - u0 : v1 - v0;
|
|
34279
|
+
const offset = (alongU ? u0 : v0) - mask.start;
|
|
33720
34280
|
const [ul, uh] = units.size;
|
|
33721
34281
|
const rows = Math.max(1, Math.round((part.y1 - part.y0) / uh));
|
|
33722
34282
|
const rowH = (part.y1 - part.y0) / rows;
|
|
@@ -33727,7 +34287,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
33727
34287
|
const shift = units.bond === "running" && r & 1 ? w / 2 : 0;
|
|
33728
34288
|
for (let i = 0; i < per + (shift ? 1 : 0); i++) {
|
|
33729
34289
|
const a = Math.max(0, i * w - shift), b = Math.min(len, i * w - shift + w);
|
|
33730
|
-
if (b - a > 1e-3) out.push({ a, b, y0: part.y0 + r * rowH, y1: part.y0 + (r + 1) * rowH, r, i });
|
|
34290
|
+
if (b - a > 1e-3) out.push({ a: offset + a, b: offset + b, y0: part.y0 + r * rowH, y1: part.y0 + (r + 1) * rowH, r, i });
|
|
33731
34291
|
}
|
|
33732
34292
|
}
|
|
33733
34293
|
return out;
|
|
@@ -33741,8 +34301,21 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
33741
34301
|
for (const q of structure.parts) {
|
|
33742
34302
|
if (q.id !== partId && same(q.aabb, part.aabb) && Math.abs(q.y1 - part.y0) < 0.01 && structure.meshesOf(q.id).some((it) => it.mesh)) return q.id;
|
|
33743
34303
|
}
|
|
34304
|
+
return part.role === "column" ? wallAround(part) : null;
|
|
34305
|
+
}
|
|
34306
|
+
function wallAround(part) {
|
|
34307
|
+
const cu = (part.aabb[0] + part.aabb[2]) / 2, cv = (part.aabb[1] + part.aabb[3]) / 2;
|
|
34308
|
+
for (const q of structure.parts) {
|
|
34309
|
+
if (q.id === part.id || q.role !== "wall" && q.role !== "partition" || !structure.meshesOf(q.id).some((it) => it.mesh)) continue;
|
|
34310
|
+
const inside2 = cu >= q.aabb[0] - 1e-3 && cu <= q.aabb[2] + 1e-3 && cv >= q.aabb[1] - 1e-3 && cv <= q.aabb[3] + 1e-3;
|
|
34311
|
+
if (inside2 && Math.min(q.y1, part.y1) - Math.max(q.y0, part.y0) > 0.5) return q.id;
|
|
34312
|
+
}
|
|
33744
34313
|
return null;
|
|
33745
34314
|
}
|
|
34315
|
+
const pillarSpans = (view) => structure.parts.filter((q) => q.role === "column" && wallAround(q) === view.host).map((q) => {
|
|
34316
|
+
const a = (view.mask.alongU ? q.aabb[0] : q.aabb[1]) - view.mask.start, b = (view.mask.alongU ? q.aabb[2] : q.aabb[3]) - view.mask.start;
|
|
34317
|
+
return { a, b, y0: q.y0, y1: q.y1 };
|
|
34318
|
+
});
|
|
33746
34319
|
const riders = (hostId) => structure.parts.filter((q) => q.id !== hostId && specOf(q.id)?.units && hostOf(q.id) === hostId && !structure.meshesOf(q.id).some((it) => it.mesh)).map((q) => q.id);
|
|
33747
34320
|
function shell(it, mask) {
|
|
33748
34321
|
const g0 = it.mesh.geometry, g = new THREE.BufferGeometry();
|
|
@@ -33831,6 +34404,17 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
33831
34404
|
texture.needsUpdate = true;
|
|
33832
34405
|
return { data, texture, w, h, alongU, start: alongU ? u0 : v0, len, y0, height: y1 - y0, rect: new THREE.Vector4(alongU ? u0 : v0, y0, len, y1 - y0) };
|
|
33833
34406
|
}
|
|
34407
|
+
function besidePillars(c, pillars) {
|
|
34408
|
+
let { a, b } = c;
|
|
34409
|
+
for (const k of pillars) {
|
|
34410
|
+
if (c.y1 <= k.y0 || c.y0 >= k.y1 || b <= k.a || a >= k.b) continue;
|
|
34411
|
+
const centre = (a + b) / 2;
|
|
34412
|
+
if (centre > k.a && centre < k.b) return [];
|
|
34413
|
+
if (centre <= k.a) b = Math.min(b, k.a);
|
|
34414
|
+
else a = Math.max(a, k.b);
|
|
34415
|
+
}
|
|
34416
|
+
return b - a > 1e-3 ? [{ ...c, a, b }] : [];
|
|
34417
|
+
}
|
|
33834
34418
|
const boxDistance = (s, y, a, b, c, d) => Math.hypot(Math.max(a - s, 0, s - b), Math.max(c - y, 0, y - d));
|
|
33835
34419
|
const ellipseDistance = (s, y, cs, cy, rs, ry) => (Math.hypot((s - cs) / Math.max(rs, 1e-4), (y - cy) / Math.max(ry, 1e-4)) - 1) * Math.min(rs, ry);
|
|
33836
34420
|
function covered(c, boxes) {
|
|
@@ -33853,9 +34437,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
33853
34437
|
const discs = [];
|
|
33854
34438
|
const flakes = [];
|
|
33855
34439
|
const shown = [];
|
|
34440
|
+
const pillars = pillarSpans(view);
|
|
33856
34441
|
for (const id of view.parts) {
|
|
33857
34442
|
const part = structure.byId.get(id), units2 = specOf(id).units, chips2 = view.chips.get(id), opening = view.openings.get(id), spalls = view.spalls.get(id);
|
|
33858
|
-
const
|
|
34443
|
+
const own = cells(part, units2, mask);
|
|
34444
|
+
const all = id === view.host ? own.flatMap((c) => besidePillars(c, pillars)) : own;
|
|
34445
|
+
if (view.fallen.has(id)) {
|
|
34446
|
+
holes.push(...all);
|
|
34447
|
+
continue;
|
|
34448
|
+
}
|
|
33859
34449
|
const thick = mask.alongU ? part.aabb[3] - part.aabb[1] : part.aabb[2] - part.aabb[0];
|
|
33860
34450
|
const mid = mask.alongU ? (part.aabb[1] + part.aabb[3]) / 2 : (part.aabb[0] + part.aabb[2]) / 2;
|
|
33861
34451
|
if (opening) discs.push({ s: along(opening.center), y: opening.center[1], r: opening.radius });
|
|
@@ -33951,52 +34541,55 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
33951
34541
|
}
|
|
33952
34542
|
return { center: local2(chip.center), along: a, up: u };
|
|
33953
34543
|
}
|
|
34544
|
+
function newView(hostId) {
|
|
34545
|
+
const items = structure.meshesOf(hostId).filter((it) => it.mesh);
|
|
34546
|
+
if (!items.length) return null;
|
|
34547
|
+
const parts = [hostId, ...riders(hostId)].filter((id) => structure.byId.get(id) && specOf(id)?.units);
|
|
34548
|
+
const mask = maskOf(hostId, parts), core = maskOf(hostId, parts);
|
|
34549
|
+
return {
|
|
34550
|
+
host: hostId,
|
|
34551
|
+
parts,
|
|
34552
|
+
items,
|
|
34553
|
+
mask,
|
|
34554
|
+
core,
|
|
34555
|
+
unitMaterial: unitsMaterial(core),
|
|
34556
|
+
shells: [],
|
|
34557
|
+
saved: null,
|
|
34558
|
+
units: null,
|
|
34559
|
+
gone: 0,
|
|
34560
|
+
pits: 0,
|
|
34561
|
+
bounds: drawnBounds(items),
|
|
34562
|
+
chips: new Map(parts.map((id) => [id, []])),
|
|
34563
|
+
spalls: new Map(parts.map((id) => [id, []])),
|
|
34564
|
+
openings: /* @__PURE__ */ new Map(),
|
|
34565
|
+
flakes: 0,
|
|
34566
|
+
fallen: /* @__PURE__ */ new Set()
|
|
34567
|
+
};
|
|
34568
|
+
}
|
|
34569
|
+
function cut(view) {
|
|
34570
|
+
if (view.saved) return;
|
|
34571
|
+
view.shells = view.items.map((it) => shell(it, view.mask));
|
|
34572
|
+
for (const m of view.shells) m.userData.behind = () => view.units;
|
|
34573
|
+
view.saved = view.items.map((it) => ({ it, v0: it.v0, data: collapseRange(it.mesh, it.v0, it.v1) }));
|
|
34574
|
+
}
|
|
33954
34575
|
function draw2(partId, change) {
|
|
33955
34576
|
if (lod !== 0) return false;
|
|
33956
34577
|
const hostId = hostOf(partId);
|
|
33957
34578
|
if (!hostId || !specOf(partId)?.units) return false;
|
|
33958
|
-
|
|
33959
|
-
if (!view)
|
|
33960
|
-
const items = structure.meshesOf(hostId).filter((it) => it.mesh);
|
|
33961
|
-
if (!items.length) return false;
|
|
33962
|
-
const parts = [hostId, ...riders(hostId)].filter((id) => structure.byId.get(id) && specOf(id)?.units);
|
|
33963
|
-
if (!parts.includes(partId)) return false;
|
|
33964
|
-
const mask = maskOf(hostId, parts), core = maskOf(hostId, parts);
|
|
33965
|
-
view = {
|
|
33966
|
-
host: hostId,
|
|
33967
|
-
parts,
|
|
33968
|
-
items,
|
|
33969
|
-
mask,
|
|
33970
|
-
core,
|
|
33971
|
-
unitMaterial: unitsMaterial(core),
|
|
33972
|
-
shells: [],
|
|
33973
|
-
saved: null,
|
|
33974
|
-
units: null,
|
|
33975
|
-
gone: 0,
|
|
33976
|
-
pits: 0,
|
|
33977
|
-
bounds: drawnBounds(items),
|
|
33978
|
-
chips: new Map(parts.map((id) => [id, []])),
|
|
33979
|
-
spalls: new Map(parts.map((id) => [id, []])),
|
|
33980
|
-
openings: /* @__PURE__ */ new Map(),
|
|
33981
|
-
flakes: 0
|
|
33982
|
-
};
|
|
33983
|
-
}
|
|
33984
|
-
if (!view.chips.has(partId)) return false;
|
|
34579
|
+
const view = views.get(hostId) ?? newView(hostId);
|
|
34580
|
+
if (!view || !view.chips.has(partId)) return false;
|
|
33985
34581
|
if (change.opening) {
|
|
33986
34582
|
if (view.openings.has(partId)) return false;
|
|
33987
34583
|
view.openings.set(partId, { center: local2(change.opening.center), radius: change.opening.radius });
|
|
33988
34584
|
}
|
|
33989
34585
|
if (change.chip) view.chips.get(partId).push(chipBox(change.chip, view.mask.alongU));
|
|
34586
|
+
for (const chip of change.chips ?? []) view.chips.get(partId).push(chipBox(chip, view.mask.alongU));
|
|
33990
34587
|
if (change.spall) {
|
|
33991
34588
|
const list2 = view.spalls.get(partId);
|
|
33992
34589
|
list2.push({ center: local2(change.spall.center), radius: change.spall.radius });
|
|
33993
34590
|
if (list2.length > MAX_FLAKES) list2.shift();
|
|
33994
34591
|
}
|
|
33995
|
-
|
|
33996
|
-
view.shells = view.items.map((it) => shell(it, view.mask));
|
|
33997
|
-
for (const m of view.shells) m.userData.behind = () => view.units;
|
|
33998
|
-
view.saved = view.items.map((it) => ({ it, v0: it.v0, data: collapseRange(it.mesh, it.v0, it.v1) }));
|
|
33999
|
-
}
|
|
34592
|
+
cut(view);
|
|
34000
34593
|
views.set(hostId, view);
|
|
34001
34594
|
if (opts.deferPaint && change.spall) dirty.add(view);
|
|
34002
34595
|
else {
|
|
@@ -34107,14 +34700,32 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
34107
34700
|
*/
|
|
34108
34701
|
chip(event) {
|
|
34109
34702
|
if (event.torn) return false;
|
|
34110
|
-
|
|
34703
|
+
const rotation2 = event.rotation ?? [0, 0, 0, 1];
|
|
34704
|
+
if (event.units?.length) return draw2(event.part, { chips: event.units.map((unit) => ({ center: unit.center, size: unit.size, rotation: rotation2 })) });
|
|
34705
|
+
return draw2(event.part, { chip: { center: event.center, size: event.size ?? [0, 0, 0], rotation: rotation2 } });
|
|
34111
34706
|
},
|
|
34112
34707
|
/** The part broke or fell: its damage goes (the plain range stays collapsed, the renderer hides the part). */
|
|
34113
34708
|
drop(partId) {
|
|
34114
|
-
|
|
34115
|
-
if (!
|
|
34709
|
+
let host = views.get(partId) ?? [...views.values()].find((view) => view.parts.includes(partId));
|
|
34710
|
+
if (!host && lod === 0 && riders(partId).length > 0) {
|
|
34711
|
+
host = newView(partId);
|
|
34712
|
+
if (host) {
|
|
34713
|
+
cut(host);
|
|
34714
|
+
views.set(partId, host);
|
|
34715
|
+
}
|
|
34716
|
+
}
|
|
34717
|
+
if (!host) return;
|
|
34718
|
+
host.fallen.add(partId);
|
|
34719
|
+
if (host.parts.some((id) => !host.fallen.has(id))) {
|
|
34720
|
+
dirty.delete(host);
|
|
34721
|
+
paint2(host);
|
|
34722
|
+
invalidate();
|
|
34723
|
+
invalidateShadow();
|
|
34724
|
+
return;
|
|
34725
|
+
}
|
|
34726
|
+
const v = host;
|
|
34116
34727
|
dispose(v);
|
|
34117
|
-
views.delete(
|
|
34728
|
+
views.delete(v.host);
|
|
34118
34729
|
if (v.saved) dropped.push(v);
|
|
34119
34730
|
},
|
|
34120
34731
|
/** LOD 0 draws the cut wall; LOD 1 and 2 give the wall its box back. */
|
|
@@ -34589,6 +35200,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
34589
35200
|
shared2.ctx.noPiece = false;
|
|
34590
35201
|
cursor.separate = opts.pieces === "meshes";
|
|
34591
35202
|
cursor.pc = null;
|
|
35203
|
+
shared2.ctx.showPillars = opts.pillars !== "hidden";
|
|
34592
35204
|
shared2.ctx.apartment = r.template === "apartment_modern";
|
|
34593
35205
|
shared2.ctx.pa = Math.max(3, Math.min(20, pr.floors != null ? pr.floors : 5));
|
|
34594
35206
|
shared2.ctx.pf = Math.max(1, Math.min(shared2.ctx.pa, pr.floor != null ? pr.floor : 3));
|
|
@@ -36723,11 +37335,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
36723
37335
|
else return false;
|
|
36724
37336
|
return true;
|
|
36725
37337
|
};
|
|
36726
|
-
const zoomOf = (tool2) =>
|
|
36727
|
-
|
|
36728
|
-
|
|
37338
|
+
const zoomOf = (tool2) => aimZoomOf(arsenal, tool2.weapon, tool2.attachments?.map((part) => part.id));
|
|
37339
|
+
const aims = (tool2) => {
|
|
37340
|
+
const kind = arsenal.weapons.get(tool2.weapon)?.action.kind;
|
|
37341
|
+
return kind === "firearm" || kind === "launcher";
|
|
36729
37342
|
};
|
|
36730
|
-
const isFirearm = (tool2) => arsenal.weapons.get(tool2.weapon)?.action.kind === "firearm";
|
|
36731
37343
|
const setAim = (on) => {
|
|
36732
37344
|
if (on === aiming) return;
|
|
36733
37345
|
aiming = on;
|
|
@@ -36754,7 +37366,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
36754
37366
|
};
|
|
36755
37367
|
const isOnRoom = (event) => Boolean(document.pointerLockElement) || event.target instanceof HTMLCanvasElement;
|
|
36756
37368
|
const onMouseDown = (event) => {
|
|
36757
|
-
if (event.button !== SECONDARY_BUTTON || !isOnRoom(event) || !
|
|
37369
|
+
if (event.button !== SECONDARY_BUTTON || !isOnRoom(event) || !aims(host.tool())) return;
|
|
36758
37370
|
event.preventDefault();
|
|
36759
37371
|
event.stopImmediatePropagation();
|
|
36760
37372
|
setAim(true);
|
|
@@ -36930,7 +37542,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
36930
37542
|
};
|
|
36931
37543
|
var accessoryTextOf = (locale) => ACCESSORY_TEXT[locale] ?? ACCESSORY_TEXT.en;
|
|
36932
37544
|
|
|
36933
|
-
// ../game-audio/dist/chunk-
|
|
37545
|
+
// ../game-audio/dist/chunk-C2K7XN2K.js
|
|
36934
37546
|
var DISTANCE_CURVES = {
|
|
36935
37547
|
/** The game's `sfx`: `vol / (1 + d² × 0.004)`, cutoff `/ (1 + d × 0.01)`, silent below 0.01 (jogo L62091–62092, L62101). */
|
|
36936
37548
|
game_sfx: { model: "inverse_square", k: 4e-3, cutoffK: 0.01, minGain: 0.01 },
|
|
@@ -37192,12 +37804,46 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37192
37804
|
}
|
|
37193
37805
|
return merged2;
|
|
37194
37806
|
}
|
|
37807
|
+
var trimmed = (refs, alias) => refs.map((ref) => ({
|
|
37808
|
+
...ref,
|
|
37809
|
+
...alias.offset === void 0 ? {} : { offset: alias.offset },
|
|
37810
|
+
...alias.duration === void 0 ? {} : { duration: alias.duration }
|
|
37811
|
+
}));
|
|
37812
|
+
function aliasSample(alias, file) {
|
|
37813
|
+
const { tiers: _tiers, fallback: _fallback, choke: _choke, ...rest2 } = file;
|
|
37814
|
+
return {
|
|
37815
|
+
...rest2,
|
|
37816
|
+
id: alias.id,
|
|
37817
|
+
close: trimmed(file.close, alias),
|
|
37818
|
+
...file.far ? { far: trimmed(file.far, alias) } : {},
|
|
37819
|
+
...alias.loop === void 0 ? {} : { loop: alias.loop },
|
|
37820
|
+
...alias.baseFrequency === void 0 ? {} : { baseFrequency: alias.baseFrequency },
|
|
37821
|
+
...alias.gain === void 0 ? {} : { gain: alias.gain },
|
|
37822
|
+
...alias.pitch === void 0 ? {} : { pitch: alias.pitch },
|
|
37823
|
+
...alias.falloff ? { falloff: alias.falloff } : {},
|
|
37824
|
+
fallback: alias.id,
|
|
37825
|
+
sources: [...file.sources, `alias: ${alias.id} \u2192 ${alias.file}`]
|
|
37826
|
+
};
|
|
37827
|
+
}
|
|
37195
37828
|
function createSoundRegistry(banks = []) {
|
|
37196
37829
|
const sounds = /* @__PURE__ */ new Map();
|
|
37197
37830
|
const loops = /* @__PURE__ */ new Map();
|
|
37198
37831
|
const sets = /* @__PURE__ */ new Map();
|
|
37199
37832
|
const samples = /* @__PURE__ */ new Map();
|
|
37200
37833
|
const owners = /* @__PURE__ */ new Map();
|
|
37834
|
+
const aliases = /* @__PURE__ */ new Map();
|
|
37835
|
+
const derived = /* @__PURE__ */ new Map();
|
|
37836
|
+
const resolveAlias = (id) => {
|
|
37837
|
+
const alias = aliases.get(id);
|
|
37838
|
+
if (!alias) return void 0;
|
|
37839
|
+
const cached = derived.get(id);
|
|
37840
|
+
if (cached) return cached;
|
|
37841
|
+
const file = samples.get(alias.file);
|
|
37842
|
+
if (!file) return void 0;
|
|
37843
|
+
const sample = aliasSample(alias, file);
|
|
37844
|
+
derived.set(id, sample);
|
|
37845
|
+
return sample;
|
|
37846
|
+
};
|
|
37201
37847
|
const registry = {
|
|
37202
37848
|
register(bank) {
|
|
37203
37849
|
for (const sound3 of bank.sounds ?? []) {
|
|
@@ -37217,6 +37863,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37217
37863
|
samples.set(sample.id, sample);
|
|
37218
37864
|
owners.set(sample.id, bank.id);
|
|
37219
37865
|
}
|
|
37866
|
+
for (const alias of bank.sampleAliases ?? []) {
|
|
37867
|
+
aliases.set(alias.id, alias);
|
|
37868
|
+
if (!owners.has(alias.id)) owners.set(alias.id, bank.id);
|
|
37869
|
+
}
|
|
37870
|
+
derived.clear();
|
|
37220
37871
|
},
|
|
37221
37872
|
patch(id, patch) {
|
|
37222
37873
|
const sound3 = sounds.get(id);
|
|
@@ -37225,22 +37876,31 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37225
37876
|
if (loop) loops.set(id, mergeRecords(loop, patch));
|
|
37226
37877
|
const sample = samples.get(id);
|
|
37227
37878
|
if (sample) samples.set(id, mergeRecords(sample, patch));
|
|
37879
|
+
derived.clear();
|
|
37228
37880
|
},
|
|
37229
37881
|
remove(id) {
|
|
37230
37882
|
sounds.delete(id);
|
|
37231
37883
|
loops.delete(id);
|
|
37232
37884
|
sets.delete(id);
|
|
37233
37885
|
samples.delete(id);
|
|
37886
|
+
aliases.delete(id);
|
|
37234
37887
|
owners.delete(id);
|
|
37888
|
+
derived.clear();
|
|
37889
|
+
},
|
|
37890
|
+
removeSample(id) {
|
|
37891
|
+
samples.delete(id);
|
|
37892
|
+
aliases.delete(id);
|
|
37893
|
+
if (!sounds.has(id) && !loops.has(id) && !sets.has(id)) owners.delete(id);
|
|
37894
|
+
derived.clear();
|
|
37235
37895
|
},
|
|
37236
37896
|
sound: (id) => sounds.get(id),
|
|
37237
37897
|
loop: (id) => loops.get(id),
|
|
37238
37898
|
set: (id) => sets.get(id),
|
|
37239
|
-
sample: (id) => samples.get(id),
|
|
37899
|
+
sample: (id) => samples.get(id) ?? resolveAlias(id),
|
|
37240
37900
|
soundIds: () => [...sounds.keys()],
|
|
37241
37901
|
setIds: () => [...sets.keys()],
|
|
37242
37902
|
loopIds: () => [...loops.keys()],
|
|
37243
|
-
sampleIds: () => [...samples.keys()],
|
|
37903
|
+
sampleIds: () => [...samples.keys(), ...[...aliases.keys()].filter((id) => !samples.has(id) && resolveAlias(id) !== void 0)],
|
|
37244
37904
|
bankOf: (id) => owners.get(id)
|
|
37245
37905
|
};
|
|
37246
37906
|
for (const bank of banks) registry.register(bank);
|
|
@@ -37357,16 +38017,16 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37357
38017
|
}
|
|
37358
38018
|
return pending;
|
|
37359
38019
|
}
|
|
37360
|
-
function drawLayer(
|
|
38020
|
+
function drawLayer(layer3, scope2) {
|
|
37361
38021
|
const pending = { at: 0, gain: 1, filters: [], modulators: [] };
|
|
37362
|
-
for (const key2 of Object.keys(
|
|
37363
|
-
if (key2 === "at" &&
|
|
37364
|
-
else if (key2 === "duration" &&
|
|
37365
|
-
else if (key2 === "gain" &&
|
|
37366
|
-
else if (key2 === "source" &&
|
|
37367
|
-
else if (key2 === "source" &&
|
|
37368
|
-
else if (key2 === "filters" &&
|
|
37369
|
-
else if (key2 === "modulators" &&
|
|
38022
|
+
for (const key2 of Object.keys(layer3)) {
|
|
38023
|
+
if (key2 === "at" && layer3.at !== void 0) pending.at = draw(layer3.at, scope2);
|
|
38024
|
+
else if (key2 === "duration" && layer3.duration !== void 0) pending.duration = draw(layer3.duration, scope2);
|
|
38025
|
+
else if (key2 === "gain" && layer3.gain !== void 0) pending.gain = draw(layer3.gain, scope2);
|
|
38026
|
+
else if (key2 === "source" && layer3.source.kind === "osc") pending.automation = drawAutomation(layer3.source.frequency, scope2);
|
|
38027
|
+
else if (key2 === "source" && layer3.source.kind === "formant_voice") pending.voice = drawVoice(layer3.source, scope2);
|
|
38028
|
+
else if (key2 === "filters" && layer3.filters) pending.filters = layer3.filters.bank.map((spec) => drawFilter(spec, scope2));
|
|
38029
|
+
else if (key2 === "modulators" && layer3.modulators) pending.modulators = layer3.modulators.map((modulator) => drawModulator(modulator, scope2));
|
|
37370
38030
|
}
|
|
37371
38031
|
return pending;
|
|
37372
38032
|
}
|
|
@@ -37377,8 +38037,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37377
38037
|
if (source.offset === "fit") return scope2.random() * Math.max(0, noiseSeconds - duration);
|
|
37378
38038
|
return scope2.random() * (source.offsetScale ?? 1);
|
|
37379
38039
|
}
|
|
37380
|
-
function finishSource(
|
|
37381
|
-
const source =
|
|
38040
|
+
function finishSource(layer3, pending, duration, offset) {
|
|
38041
|
+
const source = layer3.source;
|
|
37382
38042
|
if (source.kind === "noise") return { kind: "noise", offset, loop: source.loop === true };
|
|
37383
38043
|
if (source.kind === "osc") return { kind: "osc", wave: source.wave, frequency: finishAutomation(pending.automation ?? {}, duration) };
|
|
37384
38044
|
const voice2 = pending.voice;
|
|
@@ -37400,23 +38060,23 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37400
38060
|
function finishEnvelope(envelope2, duration, level) {
|
|
37401
38061
|
return envelope2.map(([time, value, curve, fixed2]) => ({ time: timeOf(time, duration), value: fixed2 === "fixed" ? value : value * level, curve }));
|
|
37402
38062
|
}
|
|
37403
|
-
function planLayer(
|
|
37404
|
-
const pending = drawLayer(
|
|
38063
|
+
function planLayer(layer3, scope2, defaults, levelInEnvelope, soundLevel) {
|
|
38064
|
+
const pending = drawLayer(layer3, scope2);
|
|
37405
38065
|
const duration = pending.duration ?? defaults.duration;
|
|
37406
38066
|
if (duration === void 0) throw new Error("game-audio: a layer needs a duration (its own or the recipe\u2019s)");
|
|
37407
|
-
const offset = drawOffset(
|
|
38067
|
+
const offset = drawOffset(layer3.source, duration, scope2, defaults.noiseSeconds);
|
|
37408
38068
|
const level = pending.gain * soundLevel;
|
|
37409
|
-
const sourceFrequency =
|
|
38069
|
+
const sourceFrequency = layer3.source.kind === "noise" ? 0 : startFrequency(pending.automation ?? pending.voice?.frequency ?? {});
|
|
37410
38070
|
const planned = {
|
|
37411
38071
|
at: pending.at,
|
|
37412
38072
|
duration,
|
|
37413
|
-
tail:
|
|
38073
|
+
tail: layer3.tail ?? defaults.tail ?? DEFAULT_TAIL,
|
|
37414
38074
|
level,
|
|
37415
|
-
...
|
|
37416
|
-
source: finishSource(
|
|
37417
|
-
...
|
|
38075
|
+
...layer3.wet === void 0 ? {} : { wet: layer3.wet },
|
|
38076
|
+
source: finishSource(layer3, pending, duration, offset),
|
|
38077
|
+
...layer3.filters ? {
|
|
37418
38078
|
filters: {
|
|
37419
|
-
mode:
|
|
38079
|
+
mode: layer3.filters.mode,
|
|
37420
38080
|
bank: pending.filters.map(({ spec, frequency, q, gain, level: filterLevel }) => ({
|
|
37421
38081
|
type: spec.type,
|
|
37422
38082
|
frequency: finishAutomation(frequency, duration),
|
|
@@ -37427,10 +38087,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37427
38087
|
}
|
|
37428
38088
|
} : {},
|
|
37429
38089
|
modulators: pending.modulators.map((modulator) => finishModulator(modulator, sourceFrequency)),
|
|
37430
|
-
envelope: finishEnvelope(
|
|
38090
|
+
envelope: finishEnvelope(layer3.envelope, duration, levelInEnvelope ? level : 1)
|
|
37431
38091
|
};
|
|
37432
|
-
if (!
|
|
37433
|
-
return Array.from({ length:
|
|
38092
|
+
if (!layer3.repeat) return [planned];
|
|
38093
|
+
return Array.from({ length: layer3.repeat.count }, (_, index) => ({ ...planned, at: planned.at + index * (layer3.repeat?.spacing ?? 0) }));
|
|
37434
38094
|
}
|
|
37435
38095
|
function scaleAutomation(automation, divisor) {
|
|
37436
38096
|
const scale = (value) => value === void 0 ? void 0 : value / divisor;
|
|
@@ -37438,12 +38098,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37438
38098
|
for (const key2 of ["value", "from", "to"]) if (automation[key2] !== void 0) scaled2[key2] = scale(automation[key2]);
|
|
37439
38099
|
return scaled2;
|
|
37440
38100
|
}
|
|
37441
|
-
function muffle(
|
|
37442
|
-
if (divisor === 1 || !
|
|
37443
|
-
const bank =
|
|
37444
|
-
return { ...
|
|
38101
|
+
function muffle(layer3, divisor) {
|
|
38102
|
+
if (divisor === 1 || !layer3.filters) return layer3;
|
|
38103
|
+
const bank = layer3.filters.bank.map((filter) => filter.type === "lowpass" ? { ...filter, frequency: scaleAutomation(filter.frequency, divisor) } : filter);
|
|
38104
|
+
return { ...layer3, filters: { ...layer3.filters, bank } };
|
|
37445
38105
|
}
|
|
37446
|
-
var layerEnd = (
|
|
38106
|
+
var layerEnd = (layer3) => layer3.at + layer3.duration + layer3.tail;
|
|
37447
38107
|
function planSound(recipe2, input = {}) {
|
|
37448
38108
|
const listener = input.listener ?? DEFAULT_LISTENER;
|
|
37449
38109
|
const distance3 = input.distance ?? (input.position ? listenerDistance(listener, input.position, input.distanceMode) : 0);
|
|
@@ -37471,7 +38131,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37471
38131
|
noiseSeconds: input.noiseSeconds ?? DEFAULT_NOISE_SECONDS
|
|
37472
38132
|
};
|
|
37473
38133
|
const divisor = cutoffDivisor(recipe2.falloff, distance3) / (1 - OCCLUSION_CUTOFF * occlusion);
|
|
37474
|
-
const layers = recipe2.layers.flatMap((
|
|
38134
|
+
const layers = recipe2.layers.flatMap((layer3) => planLayer(layer3, scope2, defaults, order !== "layered", level)).map((layer3) => muffle(layer3, divisor));
|
|
37475
38135
|
return { ...base, silent: false, length: Math.max(0, ...layers.map(layerEnd)), layers };
|
|
37476
38136
|
}
|
|
37477
38137
|
function fillNoise(random, length2) {
|
|
@@ -37857,7 +38517,16 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37857
38517
|
const index = pickTake(refs.length, input.memory?.get(key2), input.random);
|
|
37858
38518
|
input.memory?.set(key2, index);
|
|
37859
38519
|
const ref = refs[index];
|
|
37860
|
-
layers.push({
|
|
38520
|
+
layers.push({
|
|
38521
|
+
role,
|
|
38522
|
+
url: ref.url,
|
|
38523
|
+
take: index,
|
|
38524
|
+
gain: gain * (ref.gain ?? 1) * level,
|
|
38525
|
+
rate,
|
|
38526
|
+
at: at3,
|
|
38527
|
+
...ref.offset === void 0 ? {} : { offset: ref.offset },
|
|
38528
|
+
...ref.duration === void 0 ? {} : { duration: ref.duration }
|
|
38529
|
+
});
|
|
37861
38530
|
};
|
|
37862
38531
|
take("close", close, gains.close, 0);
|
|
37863
38532
|
take("far", far, gains.far, 0);
|
|
@@ -37884,6 +38553,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37884
38553
|
var DEFAULT_LOOP_CROSSFADE = 0.25;
|
|
37885
38554
|
var LOOKAHEAD = 1.5;
|
|
37886
38555
|
var VOLUME_SMOOTHING = 0.05;
|
|
38556
|
+
var RATE_SMOOTHING = 0.04;
|
|
38557
|
+
var RATE_RANGE = [0.25, 4];
|
|
37887
38558
|
function loopCrossfade(sound3) {
|
|
37888
38559
|
if (!sound3.loop) return void 0;
|
|
37889
38560
|
return sound3.loop === true ? DEFAULT_LOOP_CROSSFADE : Math.max(0, sound3.loop.crossfade ?? DEFAULT_LOOP_CROSSFADE);
|
|
@@ -37895,6 +38566,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37895
38566
|
param2.setValueAtTime(value(0), at3);
|
|
37896
38567
|
for (let step = 1; step <= CROSSFADE_STEPS; step++) param2.linearRampToValueAtTime(value(step / CROSSFADE_STEPS), at3 + seconds * step / CROSSFADE_STEPS);
|
|
37897
38568
|
};
|
|
38569
|
+
var loopRate = (sound3, frequency) => sound3.baseFrequency && sound3.baseFrequency > 0 && frequency > 0 ? Math.max(RATE_RANGE[0], Math.min(RATE_RANGE[1], frequency / sound3.baseFrequency)) : 1;
|
|
37898
38570
|
function createSampleLoopHandle(sound3, host, volume = 0) {
|
|
37899
38571
|
const crossfade = loopCrossfade(sound3) ?? DEFAULT_LOOP_CROSSFADE;
|
|
37900
38572
|
let level = volume;
|
|
@@ -37904,13 +38576,17 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37904
38576
|
let segments = [];
|
|
37905
38577
|
let last;
|
|
37906
38578
|
let timer;
|
|
38579
|
+
let panner;
|
|
38580
|
+
let rate = 1;
|
|
38581
|
+
let position;
|
|
37907
38582
|
const entry2 = {
|
|
37908
38583
|
get created() {
|
|
37909
38584
|
return master !== void 0;
|
|
37910
38585
|
},
|
|
37911
38586
|
rewire() {
|
|
37912
|
-
master
|
|
37913
|
-
|
|
38587
|
+
const out = panner ?? master;
|
|
38588
|
+
out?.disconnect();
|
|
38589
|
+
out?.connect(host.output(sound3.bus));
|
|
37914
38590
|
},
|
|
37915
38591
|
stop() {
|
|
37916
38592
|
stopped = true;
|
|
@@ -37927,23 +38603,29 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37927
38603
|
segments = [];
|
|
37928
38604
|
master?.disconnect();
|
|
37929
38605
|
master = void 0;
|
|
38606
|
+
panner?.disconnect();
|
|
38607
|
+
panner = void 0;
|
|
37930
38608
|
fallback2?.stop();
|
|
37931
38609
|
fallback2 = void 0;
|
|
37932
38610
|
host.unregister(entry2);
|
|
37933
38611
|
}
|
|
37934
38612
|
};
|
|
37935
|
-
const
|
|
38613
|
+
const nextTake = () => {
|
|
37936
38614
|
const takes2 = sound3.close;
|
|
37937
38615
|
const take = pickTake(takes2.length, last, host.random);
|
|
37938
38616
|
last = take;
|
|
37939
38617
|
const ref = takes2[take];
|
|
37940
|
-
|
|
38618
|
+
const buffer = ref ? host.buffer(ref.url) : void 0;
|
|
38619
|
+
return ref && buffer ? { buffer, ref } : void 0;
|
|
37941
38620
|
};
|
|
37942
38621
|
const schedule = (context, output, at3, first) => {
|
|
37943
|
-
const
|
|
37944
|
-
if (!
|
|
38622
|
+
const next = nextTake();
|
|
38623
|
+
if (!next) return void 0;
|
|
38624
|
+
const { buffer, ref } = next;
|
|
38625
|
+
const offset = Math.max(0, Math.min(ref.offset ?? 0, buffer.duration));
|
|
37945
38626
|
const source = context.createBufferSource();
|
|
37946
38627
|
source.buffer = buffer;
|
|
38628
|
+
source.playbackRate.value = rate;
|
|
37947
38629
|
const gain = context.createGain();
|
|
37948
38630
|
source.connect(gain);
|
|
37949
38631
|
gain.connect(output);
|
|
@@ -37951,15 +38633,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37951
38633
|
if (buffer.duration < 2 * crossfade || sound3.close.length === 1) {
|
|
37952
38634
|
source.loop = true;
|
|
37953
38635
|
if (!first) ramp2(gain.gain, "in", at3, Math.max(1e-3, fade));
|
|
37954
|
-
source.start(at3);
|
|
38636
|
+
source.start(at3, offset);
|
|
37955
38637
|
segments.push({ source, gain, end: Number.POSITIVE_INFINITY });
|
|
37956
38638
|
return void 0;
|
|
37957
38639
|
}
|
|
37958
38640
|
if (first) gain.gain.setValueAtTime(1, at3);
|
|
37959
38641
|
else ramp2(gain.gain, "in", at3, fade);
|
|
37960
|
-
const end3 = at3 + buffer.duration;
|
|
38642
|
+
const end3 = at3 + (buffer.duration - offset) / rate;
|
|
37961
38643
|
ramp2(gain.gain, "out", end3 - fade, fade);
|
|
37962
|
-
source.start(at3);
|
|
38644
|
+
source.start(at3, offset);
|
|
37963
38645
|
source.stop(end3);
|
|
37964
38646
|
segments.push({ source, gain, end: end3 });
|
|
37965
38647
|
source.onended = () => {
|
|
@@ -37980,14 +38662,26 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37980
38662
|
pump(context, output, next, false);
|
|
37981
38663
|
}, wait);
|
|
37982
38664
|
};
|
|
37983
|
-
const
|
|
38665
|
+
const spatial = () => {
|
|
38666
|
+
if (!position || !host.listener) return 1;
|
|
38667
|
+
return falloffGain(sound3.falloff ?? DEFAULT_SAMPLE_FALLOFF, 1, listenerDistance(host.listener(), position, host.distance));
|
|
38668
|
+
};
|
|
38669
|
+
const fileLevel = () => level * (sound3.gain ?? 1) * spatial();
|
|
38670
|
+
const place = (context) => {
|
|
38671
|
+
if (panner && position && host.listener) panner.pan.setTargetAtTime(panFor(host.listener(), position), context.currentTime, VOLUME_SMOOTHING);
|
|
38672
|
+
};
|
|
37984
38673
|
const startFiles = () => {
|
|
37985
38674
|
if (stopped || master || !host.isReady(sound3)) return master !== void 0;
|
|
37986
38675
|
const context = host.ready();
|
|
37987
38676
|
if (!context) return false;
|
|
37988
38677
|
master = context.createGain();
|
|
37989
38678
|
master.gain.setValueAtTime(fileLevel(), context.currentTime);
|
|
37990
|
-
|
|
38679
|
+
if (sound3.pan !== false && position && typeof context.createStereoPanner === "function") {
|
|
38680
|
+
panner = context.createStereoPanner();
|
|
38681
|
+
if (host.listener) panner.pan.value = panFor(host.listener(), position);
|
|
38682
|
+
master.connect(panner);
|
|
38683
|
+
panner.connect(host.output(sound3.bus));
|
|
38684
|
+
} else master.connect(host.output(sound3.bus));
|
|
37991
38685
|
host.register(entry2);
|
|
37992
38686
|
pump(context, master, context.currentTime, true);
|
|
37993
38687
|
if (fallback2) {
|
|
@@ -38013,9 +38707,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38013
38707
|
set(next) {
|
|
38014
38708
|
if (stopped) return;
|
|
38015
38709
|
if (next.volume !== void 0) level = host.muted(sound3.bus) ? 0 : Math.max(0, next.volume);
|
|
38710
|
+
if (next.position) position = next.position;
|
|
38711
|
+
if (next.frequency !== void 0 && sound3.baseFrequency) rate = loopRate(sound3, next.frequency);
|
|
38016
38712
|
if (level > 0) ensure();
|
|
38017
38713
|
const context = host.ready();
|
|
38018
|
-
if (master && context)
|
|
38714
|
+
if (master && context) {
|
|
38715
|
+
master.gain.setTargetAtTime(fileLevel(), context.currentTime, VOLUME_SMOOTHING);
|
|
38716
|
+
place(context);
|
|
38717
|
+
if (next.frequency !== void 0 && sound3.baseFrequency) for (const segment of segments) segment.source.playbackRate.setTargetAtTime(rate, context.currentTime, RATE_SMOOTHING);
|
|
38718
|
+
}
|
|
38019
38719
|
fallback2?.set(next.volume === void 0 ? next : { ...next, volume: level });
|
|
38020
38720
|
},
|
|
38021
38721
|
stop: entry2.stop
|
|
@@ -38118,9 +38818,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38118
38818
|
};
|
|
38119
38819
|
return queue;
|
|
38120
38820
|
}
|
|
38121
|
-
var end = (
|
|
38122
|
-
var firstFilter = (
|
|
38123
|
-
var offsetOf = (
|
|
38821
|
+
var end = (layer3, start) => start + layer3.duration + layer3.tail;
|
|
38822
|
+
var firstFilter = (layer3) => layer3.filters?.bank[0];
|
|
38823
|
+
var offsetOf = (layer3) => layer3.source.kind === "noise" ? layer3.source.offset : 0;
|
|
38124
38824
|
function setFilter(node, filter, time) {
|
|
38125
38825
|
if (!filter) return;
|
|
38126
38826
|
node.type = filter.type;
|
|
@@ -38129,28 +38829,28 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38129
38829
|
}
|
|
38130
38830
|
function realizeBurst(plan, target) {
|
|
38131
38831
|
const { context } = target;
|
|
38132
|
-
const
|
|
38133
|
-
const time = target.time +
|
|
38832
|
+
const layer3 = plan.layers[0];
|
|
38833
|
+
const time = target.time + layer3.at;
|
|
38134
38834
|
const gain = context.createGain();
|
|
38135
38835
|
gain.connect(target.output);
|
|
38136
|
-
const source = noiseSource(target,
|
|
38836
|
+
const source = noiseSource(target, layer3.source.kind === "noise" && layer3.source.loop);
|
|
38137
38837
|
const filter = context.createBiquadFilter();
|
|
38138
38838
|
source.connect(filter);
|
|
38139
38839
|
filter.connect(gain);
|
|
38140
|
-
setFilter(filter, firstFilter(
|
|
38141
|
-
applyEnvelope(gain.gain,
|
|
38142
|
-
source.start(time, offsetOf(
|
|
38143
|
-
source.stop(end(
|
|
38840
|
+
setFilter(filter, firstFilter(layer3), time);
|
|
38841
|
+
applyEnvelope(gain.gain, layer3.envelope, time);
|
|
38842
|
+
source.start(time, offsetOf(layer3));
|
|
38843
|
+
source.stop(end(layer3, time));
|
|
38144
38844
|
return voiceOf([source]);
|
|
38145
38845
|
}
|
|
38146
38846
|
function realizeScream(plan, target) {
|
|
38147
38847
|
const { context } = target;
|
|
38148
|
-
const
|
|
38149
|
-
const time = target.time +
|
|
38150
|
-
const source = noiseSource(target,
|
|
38848
|
+
const layer3 = plan.layers[0];
|
|
38849
|
+
const time = target.time + layer3.at;
|
|
38850
|
+
const source = noiseSource(target, layer3.source.kind === "noise" && layer3.source.loop);
|
|
38151
38851
|
const gain = context.createGain();
|
|
38152
38852
|
gain.connect(target.output);
|
|
38153
|
-
for (const band of
|
|
38853
|
+
for (const band of layer3.filters?.bank ?? []) {
|
|
38154
38854
|
const filter = context.createBiquadFilter();
|
|
38155
38855
|
filter.type = band.type;
|
|
38156
38856
|
if (band.q !== void 0) filter.Q.value = band.q;
|
|
@@ -38163,7 +38863,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38163
38863
|
level.connect(gain);
|
|
38164
38864
|
}
|
|
38165
38865
|
const sources = [source];
|
|
38166
|
-
const lfos =
|
|
38866
|
+
const lfos = layer3.modulators.map((modulator) => {
|
|
38167
38867
|
const lfo = context.createOscillator();
|
|
38168
38868
|
const depth = context.createGain();
|
|
38169
38869
|
if (modulator.wave) lfo.type = modulator.wave;
|
|
@@ -38173,75 +38873,75 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38173
38873
|
depth.connect(gain.gain);
|
|
38174
38874
|
return lfo;
|
|
38175
38875
|
});
|
|
38176
|
-
applyEnvelope(gain.gain,
|
|
38177
|
-
source.start(time, offsetOf(
|
|
38178
|
-
source.stop(end(
|
|
38876
|
+
applyEnvelope(gain.gain, layer3.envelope, time);
|
|
38877
|
+
source.start(time, offsetOf(layer3));
|
|
38878
|
+
source.stop(end(layer3, time));
|
|
38179
38879
|
for (const lfo of lfos) {
|
|
38180
38880
|
lfo.start(time);
|
|
38181
|
-
lfo.stop(end(
|
|
38881
|
+
lfo.stop(end(layer3, time));
|
|
38182
38882
|
sources.push(lfo);
|
|
38183
38883
|
}
|
|
38184
38884
|
return voiceOf(sources);
|
|
38185
38885
|
}
|
|
38186
38886
|
function realizeGroan(plan, target) {
|
|
38187
38887
|
const { context } = target;
|
|
38188
|
-
const
|
|
38189
|
-
const time = target.time +
|
|
38888
|
+
const layer3 = plan.layers[0];
|
|
38889
|
+
const time = target.time + layer3.at;
|
|
38190
38890
|
const oscillator = context.createOscillator();
|
|
38191
38891
|
const gain = context.createGain();
|
|
38192
38892
|
const filter = context.createBiquadFilter();
|
|
38193
|
-
const band = firstFilter(
|
|
38194
|
-
if (
|
|
38893
|
+
const band = firstFilter(layer3);
|
|
38894
|
+
if (layer3.source.kind === "osc") oscillator.type = layer3.source.wave;
|
|
38195
38895
|
if (band) {
|
|
38196
38896
|
filter.type = band.type;
|
|
38197
38897
|
if (band.q !== void 0) filter.Q.value = band.q;
|
|
38198
38898
|
}
|
|
38199
|
-
if (
|
|
38200
|
-
assign(oscillator.frequency,
|
|
38201
|
-
rampTo(oscillator.frequency,
|
|
38899
|
+
if (layer3.source.kind === "osc") {
|
|
38900
|
+
assign(oscillator.frequency, layer3.source.frequency, time);
|
|
38901
|
+
rampTo(oscillator.frequency, layer3.source.frequency, time);
|
|
38202
38902
|
}
|
|
38203
38903
|
if (band) assign(filter.frequency, band.frequency, time);
|
|
38204
|
-
applyEnvelope(gain.gain,
|
|
38904
|
+
applyEnvelope(gain.gain, layer3.envelope, time);
|
|
38205
38905
|
oscillator.connect(filter);
|
|
38206
38906
|
filter.connect(gain);
|
|
38207
38907
|
gain.connect(target.output);
|
|
38208
38908
|
oscillator.start(time);
|
|
38209
|
-
oscillator.stop(end(
|
|
38909
|
+
oscillator.stop(end(layer3, time));
|
|
38210
38910
|
return voiceOf([oscillator]);
|
|
38211
38911
|
}
|
|
38212
38912
|
function realizeBoom(plan, target) {
|
|
38213
38913
|
const { context } = target;
|
|
38214
|
-
const
|
|
38215
|
-
const time = target.time +
|
|
38914
|
+
const layer3 = plan.layers[0];
|
|
38915
|
+
const time = target.time + layer3.at;
|
|
38216
38916
|
const oscillator = context.createOscillator();
|
|
38217
38917
|
const gain = context.createGain();
|
|
38218
|
-
if (
|
|
38219
|
-
oscillator.type =
|
|
38220
|
-
assign(oscillator.frequency,
|
|
38221
|
-
rampTo(oscillator.frequency,
|
|
38918
|
+
if (layer3.source.kind === "osc") {
|
|
38919
|
+
oscillator.type = layer3.source.wave;
|
|
38920
|
+
assign(oscillator.frequency, layer3.source.frequency, time);
|
|
38921
|
+
rampTo(oscillator.frequency, layer3.source.frequency, time);
|
|
38222
38922
|
}
|
|
38223
|
-
applyEnvelope(gain.gain,
|
|
38923
|
+
applyEnvelope(gain.gain, layer3.envelope, time);
|
|
38224
38924
|
oscillator.connect(gain);
|
|
38225
38925
|
gain.connect(target.output);
|
|
38226
38926
|
oscillator.start(time);
|
|
38227
|
-
oscillator.stop(end(
|
|
38927
|
+
oscillator.stop(end(layer3, time));
|
|
38228
38928
|
return voiceOf([oscillator]);
|
|
38229
38929
|
}
|
|
38230
38930
|
function realizeStatic(plan, target) {
|
|
38231
38931
|
const { context } = target;
|
|
38232
|
-
const
|
|
38233
|
-
const time = target.time +
|
|
38932
|
+
const layer3 = plan.layers[0];
|
|
38933
|
+
const time = target.time + layer3.at;
|
|
38234
38934
|
const gain = context.createGain();
|
|
38235
38935
|
const source = context.createBufferSource();
|
|
38236
38936
|
const filter = context.createBiquadFilter();
|
|
38237
38937
|
source.buffer = target.noise();
|
|
38238
|
-
setFilter(filter, firstFilter(
|
|
38239
|
-
applyEnvelope(gain.gain,
|
|
38938
|
+
setFilter(filter, firstFilter(layer3), time);
|
|
38939
|
+
applyEnvelope(gain.gain, layer3.envelope, time);
|
|
38240
38940
|
source.connect(filter);
|
|
38241
38941
|
filter.connect(gain);
|
|
38242
38942
|
gain.connect(target.output);
|
|
38243
|
-
source.start(time, offsetOf(
|
|
38244
|
-
source.stop(end(
|
|
38943
|
+
source.start(time, offsetOf(layer3));
|
|
38944
|
+
source.stop(end(layer3, time));
|
|
38245
38945
|
return voiceOf([source]);
|
|
38246
38946
|
}
|
|
38247
38947
|
function realizeChord(plan, target) {
|
|
@@ -38253,14 +38953,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38253
38953
|
const source = layers[index].source;
|
|
38254
38954
|
if (source.kind === "osc") oscillators[index].type = source.wave;
|
|
38255
38955
|
}
|
|
38256
|
-
layers.forEach((
|
|
38257
|
-
if (
|
|
38956
|
+
layers.forEach((layer3, index) => {
|
|
38957
|
+
if (layer3.source.kind === "osc") assign(oscillators[index].frequency, layer3.source.frequency, target.time + layer3.at);
|
|
38258
38958
|
});
|
|
38259
38959
|
applyEnvelope(gain.gain, layers[0].envelope, target.time + layers[0].at);
|
|
38260
38960
|
for (const oscillator of oscillators) oscillator.connect(gain);
|
|
38261
38961
|
gain.connect(target.output);
|
|
38262
|
-
layers.forEach((
|
|
38263
|
-
layers.forEach((
|
|
38962
|
+
layers.forEach((layer3, index) => oscillators[index].start(target.time + layer3.at));
|
|
38963
|
+
layers.forEach((layer3, index) => oscillators[index].stop(end(layer3, target.time + layer3.at)));
|
|
38264
38964
|
return voiceOf(oscillators);
|
|
38265
38965
|
}
|
|
38266
38966
|
function realizeCalls(plan, target) {
|
|
@@ -38272,32 +38972,32 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38272
38972
|
if (band) filter.type = band.type;
|
|
38273
38973
|
filter.connect(gain);
|
|
38274
38974
|
gain.connect(target.output);
|
|
38275
|
-
const oscillators = plan.layers.map((
|
|
38276
|
-
const time = target.time +
|
|
38975
|
+
const oscillators = plan.layers.map((layer3) => {
|
|
38976
|
+
const time = target.time + layer3.at;
|
|
38277
38977
|
const oscillator = context.createOscillator();
|
|
38278
|
-
if (
|
|
38279
|
-
oscillator.type =
|
|
38280
|
-
assign(oscillator.frequency,
|
|
38281
|
-
rampTo(oscillator.frequency,
|
|
38978
|
+
if (layer3.source.kind === "osc") {
|
|
38979
|
+
oscillator.type = layer3.source.wave;
|
|
38980
|
+
assign(oscillator.frequency, layer3.source.frequency, time);
|
|
38981
|
+
rampTo(oscillator.frequency, layer3.source.frequency, time);
|
|
38282
38982
|
}
|
|
38283
38983
|
if (band) {
|
|
38284
38984
|
assign(filter.frequency, band.frequency, time);
|
|
38285
38985
|
if (band.q !== void 0) filter.Q.value = band.q;
|
|
38286
38986
|
}
|
|
38287
38987
|
const envelope2 = context.createGain();
|
|
38288
|
-
applyEnvelope(envelope2.gain,
|
|
38988
|
+
applyEnvelope(envelope2.gain, layer3.envelope, time);
|
|
38289
38989
|
oscillator.connect(envelope2);
|
|
38290
38990
|
envelope2.connect(filter);
|
|
38291
38991
|
oscillator.start(time);
|
|
38292
|
-
oscillator.stop(end(
|
|
38992
|
+
oscillator.stop(end(layer3, time));
|
|
38293
38993
|
return oscillator;
|
|
38294
38994
|
});
|
|
38295
38995
|
return voiceOf(oscillators);
|
|
38296
38996
|
}
|
|
38297
|
-
var end2 = (
|
|
38298
|
-
function outputStage2(plan,
|
|
38997
|
+
var end2 = (layer3, start) => start + layer3.duration + layer3.tail;
|
|
38998
|
+
function outputStage2(plan, layer3, target) {
|
|
38299
38999
|
const { context } = target;
|
|
38300
|
-
const level = gainNode(context,
|
|
39000
|
+
const level = gainNode(context, layer3.level);
|
|
38301
39001
|
let node = level;
|
|
38302
39002
|
if (plan.pan !== void 0 && typeof context.createStereoPanner === "function") {
|
|
38303
39003
|
const panner = context.createStereoPanner();
|
|
@@ -38306,54 +39006,54 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38306
39006
|
node = panner;
|
|
38307
39007
|
}
|
|
38308
39008
|
node.connect(target.output);
|
|
38309
|
-
if (
|
|
38310
|
-
const send = gainNode(context,
|
|
39009
|
+
if (layer3.wet && target.wet) {
|
|
39010
|
+
const send = gainNode(context, layer3.wet);
|
|
38311
39011
|
node.connect(send);
|
|
38312
39012
|
send.connect(target.wet);
|
|
38313
39013
|
}
|
|
38314
39014
|
return level;
|
|
38315
39015
|
}
|
|
38316
|
-
function realizeNoiseLayer(plan,
|
|
39016
|
+
function realizeNoiseLayer(plan, layer3, target) {
|
|
38317
39017
|
const { context } = target;
|
|
38318
|
-
const time = target.time +
|
|
38319
|
-
const source = noiseSource(target,
|
|
38320
|
-
const filters = (
|
|
39018
|
+
const time = target.time + layer3.at;
|
|
39019
|
+
const source = noiseSource(target, layer3.source.kind === "noise" && layer3.source.loop);
|
|
39020
|
+
const filters = (layer3.filters?.bank ?? []).map((filter) => {
|
|
38321
39021
|
const node = filterNode(context, filter, time);
|
|
38322
39022
|
rampTo(node.frequency, filter.frequency, time);
|
|
38323
39023
|
return node;
|
|
38324
39024
|
});
|
|
38325
39025
|
const envelope2 = context.createGain();
|
|
38326
|
-
applyEnvelope(envelope2.gain,
|
|
39026
|
+
applyEnvelope(envelope2.gain, layer3.envelope, time);
|
|
38327
39027
|
let tail = source;
|
|
38328
39028
|
for (const filter of filters) tail = tail.connect(filter);
|
|
38329
39029
|
tail.connect(envelope2);
|
|
38330
|
-
envelope2.connect(outputStage2(plan,
|
|
38331
|
-
source.start(time,
|
|
38332
|
-
source.stop(end2(
|
|
39030
|
+
envelope2.connect(outputStage2(plan, layer3, target));
|
|
39031
|
+
source.start(time, layer3.source.kind === "noise" ? layer3.source.offset : 0);
|
|
39032
|
+
source.stop(end2(layer3, time));
|
|
38333
39033
|
return [source];
|
|
38334
39034
|
}
|
|
38335
|
-
function realizeToneLayer(plan,
|
|
39035
|
+
function realizeToneLayer(plan, layer3, target) {
|
|
38336
39036
|
const { context } = target;
|
|
38337
|
-
const time = target.time +
|
|
39037
|
+
const time = target.time + layer3.at;
|
|
38338
39038
|
const oscillator = context.createOscillator();
|
|
38339
|
-
if (
|
|
38340
|
-
oscillator.type =
|
|
38341
|
-
assign(oscillator.frequency,
|
|
38342
|
-
rampTo(oscillator.frequency,
|
|
39039
|
+
if (layer3.source.kind === "osc") {
|
|
39040
|
+
oscillator.type = layer3.source.wave;
|
|
39041
|
+
assign(oscillator.frequency, layer3.source.frequency, time);
|
|
39042
|
+
rampTo(oscillator.frequency, layer3.source.frequency, time);
|
|
38343
39043
|
}
|
|
38344
39044
|
const envelope2 = context.createGain();
|
|
38345
|
-
applyEnvelope(envelope2.gain,
|
|
39045
|
+
applyEnvelope(envelope2.gain, layer3.envelope, time);
|
|
38346
39046
|
oscillator.connect(envelope2);
|
|
38347
|
-
envelope2.connect(outputStage2(plan,
|
|
39047
|
+
envelope2.connect(outputStage2(plan, layer3, target));
|
|
38348
39048
|
oscillator.start(time);
|
|
38349
|
-
oscillator.stop(end2(
|
|
39049
|
+
oscillator.stop(end2(layer3, time));
|
|
38350
39050
|
return [oscillator];
|
|
38351
39051
|
}
|
|
38352
|
-
function realizeVoiceLayer(plan,
|
|
38353
|
-
const source =
|
|
39052
|
+
function realizeVoiceLayer(plan, layer3, target) {
|
|
39053
|
+
const source = layer3.source;
|
|
38354
39054
|
if (source.kind !== "formant_voice") return [];
|
|
38355
39055
|
const { context } = target;
|
|
38356
|
-
const time = target.time +
|
|
39056
|
+
const time = target.time + layer3.at;
|
|
38357
39057
|
const oscillator = context.createOscillator();
|
|
38358
39058
|
oscillator.type = source.wave;
|
|
38359
39059
|
assign(oscillator.frequency, source.frequency, time);
|
|
@@ -38374,10 +39074,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38374
39074
|
for (const formant of formants) formant.connect(mix3);
|
|
38375
39075
|
breathLevel.connect(mix3);
|
|
38376
39076
|
const envelope2 = context.createGain();
|
|
38377
|
-
applyEnvelope(envelope2.gain,
|
|
39077
|
+
applyEnvelope(envelope2.gain, layer3.envelope, time);
|
|
38378
39078
|
mix3.connect(envelope2);
|
|
38379
|
-
envelope2.connect(outputStage2(plan,
|
|
38380
|
-
const stop = end2(
|
|
39079
|
+
envelope2.connect(outputStage2(plan, layer3, target));
|
|
39080
|
+
const stop = end2(layer3, time);
|
|
38381
39081
|
oscillator.start(time);
|
|
38382
39082
|
vibrato.start(time);
|
|
38383
39083
|
breath.start(time, source.breath.offset);
|
|
@@ -38387,24 +39087,24 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38387
39087
|
return [oscillator, vibrato, breath];
|
|
38388
39088
|
}
|
|
38389
39089
|
function realizeLayered(plan, target) {
|
|
38390
|
-
const sources = plan.layers.flatMap((
|
|
38391
|
-
if (
|
|
38392
|
-
if (
|
|
38393
|
-
return realizeVoiceLayer(plan,
|
|
39090
|
+
const sources = plan.layers.flatMap((layer3) => {
|
|
39091
|
+
if (layer3.source.kind === "noise") return realizeNoiseLayer(plan, layer3, target);
|
|
39092
|
+
if (layer3.source.kind === "osc") return realizeToneLayer(plan, layer3, target);
|
|
39093
|
+
return realizeVoiceLayer(plan, layer3, target);
|
|
38394
39094
|
});
|
|
38395
39095
|
return voiceOf(sources);
|
|
38396
39096
|
}
|
|
38397
39097
|
function realizeSiren(plan, target) {
|
|
38398
39098
|
const { context } = target;
|
|
38399
|
-
const
|
|
38400
|
-
const time = target.time +
|
|
39099
|
+
const layer3 = plan.layers[0];
|
|
39100
|
+
const time = target.time + layer3.at;
|
|
38401
39101
|
const oscillator = context.createOscillator();
|
|
38402
|
-
if (
|
|
38403
|
-
oscillator.type =
|
|
38404
|
-
assign(oscillator.frequency,
|
|
38405
|
-
rampTo(oscillator.frequency,
|
|
39102
|
+
if (layer3.source.kind === "osc") {
|
|
39103
|
+
oscillator.type = layer3.source.wave;
|
|
39104
|
+
assign(oscillator.frequency, layer3.source.frequency, time);
|
|
39105
|
+
rampTo(oscillator.frequency, layer3.source.frequency, time);
|
|
38406
39106
|
}
|
|
38407
|
-
const depths =
|
|
39107
|
+
const depths = layer3.modulators.map((modulator) => {
|
|
38408
39108
|
const lfo = context.createOscillator();
|
|
38409
39109
|
if (modulator.wave) lfo.type = modulator.wave;
|
|
38410
39110
|
lfo.frequency.value = modulator.rate;
|
|
@@ -38415,57 +39115,57 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38415
39115
|
});
|
|
38416
39116
|
const lfos = depths.map(({ lfo }) => lfo);
|
|
38417
39117
|
const envelope2 = context.createGain();
|
|
38418
|
-
applyEnvelope(envelope2.gain,
|
|
39118
|
+
applyEnvelope(envelope2.gain, layer3.envelope, time);
|
|
38419
39119
|
for (const { depth, target: modulated } of depths) if (modulated === "gain") depth.connect(envelope2.gain);
|
|
38420
|
-
const filters = (
|
|
39120
|
+
const filters = (layer3.filters?.bank ?? []).map((filter) => filterNode(context, filter, time));
|
|
38421
39121
|
let tail = oscillator;
|
|
38422
39122
|
for (const filter of filters) tail = tail.connect(filter);
|
|
38423
39123
|
tail.connect(envelope2);
|
|
38424
39124
|
envelope2.connect(target.output);
|
|
38425
|
-
if (
|
|
38426
|
-
const send = gainNode(context,
|
|
39125
|
+
if (layer3.wet && target.wet) {
|
|
39126
|
+
const send = gainNode(context, layer3.wet);
|
|
38427
39127
|
envelope2.connect(send);
|
|
38428
39128
|
send.connect(target.wet);
|
|
38429
39129
|
}
|
|
38430
|
-
const stop = end2(
|
|
39130
|
+
const stop = end2(layer3, time);
|
|
38431
39131
|
oscillator.start(time);
|
|
38432
39132
|
for (const lfo of lfos) lfo.start(time);
|
|
38433
39133
|
oscillator.stop(stop);
|
|
38434
39134
|
for (const lfo of lfos) lfo.stop(stop);
|
|
38435
39135
|
return voiceOf([oscillator, ...lfos]);
|
|
38436
39136
|
}
|
|
38437
|
-
function noiseLayer(
|
|
39137
|
+
function noiseLayer(layer3, target, time) {
|
|
38438
39138
|
const { context } = target;
|
|
38439
|
-
const source = noiseSource(target,
|
|
38440
|
-
const filters = (
|
|
39139
|
+
const source = noiseSource(target, layer3.source.kind === "noise" && layer3.source.loop);
|
|
39140
|
+
const filters = (layer3.filters?.bank ?? []).map((filter) => filterNode(context, filter, time));
|
|
38441
39141
|
const envelope2 = context.createGain();
|
|
38442
|
-
applyEnvelope(envelope2.gain,
|
|
39142
|
+
applyEnvelope(envelope2.gain, layer3.envelope, time);
|
|
38443
39143
|
let tail = source;
|
|
38444
39144
|
for (const filter of filters) tail = tail.connect(filter);
|
|
38445
39145
|
tail.connect(envelope2).connect(target.output);
|
|
38446
|
-
source.start(time,
|
|
38447
|
-
source.stop(time +
|
|
39146
|
+
source.start(time, layer3.source.kind === "noise" ? layer3.source.offset : 0);
|
|
39147
|
+
source.stop(time + layer3.duration + layer3.tail);
|
|
38448
39148
|
return source;
|
|
38449
39149
|
}
|
|
38450
|
-
function toneLayer(
|
|
39150
|
+
function toneLayer(layer3, target, time) {
|
|
38451
39151
|
const { context } = target;
|
|
38452
39152
|
const oscillator = context.createOscillator();
|
|
38453
|
-
if (
|
|
38454
|
-
oscillator.type =
|
|
38455
|
-
assign(oscillator.frequency,
|
|
38456
|
-
rampTo(oscillator.frequency,
|
|
39153
|
+
if (layer3.source.kind === "osc") {
|
|
39154
|
+
oscillator.type = layer3.source.wave;
|
|
39155
|
+
assign(oscillator.frequency, layer3.source.frequency, time);
|
|
39156
|
+
rampTo(oscillator.frequency, layer3.source.frequency, time);
|
|
38457
39157
|
}
|
|
38458
39158
|
const envelope2 = context.createGain();
|
|
38459
|
-
applyEnvelope(envelope2.gain,
|
|
39159
|
+
applyEnvelope(envelope2.gain, layer3.envelope, time);
|
|
38460
39160
|
oscillator.connect(envelope2).connect(target.output);
|
|
38461
39161
|
oscillator.start(time);
|
|
38462
|
-
oscillator.stop(time +
|
|
39162
|
+
oscillator.stop(time + layer3.duration + layer3.tail);
|
|
38463
39163
|
return oscillator;
|
|
38464
39164
|
}
|
|
38465
39165
|
function realizeWeapon(plan, target) {
|
|
38466
|
-
const sources = plan.layers.map((
|
|
38467
|
-
const time = target.time +
|
|
38468
|
-
return
|
|
39166
|
+
const sources = plan.layers.map((layer3) => {
|
|
39167
|
+
const time = target.time + layer3.at;
|
|
39168
|
+
return layer3.source.kind === "noise" ? noiseLayer(layer3, target, time) : toneLayer(layer3, target, time);
|
|
38469
39169
|
});
|
|
38470
39170
|
return voiceOf(sources);
|
|
38471
39171
|
}
|
|
@@ -38513,19 +39213,19 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38513
39213
|
rate: modulator.rate * rate,
|
|
38514
39214
|
...modulator.target === "frequency" ? { depth: modulator.depth * rate } : {}
|
|
38515
39215
|
});
|
|
38516
|
-
var tuneLayer = (
|
|
38517
|
-
...
|
|
38518
|
-
at:
|
|
38519
|
-
duration:
|
|
38520
|
-
tail:
|
|
38521
|
-
source: tuneSource(
|
|
38522
|
-
...
|
|
38523
|
-
modulators:
|
|
38524
|
-
envelope:
|
|
39216
|
+
var tuneLayer = (layer3, rate) => ({
|
|
39217
|
+
...layer3,
|
|
39218
|
+
at: layer3.at / rate,
|
|
39219
|
+
duration: layer3.duration / rate,
|
|
39220
|
+
tail: layer3.tail / rate,
|
|
39221
|
+
source: tuneSource(layer3.source, rate),
|
|
39222
|
+
...layer3.filters ? { filters: { ...layer3.filters, bank: layer3.filters.bank.map((filter) => tuneFilter(filter, rate)) } } : {},
|
|
39223
|
+
modulators: layer3.modulators.map((modulator) => tuneModulator(modulator, rate)),
|
|
39224
|
+
envelope: layer3.envelope.map((point) => ({ ...point, time: point.time / rate }))
|
|
38525
39225
|
});
|
|
38526
39226
|
function retunePlan(plan, rate) {
|
|
38527
39227
|
if (rate === 1 || !(rate > 0)) return plan;
|
|
38528
|
-
return { ...plan, length: plan.length / rate, layers: plan.layers.map((
|
|
39228
|
+
return { ...plan, length: plan.length / rate, layers: plan.layers.map((layer3) => tuneLayer(layer3, rate)) };
|
|
38529
39229
|
}
|
|
38530
39230
|
function createSetPicker() {
|
|
38531
39231
|
const last = /* @__PURE__ */ new Map();
|
|
@@ -38613,6 +39313,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38613
39313
|
}
|
|
38614
39314
|
};
|
|
38615
39315
|
}
|
|
39316
|
+
var TRIM_FADE = 0.04;
|
|
38616
39317
|
function realizeSample(plan, target) {
|
|
38617
39318
|
const context = target.context;
|
|
38618
39319
|
let head = target.output;
|
|
@@ -38634,16 +39335,26 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38634
39335
|
voice2.connect(head);
|
|
38635
39336
|
head = voice2;
|
|
38636
39337
|
const sources = [];
|
|
38637
|
-
for (const
|
|
38638
|
-
const buffer = target.buffer(
|
|
39338
|
+
for (const layer3 of plan.layers) {
|
|
39339
|
+
const buffer = target.buffer(layer3.url);
|
|
38639
39340
|
if (!buffer) continue;
|
|
38640
39341
|
const source = context.createBufferSource();
|
|
38641
39342
|
source.buffer = buffer;
|
|
38642
|
-
source.playbackRate.value =
|
|
38643
|
-
const gain = gainNode(context,
|
|
39343
|
+
source.playbackRate.value = layer3.rate;
|
|
39344
|
+
const gain = gainNode(context, layer3.gain);
|
|
38644
39345
|
source.connect(gain);
|
|
38645
39346
|
gain.connect(head);
|
|
38646
|
-
|
|
39347
|
+
const at3 = target.time + layer3.at;
|
|
39348
|
+
const offset = Math.max(0, Math.min(layer3.offset ?? 0, buffer.duration));
|
|
39349
|
+
if (layer3.duration === void 0) source.start(at3, offset);
|
|
39350
|
+
else {
|
|
39351
|
+
const duration = Math.max(0, Math.min(layer3.duration, buffer.duration - offset));
|
|
39352
|
+
const end3 = at3 + duration / layer3.rate;
|
|
39353
|
+
const fade = Math.min(TRIM_FADE, (end3 - at3) / 4);
|
|
39354
|
+
gain.gain.setValueAtTime(layer3.gain, end3 - fade);
|
|
39355
|
+
gain.gain.linearRampToValueAtTime(0, end3);
|
|
39356
|
+
source.start(at3, offset, duration);
|
|
39357
|
+
}
|
|
38647
39358
|
sources.push(source);
|
|
38648
39359
|
}
|
|
38649
39360
|
const realized = voiceOf(sources);
|
|
@@ -38663,7 +39374,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38663
39374
|
}
|
|
38664
39375
|
function sampleLength(plan, seconds) {
|
|
38665
39376
|
let length2 = 0;
|
|
38666
|
-
for (const
|
|
39377
|
+
for (const layer3 of plan.layers) {
|
|
39378
|
+
const file = seconds(layer3.url) ?? 0;
|
|
39379
|
+
const played = layer3.duration === void 0 ? file - (layer3.offset ?? 0) : Math.min(layer3.duration, file - (layer3.offset ?? 0));
|
|
39380
|
+
length2 = Math.max(length2, layer3.at + Math.max(0, played) / layer3.rate);
|
|
39381
|
+
}
|
|
38667
39382
|
return length2;
|
|
38668
39383
|
}
|
|
38669
39384
|
function limiterCurve2(knee, ceiling, range3, points = 2049) {
|
|
@@ -38677,8 +39392,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38677
39392
|
}
|
|
38678
39393
|
return curve;
|
|
38679
39394
|
}
|
|
38680
|
-
var usesNoise = (recipe2) => recipe2.layers.some((
|
|
38681
|
-
var planUsesNoise = (plan) => plan.layers.some((
|
|
39395
|
+
var usesNoise = (recipe2) => recipe2.layers.some((layer3) => layer3.source.kind !== "osc");
|
|
39396
|
+
var planUsesNoise = (plan) => plan.layers.some((layer3) => layer3.source.kind !== "osc");
|
|
38682
39397
|
function createAudioEngine(options = {}) {
|
|
38683
39398
|
const seed = options.seed ?? 1;
|
|
38684
39399
|
const registry = createSoundRegistry(options.banks);
|
|
@@ -38917,7 +39632,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38917
39632
|
level: plan.level,
|
|
38918
39633
|
distance: plan.distance,
|
|
38919
39634
|
...plan.pan === void 0 ? {} : { pan: plan.pan },
|
|
38920
|
-
layers: plan.layers.map((
|
|
39635
|
+
layers: plan.layers.map((layer3) => ({ role: layer3.role, url: layer3.url, take: layer3.take, rate: layer3.rate })),
|
|
38921
39636
|
...plan.tier ? { tier: plan.tier } : {}
|
|
38922
39637
|
});
|
|
38923
39638
|
voices.setLength(voiceId, sampleLength(plan, (url2) => sampleStore.seconds(url2)) + (playOptions.delay ?? 0));
|
|
@@ -39050,7 +39765,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
39050
39765
|
random: engineRandom,
|
|
39051
39766
|
register: loopHost.register,
|
|
39052
39767
|
unregister: loopHost.unregister,
|
|
39053
|
-
muted: (bus) => busSettings.get(bus)?.muted === true
|
|
39768
|
+
muted: (bus) => busSettings.get(bus)?.muted === true,
|
|
39769
|
+
listener: () => listener,
|
|
39770
|
+
...options.distance ? { distance: options.distance } : {}
|
|
39054
39771
|
},
|
|
39055
39772
|
loopOptions.volume
|
|
39056
39773
|
);
|
|
@@ -39507,6 +40224,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
39507
40224
|
}
|
|
39508
40225
|
return { id: options.id, samples };
|
|
39509
40226
|
}
|
|
40227
|
+
var CATALOG = new Map([...SFX_CATALOG, ...SFX_IMPACTS].map((entry2) => [entry2.id, entry2]));
|
|
39510
40228
|
var PT = {
|
|
39511
40229
|
group: "Som",
|
|
39512
40230
|
name: "Painel de som (arquivos e C1\u2013C10)",
|
|
@@ -39581,9 +40299,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
39581
40299
|
strengths: { light: "leve", medium: "m\xE9dio", heavy: "forte" },
|
|
39582
40300
|
states: { file: "A", synth: "S", missing: "F" },
|
|
39583
40301
|
criteria: { C1: "C1 Sincronia", C2: "C2 Certo p/ a\xE7\xE3o", C3: "C3 Dist\xE2ncia", C4: "C4 Posi\xE7\xE3o", C5: "C5 Varia\xE7\xE3o", C6: "C6 Volume", C7: "C7 Intensidade", C8: "C8 Cauda", C9: "C9 Rajada", C10: "C10 Escuta" },
|
|
39584
|
-
metrics: { source: "1 \xB7 Fonte do que tocou", chosen: "1 \xB7 Escolhido", matrix: "2 \xB7 Matriz", last: "\xDAltimo tocado", ab: "4 \xB7 A \xD7 B", blind: "4 \xB7 X", verdicts: "4 \xB7 Prefer\xEAncias", state: "5 \xB7 Medi\xE7\xE3o", count: "1 \xB7 Cat\xE1logo" },
|
|
40302
|
+
metrics: { source: "1 \xB7 Fonte do que tocou", chosen: "1 \xB7 Escolhido", matrix: "2 \xB7 Matriz", last: "\xDAltimo tocado", ab: "4 \xB7 A \xD7 B", blind: "4 \xB7 X", verdicts: "4 \xB7 Prefer\xEAncias", state: "5 \xB7 Medi\xE7\xE3o", count: "1 \xB7 Cat\xE1logo", unlicensed: "1 \xB7 Arquivo sem licen\xE7a" },
|
|
39585
40303
|
run: { idle: "parada", measuring: "medindo\u2026", done: "pronta", failed: "falhou", recording: "gravando\u2026", recorded: "grava\xE7\xE3o baixada" },
|
|
39586
|
-
words: { none: "\u2014", hidden: "? (revele)", prefers: "prefere", approved: "aprovado pelo dono" },
|
|
40304
|
+
words: { none: "\u2014", hidden: "? (revele)", prefers: "prefere", approved: "aprovado pelo dono", local_file: "arquivo do pacote local", sdk_file: "grava\xE7\xE3o do SDK", synth: "s\xEDntese do SDK" },
|
|
39587
40305
|
sources: { sdk: "SDK", user: "seu som", synth: "sintetizado" },
|
|
39588
40306
|
probe: "Fonte do som",
|
|
39589
40307
|
wall: "Parede (oclus\xE3o)",
|
|
@@ -39654,9 +40372,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
39654
40372
|
environments: { indoor: "indoor", outdoor: "outdoor" },
|
|
39655
40373
|
strengths: { light: "light", medium: "medium", heavy: "heavy" },
|
|
39656
40374
|
criteria: { C1: "C1 Sync", C2: "C2 Right sound", C3: "C3 Distance", C4: "C4 Position", C5: "C5 Variation", C6: "C6 Level", C7: "C7 Strength", C8: "C8 Tail", C9: "C9 Burst", C10: "C10 Listening" },
|
|
39657
|
-
metrics: { source: "1 \xB7 Source of what played", chosen: "1 \xB7 Chosen", matrix: "2 \xB7 Matrix", last: "Last played", ab: "4 \xB7 A \xD7 B", blind: "4 \xB7 X", verdicts: "4 \xB7 Preferences", state: "5 \xB7 Measurement", count: "1 \xB7 Catalogue" },
|
|
40375
|
+
metrics: { source: "1 \xB7 Source of what played", chosen: "1 \xB7 Chosen", matrix: "2 \xB7 Matrix", last: "Last played", ab: "4 \xB7 A \xD7 B", blind: "4 \xB7 X", verdicts: "4 \xB7 Preferences", state: "5 \xB7 Measurement", count: "1 \xB7 Catalogue", unlicensed: "1 \xB7 File without licence" },
|
|
39658
40376
|
run: { idle: "idle", measuring: "measuring\u2026", done: "done", failed: "failed", recording: "recording\u2026", recorded: "recording downloaded" },
|
|
39659
|
-
words: { none: "\u2014", hidden: "? (reveal)", prefers: "prefers", approved: "approved by the owner" },
|
|
40377
|
+
words: { none: "\u2014", hidden: "? (reveal)", prefers: "prefers", approved: "approved by the owner", local_file: "local pack file", sdk_file: "SDK recording", synth: "SDK synthesis" },
|
|
39660
40378
|
sources: { sdk: "SDK", user: "your sound", synth: "synthesized" },
|
|
39661
40379
|
probe: "Sound source",
|
|
39662
40380
|
wall: "Wall (occlusion)",
|
|
@@ -39727,6 +40445,66 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
39727
40445
|
};
|
|
39728
40446
|
}
|
|
39729
40447
|
var sceneMany = (count, make3) => Array.from({ length: count }, make3);
|
|
40448
|
+
var hz = (midi) => 440 * 2 ** ((midi - 69) / 12);
|
|
40449
|
+
var layer = (note2, beat, wave, level) => {
|
|
40450
|
+
const [at3, midi, beats] = note2;
|
|
40451
|
+
const length2 = beats * beat;
|
|
40452
|
+
return {
|
|
40453
|
+
at: at3 * beat,
|
|
40454
|
+
duration: length2,
|
|
40455
|
+
source: { kind: "osc", wave, frequency: { set: hz(midi) } },
|
|
40456
|
+
envelope: [[0, 1e-4, "set"], [0.01, level, "linear"], [Math.max(0.02, length2 * 0.9), level * 0.35, "linear"], [length2, 1e-4, "exp", "fixed"]]
|
|
40457
|
+
};
|
|
40458
|
+
};
|
|
40459
|
+
function radioTrack(spec) {
|
|
40460
|
+
const beat = 60 / spec.bpm;
|
|
40461
|
+
const recipes = Array.from({ length: spec.bars }, (_, bar2) => {
|
|
40462
|
+
const inBar = (notes) => notes.filter((n) => n[0] >= bar2 * 4 && n[0] < bar2 * 4 + 4).map((n) => [n[0] - bar2 * 4, n[1], n[2]]);
|
|
40463
|
+
const layers = [
|
|
40464
|
+
...inBar(spec.bass).map((n) => layer(n, beat, "triangle", 0.16)),
|
|
40465
|
+
...inBar(spec.chords).map((n) => layer(n, beat, "sine", 0.05)),
|
|
40466
|
+
...inBar(spec.melody).map((n) => layer(n, beat, spec.wave, 0.07))
|
|
40467
|
+
];
|
|
40468
|
+
return { id: `${spec.id}_${bar2}`, bus: "world", duration: 4 * beat, layers, falloff: { model: "none" } };
|
|
40469
|
+
});
|
|
40470
|
+
return { song: { id: spec.id, barSeconds: 4 * beat, bars: recipes.map((r) => r.id) }, recipes };
|
|
40471
|
+
}
|
|
40472
|
+
var chord = (bar2, root, minor = false) => [[bar2 * 4, root, 4], [bar2 * 4, root + (minor ? 3 : 4), 4], [bar2 * 4, root + 7, 4]];
|
|
40473
|
+
var bassLine = (roots, pattern) => roots.flatMap((root, bar2) => pattern.map((b) => [bar2 * 4 + b, root - 12, 0.9]));
|
|
40474
|
+
var TRACKS = [
|
|
40475
|
+
// a bright pop loop: I–V–vi–IV in C
|
|
40476
|
+
radioTrack({
|
|
40477
|
+
id: "radio_track_pop",
|
|
40478
|
+
bpm: 112,
|
|
40479
|
+
bars: 4,
|
|
40480
|
+
wave: "square",
|
|
40481
|
+
bass: bassLine([48, 55, 57, 53], [0, 1.5, 2, 3]),
|
|
40482
|
+
chords: [...chord(0, 60), ...chord(1, 55), ...chord(2, 57, true), ...chord(3, 53)],
|
|
40483
|
+
melody: [[0, 76, 1], [1, 74, 0.5], [1.5, 72, 1.5], [4, 74, 1], [5, 76, 1], [6, 79, 2], [8, 76, 1], [9, 74, 1], [10, 72, 2], [12, 72, 1], [13, 74, 1], [14, 72, 2]]
|
|
40484
|
+
}),
|
|
40485
|
+
// a syncopated loop in A minor, the bass on the off-beats
|
|
40486
|
+
radioTrack({
|
|
40487
|
+
id: "radio_track_groove",
|
|
40488
|
+
bpm: 100,
|
|
40489
|
+
bars: 4,
|
|
40490
|
+
wave: "triangle",
|
|
40491
|
+
bass: bassLine([57, 62, 64, 57], [0, 0.75, 1.5, 2.5, 3.25]),
|
|
40492
|
+
chords: [...chord(0, 57, true), ...chord(1, 62, true), ...chord(2, 64), ...chord(3, 57, true)],
|
|
40493
|
+
melody: [[0.5, 72, 0.5], [1.25, 76, 0.75], [2.5, 74, 1], [4.5, 77, 0.5], [5.25, 74, 0.75], [6.5, 72, 1.5], [8.5, 71, 0.5], [9.25, 74, 0.75], [10.5, 76, 1.5], [12.5, 72, 0.5], [13.25, 69, 2]]
|
|
40494
|
+
}),
|
|
40495
|
+
// a slow blues-like loop in F with a swung melody
|
|
40496
|
+
radioTrack({
|
|
40497
|
+
id: "radio_track_slow",
|
|
40498
|
+
bpm: 76,
|
|
40499
|
+
bars: 4,
|
|
40500
|
+
wave: "sine",
|
|
40501
|
+
bass: bassLine([53, 58, 53, 60], [0, 2]),
|
|
40502
|
+
chords: [...chord(0, 65), ...chord(1, 58), ...chord(2, 65), ...chord(3, 60)],
|
|
40503
|
+
melody: [[0, 72, 1.5], [1.67, 75, 0.33], [2, 77, 2], [4, 74, 1], [5, 72, 1], [6, 70, 2], [8, 72, 1.5], [9.67, 69, 0.33], [10, 65, 2], [12, 67, 1], [13, 70, 1], [14, 72, 2]]
|
|
40504
|
+
})
|
|
40505
|
+
];
|
|
40506
|
+
var RADIO_TRACKS = TRACKS.map((t) => t.song);
|
|
40507
|
+
var RADIO_BANK = { id: "vehicle_radio", sounds: TRACKS.flatMap((t) => t.recipes), loops: [] };
|
|
39730
40508
|
var FOLEY_FALLOFF = {
|
|
39731
40509
|
model: "inverse_square",
|
|
39732
40510
|
k: 0.02,
|
|
@@ -40333,11 +41111,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
40333
41111
|
...s.splash ? [sceneNoise({ type: "bandpass", f: s.splash.f * take.f, f2: s.splash.f2 * take.f, q: 1.4, d: s.splash.d * take.t * weight ** 0.4, vol: s.splash.vol * gait.vol * take.v * weight ** 0.5 })] : []
|
|
40334
41112
|
];
|
|
40335
41113
|
}
|
|
40336
|
-
var quieter = (level, layers) => layers.map((
|
|
40337
|
-
const gain =
|
|
40338
|
-
if (typeof gain === "number") return { ...
|
|
40339
|
-
if (Array.isArray(gain)) return { ...
|
|
40340
|
-
return
|
|
41114
|
+
var quieter = (level, layers) => layers.map((layer22) => {
|
|
41115
|
+
const gain = layer22.gain ?? 1;
|
|
41116
|
+
if (typeof gain === "number") return { ...layer22, gain: gain * level };
|
|
41117
|
+
if (Array.isArray(gain)) return { ...layer22, gain: [gain[0] * level, gain[1] * level] };
|
|
41118
|
+
return layer22;
|
|
40341
41119
|
});
|
|
40342
41120
|
var recipe = (id, layers, falloff, bus = "world") => ({ id, bus, pan: true, layers, falloff, sources: ["sdk"] });
|
|
40343
41121
|
var takeId = (id, index) => `${id}_${String(index + 1).padStart(2, "0")}`;
|
|
@@ -40353,7 +41131,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
40353
41131
|
(take) => quieter(LANDING_LEVEL, [
|
|
40354
41132
|
// both feet, a hair apart, then the knees taking the weight (a low body thump) and the clothes settling
|
|
40355
41133
|
...footLayers(surface, take, GAITS.run, LANDINGS[landing2].weight),
|
|
40356
|
-
...footLayers(surface, { ...take, v: take.v * 0.6 }, GAITS.run, LANDINGS[landing2].weight * 0.6).map((
|
|
41134
|
+
...footLayers(surface, { ...take, v: take.v * 0.6 }, GAITS.run, LANDINGS[landing2].weight * 0.6).map((layer22) => ({ ...layer22, at: (typeof layer22.at === "number" ? layer22.at : 0) + 0.018 * take.t })),
|
|
40357
41135
|
sceneTone({ f: 60 * take.f, f2: 38, d: 0.14 * LANDINGS[landing2].weight * take.t, vol: 0.22 * LANDINGS[landing2].weight ** 0.7 * take.v, delay: 0.02 }),
|
|
40358
41136
|
sceneNoise({ type: "bandpass", f: [1800, 2600], q: 0.8, d: 0.18, vol: LANDINGS[landing2].cloth * take.v, delay: 0.04 })
|
|
40359
41137
|
]),
|
|
@@ -40399,7 +41177,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
40399
41177
|
fall_damage: (take) => [
|
|
40400
41178
|
...BODY.body_fall(take),
|
|
40401
41179
|
sceneNoise({ type: "highpass", f: 2800, d: 0.02, vol: 0.35 * take.v, delay: 0.01 }),
|
|
40402
|
-
...voice({ f0: 170, f1: 110, d: 0.32, fA: 650, fB: 1150, noise: 0.25, vol: 0.32 })(take).map((
|
|
41180
|
+
...voice({ f0: 170, f1: 110, d: 0.32, fA: 650, fB: 1150, noise: 0.25, vol: 0.32 })(take).map((layer22) => ({ ...layer22, at: 0.08 }))
|
|
40403
41181
|
],
|
|
40404
41182
|
player_hurt: voice({ f0: 150, f1: 105, d: 0.26, fA: 620, fB: 1100, noise: 0.3, vol: 0.35 }),
|
|
40405
41183
|
player_breath_run: (take) => [
|
|
@@ -42472,7 +43250,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
42472
43250
|
if (base.space === "indoor") {
|
|
42473
43251
|
for (const voice2 of shot.voices) if (voice2.group === "tail") playGunshotVoice(voice2, extras);
|
|
42474
43252
|
}
|
|
42475
|
-
const layers = handle?.kind === "sample" ? handle.plan.layers.map((
|
|
43253
|
+
const layers = handle?.kind === "sample" ? handle.plan.layers.map((layer3) => ({ role: layer3.role, take: layer3.take, rate: layer3.rate })) : [];
|
|
42476
43254
|
options.onGunshot?.(shot, { ...base, take, pitch }, { kind: "sample", id: recorded, layers });
|
|
42477
43255
|
return;
|
|
42478
43256
|
}
|
|
@@ -43294,6 +44072,19 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
43294
44072
|
"drink",
|
|
43295
44073
|
"sticky"
|
|
43296
44074
|
]
|
|
44075
|
+
},
|
|
44076
|
+
{
|
|
44077
|
+
id: "mud",
|
|
44078
|
+
color: 4008988,
|
|
44079
|
+
opacity: 0.95,
|
|
44080
|
+
stainColor: 3811866,
|
|
44081
|
+
viscosity: 40,
|
|
44082
|
+
density: 1600,
|
|
44083
|
+
dryTime: 900,
|
|
44084
|
+
gloss: 0.4,
|
|
44085
|
+
tags: [
|
|
44086
|
+
"dirty"
|
|
44087
|
+
]
|
|
43297
44088
|
}
|
|
43298
44089
|
];
|
|
43299
44090
|
var LIQUIDS = liquids_default;
|
|
@@ -49899,6 +50690,273 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
49899
50690
|
return group;
|
|
49900
50691
|
}
|
|
49901
50692
|
|
|
50693
|
+
// src/models/rounded-box.ts
|
|
50694
|
+
var uvAlong = (THREE, faceDirection, normal, uvAxis, projectionAxis, radius, sideLength) => {
|
|
50695
|
+
const arcLength = 2 * Math.PI * radius / 4;
|
|
50696
|
+
const centerLength = Math.max(sideLength - 2 * radius, 0);
|
|
50697
|
+
const halfArc = Math.PI / 4;
|
|
50698
|
+
const projected = new THREE.Vector3().copy(normal);
|
|
50699
|
+
projected[projectionAxis] = 0;
|
|
50700
|
+
projected.normalize();
|
|
50701
|
+
const arcUvRatio = 0.5 * arcLength / (arcLength + centerLength);
|
|
50702
|
+
const arcAngleRatio = 1 - projected.angleTo(faceDirection) / halfArc;
|
|
50703
|
+
if (Math.sign(projected[uvAxis]) === 1) return arcAngleRatio * arcUvRatio;
|
|
50704
|
+
const centerUv = centerLength / (arcLength + centerLength);
|
|
50705
|
+
return centerUv + arcUvRatio + arcUvRatio * (1 - arcAngleRatio);
|
|
50706
|
+
};
|
|
50707
|
+
var FACES = [
|
|
50708
|
+
{ direction: [1, 0, 0], u: ["z", "y", false], v: ["y", "z", true] },
|
|
50709
|
+
{ direction: [-1, 0, 0], u: ["z", "y", true], v: ["y", "z", true] },
|
|
50710
|
+
{ direction: [0, 1, 0], u: ["x", "z", true], v: ["z", "x", false] },
|
|
50711
|
+
{ direction: [0, -1, 0], u: ["x", "z", true], v: ["z", "x", true] },
|
|
50712
|
+
{ direction: [0, 0, 1], u: ["x", "y", true], v: ["y", "x", true] },
|
|
50713
|
+
{ direction: [0, 0, -1], u: ["x", "y", false], v: ["y", "x", true] }
|
|
50714
|
+
];
|
|
50715
|
+
function createRoundedBoxGeometry(THREE, width, height, depth, segments, radius) {
|
|
50716
|
+
const count = segments * 2 + 1;
|
|
50717
|
+
const rounding = Math.min(width / 2, height / 2, depth / 2, radius);
|
|
50718
|
+
const geometry = new THREE.BoxGeometry(1, 1, 1, count, count, count);
|
|
50719
|
+
const flat2 = geometry.toNonIndexed();
|
|
50720
|
+
geometry.setIndex(null);
|
|
50721
|
+
geometry.setAttribute("position", flat2.attributes.position);
|
|
50722
|
+
geometry.setAttribute("normal", flat2.attributes.normal);
|
|
50723
|
+
geometry.setAttribute("uv", flat2.attributes.uv);
|
|
50724
|
+
const position = new THREE.Vector3();
|
|
50725
|
+
const normal = new THREE.Vector3();
|
|
50726
|
+
const box5 = new THREE.Vector3(width, height, depth).divideScalar(2).subScalar(rounding);
|
|
50727
|
+
const positions2 = geometry.attributes.position.array;
|
|
50728
|
+
const normals = geometry.attributes.normal.array;
|
|
50729
|
+
const uvs = geometry.attributes.uv.array;
|
|
50730
|
+
const faceTriangles = positions2.length / 6;
|
|
50731
|
+
const halfSegment = 0.5 / count;
|
|
50732
|
+
const sides = { x: width, y: height, z: depth };
|
|
50733
|
+
for (let i = 0, j = 0; i < positions2.length; i += 3, j += 2) {
|
|
50734
|
+
position.fromArray(positions2, i);
|
|
50735
|
+
normal.copy(position);
|
|
50736
|
+
normal.x -= Math.sign(normal.x) * halfSegment;
|
|
50737
|
+
normal.y -= Math.sign(normal.y) * halfSegment;
|
|
50738
|
+
normal.z -= Math.sign(normal.z) * halfSegment;
|
|
50739
|
+
normal.normalize();
|
|
50740
|
+
positions2[i] = box5.x * Math.sign(position.x) + normal.x * rounding;
|
|
50741
|
+
positions2[i + 1] = box5.y * Math.sign(position.y) + normal.y * rounding;
|
|
50742
|
+
positions2[i + 2] = box5.z * Math.sign(position.z) + normal.z * rounding;
|
|
50743
|
+
normals[i] = normal.x;
|
|
50744
|
+
normals[i + 1] = normal.y;
|
|
50745
|
+
normals[i + 2] = normal.z;
|
|
50746
|
+
const face = FACES[Math.floor(i / faceTriangles)];
|
|
50747
|
+
if (!face) continue;
|
|
50748
|
+
const direction = new THREE.Vector3(...face.direction);
|
|
50749
|
+
for (const [offset, [uvAxis, projectionAxis, mirrored]] of [[0, face.u], [1, face.v]]) {
|
|
50750
|
+
const value = uvAlong(THREE, direction, normal, uvAxis, projectionAxis, rounding, sides[uvAxis]);
|
|
50751
|
+
uvs[j + offset] = mirrored ? 1 - value : value;
|
|
50752
|
+
}
|
|
50753
|
+
}
|
|
50754
|
+
return geometry;
|
|
50755
|
+
}
|
|
50756
|
+
|
|
50757
|
+
// src/models/kit.ts
|
|
50758
|
+
var PI2 = Math.PI;
|
|
50759
|
+
var createMaterials = (THREE) => {
|
|
50760
|
+
const standard = (color2, roughness = 0.7, metalness = 0.2, extra = {}) => new THREE.MeshStandardMaterial({ color: color2, roughness, metalness, ...extra });
|
|
50761
|
+
const basic = (color2, extra = {}) => new THREE.MeshBasicMaterial({ color: color2, ...extra });
|
|
50762
|
+
const additive = { transparent: true, opacity: 0.95, blending: THREE.AdditiveBlending, depthWrite: false };
|
|
50763
|
+
const materials = {
|
|
50764
|
+
metal: standard(3422010, 0.42, 0.75),
|
|
50765
|
+
steel: standard(7106418, 0.32, 0.85),
|
|
50766
|
+
steelL: standard(9080208, 0.28, 0.9),
|
|
50767
|
+
dark: standard(1711133, 0.55, 0.5),
|
|
50768
|
+
poly: standard(2369058, 0.8, 0.05),
|
|
50769
|
+
olive: standard(4936241, 0.8, 0.05),
|
|
50770
|
+
tan: standard(10259043, 0.8, 0.05),
|
|
50771
|
+
wood: standard(4860951, 0.55, 0),
|
|
50772
|
+
woodL: standard(6175263, 0.55, 0),
|
|
50773
|
+
brass: standard(12819013, 0.28, 0.9),
|
|
50774
|
+
copper: standard(11561531, 0.3, 0.85),
|
|
50775
|
+
lead: standard(7171955, 0.5, 0.5),
|
|
50776
|
+
shell: standard(10692380, 0.5, 0.05),
|
|
50777
|
+
glass: standard(8364968, 0.05, 0.1, { transparent: true, opacity: 0.42 }),
|
|
50778
|
+
lens: standard(2311770, 0.05, 0.3, { transparent: true, opacity: 0.9, emissive: 399392 }),
|
|
50779
|
+
rubber: standard(1381653, 0.85, 0),
|
|
50780
|
+
white: standard(13617332, 0.8, 0),
|
|
50781
|
+
hole: standard(526343, 1, 0),
|
|
50782
|
+
bake: standard(5911072, 0.55, 0),
|
|
50783
|
+
rust: standard(7027230, 0.95, 0.3),
|
|
50784
|
+
rustD: standard(4860440, 0.95, 0.25),
|
|
50785
|
+
worn: standard(5593178, 0.6, 0.6),
|
|
50786
|
+
fire: basic(16742946),
|
|
50787
|
+
fire2: basic(16764762),
|
|
50788
|
+
flashA: basic(16757575, additive),
|
|
50789
|
+
flashB: basic(16773568, additive),
|
|
50790
|
+
smokeP: standard(9079430, 1, 0, { transparent: true, opacity: 0.35, depthWrite: false }),
|
|
50791
|
+
/** Launcher paints. */
|
|
50792
|
+
yellow: standard(11570978, 0.6, 0),
|
|
50793
|
+
red: standard(9313300, 0.45, 0.1),
|
|
50794
|
+
redPaint: standard(10691354, 0.35, 0.2),
|
|
50795
|
+
tape: standard(9079944, 0.9, 0),
|
|
50796
|
+
pipe: standard(10115634, 0.35, 0.8),
|
|
50797
|
+
green: standard(3818536, 0.75, 0.05),
|
|
50798
|
+
/** Explosive finishes: the molotov's bottle, the dynamite's paper, the C4's putty and the detonator's wire. */
|
|
50799
|
+
bottle: standard(3103284, 0.1, 0.1, { transparent: true, opacity: 0.72 }),
|
|
50800
|
+
dynamite: standard(10365471, 0.7, 0),
|
|
50801
|
+
c4: standard(7170636, 0.95, 0),
|
|
50802
|
+
wire: standard(11542560, 0.5, 0),
|
|
50803
|
+
/** Magazine finishes named by the options. */
|
|
50804
|
+
bakelite: standard(6958620, 0.6, 0),
|
|
50805
|
+
polyMag: standard(2763302, 0.85, 0)
|
|
50806
|
+
};
|
|
50807
|
+
markShared(...Object.values(materials));
|
|
50808
|
+
return materials;
|
|
50809
|
+
};
|
|
50810
|
+
var kits = /* @__PURE__ */ new WeakMap();
|
|
50811
|
+
function modelKit(host) {
|
|
50812
|
+
const cached = kits.get(host);
|
|
50813
|
+
if (cached) return cached;
|
|
50814
|
+
const THREE = shapeGeometries(host);
|
|
50815
|
+
const geometries = /* @__PURE__ */ new Map();
|
|
50816
|
+
const shadowed = (mesh3) => {
|
|
50817
|
+
mesh3.castShadow = true;
|
|
50818
|
+
mesh3.receiveShadow = true;
|
|
50819
|
+
return mesh3;
|
|
50820
|
+
};
|
|
50821
|
+
const place = (parent, mesh3, x, y, z) => {
|
|
50822
|
+
mesh3.position.set(x, y, z);
|
|
50823
|
+
parent.add(mesh3);
|
|
50824
|
+
return mesh3;
|
|
50825
|
+
};
|
|
50826
|
+
const kit = {
|
|
50827
|
+
THREE,
|
|
50828
|
+
M: createMaterials(THREE),
|
|
50829
|
+
roundness: null,
|
|
50830
|
+
group: () => new THREE.Group(),
|
|
50831
|
+
box(parent, w, h, d, material, x, y, z, rz = 0, ry = 0, rx = 0) {
|
|
50832
|
+
const radius = Math.min(w, h, d) * (kit.roundness ?? 0.2);
|
|
50833
|
+
const key2 = `${w.toFixed(4)},${h.toFixed(4)},${d.toFixed(4)},${radius.toFixed(5)}`;
|
|
50834
|
+
let geometry = geometries.get(key2);
|
|
50835
|
+
if (!geometry) {
|
|
50836
|
+
geometry = radius > 25e-5 ? createRoundedBoxGeometry(THREE, w, h, d, 2, radius) : new THREE.BoxGeometry(w, h, d);
|
|
50837
|
+
markShared(geometry);
|
|
50838
|
+
geometries.set(key2, geometry);
|
|
50839
|
+
}
|
|
50840
|
+
const mesh3 = place(parent, shadowed(new THREE.Mesh(geometry, material)), x, y, z);
|
|
50841
|
+
mesh3.rotation.set(rx, ry, rz);
|
|
50842
|
+
return mesh3;
|
|
50843
|
+
},
|
|
50844
|
+
cylinderX(parent, radius, length2, material, x, y, z, segments = 16, radiusEnd) {
|
|
50845
|
+
const mesh3 = shadowed(new THREE.Mesh(new THREE.CylinderGeometry(radiusEnd ?? radius, radius, length2, segments), material));
|
|
50846
|
+
mesh3.rotation.z = -PI2 / 2;
|
|
50847
|
+
return place(parent, mesh3, x, y, z);
|
|
50848
|
+
},
|
|
50849
|
+
cylinderY(parent, radius, height, material, x, y, z, segments = 16, radiusEnd) {
|
|
50850
|
+
return place(parent, shadowed(new THREE.Mesh(new THREE.CylinderGeometry(radiusEnd ?? radius, radius, height, segments), material)), x, y, z);
|
|
50851
|
+
},
|
|
50852
|
+
cylinderZ(parent, radius, length2, material, x, y, z, segments = 16) {
|
|
50853
|
+
const mesh3 = shadowed(new THREE.Mesh(new THREE.CylinderGeometry(radius, radius, length2, segments), material));
|
|
50854
|
+
mesh3.rotation.x = PI2 / 2;
|
|
50855
|
+
return place(parent, mesh3, x, y, z);
|
|
50856
|
+
},
|
|
50857
|
+
sphere(parent, radius, material, x, y, z, detail = 1) {
|
|
50858
|
+
return place(parent, shadowed(new THREE.Mesh(new THREE.IcosahedronGeometry(radius, detail), material)), x, y, z);
|
|
50859
|
+
},
|
|
50860
|
+
torus: (parent, geometry, material, x, y, z) => place(parent, shadowed(new THREE.Mesh(geometry, material)), x, y, z),
|
|
50861
|
+
mark(parent, x, y, z) {
|
|
50862
|
+
const object2 = new THREE.Object3D();
|
|
50863
|
+
object2.position.set(x, y, z);
|
|
50864
|
+
parent.add(object2);
|
|
50865
|
+
return object2;
|
|
50866
|
+
},
|
|
50867
|
+
pivot(parent, x = 0, y = 0, z = 0) {
|
|
50868
|
+
const group = new THREE.Group();
|
|
50869
|
+
group.position.set(x, y, z);
|
|
50870
|
+
parent.add(group);
|
|
50871
|
+
return group;
|
|
50872
|
+
}
|
|
50873
|
+
};
|
|
50874
|
+
kits.set(host, kit);
|
|
50875
|
+
return kit;
|
|
50876
|
+
}
|
|
50877
|
+
function heatify(glow, mesh3) {
|
|
50878
|
+
mesh3.material = mesh3.material.clone();
|
|
50879
|
+
glow.push(mesh3);
|
|
50880
|
+
return mesh3;
|
|
50881
|
+
}
|
|
50882
|
+
|
|
50883
|
+
// src/models/explosives.ts
|
|
50884
|
+
var grenade = (kit, group) => {
|
|
50885
|
+
const { M, sphere: sphere2, cylinderY, box: box5, torus: torus2, THREE } = kit;
|
|
50886
|
+
sphere2(group, 0.032, M.olive, 0, 0.032, 0, 1);
|
|
50887
|
+
cylinderY(group, 0.011, 0.022, M.metal, 0, 0.072, 0);
|
|
50888
|
+
box5(group, 0.012, 0.07, 6e-3, M.metal, 0.016, 0.05, 0, 0.2);
|
|
50889
|
+
torus2(group, new THREE.TorusGeometry(85e-4, 16e-4, 6, 12), M.steel, -0.012, 0.082, 0);
|
|
50890
|
+
kit.mark(group, 0, 0.032, 0).name = "handle";
|
|
50891
|
+
};
|
|
50892
|
+
var molotov = (kit, group) => {
|
|
50893
|
+
const { M, cylinderY, box: box5 } = kit;
|
|
50894
|
+
cylinderY(group, 0.036, 0.17, M.bottle, 0, 0.085, 0, 10);
|
|
50895
|
+
cylinderY(group, 0.012, 0.06, M.bottle, 0, 0.2, 0, 8, 0.036);
|
|
50896
|
+
box5(group, 0.03, 0.08, 0.02, M.white, 5e-3, 0.25, 0, 0.3);
|
|
50897
|
+
cylinderY(group, 0.02, 0.07, M.fire, 0.01, 0.31, 0, 6, 0).userData.flame = true;
|
|
50898
|
+
kit.mark(group, 0, 0.085, 0).name = "handle";
|
|
50899
|
+
};
|
|
50900
|
+
var pipeBomb = (kit, group) => {
|
|
50901
|
+
const { M, cylinderX, cylinderY } = kit;
|
|
50902
|
+
cylinderX(group, 0.025, 0.2, M.metal, 0, 0.03, 0, 8);
|
|
50903
|
+
cylinderX(group, 0.031, 0.025, M.dark, -0.1, 0.03, 0, 6);
|
|
50904
|
+
cylinderX(group, 0.031, 0.025, M.dark, 0.1, 0.03, 0, 6);
|
|
50905
|
+
cylinderY(group, 2e-3, 0.06, M.white, 0.1, 0.07, 0);
|
|
50906
|
+
kit.mark(group, 0, 0.03, 0).name = "handle";
|
|
50907
|
+
};
|
|
50908
|
+
var dynamite = (kit, group) => {
|
|
50909
|
+
const { M, cylinderX } = kit;
|
|
50910
|
+
for (const [z, y] of [[-0.015, 0], [0.015, 0], [0, 0.026]]) cylinderX(group, 0.014, 0.2, M.dynamite, 0, 0.016 + y, z, 8);
|
|
50911
|
+
cylinderX(group, 0.031, 0.03, M.dark, -0.04, 0.025, 0, 8);
|
|
50912
|
+
cylinderX(group, 0.031, 0.03, M.dark, 0.05, 0.025, 0, 8);
|
|
50913
|
+
cylinderX(group, 2e-3, 0.1, M.white, 0.14, 0.03, 0, 4);
|
|
50914
|
+
kit.mark(group, 0, 0.025, 0).name = "handle";
|
|
50915
|
+
};
|
|
50916
|
+
var c4 = (kit, group) => {
|
|
50917
|
+
const { M, box: box5, cylinderY } = kit;
|
|
50918
|
+
box5(group, 0.28, 0.05, 0.11, M.c4, 0, 0.025, 0);
|
|
50919
|
+
box5(group, 0.05, 0.03, 0.04, M.dark, 0.06, 0.065, 0);
|
|
50920
|
+
cylinderY(group, 4e-3, 0.05, M.metal, 0.03, 0.07, 0);
|
|
50921
|
+
box5(group, 0.24, 3e-3, 3e-3, M.wire, 0.18, 0.055, 0.02);
|
|
50922
|
+
box5(group, 0.24, 3e-3, 3e-3, M.metal, 0.18, 0.055, 0.03);
|
|
50923
|
+
kit.mark(group, 0, 0.025, 0).name = "handle";
|
|
50924
|
+
};
|
|
50925
|
+
var claymore = (kit, group) => {
|
|
50926
|
+
const { M, box: box5 } = kit;
|
|
50927
|
+
for (const i of [-1, 0, 1]) box5(group, 0.075, 0.083, 0.035, M.olive, i * 0.072, 0.12, Math.abs(i) * 0.012, 0, -i * 0.25);
|
|
50928
|
+
for (const [x, z] of [[-0.07, 0.03], [-0.07, -0.03], [0.07, 0.03], [0.07, -0.03]]) box5(group, 4e-3, 0.09, 4e-3, M.metal, x, 0.04, z, x > 0 ? -0.25 : 0.25);
|
|
50929
|
+
kit.mark(group, 0, 0.12, 0).name = "handle";
|
|
50930
|
+
};
|
|
50931
|
+
var flashbang = (kit, group) => {
|
|
50932
|
+
const { M, cylinderY, box: box5 } = kit;
|
|
50933
|
+
cylinderY(group, 0.022, 0.13, M.olive, 0, 0.065, 0, 10);
|
|
50934
|
+
for (let i = 0; i < 4; i++) cylinderY(group, 0.023, 8e-3, M.dark, 0, 0.025 + i * 0.028, 0, 10);
|
|
50935
|
+
cylinderY(group, 0.012, 0.02, M.metal, 0, 0.14, 0);
|
|
50936
|
+
box5(group, 0.01, 0.08, 5e-3, M.metal, 0.024, 0.1, 0, 0.15);
|
|
50937
|
+
kit.mark(group, 0, 0.065, 0).name = "handle";
|
|
50938
|
+
};
|
|
50939
|
+
var BUILDERS3 = {
|
|
50940
|
+
m67: grenade,
|
|
50941
|
+
molotov,
|
|
50942
|
+
pipe_bomb: pipeBomb,
|
|
50943
|
+
dynamite,
|
|
50944
|
+
c4,
|
|
50945
|
+
claymore,
|
|
50946
|
+
flashbang
|
|
50947
|
+
};
|
|
50948
|
+
var EXPLOSIVE_MODEL_IDS = Object.keys(BUILDERS3);
|
|
50949
|
+
var hasExplosiveModel = (explosiveId) => explosiveId in BUILDERS3;
|
|
50950
|
+
function buildExplosiveModel(THREE, explosiveId) {
|
|
50951
|
+
const builder = BUILDERS3[explosiveId];
|
|
50952
|
+
if (!builder) return void 0;
|
|
50953
|
+
const kit = modelKit(THREE);
|
|
50954
|
+
const group = markKitOrigin(kit.group(), { owner: "game-weapons-three", kind: "explosive", id: explosiveId });
|
|
50955
|
+
group.name = explosiveId;
|
|
50956
|
+
builder(kit, group);
|
|
50957
|
+
return group;
|
|
50958
|
+
}
|
|
50959
|
+
|
|
49902
50960
|
// src/weapon-item-model.ts
|
|
49903
50961
|
var SHIPPED_WEAPON_ITEM_MODELS = [
|
|
49904
50962
|
["wrench", { item: "adjustable_wrench" }],
|
|
@@ -49907,8 +50965,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
49907
50965
|
["crossbow", { turn: 1 }],
|
|
49908
50966
|
["knife", { flip: true }],
|
|
49909
50967
|
["meat_cleaver", { flip: true }],
|
|
49910
|
-
["screwdriver", { flip: true }]
|
|
50968
|
+
["screwdriver", { flip: true }],
|
|
50969
|
+
// the Itens do Vale Cinzento hammer is a claw hammer: the head and the two-pronged claw
|
|
50970
|
+
["claw_hammer", { item: "hammer" }]
|
|
49911
50971
|
];
|
|
50972
|
+
var hasThrowableModel = (def) => def.action?.kind === "throwable" && def.action.explosive !== void 0 && hasExplosiveModel(def.action.explosive);
|
|
50973
|
+
var buildThrowableModel = (THREE, def) => def.action?.kind === "throwable" && def.action.explosive !== void 0 ? buildExplosiveModel(THREE, def.action.explosive) : void 0;
|
|
49912
50974
|
var weaponPropsOver = (models) => {
|
|
49913
50975
|
const itemModelOf = (weaponId, items) => {
|
|
49914
50976
|
const id = models.get(weaponId)?.item ?? weaponId;
|
|
@@ -49924,7 +50986,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
49924
50986
|
get: (weaponId) => models.get(weaponId),
|
|
49925
50987
|
itemModelOf,
|
|
49926
50988
|
buildItemModel,
|
|
49927
|
-
buildModel: (THREE, def, items) => buildItemModel(THREE, def, items) ?? buildProp(THREE, weaponProp(def))
|
|
50989
|
+
buildModel: (THREE, def, items) => buildItemModel(THREE, def, items) ?? buildThrowableModel(THREE, def) ?? buildProp(THREE, weaponProp(def))
|
|
49928
50990
|
};
|
|
49929
50991
|
};
|
|
49930
50992
|
var defaultProps;
|
|
@@ -49936,6 +50998,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
49936
50998
|
|
|
49937
50999
|
// src/box-fx.ts
|
|
49938
51000
|
var EJECTS_ON_SHOT = /* @__PURE__ */ new Set(["pistol", "smg", "carbine", "rifle", "sniper", "shotgun"]);
|
|
51001
|
+
var SPOUTS = /* @__PURE__ */ new Set(["firearm", "flame", "heat", "extinguisher"]);
|
|
49939
51002
|
var DROPS_MAGAZINE = /* @__PURE__ */ new Set(["pistol", "smg", "carbine", "rifle", "sniper"]);
|
|
49940
51003
|
var CYCLES = /* @__PURE__ */ new Set(["shotgun_pump_12", "rifle_bolt_308"]);
|
|
49941
51004
|
var FALLBACK_ENERGY = 300;
|
|
@@ -49970,6 +51033,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
49970
51033
|
const q = new THREE.Quaternion();
|
|
49971
51034
|
const q2 = new THREE.Quaternion();
|
|
49972
51035
|
const pointForward = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI / 2);
|
|
51036
|
+
const frontOf = new THREE.Vector3();
|
|
49973
51037
|
const equip = (weapon) => {
|
|
49974
51038
|
if (model) hand.remove(model);
|
|
49975
51039
|
model = null;
|
|
@@ -49980,6 +51044,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
49980
51044
|
const length2 = new THREE.Box3().setFromObject(model).getSize(v).x;
|
|
49981
51045
|
rear = new THREE.Box3().setFromObject(model).min.x;
|
|
49982
51046
|
lengthMetres = length2;
|
|
51047
|
+
frontOf.copy(new THREE.Box3().setFromObject(model).getCenter(v)).setX(rear + length2);
|
|
49983
51048
|
model.quaternion.copy(pointForward);
|
|
49984
51049
|
hand.add(model);
|
|
49985
51050
|
inHand = def.id;
|
|
@@ -50080,6 +51145,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
50080
51145
|
inHand = null;
|
|
50081
51146
|
hold = null;
|
|
50082
51147
|
},
|
|
51148
|
+
muzzle() {
|
|
51149
|
+
if (!model || !def || !SPOUTS.has(def.action.kind)) return null;
|
|
51150
|
+
hand.updateMatrixWorld(true);
|
|
51151
|
+
const at3 = model.localToWorld(v.copy(frontOf));
|
|
51152
|
+
const along = v2.set(1, 0, 0).applyQuaternion(model.getWorldQuaternion(q2)).normalize();
|
|
51153
|
+
return { position: [at3.x, at3.y, at3.z], direction: [along.x, along.y, along.z], drawsFlash: false };
|
|
51154
|
+
},
|
|
50083
51155
|
handTargets() {
|
|
50084
51156
|
if (!model || !hold) return null;
|
|
50085
51157
|
hand.updateMatrixWorld(true);
|
|
@@ -51680,193 +52752,23 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
51680
52752
|
options: {
|
|
51681
52753
|
rpm: 3e3
|
|
51682
52754
|
}
|
|
51683
|
-
}
|
|
51684
|
-
|
|
51685
|
-
|
|
51686
|
-
|
|
51687
|
-
|
|
51688
|
-
|
|
51689
|
-
|
|
51690
|
-
|
|
51691
|
-
|
|
51692
|
-
|
|
51693
|
-
|
|
51694
|
-
|
|
51695
|
-
|
|
51696
|
-
|
|
51697
|
-
const centerUv = centerLength / (arcLength + centerLength);
|
|
51698
|
-
return centerUv + arcUvRatio + arcUvRatio * (1 - arcAngleRatio);
|
|
51699
|
-
};
|
|
51700
|
-
var FACES = [
|
|
51701
|
-
{ direction: [1, 0, 0], u: ["z", "y", false], v: ["y", "z", true] },
|
|
51702
|
-
{ direction: [-1, 0, 0], u: ["z", "y", true], v: ["y", "z", true] },
|
|
51703
|
-
{ direction: [0, 1, 0], u: ["x", "z", true], v: ["z", "x", false] },
|
|
51704
|
-
{ direction: [0, -1, 0], u: ["x", "z", true], v: ["z", "x", true] },
|
|
51705
|
-
{ direction: [0, 0, 1], u: ["x", "y", true], v: ["y", "x", true] },
|
|
51706
|
-
{ direction: [0, 0, -1], u: ["x", "y", false], v: ["y", "x", true] }
|
|
51707
|
-
];
|
|
51708
|
-
function createRoundedBoxGeometry(THREE, width, height, depth, segments, radius) {
|
|
51709
|
-
const count = segments * 2 + 1;
|
|
51710
|
-
const rounding = Math.min(width / 2, height / 2, depth / 2, radius);
|
|
51711
|
-
const geometry = new THREE.BoxGeometry(1, 1, 1, count, count, count);
|
|
51712
|
-
const flat2 = geometry.toNonIndexed();
|
|
51713
|
-
geometry.setIndex(null);
|
|
51714
|
-
geometry.setAttribute("position", flat2.attributes.position);
|
|
51715
|
-
geometry.setAttribute("normal", flat2.attributes.normal);
|
|
51716
|
-
geometry.setAttribute("uv", flat2.attributes.uv);
|
|
51717
|
-
const position = new THREE.Vector3();
|
|
51718
|
-
const normal = new THREE.Vector3();
|
|
51719
|
-
const box5 = new THREE.Vector3(width, height, depth).divideScalar(2).subScalar(rounding);
|
|
51720
|
-
const positions2 = geometry.attributes.position.array;
|
|
51721
|
-
const normals = geometry.attributes.normal.array;
|
|
51722
|
-
const uvs = geometry.attributes.uv.array;
|
|
51723
|
-
const faceTriangles = positions2.length / 6;
|
|
51724
|
-
const halfSegment = 0.5 / count;
|
|
51725
|
-
const sides = { x: width, y: height, z: depth };
|
|
51726
|
-
for (let i = 0, j = 0; i < positions2.length; i += 3, j += 2) {
|
|
51727
|
-
position.fromArray(positions2, i);
|
|
51728
|
-
normal.copy(position);
|
|
51729
|
-
normal.x -= Math.sign(normal.x) * halfSegment;
|
|
51730
|
-
normal.y -= Math.sign(normal.y) * halfSegment;
|
|
51731
|
-
normal.z -= Math.sign(normal.z) * halfSegment;
|
|
51732
|
-
normal.normalize();
|
|
51733
|
-
positions2[i] = box5.x * Math.sign(position.x) + normal.x * rounding;
|
|
51734
|
-
positions2[i + 1] = box5.y * Math.sign(position.y) + normal.y * rounding;
|
|
51735
|
-
positions2[i + 2] = box5.z * Math.sign(position.z) + normal.z * rounding;
|
|
51736
|
-
normals[i] = normal.x;
|
|
51737
|
-
normals[i + 1] = normal.y;
|
|
51738
|
-
normals[i + 2] = normal.z;
|
|
51739
|
-
const face = FACES[Math.floor(i / faceTriangles)];
|
|
51740
|
-
if (!face) continue;
|
|
51741
|
-
const direction = new THREE.Vector3(...face.direction);
|
|
51742
|
-
for (const [offset, [uvAxis, projectionAxis, mirrored]] of [[0, face.u], [1, face.v]]) {
|
|
51743
|
-
const value = uvAlong(THREE, direction, normal, uvAxis, projectionAxis, rounding, sides[uvAxis]);
|
|
51744
|
-
uvs[j + offset] = mirrored ? 1 - value : value;
|
|
52755
|
+
},
|
|
52756
|
+
m79: {
|
|
52757
|
+
builder: "breakLauncher",
|
|
52758
|
+
caliber: "40\xD746",
|
|
52759
|
+
length: 730,
|
|
52760
|
+
barrel: 356,
|
|
52761
|
+
options: {
|
|
52762
|
+
stock: "fixed",
|
|
52763
|
+
wood: 1,
|
|
52764
|
+
mag: "none",
|
|
52765
|
+
hg: "wood",
|
|
52766
|
+
hgFrac: 0.4,
|
|
52767
|
+
br: 0.022,
|
|
52768
|
+
hR: 0.05
|
|
51745
52769
|
}
|
|
51746
52770
|
}
|
|
51747
|
-
return geometry;
|
|
51748
|
-
}
|
|
51749
|
-
|
|
51750
|
-
// src/models/kit.ts
|
|
51751
|
-
var PI2 = Math.PI;
|
|
51752
|
-
var createMaterials = (THREE) => {
|
|
51753
|
-
const standard = (color2, roughness = 0.7, metalness = 0.2, extra = {}) => new THREE.MeshStandardMaterial({ color: color2, roughness, metalness, ...extra });
|
|
51754
|
-
const basic = (color2, extra = {}) => new THREE.MeshBasicMaterial({ color: color2, ...extra });
|
|
51755
|
-
const additive = { transparent: true, opacity: 0.95, blending: THREE.AdditiveBlending, depthWrite: false };
|
|
51756
|
-
const materials = {
|
|
51757
|
-
metal: standard(3422010, 0.42, 0.75),
|
|
51758
|
-
steel: standard(7106418, 0.32, 0.85),
|
|
51759
|
-
steelL: standard(9080208, 0.28, 0.9),
|
|
51760
|
-
dark: standard(1711133, 0.55, 0.5),
|
|
51761
|
-
poly: standard(2369058, 0.8, 0.05),
|
|
51762
|
-
olive: standard(4936241, 0.8, 0.05),
|
|
51763
|
-
tan: standard(10259043, 0.8, 0.05),
|
|
51764
|
-
wood: standard(4860951, 0.55, 0),
|
|
51765
|
-
woodL: standard(6175263, 0.55, 0),
|
|
51766
|
-
brass: standard(12819013, 0.28, 0.9),
|
|
51767
|
-
copper: standard(11561531, 0.3, 0.85),
|
|
51768
|
-
lead: standard(7171955, 0.5, 0.5),
|
|
51769
|
-
shell: standard(10692380, 0.5, 0.05),
|
|
51770
|
-
glass: standard(8364968, 0.05, 0.1, { transparent: true, opacity: 0.42 }),
|
|
51771
|
-
lens: standard(2311770, 0.05, 0.3, { transparent: true, opacity: 0.9, emissive: 399392 }),
|
|
51772
|
-
rubber: standard(1381653, 0.85, 0),
|
|
51773
|
-
white: standard(13617332, 0.8, 0),
|
|
51774
|
-
hole: standard(526343, 1, 0),
|
|
51775
|
-
bake: standard(5911072, 0.55, 0),
|
|
51776
|
-
rust: standard(7027230, 0.95, 0.3),
|
|
51777
|
-
rustD: standard(4860440, 0.95, 0.25),
|
|
51778
|
-
worn: standard(5593178, 0.6, 0.6),
|
|
51779
|
-
fire: basic(16742946),
|
|
51780
|
-
fire2: basic(16764762),
|
|
51781
|
-
flashA: basic(16757575, additive),
|
|
51782
|
-
flashB: basic(16773568, additive),
|
|
51783
|
-
smokeP: standard(9079430, 1, 0, { transparent: true, opacity: 0.35, depthWrite: false }),
|
|
51784
|
-
/** Launcher paints. */
|
|
51785
|
-
yellow: standard(11570978, 0.6, 0),
|
|
51786
|
-
red: standard(9313300, 0.45, 0.1),
|
|
51787
|
-
redPaint: standard(10691354, 0.35, 0.2),
|
|
51788
|
-
tape: standard(9079944, 0.9, 0),
|
|
51789
|
-
pipe: standard(10115634, 0.35, 0.8),
|
|
51790
|
-
green: standard(3818536, 0.75, 0.05),
|
|
51791
|
-
/** Magazine finishes named by the options. */
|
|
51792
|
-
bakelite: standard(6958620, 0.6, 0),
|
|
51793
|
-
polyMag: standard(2763302, 0.85, 0)
|
|
51794
|
-
};
|
|
51795
|
-
markShared(...Object.values(materials));
|
|
51796
|
-
return materials;
|
|
51797
52771
|
};
|
|
51798
|
-
var kits = /* @__PURE__ */ new WeakMap();
|
|
51799
|
-
function modelKit(host) {
|
|
51800
|
-
const cached = kits.get(host);
|
|
51801
|
-
if (cached) return cached;
|
|
51802
|
-
const THREE = shapeGeometries(host);
|
|
51803
|
-
const geometries = /* @__PURE__ */ new Map();
|
|
51804
|
-
const shadowed = (mesh3) => {
|
|
51805
|
-
mesh3.castShadow = true;
|
|
51806
|
-
mesh3.receiveShadow = true;
|
|
51807
|
-
return mesh3;
|
|
51808
|
-
};
|
|
51809
|
-
const place = (parent, mesh3, x, y, z) => {
|
|
51810
|
-
mesh3.position.set(x, y, z);
|
|
51811
|
-
parent.add(mesh3);
|
|
51812
|
-
return mesh3;
|
|
51813
|
-
};
|
|
51814
|
-
const kit = {
|
|
51815
|
-
THREE,
|
|
51816
|
-
M: createMaterials(THREE),
|
|
51817
|
-
roundness: null,
|
|
51818
|
-
group: () => new THREE.Group(),
|
|
51819
|
-
box(parent, w, h, d, material, x, y, z, rz = 0, ry = 0, rx = 0) {
|
|
51820
|
-
const radius = Math.min(w, h, d) * (kit.roundness ?? 0.2);
|
|
51821
|
-
const key2 = `${w.toFixed(4)},${h.toFixed(4)},${d.toFixed(4)},${radius.toFixed(5)}`;
|
|
51822
|
-
let geometry = geometries.get(key2);
|
|
51823
|
-
if (!geometry) {
|
|
51824
|
-
geometry = radius > 25e-5 ? createRoundedBoxGeometry(THREE, w, h, d, 2, radius) : new THREE.BoxGeometry(w, h, d);
|
|
51825
|
-
markShared(geometry);
|
|
51826
|
-
geometries.set(key2, geometry);
|
|
51827
|
-
}
|
|
51828
|
-
const mesh3 = place(parent, shadowed(new THREE.Mesh(geometry, material)), x, y, z);
|
|
51829
|
-
mesh3.rotation.set(rx, ry, rz);
|
|
51830
|
-
return mesh3;
|
|
51831
|
-
},
|
|
51832
|
-
cylinderX(parent, radius, length2, material, x, y, z, segments = 16, radiusEnd) {
|
|
51833
|
-
const mesh3 = shadowed(new THREE.Mesh(new THREE.CylinderGeometry(radiusEnd ?? radius, radius, length2, segments), material));
|
|
51834
|
-
mesh3.rotation.z = -PI2 / 2;
|
|
51835
|
-
return place(parent, mesh3, x, y, z);
|
|
51836
|
-
},
|
|
51837
|
-
cylinderY(parent, radius, height, material, x, y, z, segments = 16, radiusEnd) {
|
|
51838
|
-
return place(parent, shadowed(new THREE.Mesh(new THREE.CylinderGeometry(radiusEnd ?? radius, radius, height, segments), material)), x, y, z);
|
|
51839
|
-
},
|
|
51840
|
-
cylinderZ(parent, radius, length2, material, x, y, z, segments = 16) {
|
|
51841
|
-
const mesh3 = shadowed(new THREE.Mesh(new THREE.CylinderGeometry(radius, radius, length2, segments), material));
|
|
51842
|
-
mesh3.rotation.x = PI2 / 2;
|
|
51843
|
-
return place(parent, mesh3, x, y, z);
|
|
51844
|
-
},
|
|
51845
|
-
sphere(parent, radius, material, x, y, z, detail = 1) {
|
|
51846
|
-
return place(parent, shadowed(new THREE.Mesh(new THREE.IcosahedronGeometry(radius, detail), material)), x, y, z);
|
|
51847
|
-
},
|
|
51848
|
-
torus: (parent, geometry, material, x, y, z) => place(parent, shadowed(new THREE.Mesh(geometry, material)), x, y, z),
|
|
51849
|
-
mark(parent, x, y, z) {
|
|
51850
|
-
const object2 = new THREE.Object3D();
|
|
51851
|
-
object2.position.set(x, y, z);
|
|
51852
|
-
parent.add(object2);
|
|
51853
|
-
return object2;
|
|
51854
|
-
},
|
|
51855
|
-
pivot(parent, x = 0, y = 0, z = 0) {
|
|
51856
|
-
const group = new THREE.Group();
|
|
51857
|
-
group.position.set(x, y, z);
|
|
51858
|
-
parent.add(group);
|
|
51859
|
-
return group;
|
|
51860
|
-
}
|
|
51861
|
-
};
|
|
51862
|
-
kits.set(host, kit);
|
|
51863
|
-
return kit;
|
|
51864
|
-
}
|
|
51865
|
-
function heatify(glow, mesh3) {
|
|
51866
|
-
mesh3.material = mesh3.material.clone();
|
|
51867
|
-
glow.push(mesh3);
|
|
51868
|
-
return mesh3;
|
|
51869
|
-
}
|
|
51870
52772
|
|
|
51871
52773
|
// src/models/break-action.ts
|
|
51872
52774
|
function buildBreakAction(kit, options) {
|
|
@@ -51901,6 +52803,509 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
51901
52803
|
return { group, parts };
|
|
51902
52804
|
}
|
|
51903
52805
|
|
|
52806
|
+
// src/models/attachments/muzzle-brake.ts
|
|
52807
|
+
function buildBrake(kit, parent, kind, x, y, barrelRadius, heat = () => void 0) {
|
|
52808
|
+
const { M, box: box5, cylinderX } = kit;
|
|
52809
|
+
const scale = kind === 2 ? 3.2 : 2;
|
|
52810
|
+
const length2 = kind === 2 ? 0.12 : 0.06;
|
|
52811
|
+
heat(cylinderX(parent, barrelRadius * scale, length2, M.dark, x - length2 / 2, y, 0, kind === 2 ? 8 : 16));
|
|
52812
|
+
for (let i = 0; i < 3; i++) box5(parent, length2 * 0.16, barrelRadius * scale * 1.3, barrelRadius * scale * 2.2, M.hole, x - length2 * 0.25 - i * length2 * 0.25, y, 0);
|
|
52813
|
+
}
|
|
52814
|
+
|
|
52815
|
+
// src/models/capture.ts
|
|
52816
|
+
function captured(parent, draw2) {
|
|
52817
|
+
const before = parent.children.length;
|
|
52818
|
+
draw2();
|
|
52819
|
+
return parent.children.slice(before);
|
|
52820
|
+
}
|
|
52821
|
+
function recordFitting(parts, id, parent, draw2) {
|
|
52822
|
+
parts.fittings = { ...parts.fittings, [id]: captured(parent, draw2) };
|
|
52823
|
+
}
|
|
52824
|
+
|
|
52825
|
+
// src/models/details.ts
|
|
52826
|
+
var PI3 = Math.PI;
|
|
52827
|
+
function rail(kit, parent, x, length2, y, z, width, rotationX = 0) {
|
|
52828
|
+
const { M, box: box5 } = kit;
|
|
52829
|
+
const pivot = kit.pivot(parent, 0, y, z);
|
|
52830
|
+
pivot.rotation.x = rotationX;
|
|
52831
|
+
box5(pivot, length2, 5e-3, width, M.dark, x + length2 / 2, 0, 0);
|
|
52832
|
+
const slots = Math.floor(length2 / 95e-4);
|
|
52833
|
+
for (let i = 0; i < slots; i++) box5(pivot, 52e-4, 35e-4, width * 1.12, M.metal, x + 6e-3 + i * 95e-4, 35e-4, 0);
|
|
52834
|
+
return pivot;
|
|
52835
|
+
}
|
|
52836
|
+
function vents(kit, parent, x, length2, y, z, count, height) {
|
|
52837
|
+
for (let i = 0; i < count; i++) kit.box(parent, length2 / count * 0.45, height, 3e-3, kit.M.hole, x + (i + 0.5) * length2 / count, y, z);
|
|
52838
|
+
}
|
|
52839
|
+
function scope(kit, parent, kind, cx, cy, cz = 0) {
|
|
52840
|
+
const { M, box: box5, cylinderX, cylinderY, cylinderZ, THREE } = kit;
|
|
52841
|
+
if (kind === 1) {
|
|
52842
|
+
box5(parent, 0.044, 0.01, 0.028, M.dark, cx, cy + 5e-3, cz);
|
|
52843
|
+
cylinderX(parent, 0.0155, 0.034, M.dark, cx + 4e-3, cy + 0.026, cz, 18);
|
|
52844
|
+
cylinderX(parent, 0.0125, 2e-3, M.lens, cx + 0.022, cy + 0.026, cz, 18);
|
|
52845
|
+
cylinderY(parent, 4e-3, 6e-3, M.dark, cx + 4e-3, cy + 0.044, cz, 10);
|
|
52846
|
+
return;
|
|
52847
|
+
}
|
|
52848
|
+
if (kind === 2) {
|
|
52849
|
+
box5(parent, 0.07, 0.012, 0.026, M.dark, cx, cy + 6e-3, cz);
|
|
52850
|
+
cylinderX(parent, 0.016, 0.1, M.dark, cx - 0.01, cy + 0.032, cz, 18);
|
|
52851
|
+
cylinderX(parent, 0.016, 0.035, M.dark, cx + 0.055, cy + 0.032, cz, 18, 0.02);
|
|
52852
|
+
cylinderX(parent, 0.017, 2e-3, M.lens, cx + 0.073, cy + 0.032, cz, 18);
|
|
52853
|
+
cylinderY(parent, 7e-3, 0.012, M.dark, cx, cy + 0.052, cz, 12);
|
|
52854
|
+
box5(parent, 0.03, 0.01, 0.012, M.dark, cx - 0.01, cy + 0.054, cz);
|
|
52855
|
+
return;
|
|
52856
|
+
}
|
|
52857
|
+
const sleeve = kind === 4 ? 0.2 : 0.32;
|
|
52858
|
+
cylinderX(parent, 0.0135, sleeve * 0.55, M.dark, cx, cy + 0.045, cz, 18);
|
|
52859
|
+
cylinderX(parent, 0.0135, sleeve * 0.25, M.dark, cx + sleeve * 0.36, cy + 0.045, cz, 18, 0.026);
|
|
52860
|
+
cylinderX(parent, 0.026, 0.05, M.dark, cx + sleeve * 0.5, cy + 0.045, cz, 18);
|
|
52861
|
+
cylinderX(parent, 0.024, 2e-3, M.lens, cx + sleeve * 0.5 + 0.026, cy + 0.045, cz, 18);
|
|
52862
|
+
cylinderX(parent, 0.019, 0.06, M.dark, cx - sleeve * 0.38, cy + 0.045, cz, 18, 0.0135);
|
|
52863
|
+
cylinderX(parent, 0.019, 0.035, M.rubber, cx - sleeve * 0.38 - 0.045, cy + 0.045, cz, 18);
|
|
52864
|
+
cylinderX(parent, 0.017, 2e-3, M.lens, cx - sleeve * 0.38 - 0.063, cy + 0.045, cz, 18);
|
|
52865
|
+
cylinderY(parent, 0.01, 0.022, M.dark, cx, cy + 0.066, cz, 14);
|
|
52866
|
+
cylinderY(parent, 0.011, 4e-3, M.metal, cx, cy + 0.078, cz, 14);
|
|
52867
|
+
cylinderZ(parent, 0.01, 0.022, M.dark, cx, cy + 0.045, cz + 0.022, 14);
|
|
52868
|
+
for (const offset of [-0.07, 0.07]) {
|
|
52869
|
+
const ring3 = kit.torus(parent, new THREE.TorusGeometry(0.0155, 3e-3, 8, 20), M.dark, cx + offset, cy + 0.045, cz);
|
|
52870
|
+
ring3.rotation.y = PI3 / 2;
|
|
52871
|
+
box5(parent, 0.016, 0.03, 0.022, M.dark, cx + offset, cy + 0.018, cz);
|
|
52872
|
+
}
|
|
52873
|
+
}
|
|
52874
|
+
var buttpad = (kit, parent, x, y, height, width) => void kit.box(parent, 0.012, height, width, kit.M.rubber, x, y, 0);
|
|
52875
|
+
var swivel = (kit, parent, x, y) => void kit.torus(parent, new kit.THREE.TorusGeometry(6e-3, 15e-4, 6, 12), kit.M.metal, x, y, 0);
|
|
52876
|
+
|
|
52877
|
+
// src/models/attachments/bipod.ts
|
|
52878
|
+
function buildBipod(kit, parent, x, y) {
|
|
52879
|
+
const { M, box: box5, cylinderX } = kit;
|
|
52880
|
+
cylinderX(parent, 8e-3, 0.02, M.dark, x, y, 0, 12);
|
|
52881
|
+
for (const side of [-1, 1]) {
|
|
52882
|
+
const leg = kit.pivot(parent, x, y, side * 0.012);
|
|
52883
|
+
leg.rotation.set(side * 0.15, 0, -0.35);
|
|
52884
|
+
box5(leg, 6e-3, 0.2, 6e-3, M.dark, 0, -0.1, 0);
|
|
52885
|
+
box5(leg, 0.01, 6e-3, 0.01, M.rubber, 0, -0.2, 0);
|
|
52886
|
+
}
|
|
52887
|
+
}
|
|
52888
|
+
var buildBipodModel = ({ kit }) => {
|
|
52889
|
+
const group = kit.group();
|
|
52890
|
+
buildBipod(kit, group, 0, 0);
|
|
52891
|
+
return group;
|
|
52892
|
+
};
|
|
52893
|
+
|
|
52894
|
+
// src/models/rifle-fittings.ts
|
|
52895
|
+
var SCOPE_IDS = { 1: "red_dot", 2: "acog_4x", 3: "scope_3_9x", 4: "scope_6_24x" };
|
|
52896
|
+
function buildFittings(context, gripX) {
|
|
52897
|
+
const { kit, group, parts, options: o, furniture: furn, length: L, receiverStart: x0, receiverEnd: x1, receiverHeight: hR, receiverWidth: wR, barrelRadius: r, barrelY: by } = context;
|
|
52898
|
+
const { M, box: box5, cylinderX, cylinderZ, sphere: sphere2 } = kit;
|
|
52899
|
+
const middle = (x0 + x1) / 2;
|
|
52900
|
+
if (o.scope) recordFitting(parts, SCOPE_IDS[o.scope] ?? "scope", group, () => scope(kit, group, o.scope, middle + 0.03, hR / 2 + (o.rail ? 6e-3 : 0), o.scope === 4 ? -0.02 : 0));
|
|
52901
|
+
if (o.carry) {
|
|
52902
|
+
box5(group, 0.15, 0.026, 0.014, M.metal, middle, hR / 2 + 0.03, 0);
|
|
52903
|
+
box5(group, 0.012, 0.03, 0.014, M.metal, middle + 0.07, hR / 2 + 0.014, 0);
|
|
52904
|
+
box5(group, 0.012, 0.03, 0.014, M.metal, middle - 0.07, hR / 2 + 0.014, 0);
|
|
52905
|
+
}
|
|
52906
|
+
if (o.bipod) recordFitting(parts, "bipod", group, () => buildBipod(kit, group, x1 + (L - x1) * 0.45 + 0.04, by - 0.012));
|
|
52907
|
+
if (o.bolt) {
|
|
52908
|
+
const handle = kit.pivot(group, x1 - 0.045, by, 0);
|
|
52909
|
+
parts.boltHandle = handle;
|
|
52910
|
+
parts.boltHandleRest = handle.position.x;
|
|
52911
|
+
cylinderZ(handle, 42e-4, 0.05, M.steelL, 0, 0, wR / 2 + 0.022, 12);
|
|
52912
|
+
sphere2(handle, 95e-4, M.dark, 0, -4e-3, wR / 2 + 0.048, 1);
|
|
52913
|
+
cylinderX(group, hR * 0.3, 0.03, M.steel, x0 + 5e-3, by, 0, 16);
|
|
52914
|
+
}
|
|
52915
|
+
if (o.lever) {
|
|
52916
|
+
const lever = kit.pivot(group, gripX - 0.02, -hR / 2 - 0.01, 0);
|
|
52917
|
+
parts.lever = lever;
|
|
52918
|
+
box5(lever, 0.11, 6e-3, 0.012, M.metal, 0.055, -0.052, 0);
|
|
52919
|
+
box5(lever, 6e-3, 0.05, 0.012, M.metal, 3e-3, -0.028, 0);
|
|
52920
|
+
box5(lever, 6e-3, 0.05, 0.012, M.metal, 0.108, -0.028, 0);
|
|
52921
|
+
box5(lever, 0.04, 6e-3, 0.012, M.metal, 0.08, -2e-3, 0);
|
|
52922
|
+
box5(group, 0.03, 0.012, 3e-3, M.dark, x1 - 0.04, by, wR / 2 + 1e-3);
|
|
52923
|
+
}
|
|
52924
|
+
if (o.tube) {
|
|
52925
|
+
const tubeLength = (L - x1) * (o.tubeLen || 0.8);
|
|
52926
|
+
cylinderX(group, 0.0105, tubeLength, M.metal, x1 + tubeLength / 2, by - 0.023, 0, 16);
|
|
52927
|
+
cylinderX(group, 0.0125, 0.02, M.dark, x1 + tubeLength + 6e-3, by - 0.023, 0, 16);
|
|
52928
|
+
}
|
|
52929
|
+
if (o.pump) {
|
|
52930
|
+
const pump = kit.pivot(group);
|
|
52931
|
+
parts.pump = pump;
|
|
52932
|
+
box5(pump, 0.17, 0.042, 0.046, furn, x1 + 0.14, by - 0.022, 0);
|
|
52933
|
+
for (let i = 0; i < 8; i++) box5(pump, 6e-3, 0.044, 0.048, M.dark, x1 + 0.07 + i * 0.02, by - 0.022, 0);
|
|
52934
|
+
}
|
|
52935
|
+
if (o.heat) {
|
|
52936
|
+
cylinderX(group, r * 1.75, (L - x1) * 0.7, M.dark, x1 + (L - x1) * 0.4, by, 0, 12);
|
|
52937
|
+
for (let i = 0; i < 10; i++) box5(group, 8e-3, r * 1.5, 4e-3, M.hole, x1 + (L - x1) * (0.1 + i * 0.06), by + r * 0.8, r * 1.5);
|
|
52938
|
+
}
|
|
52939
|
+
if (o.bayo) box5(group, 0.025, 8e-3, 0.01, M.metal, L - 0.07, by - 0.016, 0);
|
|
52940
|
+
if (o.rod) cylinderX(group, 3e-3, (L - x1) * 0.85, M.steel, x1 + (L - x1) * 0.45, by - 0.014, 0, 8);
|
|
52941
|
+
}
|
|
52942
|
+
|
|
52943
|
+
// src/models/rifle-forend.ts
|
|
52944
|
+
var PI4 = Math.PI;
|
|
52945
|
+
function buildForend(context) {
|
|
52946
|
+
const { kit, group, options: o, furniture: furn, length: L, receiverEnd: x1, receiverHeight: hR, receiverWidth: wR, barrelRadius: r, barrelY: by } = context;
|
|
52947
|
+
const { M, box: box5 } = kit;
|
|
52948
|
+
const hasLongScope = (o.scope ?? 0) >= 3;
|
|
52949
|
+
if (!context.isTraditional && o.hg !== "none") {
|
|
52950
|
+
const handguardLength = (L - x1) * (o.hgFrac || 0.5);
|
|
52951
|
+
const hx = x1 + handguardLength / 2;
|
|
52952
|
+
const hh = hR * 0.8;
|
|
52953
|
+
if (o.hg === "rail") {
|
|
52954
|
+
box5(group, handguardLength, hh, wR * 1.04, M.dark, hx, by - 2e-3, 0);
|
|
52955
|
+
rail(kit, group, x1, handguardLength, by + hh / 2, 0, wR * 0.66);
|
|
52956
|
+
rail(kit, group, x1 + 0.01, handguardLength - 0.02, by - 2e-3, wR * 0.54, wR * 0.4, PI4 / 2);
|
|
52957
|
+
rail(kit, group, x1 + 0.01, handguardLength - 0.02, by - 2e-3, -wR * 0.54, wR * 0.4, -PI4 / 2);
|
|
52958
|
+
rail(kit, group, x1 + 0.01, handguardLength - 0.02, by - hh / 2, 0, wR * 0.6, PI4);
|
|
52959
|
+
} else {
|
|
52960
|
+
const material = o.hg === "wood" ? M.wood : furn;
|
|
52961
|
+
if (o.ak) {
|
|
52962
|
+
box5(group, handguardLength, hh * 0.55, wR * 1.08, material, hx, by - hh * 0.22, 0);
|
|
52963
|
+
box5(group, handguardLength * 0.75, hh * 0.35, wR * 0.7, material, hx - handguardLength * 0.1, by + r * 2.2, 0);
|
|
52964
|
+
} else {
|
|
52965
|
+
box5(group, handguardLength, hh, wR * 1.08, material, hx, by - 2e-3, 0);
|
|
52966
|
+
vents(kit, group, x1 + 0.01, handguardLength - 0.02, by + hh * 0.15, wR * 0.54 + 1e-3, Math.round(handguardLength / 0.025), hh * 0.3);
|
|
52967
|
+
vents(kit, group, x1 + 0.01, handguardLength - 0.02, by + hh * 0.15, -wR * 0.54 - 1e-3, Math.round(handguardLength / 0.025), hh * 0.3);
|
|
52968
|
+
}
|
|
52969
|
+
}
|
|
52970
|
+
if (!hasLongScope && !o.rail && o.ak) {
|
|
52971
|
+
box5(group, 0.03, 0.016, wR * 0.6, M.metal, x1 + 0.02, by + r * 2.5 + 0.01, 0);
|
|
52972
|
+
box5(group, 0.012, 4e-3, wR * 0.5, M.dark, x1 + 0.03, by + r * 2.5 + 0.019, 0);
|
|
52973
|
+
}
|
|
52974
|
+
}
|
|
52975
|
+
if (hasLongScope) return;
|
|
52976
|
+
const sightX = L - (o.ak ? 0.06 : 0.08);
|
|
52977
|
+
if (o.ak) {
|
|
52978
|
+
box5(group, 0.022, 0.022, wR * 0.6, M.metal, sightX, by + 8e-3, 0);
|
|
52979
|
+
box5(group, 6e-3, 0.024, 4e-3, M.metal, sightX, by + 0.026, 8e-3);
|
|
52980
|
+
box5(group, 6e-3, 0.024, 4e-3, M.metal, sightX, by + 0.026, -8e-3);
|
|
52981
|
+
box5(group, 3e-3, 0.016, 3e-3, M.dark, sightX, by + 0.022, 0);
|
|
52982
|
+
} else if (!o.rail || o.carry) {
|
|
52983
|
+
box5(group, 0.018, 0.014, wR * 0.55, M.dark, sightX, by + 8e-3, 0);
|
|
52984
|
+
box5(group, 0.012, 0.034, 8e-3, M.dark, sightX, by + 0.03, 0, -0.25);
|
|
52985
|
+
} else box5(group, 0.012, 0.024, 0.012, M.dark, sightX - 0.04, by + hR * 0.4 + 0.012, 0);
|
|
52986
|
+
}
|
|
52987
|
+
|
|
52988
|
+
// src/models/attachments/belt-box.ts
|
|
52989
|
+
function buildBeltBox(kit, belt) {
|
|
52990
|
+
const { M, box: box5, cylinderX } = kit;
|
|
52991
|
+
box5(belt, 0.11, 0.1, 0.08, M.olive, 0, 0, 0);
|
|
52992
|
+
box5(belt, 0.112, 0.012, 0.082, M.dark, 0, 0.046, 0);
|
|
52993
|
+
for (let i = 0; i < 7; i++) {
|
|
52994
|
+
cylinderX(belt, 42e-4, 0.034, M.brass, -0.04 + i * 0.012, 0.07, 0.035, 10);
|
|
52995
|
+
box5(belt, 6e-3, 6e-3, 0.012, M.metal, -0.04 + i * 0.012, 0.066, 0.035);
|
|
52996
|
+
}
|
|
52997
|
+
}
|
|
52998
|
+
|
|
52999
|
+
// src/models/attachments/drum.ts
|
|
53000
|
+
function buildDrum(kit, magazine) {
|
|
53001
|
+
const { M, box: box5, cylinderZ } = kit;
|
|
53002
|
+
cylinderZ(magazine, 0.075, 0.07, M.dark, 0.02, -0.085, 0, 22);
|
|
53003
|
+
cylinderZ(magazine, 0.05, 0.074, M.metal, 0.02, -0.085, 0, 18);
|
|
53004
|
+
box5(magazine, 0.05, 0.04, 0.03, M.dark, 0, -0.02, 0);
|
|
53005
|
+
}
|
|
53006
|
+
|
|
53007
|
+
// src/models/helical-magazine.ts
|
|
53008
|
+
var PI5 = Math.PI;
|
|
53009
|
+
var LENGTH = 0.26;
|
|
53010
|
+
var RADIUS = 0.026;
|
|
53011
|
+
var TURNS = 11;
|
|
53012
|
+
function buildHelicalMagazine(context) {
|
|
53013
|
+
const { kit, group, parts, receiverEnd, barrelY, barrelRadius } = context;
|
|
53014
|
+
const { M, cylinderX, box: box5 } = kit;
|
|
53015
|
+
const x = receiverEnd + LENGTH / 2 + 0.02;
|
|
53016
|
+
const y = barrelY - barrelRadius - RADIUS - 0.012;
|
|
53017
|
+
const magazine = kit.pivot(group, x, y, 0);
|
|
53018
|
+
parts.mag = magazine;
|
|
53019
|
+
cylinderX(magazine, RADIUS, LENGTH, M.dark, 0, 0, 0, 20);
|
|
53020
|
+
cylinderX(magazine, RADIUS * 1.06, 0.01, M.metal, -LENGTH / 2, 0, 0, 20);
|
|
53021
|
+
cylinderX(magazine, RADIUS * 1.06, 0.01, M.metal, LENGTH / 2, 0, 0, 20);
|
|
53022
|
+
for (let i = 0; i < TURNS; i++) box5(magazine, 0.012, RADIUS * 2.15, 0.014, M.metal, -LENGTH / 2 + (i + 0.5) * LENGTH / TURNS, 0, 0, 0, 0, i * PI5 / 4);
|
|
53023
|
+
box5(magazine, 0.05, 0.03, 0.03, M.dark, -LENGTH / 2 - 0.02, RADIUS * 0.4, 0);
|
|
53024
|
+
parts.magDrop = 0.16;
|
|
53025
|
+
return x;
|
|
53026
|
+
}
|
|
53027
|
+
|
|
53028
|
+
// src/models/rifle-controls.ts
|
|
53029
|
+
function buildGrip(context) {
|
|
53030
|
+
const { kit, group, parts, options: o, furniture: furn, receiverStart: x0, receiverHeight: hR, receiverWidth: wR } = context;
|
|
53031
|
+
const { M, box: box5 } = kit;
|
|
53032
|
+
const gx = x0 + (o.gripAt || 0.07);
|
|
53033
|
+
if (!context.isTraditional && o.grip !== "none") {
|
|
53034
|
+
const grip = kit.pivot(group, gx - 0.012, -hR / 2 - 0.046, 0);
|
|
53035
|
+
grip.rotation.z = -0.3;
|
|
53036
|
+
parts.grip = grip;
|
|
53037
|
+
box5(grip, 0.032, 0.105, 0.028, furn, 0, 0, 0);
|
|
53038
|
+
for (let i = 0; i < 3; i++) box5(grip, 6e-3, 0.012, 0.026, furn, 0.017, 0.022 - i * 0.02, 0);
|
|
53039
|
+
box5(grip, 0.034, 8e-3, 0.03, furn, 0, -0.052, 0);
|
|
53040
|
+
}
|
|
53041
|
+
box5(group, 0.06, 4e-3, 0.01, M.metal, gx + 0.03, -hR / 2 - 0.024, 0);
|
|
53042
|
+
box5(group, 4e-3, 0.022, 0.01, M.metal, gx + 0.06, -hR / 2 - 0.013, 0);
|
|
53043
|
+
parts.trigger = box5(group, 4e-3, 0.016, 4e-3, M.dark, gx + 0.024, -hR / 2 - 0.012, 0, 0.15);
|
|
53044
|
+
if (o.sel) parts.safety = box5(group, 0.016, 5e-3, 3e-3, M.dark, gx + 5e-3, -hR * 0.15, -wR / 2 - 2e-3, 0.4);
|
|
53045
|
+
return gx;
|
|
53046
|
+
}
|
|
53047
|
+
function buildMagazine(context, gx) {
|
|
53048
|
+
const { kit, group, parts, options: o, receiverStart: x0, receiverHeight: hR, receiverWidth: wR, receiverLength: RL } = context;
|
|
53049
|
+
const { M, box: box5 } = kit;
|
|
53050
|
+
if (o.mag === "helical") return buildHelicalMagazine(context);
|
|
53051
|
+
const mx = o.magAt != null ? x0 + o.magAt : gx + 0.075;
|
|
53052
|
+
const scale = o.magLen || 1;
|
|
53053
|
+
const magazine = kit.pivot(group, mx, -hR / 2, 0);
|
|
53054
|
+
parts.mag = magazine;
|
|
53055
|
+
const finish = o.magMat === "bakelite" ? M.bakelite : o.magMat === "poly" ? M.polyMag : void 0;
|
|
53056
|
+
if (o.mag === "curved") {
|
|
53057
|
+
let px = 0;
|
|
53058
|
+
let py = 0;
|
|
53059
|
+
const material = finish ?? M.metal;
|
|
53060
|
+
for (const angle of [0.06, 0.22, 0.38]) {
|
|
53061
|
+
const length2 = 0.07 * scale;
|
|
53062
|
+
const cx = px + Math.sin(angle) * length2 / 2;
|
|
53063
|
+
const cy = py - Math.cos(angle) * length2 / 2;
|
|
53064
|
+
box5(magazine, 0.052, length2 + 4e-3, 0.024, material, cx, cy, 0, angle);
|
|
53065
|
+
box5(magazine, 0.04, length2 * 0.8, 0.026, M.dark, cx, cy, 0, angle);
|
|
53066
|
+
px += Math.sin(angle) * length2;
|
|
53067
|
+
py -= Math.cos(angle) * length2;
|
|
53068
|
+
}
|
|
53069
|
+
box5(magazine, 0.058, 8e-3, 0.028, material, px, py, 0, 0.38);
|
|
53070
|
+
parts.magDrop = 0.07 * scale * 3 + 0.04;
|
|
53071
|
+
} else if (o.mag === "box") {
|
|
53072
|
+
const length2 = 0.13 * scale;
|
|
53073
|
+
const curve = o.curve || 0;
|
|
53074
|
+
const segment = length2 / 3;
|
|
53075
|
+
const material = finish ?? M.dark;
|
|
53076
|
+
let px = 0;
|
|
53077
|
+
let py = 0;
|
|
53078
|
+
let angle = 0.08;
|
|
53079
|
+
for (let i = 0; i < 3; i++) {
|
|
53080
|
+
angle = 0.08 + curve * i;
|
|
53081
|
+
const cx = px + Math.sin(angle) * segment / 2;
|
|
53082
|
+
const cy = py - Math.cos(angle) * segment / 2;
|
|
53083
|
+
box5(magazine, 0.05, segment + 4e-3, 0.024, material, cx, cy, 0, angle);
|
|
53084
|
+
box5(magazine, 0.04, 3e-3, 0.026, M.metal, cx, cy, 0, angle);
|
|
53085
|
+
px += Math.sin(angle) * segment;
|
|
53086
|
+
py -= Math.cos(angle) * segment;
|
|
53087
|
+
}
|
|
53088
|
+
box5(magazine, 0.056, 7e-3, 0.028, material, px, py - 2e-3, 0, angle);
|
|
53089
|
+
parts.magDrop = length2 + 0.03;
|
|
53090
|
+
} else if (o.mag === "drum") {
|
|
53091
|
+
buildDrum(kit, magazine);
|
|
53092
|
+
parts.magDrop = 0.2;
|
|
53093
|
+
} else if (o.mag === "internal") {
|
|
53094
|
+
box5(group, 0.08, 0.025, 0.03, context.isTraditional ? context.furniture : M.metal, mx, -hR / 2 - 0.012, 0);
|
|
53095
|
+
parts.mag = null;
|
|
53096
|
+
} else parts.mag = null;
|
|
53097
|
+
if (o.mag === "belt") {
|
|
53098
|
+
const belt = kit.pivot(group, mx + 0.02, -hR / 2 - 0.05, -0.045);
|
|
53099
|
+
parts.belt = belt;
|
|
53100
|
+
buildBeltBox(kit, belt);
|
|
53101
|
+
const cover = kit.pivot(group, x0 + 0.01, hR / 2, 0);
|
|
53102
|
+
parts.cover = cover;
|
|
53103
|
+
box5(cover, RL - 0.03, 0.014, wR * 1.05, M.metal, (RL - 0.03) / 2, 7e-3, 0);
|
|
53104
|
+
box5(cover, 0.02, 0.012, wR * 0.6, M.dark, RL - 0.04, 0.016, 0);
|
|
53105
|
+
}
|
|
53106
|
+
return mx;
|
|
53107
|
+
}
|
|
53108
|
+
|
|
53109
|
+
// src/models/rifle-stock.ts
|
|
53110
|
+
function buildStock(context, magazineX) {
|
|
53111
|
+
const { kit, group, options: o, furniture: furn, length: L, stockLength: S, receiverStart: x0, receiverEnd: x1, receiverHeight: hR } = context;
|
|
53112
|
+
const { M, box: box5, cylinderX } = kit;
|
|
53113
|
+
if (context.isTraditional) {
|
|
53114
|
+
buttpad(kit, group, 6e-3, -0.04, 0.13, 0.038);
|
|
53115
|
+
box5(group, 0.03, 0.13, 0.038, furn, 0.024, -0.04, 0);
|
|
53116
|
+
box5(group, S, 0.055, 0.034, furn, S / 2, -0.012, 0, 0.06);
|
|
53117
|
+
box5(group, 0.09, 0.05, 0.032, furn, x0 - 0.02, -0.035, 0, 0.25);
|
|
53118
|
+
const forendLength = x1 - x0 + (L - x1) * (o.fore ?? 0.62);
|
|
53119
|
+
if (forendLength > 0) box5(group, forendLength, 0.045, 0.04, furn, x0 + forendLength / 2, -hR / 2 + 4e-3, 0);
|
|
53120
|
+
if (o.stock === "straight") box5(group, 0.15, 0.04, 0.035, furn, x1 + 0.08, -hR / 2, 0);
|
|
53121
|
+
box5(group, 0.04, 4e-3, 0.03, M.metal, magazineX, -hR / 2 - 0.022, 0);
|
|
53122
|
+
swivel(kit, group, 0.2, -0.08);
|
|
53123
|
+
swivel(kit, group, x1 + (L - x1) * 0.45, -hR / 2 - 0.03);
|
|
53124
|
+
if (o.bands) for (const fraction of [0.35, 0.75]) cylinderX(group, 0.024, 8e-3, M.metal, x1 + (L - x1) * fraction * (o.fore || 0.62), -4e-3, 0, 16);
|
|
53125
|
+
} else if (o.stock === "fixed" || o.stock === "wood") {
|
|
53126
|
+
box5(group, S, 0.05, 0.03, furn, S / 2, -8e-3, 0, 0.05);
|
|
53127
|
+
box5(group, 0.03, 0.13, 0.036, furn, 0.022, -0.035, 0);
|
|
53128
|
+
buttpad(kit, group, 4e-3, -0.035, 0.13, 0.036);
|
|
53129
|
+
if (o.stock === "wood") box5(group, S * 0.6, 0.03, 0.028, furn, S * 0.55, -0.045, 0, 0.2);
|
|
53130
|
+
swivel(kit, group, 0.08, -0.09);
|
|
53131
|
+
} else if (o.stock === "skeleton") {
|
|
53132
|
+
box5(group, S, 0.014, 0.026, furn, S / 2, 0.012, 0, 0.03);
|
|
53133
|
+
box5(group, S, 0.014, 0.026, furn, S / 2, -0.05, 0, -0.08);
|
|
53134
|
+
box5(group, 0.03, 0.12, 0.034, furn, 0.02, -0.025, 0);
|
|
53135
|
+
buttpad(kit, group, 4e-3, -0.025, 0.12, 0.034);
|
|
53136
|
+
} else if (o.stock === "retract") {
|
|
53137
|
+
cylinderX(group, 0.013, S, M.metal, S / 2, 0, 0, 16);
|
|
53138
|
+
for (let i = 0; i < 5; i++) box5(group, 3e-3, 3e-3, 8e-3, M.dark, S * 0.2 + i * 0.015, -0.013, 0);
|
|
53139
|
+
box5(group, 0.034, 0.11, 0.036, furn, 0.02, -0.025, 0);
|
|
53140
|
+
box5(group, S * 0.55, 0.032, 0.03, furn, S * 0.35, 0, 0);
|
|
53141
|
+
buttpad(kit, group, 3e-3, -0.025, 0.11, 0.036);
|
|
53142
|
+
} else if (o.stock === "fold") {
|
|
53143
|
+
box5(group, S, 6e-3, 6e-3, M.metal, S / 2, 0.01, 0.012);
|
|
53144
|
+
box5(group, S, 6e-3, 6e-3, M.metal, S / 2, -0.04, 0.012, -0.12);
|
|
53145
|
+
box5(group, 0.012, 0.1, 0.03, M.metal, 6e-3, -0.02, 0.012);
|
|
53146
|
+
}
|
|
53147
|
+
}
|
|
53148
|
+
|
|
53149
|
+
// src/models/rifle.ts
|
|
53150
|
+
var PI6 = Math.PI;
|
|
53151
|
+
function buildReceiver(context) {
|
|
53152
|
+
const { kit, group, parts, options: o, length: L, receiverStart: x0, receiverEnd: x1, receiverHeight: hR, receiverWidth: wR, receiverLength: RL, barrelY: by } = context;
|
|
53153
|
+
const { M, box: box5, cylinderX, cylinderY, cylinderZ, sphere: sphere2 } = kit;
|
|
53154
|
+
const receiverMaterial = o.tan ? M.tan : M.metal;
|
|
53155
|
+
const middle = (x0 + x1) / 2;
|
|
53156
|
+
if (o.round) {
|
|
53157
|
+
cylinderX(group, hR * 0.36, RL, M.steel, middle, by, 0, 20);
|
|
53158
|
+
cylinderX(group, hR * 0.32, 0.05, M.steel, x0 - 0.01, by, 0, 18);
|
|
53159
|
+
} else if (o.ar) {
|
|
53160
|
+
box5(group, RL, hR * 0.5, wR, receiverMaterial, middle, hR * 0.25, 0);
|
|
53161
|
+
box5(group, RL * 0.92, hR * 0.52, wR * 0.96, receiverMaterial, middle - RL * 0.02, -hR * 0.24, 0);
|
|
53162
|
+
box5(group, 0.05, 0.03, wR * 1.15, receiverMaterial, x0 + RL * 0.62, -hR * 0.5 - 0.01, 0);
|
|
53163
|
+
cylinderZ(group, 6e-3, 0.012, M.metal, x1 - 0.03, hR * 0.28, wR / 2 + 6e-3, 12);
|
|
53164
|
+
box5(group, 0.012, 0.01, 0.012, M.metal, x1 - 0.05, hR * 0.12, wR / 2 + 6e-3);
|
|
53165
|
+
box5(group, 0.03, 8e-3, 0.012, M.dark, x0 + 0.02, hR / 2 + 4e-3, 0);
|
|
53166
|
+
box5(group, 0.012, 6e-3, 4e-3, M.dark, x0 + RL * 0.55, -hR * 0.15, -wR / 2 - 2e-3);
|
|
53167
|
+
} else box5(group, RL, hR, wR, receiverMaterial, middle, 0, 0);
|
|
53168
|
+
if (o.ak) {
|
|
53169
|
+
box5(group, RL * 0.86, hR * 0.28, wR * 0.95, M.metal, middle - 8e-3, hR / 2 + 4e-3, 0);
|
|
53170
|
+
for (let i = 0; i < 3; i++) box5(group, 4e-3, hR * 0.3, wR * 0.97, M.dark, x0 + RL * 0.25 + i * 0.02, hR / 2 + 4e-3, 0);
|
|
53171
|
+
box5(group, RL * 0.5, 0.012, 3e-3, M.metal, x0 + RL * 0.55, -hR * 0.02, wR / 2 + 15e-4, -0.05);
|
|
53172
|
+
box5(group, 0.012, 0.014, 3e-3, M.dark, x0 + RL * 0.32, -hR * 0.05, wR / 2 + 2e-3);
|
|
53173
|
+
}
|
|
53174
|
+
if (o.g3) {
|
|
53175
|
+
cylinderX(group, 9e-3, (L - x1) * 0.6, M.metal, x1 + (L - x1) * 0.28, hR * 0.48, 0, 14);
|
|
53176
|
+
box5(group, 0.012, 0.024, 8e-3, M.dark, x1 + (L - x1) * 0.5, hR * 0.48, -0.012);
|
|
53177
|
+
cylinderY(group, 0.012, 0.016, M.dark, x0 + 0.03, hR / 2 + 8e-3, 0, 12);
|
|
53178
|
+
}
|
|
53179
|
+
const ejectX = x1 - (o.ejectBack || 0.07);
|
|
53180
|
+
const ejectY = o.ar ? hR * 0.2 : by;
|
|
53181
|
+
box5(group, 0.05, hR * 0.36, 4e-3, M.hole, ejectX, ejectY, wR / 2 - 4e-4);
|
|
53182
|
+
const bolt = kit.pivot(group);
|
|
53183
|
+
parts.bolt = bolt;
|
|
53184
|
+
parts.stroke = Math.min(0.1, RL * 0.32);
|
|
53185
|
+
box5(bolt, 0.044, hR * 0.26, 6e-3, M.steelL, ejectX, ejectY, wR / 2 - 12e-4);
|
|
53186
|
+
if (o.charge) {
|
|
53187
|
+
box5(bolt, 0.012, 0.01, 0.03, M.metal, ejectX + 0.04, ejectY + 4e-3, wR / 2 + 0.012);
|
|
53188
|
+
sphere2(bolt, 65e-4, M.metal, ejectX + 0.04, ejectY + 4e-3, wR / 2 + 0.028, 1);
|
|
53189
|
+
}
|
|
53190
|
+
if (o.ar) box5(group, 0.012, 0.016, 6e-3, receiverMaterial, ejectX - 0.03, ejectY + 4e-3, wR / 2 + 4e-3);
|
|
53191
|
+
if (o.rail) rail(kit, group, x0 - 5e-3, RL + 0.07, hR / 2 + (o.ar ? 0 : 3e-3), 0, wR * 0.68);
|
|
53192
|
+
}
|
|
53193
|
+
function buildBarrel(context) {
|
|
53194
|
+
const { kit, group, parts, options: o, length: L, barrelLength: Bl, receiverEnd: x1, barrelRadius: r, barrelY: by } = context;
|
|
53195
|
+
const { M, box: box5, cylinderX } = kit;
|
|
53196
|
+
heatify(parts.glow, cylinderX(group, r, Bl, M.metal, L - Bl / 2, by, 0, 16));
|
|
53197
|
+
if (o.jacket) {
|
|
53198
|
+
cylinderX(group, r * 2, (L - x1) * 0.6, M.dark, x1 + (L - x1) * 0.3, by, 0, 16);
|
|
53199
|
+
for (let i = 0; i < 6; i++) cylinderX(group, r * 2.15, 4e-3, M.metal, x1 + (L - x1) * (0.05 + i * 0.09), by, 0, 16);
|
|
53200
|
+
}
|
|
53201
|
+
if (o.gas) cylinderX(group, r * 0.75, (L - x1) * 0.55, M.metal, x1 + (L - x1) * 0.3, by + r * 2.2, 0, 14);
|
|
53202
|
+
if (o.brake) {
|
|
53203
|
+
const kind = o.brake === 2 ? 2 : 1;
|
|
53204
|
+
recordFitting(parts, kind === 2 ? "muzzle_brake_heavy" : "muzzle_brake", group, () => buildBrake(kit, group, kind, L, by, r, (body) => void heatify(parts.glow, body)));
|
|
53205
|
+
} else if (!o.noFH) {
|
|
53206
|
+
recordFitting(parts, "muzzle_default", group, () => {
|
|
53207
|
+
heatify(parts.glow, cylinderX(group, r * 1.45, 0.042, M.dark, L - 0.021, by, 0, 16));
|
|
53208
|
+
for (let i = 0; i < 4; i++) {
|
|
53209
|
+
const angle = i * PI6 / 2 + PI6 / 4;
|
|
53210
|
+
box5(group, 0.026, 25e-4, 4e-3, M.hole, L - 0.02, by + Math.cos(angle) * r * 1.42, Math.sin(angle) * r * 1.42, 0, 0, angle);
|
|
53211
|
+
}
|
|
53212
|
+
});
|
|
53213
|
+
}
|
|
53214
|
+
cylinderX(group, r * 0.55, 4e-3, M.hole, L + 5e-4, by, 0, 12);
|
|
53215
|
+
}
|
|
53216
|
+
var familyOf = (o) => {
|
|
53217
|
+
if (o.mag === "belt") return "belt";
|
|
53218
|
+
if (o.pump) return "pump";
|
|
53219
|
+
if (o.lever) return "lever";
|
|
53220
|
+
if (o.tube) return "semi12";
|
|
53221
|
+
if (o.bolt) return o.mag === "box" ? "boltmag" : "bolt";
|
|
53222
|
+
return o.mag === "internal" ? "semiint" : "rifle";
|
|
53223
|
+
};
|
|
53224
|
+
function buildRifle(kit, options) {
|
|
53225
|
+
const { M } = kit;
|
|
53226
|
+
const group = kit.group();
|
|
53227
|
+
const parts = { family: "rifle", glow: [] };
|
|
53228
|
+
const length2 = (options.L ?? 0) / 1e3;
|
|
53229
|
+
const barrelLength = (options.B ?? 0) / 1e3;
|
|
53230
|
+
const isTraditional = options.stock === "trad" || options.stock === "straight";
|
|
53231
|
+
const stockLength = options.stock === "none" ? 0 : options.stockLen || Math.min(0.36, Math.max(0.2, 0.3 * length2));
|
|
53232
|
+
const receiverStart = stockLength;
|
|
53233
|
+
const receiverEnd = Math.max(receiverStart + 0.12, length2 - barrelLength * 0.92);
|
|
53234
|
+
const receiverHeight = options.hR || 0.06;
|
|
53235
|
+
const context = {
|
|
53236
|
+
kit,
|
|
53237
|
+
group,
|
|
53238
|
+
parts,
|
|
53239
|
+
options,
|
|
53240
|
+
furniture: options.wood ? M.wood : options.olive ? M.olive : options.tan ? M.tan : M.poly,
|
|
53241
|
+
isTraditional,
|
|
53242
|
+
length: length2,
|
|
53243
|
+
barrelLength,
|
|
53244
|
+
stockLength,
|
|
53245
|
+
receiverStart,
|
|
53246
|
+
receiverEnd,
|
|
53247
|
+
receiverHeight,
|
|
53248
|
+
receiverWidth: options.wR || 0.034,
|
|
53249
|
+
barrelRadius: options.br || 85e-4,
|
|
53250
|
+
barrelY: receiverHeight * 0.15,
|
|
53251
|
+
receiverLength: receiverEnd - receiverStart
|
|
53252
|
+
};
|
|
53253
|
+
buildReceiver(context);
|
|
53254
|
+
buildBarrel(context);
|
|
53255
|
+
buildForend(context);
|
|
53256
|
+
const gripX = buildGrip(context);
|
|
53257
|
+
const magazineX = buildMagazine(context, gripX);
|
|
53258
|
+
parts.stockMeshes = context.isTraditional ? [] : captured(group, () => buildStock(context, magazineX));
|
|
53259
|
+
if (context.isTraditional) buildStock(context, magazineX);
|
|
53260
|
+
buildFittings(context, gripX);
|
|
53261
|
+
const hasHandguard = !context.isTraditional && options.hg !== "none";
|
|
53262
|
+
parts.frames = {
|
|
53263
|
+
length: length2,
|
|
53264
|
+
barrelY: context.barrelY,
|
|
53265
|
+
barrelRadius: context.barrelRadius,
|
|
53266
|
+
receiverStart,
|
|
53267
|
+
receiverEnd,
|
|
53268
|
+
receiverHeight,
|
|
53269
|
+
receiverWidth: context.receiverWidth,
|
|
53270
|
+
handguardEnd: receiverEnd + (length2 - receiverEnd) * (hasHandguard ? options.hgFrac || 0.5 : 0.4),
|
|
53271
|
+
magazineX,
|
|
53272
|
+
gripX,
|
|
53273
|
+
hasRail: Boolean(options.rail)
|
|
53274
|
+
};
|
|
53275
|
+
const { barrelY: by, receiverWidth: wR } = context;
|
|
53276
|
+
const ejectX = receiverEnd - (options.ejectBack || 0.07);
|
|
53277
|
+
const ejectY = options.ar ? receiverHeight * 0.2 : by;
|
|
53278
|
+
parts.muzzle = kit.mark(group, length2 + 0.01, by, 0);
|
|
53279
|
+
parts.eject = kit.mark(group, ejectX, ejectY, wR / 2 + 6e-3);
|
|
53280
|
+
parts.loadPort = kit.mark(group, receiverEnd - 0.05, -receiverHeight / 2 - 4e-3, 0);
|
|
53281
|
+
parts.topLoad = kit.mark(group, ejectX, receiverHeight / 2 + 4e-3, 0);
|
|
53282
|
+
parts.family = familyOf(options);
|
|
53283
|
+
return { group, parts };
|
|
53284
|
+
}
|
|
53285
|
+
|
|
53286
|
+
// src/models/break-launcher.ts
|
|
53287
|
+
function buildBreakLauncher(kit, options) {
|
|
53288
|
+
const built2 = buildRifle(kit, options);
|
|
53289
|
+
const { group, parts } = built2;
|
|
53290
|
+
const frames = parts.frames;
|
|
53291
|
+
if (!frames) return built2;
|
|
53292
|
+
const hingeY = frames.barrelY - frames.barrelRadius;
|
|
53293
|
+
const barrels = kit.pivot(group, frames.receiverEnd, hingeY, 0);
|
|
53294
|
+
group.updateMatrixWorld(true);
|
|
53295
|
+
const centre = new kit.THREE.Vector3();
|
|
53296
|
+
for (const child of [...group.children]) {
|
|
53297
|
+
if (child === barrels) continue;
|
|
53298
|
+
const mesh3 = child;
|
|
53299
|
+
const isAhead = mesh3.isMesh ? new kit.THREE.Box3().setFromObject(mesh3).getCenter(centre).x > frames.receiverEnd : child === parts.muzzle;
|
|
53300
|
+
if (isAhead) barrels.attach(child);
|
|
53301
|
+
}
|
|
53302
|
+
parts.barrels = barrels;
|
|
53303
|
+
parts.breech = [kit.mark(barrels, 4e-3, frames.barrelY - hingeY, 0)];
|
|
53304
|
+
parts.eject = parts.breech[0];
|
|
53305
|
+
parts.family = "break";
|
|
53306
|
+
return built2;
|
|
53307
|
+
}
|
|
53308
|
+
|
|
51904
53309
|
// src/models/attachments/mount-frames.ts
|
|
51905
53310
|
var DEFAULT_BARREL_RADIUS = 85e-4;
|
|
51906
53311
|
var DEFAULT_RECEIVER_WIDTH = 0.034;
|
|
@@ -51975,58 +53380,6 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
51975
53380
|
}
|
|
51976
53381
|
}
|
|
51977
53382
|
|
|
51978
|
-
// src/models/details.ts
|
|
51979
|
-
var PI3 = Math.PI;
|
|
51980
|
-
function rail(kit, parent, x, length2, y, z, width, rotationX = 0) {
|
|
51981
|
-
const { M, box: box5 } = kit;
|
|
51982
|
-
const pivot = kit.pivot(parent, 0, y, z);
|
|
51983
|
-
pivot.rotation.x = rotationX;
|
|
51984
|
-
box5(pivot, length2, 5e-3, width, M.dark, x + length2 / 2, 0, 0);
|
|
51985
|
-
const slots = Math.floor(length2 / 95e-4);
|
|
51986
|
-
for (let i = 0; i < slots; i++) box5(pivot, 52e-4, 35e-4, width * 1.12, M.metal, x + 6e-3 + i * 95e-4, 35e-4, 0);
|
|
51987
|
-
return pivot;
|
|
51988
|
-
}
|
|
51989
|
-
function vents(kit, parent, x, length2, y, z, count, height) {
|
|
51990
|
-
for (let i = 0; i < count; i++) kit.box(parent, length2 / count * 0.45, height, 3e-3, kit.M.hole, x + (i + 0.5) * length2 / count, y, z);
|
|
51991
|
-
}
|
|
51992
|
-
function scope(kit, parent, kind, cx, cy, cz = 0) {
|
|
51993
|
-
const { M, box: box5, cylinderX, cylinderY, cylinderZ, THREE } = kit;
|
|
51994
|
-
if (kind === 1) {
|
|
51995
|
-
box5(parent, 0.044, 0.01, 0.028, M.dark, cx, cy + 5e-3, cz);
|
|
51996
|
-
cylinderX(parent, 0.0155, 0.034, M.dark, cx + 4e-3, cy + 0.026, cz, 18);
|
|
51997
|
-
cylinderX(parent, 0.0125, 2e-3, M.lens, cx + 0.022, cy + 0.026, cz, 18);
|
|
51998
|
-
cylinderY(parent, 4e-3, 6e-3, M.dark, cx + 4e-3, cy + 0.044, cz, 10);
|
|
51999
|
-
return;
|
|
52000
|
-
}
|
|
52001
|
-
if (kind === 2) {
|
|
52002
|
-
box5(parent, 0.07, 0.012, 0.026, M.dark, cx, cy + 6e-3, cz);
|
|
52003
|
-
cylinderX(parent, 0.016, 0.1, M.dark, cx - 0.01, cy + 0.032, cz, 18);
|
|
52004
|
-
cylinderX(parent, 0.016, 0.035, M.dark, cx + 0.055, cy + 0.032, cz, 18, 0.02);
|
|
52005
|
-
cylinderX(parent, 0.017, 2e-3, M.lens, cx + 0.073, cy + 0.032, cz, 18);
|
|
52006
|
-
cylinderY(parent, 7e-3, 0.012, M.dark, cx, cy + 0.052, cz, 12);
|
|
52007
|
-
box5(parent, 0.03, 0.01, 0.012, M.dark, cx - 0.01, cy + 0.054, cz);
|
|
52008
|
-
return;
|
|
52009
|
-
}
|
|
52010
|
-
const sleeve = kind === 4 ? 0.2 : 0.32;
|
|
52011
|
-
cylinderX(parent, 0.0135, sleeve * 0.55, M.dark, cx, cy + 0.045, cz, 18);
|
|
52012
|
-
cylinderX(parent, 0.0135, sleeve * 0.25, M.dark, cx + sleeve * 0.36, cy + 0.045, cz, 18, 0.026);
|
|
52013
|
-
cylinderX(parent, 0.026, 0.05, M.dark, cx + sleeve * 0.5, cy + 0.045, cz, 18);
|
|
52014
|
-
cylinderX(parent, 0.024, 2e-3, M.lens, cx + sleeve * 0.5 + 0.026, cy + 0.045, cz, 18);
|
|
52015
|
-
cylinderX(parent, 0.019, 0.06, M.dark, cx - sleeve * 0.38, cy + 0.045, cz, 18, 0.0135);
|
|
52016
|
-
cylinderX(parent, 0.019, 0.035, M.rubber, cx - sleeve * 0.38 - 0.045, cy + 0.045, cz, 18);
|
|
52017
|
-
cylinderX(parent, 0.017, 2e-3, M.lens, cx - sleeve * 0.38 - 0.063, cy + 0.045, cz, 18);
|
|
52018
|
-
cylinderY(parent, 0.01, 0.022, M.dark, cx, cy + 0.066, cz, 14);
|
|
52019
|
-
cylinderY(parent, 0.011, 4e-3, M.metal, cx, cy + 0.078, cz, 14);
|
|
52020
|
-
cylinderZ(parent, 0.01, 0.022, M.dark, cx, cy + 0.045, cz + 0.022, 14);
|
|
52021
|
-
for (const offset of [-0.07, 0.07]) {
|
|
52022
|
-
const ring3 = kit.torus(parent, new THREE.TorusGeometry(0.0155, 3e-3, 8, 20), M.dark, cx + offset, cy + 0.045, cz);
|
|
52023
|
-
ring3.rotation.y = PI3 / 2;
|
|
52024
|
-
box5(parent, 0.016, 0.03, 0.022, M.dark, cx + offset, cy + 0.018, cz);
|
|
52025
|
-
}
|
|
52026
|
-
}
|
|
52027
|
-
var buttpad = (kit, parent, x, y, height, width) => void kit.box(parent, 0.012, height, width, kit.M.rubber, x, y, 0);
|
|
52028
|
-
var swivel = (kit, parent, x, y) => void kit.torus(parent, new kit.THREE.TorusGeometry(6e-3, 15e-4, 6, 12), kit.M.metal, x, y, 0);
|
|
52029
|
-
|
|
52030
53383
|
// src/models/bullpup.ts
|
|
52031
53384
|
function buildBullpup(kit, options) {
|
|
52032
53385
|
const { M, box: box5, cylinderX } = kit;
|
|
@@ -52152,7 +53505,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
52152
53505
|
}
|
|
52153
53506
|
|
|
52154
53507
|
// src/models/launcher-rounds.ts
|
|
52155
|
-
var
|
|
53508
|
+
var PI7 = Math.PI;
|
|
52156
53509
|
function buildRocketGrenade(kit) {
|
|
52157
53510
|
const { M, cylinderX } = kit;
|
|
52158
53511
|
const round5 = kit.group();
|
|
@@ -52182,7 +53535,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
52182
53535
|
cylinderX(rocket, diameter, 0.12, M.olive, 0.36, 0, 0, 18, diameter * 0.25);
|
|
52183
53536
|
for (let i = 0; i < 4; i++) {
|
|
52184
53537
|
const fin = box5(rocket, 0.06, 2e-3, diameter * 1.4, M.metal, -0.17, 0, 0);
|
|
52185
|
-
fin.rotation.x = i *
|
|
53538
|
+
fin.rotation.x = i * PI7 / 4;
|
|
52186
53539
|
}
|
|
52187
53540
|
return rocket;
|
|
52188
53541
|
}
|
|
@@ -52320,7 +53673,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
52320
53673
|
}
|
|
52321
53674
|
|
|
52322
53675
|
// src/models/m134.ts
|
|
52323
|
-
var
|
|
53676
|
+
var PI8 = Math.PI;
|
|
52324
53677
|
var BARRELS = 6;
|
|
52325
53678
|
var CLUSTER_RADIUS = 0.03;
|
|
52326
53679
|
var BARREL_RADIUS = 78e-4;
|
|
@@ -52332,7 +53685,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
52332
53685
|
const length2 = BARREL_END - 0.3;
|
|
52333
53686
|
let heated;
|
|
52334
53687
|
for (let i = 0; i < BARRELS; i++) {
|
|
52335
|
-
const angle = i * 2 *
|
|
53688
|
+
const angle = i * 2 * PI8 / BARRELS;
|
|
52336
53689
|
const y = Math.cos(angle) * CLUSTER_RADIUS;
|
|
52337
53690
|
const z = Math.sin(angle) * CLUSTER_RADIUS;
|
|
52338
53691
|
const barrel = cylinderX(barrels, BARREL_RADIUS, length2, M.metal, 0.3 + length2 / 2, y, z, 14);
|
|
@@ -52481,7 +53834,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
52481
53834
|
}
|
|
52482
53835
|
|
|
52483
53836
|
// src/models/pistol-slide.ts
|
|
52484
|
-
var
|
|
53837
|
+
var PI9 = Math.PI;
|
|
52485
53838
|
function buildSlide(kit, slide2, parts, options, style, size, metal2) {
|
|
52486
53839
|
const { M, box: box5, cylinderX } = kit;
|
|
52487
53840
|
const { length: L, width: w } = size;
|
|
@@ -52509,8 +53862,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
52509
53862
|
if (style.tri) {
|
|
52510
53863
|
const tube2 = new kit.THREE.Mesh(new kit.THREE.CylinderGeometry(0.016, 0.016, L * 0.6, 3), metal2);
|
|
52511
53864
|
tube2.castShadow = tube2.receiveShadow = true;
|
|
52512
|
-
tube2.rotation.set(0, 0, -
|
|
52513
|
-
tube2.rotateY(
|
|
53865
|
+
tube2.rotation.set(0, 0, -PI9 / 2);
|
|
53866
|
+
tube2.rotateY(PI9 / 6);
|
|
52514
53867
|
tube2.position.set(L * 0.7, slideHeight * 0.08, 0);
|
|
52515
53868
|
slide2.add(tube2);
|
|
52516
53869
|
heatify(parts.glow, tube2);
|
|
@@ -52562,7 +53915,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
52562
53915
|
};
|
|
52563
53916
|
|
|
52564
53917
|
// src/models/pistol.ts
|
|
52565
|
-
var
|
|
53918
|
+
var PI10 = Math.PI;
|
|
52566
53919
|
function buildFrame2(kit, group, parts, options, style, size, materials) {
|
|
52567
53920
|
const { M, box: box5, cylinderZ, sphere: sphere2 } = kit;
|
|
52568
53921
|
const { length: L, height: h, width: w } = size;
|
|
@@ -52654,8 +54007,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
52654
54007
|
box5(group, 4e-3, 0.03, 9e-3, frameMetal, gx + 0.073, ty - 0.02, 0, 0.2);
|
|
52655
54008
|
box5(group, 8e-3, 6e-3, 9e-3, frameMetal, gx + 0.074, ty - 0.037, 0, 0.4);
|
|
52656
54009
|
} else {
|
|
52657
|
-
const guard = kit.torus(group, new kit.THREE.TorusGeometry(0.019, 22e-4, 6, 16,
|
|
52658
|
-
guard.rotation.z =
|
|
54010
|
+
const guard = kit.torus(group, new kit.THREE.TorusGeometry(0.019, 22e-4, 6, 16, PI10), frameMetal, gx + 0.05, ty - 0.014, 0);
|
|
54011
|
+
guard.rotation.z = PI10;
|
|
52659
54012
|
guard.scale.set(1.2, 1, 1);
|
|
52660
54013
|
}
|
|
52661
54014
|
const isGlock = options.st === "glock" || !options.st;
|
|
@@ -52679,7 +54032,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
52679
54032
|
}
|
|
52680
54033
|
|
|
52681
54034
|
// src/models/revolver.ts
|
|
52682
|
-
var
|
|
54035
|
+
var PI11 = Math.PI;
|
|
52683
54036
|
var DEFAULT_CHAMBERS = 6;
|
|
52684
54037
|
function buildRevolver(kit, options) {
|
|
52685
54038
|
const { M, box: box5, cylinderX } = kit;
|
|
@@ -52697,12 +54050,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
52697
54050
|
parts.cylinder = cylinder2;
|
|
52698
54051
|
cylinderX(cylinder2, 0.0215, 0.042, metal2, 0, 0, 0, 24);
|
|
52699
54052
|
for (let i = 0; i < chambers; i++) {
|
|
52700
|
-
const angle = i * 2 *
|
|
54053
|
+
const angle = i * 2 * PI11 / chambers;
|
|
52701
54054
|
box5(cylinder2, 0.026, 5e-3, 5e-3, M.dark, 0, Math.cos(angle) * 0.0205, Math.sin(angle) * 0.0205, 0, 0, angle);
|
|
52702
54055
|
}
|
|
52703
54056
|
parts.chambers = [];
|
|
52704
54057
|
for (let i = 0; i < chambers; i++) {
|
|
52705
|
-
const angle = i * 2 *
|
|
54058
|
+
const angle = i * 2 * PI11 / chambers + PI11 / chambers;
|
|
52706
54059
|
parts.chambers.push(kit.mark(cylinder2, -0.022, Math.cos(angle) * 0.013, Math.sin(angle) * 0.013));
|
|
52707
54060
|
cylinderX(cylinder2, 46e-4, 2e-3, M.brass, -0.0215, Math.cos(angle) * 0.013, Math.sin(angle) * 0.013, 12);
|
|
52708
54061
|
}
|
|
@@ -52727,434 +54080,6 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
52727
54080
|
return { group, parts };
|
|
52728
54081
|
}
|
|
52729
54082
|
|
|
52730
|
-
// src/models/attachments/muzzle-brake.ts
|
|
52731
|
-
function buildBrake(kit, parent, kind, x, y, barrelRadius, heat = () => void 0) {
|
|
52732
|
-
const { M, box: box5, cylinderX } = kit;
|
|
52733
|
-
const scale = kind === 2 ? 3.2 : 2;
|
|
52734
|
-
const length2 = kind === 2 ? 0.12 : 0.06;
|
|
52735
|
-
heat(cylinderX(parent, barrelRadius * scale, length2, M.dark, x - length2 / 2, y, 0, kind === 2 ? 8 : 16));
|
|
52736
|
-
for (let i = 0; i < 3; i++) box5(parent, length2 * 0.16, barrelRadius * scale * 1.3, barrelRadius * scale * 2.2, M.hole, x - length2 * 0.25 - i * length2 * 0.25, y, 0);
|
|
52737
|
-
}
|
|
52738
|
-
|
|
52739
|
-
// src/models/capture.ts
|
|
52740
|
-
function captured(parent, draw2) {
|
|
52741
|
-
const before = parent.children.length;
|
|
52742
|
-
draw2();
|
|
52743
|
-
return parent.children.slice(before);
|
|
52744
|
-
}
|
|
52745
|
-
function recordFitting(parts, id, parent, draw2) {
|
|
52746
|
-
parts.fittings = { ...parts.fittings, [id]: captured(parent, draw2) };
|
|
52747
|
-
}
|
|
52748
|
-
|
|
52749
|
-
// src/models/attachments/bipod.ts
|
|
52750
|
-
function buildBipod(kit, parent, x, y) {
|
|
52751
|
-
const { M, box: box5, cylinderX } = kit;
|
|
52752
|
-
cylinderX(parent, 8e-3, 0.02, M.dark, x, y, 0, 12);
|
|
52753
|
-
for (const side of [-1, 1]) {
|
|
52754
|
-
const leg = kit.pivot(parent, x, y, side * 0.012);
|
|
52755
|
-
leg.rotation.set(side * 0.15, 0, -0.35);
|
|
52756
|
-
box5(leg, 6e-3, 0.2, 6e-3, M.dark, 0, -0.1, 0);
|
|
52757
|
-
box5(leg, 0.01, 6e-3, 0.01, M.rubber, 0, -0.2, 0);
|
|
52758
|
-
}
|
|
52759
|
-
}
|
|
52760
|
-
var buildBipodModel = ({ kit }) => {
|
|
52761
|
-
const group = kit.group();
|
|
52762
|
-
buildBipod(kit, group, 0, 0);
|
|
52763
|
-
return group;
|
|
52764
|
-
};
|
|
52765
|
-
|
|
52766
|
-
// src/models/rifle-fittings.ts
|
|
52767
|
-
var SCOPE_IDS = { 1: "red_dot", 2: "acog_4x", 3: "scope_3_9x", 4: "scope_6_24x" };
|
|
52768
|
-
function buildFittings(context, gripX) {
|
|
52769
|
-
const { kit, group, parts, options: o, furniture: furn, length: L, receiverStart: x0, receiverEnd: x1, receiverHeight: hR, receiverWidth: wR, barrelRadius: r, barrelY: by } = context;
|
|
52770
|
-
const { M, box: box5, cylinderX, cylinderZ, sphere: sphere2 } = kit;
|
|
52771
|
-
const middle = (x0 + x1) / 2;
|
|
52772
|
-
if (o.scope) recordFitting(parts, SCOPE_IDS[o.scope] ?? "scope", group, () => scope(kit, group, o.scope, middle + 0.03, hR / 2 + (o.rail ? 6e-3 : 0), o.scope === 4 ? -0.02 : 0));
|
|
52773
|
-
if (o.carry) {
|
|
52774
|
-
box5(group, 0.15, 0.026, 0.014, M.metal, middle, hR / 2 + 0.03, 0);
|
|
52775
|
-
box5(group, 0.012, 0.03, 0.014, M.metal, middle + 0.07, hR / 2 + 0.014, 0);
|
|
52776
|
-
box5(group, 0.012, 0.03, 0.014, M.metal, middle - 0.07, hR / 2 + 0.014, 0);
|
|
52777
|
-
}
|
|
52778
|
-
if (o.bipod) recordFitting(parts, "bipod", group, () => buildBipod(kit, group, x1 + (L - x1) * 0.45 + 0.04, by - 0.012));
|
|
52779
|
-
if (o.bolt) {
|
|
52780
|
-
const handle = kit.pivot(group, x1 - 0.045, by, 0);
|
|
52781
|
-
parts.boltHandle = handle;
|
|
52782
|
-
parts.boltHandleRest = handle.position.x;
|
|
52783
|
-
cylinderZ(handle, 42e-4, 0.05, M.steelL, 0, 0, wR / 2 + 0.022, 12);
|
|
52784
|
-
sphere2(handle, 95e-4, M.dark, 0, -4e-3, wR / 2 + 0.048, 1);
|
|
52785
|
-
cylinderX(group, hR * 0.3, 0.03, M.steel, x0 + 5e-3, by, 0, 16);
|
|
52786
|
-
}
|
|
52787
|
-
if (o.lever) {
|
|
52788
|
-
const lever = kit.pivot(group, gripX - 0.02, -hR / 2 - 0.01, 0);
|
|
52789
|
-
parts.lever = lever;
|
|
52790
|
-
box5(lever, 0.11, 6e-3, 0.012, M.metal, 0.055, -0.052, 0);
|
|
52791
|
-
box5(lever, 6e-3, 0.05, 0.012, M.metal, 3e-3, -0.028, 0);
|
|
52792
|
-
box5(lever, 6e-3, 0.05, 0.012, M.metal, 0.108, -0.028, 0);
|
|
52793
|
-
box5(lever, 0.04, 6e-3, 0.012, M.metal, 0.08, -2e-3, 0);
|
|
52794
|
-
box5(group, 0.03, 0.012, 3e-3, M.dark, x1 - 0.04, by, wR / 2 + 1e-3);
|
|
52795
|
-
}
|
|
52796
|
-
if (o.tube) {
|
|
52797
|
-
const tubeLength = (L - x1) * (o.tubeLen || 0.8);
|
|
52798
|
-
cylinderX(group, 0.0105, tubeLength, M.metal, x1 + tubeLength / 2, by - 0.023, 0, 16);
|
|
52799
|
-
cylinderX(group, 0.0125, 0.02, M.dark, x1 + tubeLength + 6e-3, by - 0.023, 0, 16);
|
|
52800
|
-
}
|
|
52801
|
-
if (o.pump) {
|
|
52802
|
-
const pump = kit.pivot(group);
|
|
52803
|
-
parts.pump = pump;
|
|
52804
|
-
box5(pump, 0.17, 0.042, 0.046, furn, x1 + 0.14, by - 0.022, 0);
|
|
52805
|
-
for (let i = 0; i < 8; i++) box5(pump, 6e-3, 0.044, 0.048, M.dark, x1 + 0.07 + i * 0.02, by - 0.022, 0);
|
|
52806
|
-
}
|
|
52807
|
-
if (o.heat) {
|
|
52808
|
-
cylinderX(group, r * 1.75, (L - x1) * 0.7, M.dark, x1 + (L - x1) * 0.4, by, 0, 12);
|
|
52809
|
-
for (let i = 0; i < 10; i++) box5(group, 8e-3, r * 1.5, 4e-3, M.hole, x1 + (L - x1) * (0.1 + i * 0.06), by + r * 0.8, r * 1.5);
|
|
52810
|
-
}
|
|
52811
|
-
if (o.bayo) box5(group, 0.025, 8e-3, 0.01, M.metal, L - 0.07, by - 0.016, 0);
|
|
52812
|
-
if (o.rod) cylinderX(group, 3e-3, (L - x1) * 0.85, M.steel, x1 + (L - x1) * 0.45, by - 0.014, 0, 8);
|
|
52813
|
-
}
|
|
52814
|
-
|
|
52815
|
-
// src/models/rifle-forend.ts
|
|
52816
|
-
var PI9 = Math.PI;
|
|
52817
|
-
function buildForend(context) {
|
|
52818
|
-
const { kit, group, options: o, furniture: furn, length: L, receiverEnd: x1, receiverHeight: hR, receiverWidth: wR, barrelRadius: r, barrelY: by } = context;
|
|
52819
|
-
const { M, box: box5 } = kit;
|
|
52820
|
-
const hasLongScope = (o.scope ?? 0) >= 3;
|
|
52821
|
-
if (!context.isTraditional && o.hg !== "none") {
|
|
52822
|
-
const handguardLength = (L - x1) * (o.hgFrac || 0.5);
|
|
52823
|
-
const hx = x1 + handguardLength / 2;
|
|
52824
|
-
const hh = hR * 0.8;
|
|
52825
|
-
if (o.hg === "rail") {
|
|
52826
|
-
box5(group, handguardLength, hh, wR * 1.04, M.dark, hx, by - 2e-3, 0);
|
|
52827
|
-
rail(kit, group, x1, handguardLength, by + hh / 2, 0, wR * 0.66);
|
|
52828
|
-
rail(kit, group, x1 + 0.01, handguardLength - 0.02, by - 2e-3, wR * 0.54, wR * 0.4, PI9 / 2);
|
|
52829
|
-
rail(kit, group, x1 + 0.01, handguardLength - 0.02, by - 2e-3, -wR * 0.54, wR * 0.4, -PI9 / 2);
|
|
52830
|
-
rail(kit, group, x1 + 0.01, handguardLength - 0.02, by - hh / 2, 0, wR * 0.6, PI9);
|
|
52831
|
-
} else {
|
|
52832
|
-
const material = o.hg === "wood" ? M.wood : furn;
|
|
52833
|
-
if (o.ak) {
|
|
52834
|
-
box5(group, handguardLength, hh * 0.55, wR * 1.08, material, hx, by - hh * 0.22, 0);
|
|
52835
|
-
box5(group, handguardLength * 0.75, hh * 0.35, wR * 0.7, material, hx - handguardLength * 0.1, by + r * 2.2, 0);
|
|
52836
|
-
} else {
|
|
52837
|
-
box5(group, handguardLength, hh, wR * 1.08, material, hx, by - 2e-3, 0);
|
|
52838
|
-
vents(kit, group, x1 + 0.01, handguardLength - 0.02, by + hh * 0.15, wR * 0.54 + 1e-3, Math.round(handguardLength / 0.025), hh * 0.3);
|
|
52839
|
-
vents(kit, group, x1 + 0.01, handguardLength - 0.02, by + hh * 0.15, -wR * 0.54 - 1e-3, Math.round(handguardLength / 0.025), hh * 0.3);
|
|
52840
|
-
}
|
|
52841
|
-
}
|
|
52842
|
-
if (!hasLongScope && !o.rail && o.ak) {
|
|
52843
|
-
box5(group, 0.03, 0.016, wR * 0.6, M.metal, x1 + 0.02, by + r * 2.5 + 0.01, 0);
|
|
52844
|
-
box5(group, 0.012, 4e-3, wR * 0.5, M.dark, x1 + 0.03, by + r * 2.5 + 0.019, 0);
|
|
52845
|
-
}
|
|
52846
|
-
}
|
|
52847
|
-
if (hasLongScope) return;
|
|
52848
|
-
const sightX = L - (o.ak ? 0.06 : 0.08);
|
|
52849
|
-
if (o.ak) {
|
|
52850
|
-
box5(group, 0.022, 0.022, wR * 0.6, M.metal, sightX, by + 8e-3, 0);
|
|
52851
|
-
box5(group, 6e-3, 0.024, 4e-3, M.metal, sightX, by + 0.026, 8e-3);
|
|
52852
|
-
box5(group, 6e-3, 0.024, 4e-3, M.metal, sightX, by + 0.026, -8e-3);
|
|
52853
|
-
box5(group, 3e-3, 0.016, 3e-3, M.dark, sightX, by + 0.022, 0);
|
|
52854
|
-
} else if (!o.rail || o.carry) {
|
|
52855
|
-
box5(group, 0.018, 0.014, wR * 0.55, M.dark, sightX, by + 8e-3, 0);
|
|
52856
|
-
box5(group, 0.012, 0.034, 8e-3, M.dark, sightX, by + 0.03, 0, -0.25);
|
|
52857
|
-
} else box5(group, 0.012, 0.024, 0.012, M.dark, sightX - 0.04, by + hR * 0.4 + 0.012, 0);
|
|
52858
|
-
}
|
|
52859
|
-
|
|
52860
|
-
// src/models/attachments/belt-box.ts
|
|
52861
|
-
function buildBeltBox(kit, belt) {
|
|
52862
|
-
const { M, box: box5, cylinderX } = kit;
|
|
52863
|
-
box5(belt, 0.11, 0.1, 0.08, M.olive, 0, 0, 0);
|
|
52864
|
-
box5(belt, 0.112, 0.012, 0.082, M.dark, 0, 0.046, 0);
|
|
52865
|
-
for (let i = 0; i < 7; i++) {
|
|
52866
|
-
cylinderX(belt, 42e-4, 0.034, M.brass, -0.04 + i * 0.012, 0.07, 0.035, 10);
|
|
52867
|
-
box5(belt, 6e-3, 6e-3, 0.012, M.metal, -0.04 + i * 0.012, 0.066, 0.035);
|
|
52868
|
-
}
|
|
52869
|
-
}
|
|
52870
|
-
|
|
52871
|
-
// src/models/attachments/drum.ts
|
|
52872
|
-
function buildDrum(kit, magazine) {
|
|
52873
|
-
const { M, box: box5, cylinderZ } = kit;
|
|
52874
|
-
cylinderZ(magazine, 0.075, 0.07, M.dark, 0.02, -0.085, 0, 22);
|
|
52875
|
-
cylinderZ(magazine, 0.05, 0.074, M.metal, 0.02, -0.085, 0, 18);
|
|
52876
|
-
box5(magazine, 0.05, 0.04, 0.03, M.dark, 0, -0.02, 0);
|
|
52877
|
-
}
|
|
52878
|
-
|
|
52879
|
-
// src/models/helical-magazine.ts
|
|
52880
|
-
var PI10 = Math.PI;
|
|
52881
|
-
var LENGTH = 0.26;
|
|
52882
|
-
var RADIUS = 0.026;
|
|
52883
|
-
var TURNS = 11;
|
|
52884
|
-
function buildHelicalMagazine(context) {
|
|
52885
|
-
const { kit, group, parts, receiverEnd, barrelY, barrelRadius } = context;
|
|
52886
|
-
const { M, cylinderX, box: box5 } = kit;
|
|
52887
|
-
const x = receiverEnd + LENGTH / 2 + 0.02;
|
|
52888
|
-
const y = barrelY - barrelRadius - RADIUS - 0.012;
|
|
52889
|
-
const magazine = kit.pivot(group, x, y, 0);
|
|
52890
|
-
parts.mag = magazine;
|
|
52891
|
-
cylinderX(magazine, RADIUS, LENGTH, M.dark, 0, 0, 0, 20);
|
|
52892
|
-
cylinderX(magazine, RADIUS * 1.06, 0.01, M.metal, -LENGTH / 2, 0, 0, 20);
|
|
52893
|
-
cylinderX(magazine, RADIUS * 1.06, 0.01, M.metal, LENGTH / 2, 0, 0, 20);
|
|
52894
|
-
for (let i = 0; i < TURNS; i++) box5(magazine, 0.012, RADIUS * 2.15, 0.014, M.metal, -LENGTH / 2 + (i + 0.5) * LENGTH / TURNS, 0, 0, 0, 0, i * PI10 / 4);
|
|
52895
|
-
box5(magazine, 0.05, 0.03, 0.03, M.dark, -LENGTH / 2 - 0.02, RADIUS * 0.4, 0);
|
|
52896
|
-
parts.magDrop = 0.16;
|
|
52897
|
-
return x;
|
|
52898
|
-
}
|
|
52899
|
-
|
|
52900
|
-
// src/models/rifle-controls.ts
|
|
52901
|
-
function buildGrip(context) {
|
|
52902
|
-
const { kit, group, parts, options: o, furniture: furn, receiverStart: x0, receiverHeight: hR, receiverWidth: wR } = context;
|
|
52903
|
-
const { M, box: box5 } = kit;
|
|
52904
|
-
const gx = x0 + (o.gripAt || 0.07);
|
|
52905
|
-
if (!context.isTraditional && o.grip !== "none") {
|
|
52906
|
-
const grip = kit.pivot(group, gx - 0.012, -hR / 2 - 0.046, 0);
|
|
52907
|
-
grip.rotation.z = -0.3;
|
|
52908
|
-
parts.grip = grip;
|
|
52909
|
-
box5(grip, 0.032, 0.105, 0.028, furn, 0, 0, 0);
|
|
52910
|
-
for (let i = 0; i < 3; i++) box5(grip, 6e-3, 0.012, 0.026, furn, 0.017, 0.022 - i * 0.02, 0);
|
|
52911
|
-
box5(grip, 0.034, 8e-3, 0.03, furn, 0, -0.052, 0);
|
|
52912
|
-
}
|
|
52913
|
-
box5(group, 0.06, 4e-3, 0.01, M.metal, gx + 0.03, -hR / 2 - 0.024, 0);
|
|
52914
|
-
box5(group, 4e-3, 0.022, 0.01, M.metal, gx + 0.06, -hR / 2 - 0.013, 0);
|
|
52915
|
-
parts.trigger = box5(group, 4e-3, 0.016, 4e-3, M.dark, gx + 0.024, -hR / 2 - 0.012, 0, 0.15);
|
|
52916
|
-
if (o.sel) parts.safety = box5(group, 0.016, 5e-3, 3e-3, M.dark, gx + 5e-3, -hR * 0.15, -wR / 2 - 2e-3, 0.4);
|
|
52917
|
-
return gx;
|
|
52918
|
-
}
|
|
52919
|
-
function buildMagazine(context, gx) {
|
|
52920
|
-
const { kit, group, parts, options: o, receiverStart: x0, receiverHeight: hR, receiverWidth: wR, receiverLength: RL } = context;
|
|
52921
|
-
const { M, box: box5 } = kit;
|
|
52922
|
-
if (o.mag === "helical") return buildHelicalMagazine(context);
|
|
52923
|
-
const mx = o.magAt != null ? x0 + o.magAt : gx + 0.075;
|
|
52924
|
-
const scale = o.magLen || 1;
|
|
52925
|
-
const magazine = kit.pivot(group, mx, -hR / 2, 0);
|
|
52926
|
-
parts.mag = magazine;
|
|
52927
|
-
const finish = o.magMat === "bakelite" ? M.bakelite : o.magMat === "poly" ? M.polyMag : void 0;
|
|
52928
|
-
if (o.mag === "curved") {
|
|
52929
|
-
let px = 0;
|
|
52930
|
-
let py = 0;
|
|
52931
|
-
const material = finish ?? M.metal;
|
|
52932
|
-
for (const angle of [0.06, 0.22, 0.38]) {
|
|
52933
|
-
const length2 = 0.07 * scale;
|
|
52934
|
-
const cx = px + Math.sin(angle) * length2 / 2;
|
|
52935
|
-
const cy = py - Math.cos(angle) * length2 / 2;
|
|
52936
|
-
box5(magazine, 0.052, length2 + 4e-3, 0.024, material, cx, cy, 0, angle);
|
|
52937
|
-
box5(magazine, 0.04, length2 * 0.8, 0.026, M.dark, cx, cy, 0, angle);
|
|
52938
|
-
px += Math.sin(angle) * length2;
|
|
52939
|
-
py -= Math.cos(angle) * length2;
|
|
52940
|
-
}
|
|
52941
|
-
box5(magazine, 0.058, 8e-3, 0.028, material, px, py, 0, 0.38);
|
|
52942
|
-
parts.magDrop = 0.07 * scale * 3 + 0.04;
|
|
52943
|
-
} else if (o.mag === "box") {
|
|
52944
|
-
const length2 = 0.13 * scale;
|
|
52945
|
-
const curve = o.curve || 0;
|
|
52946
|
-
const segment = length2 / 3;
|
|
52947
|
-
const material = finish ?? M.dark;
|
|
52948
|
-
let px = 0;
|
|
52949
|
-
let py = 0;
|
|
52950
|
-
let angle = 0.08;
|
|
52951
|
-
for (let i = 0; i < 3; i++) {
|
|
52952
|
-
angle = 0.08 + curve * i;
|
|
52953
|
-
const cx = px + Math.sin(angle) * segment / 2;
|
|
52954
|
-
const cy = py - Math.cos(angle) * segment / 2;
|
|
52955
|
-
box5(magazine, 0.05, segment + 4e-3, 0.024, material, cx, cy, 0, angle);
|
|
52956
|
-
box5(magazine, 0.04, 3e-3, 0.026, M.metal, cx, cy, 0, angle);
|
|
52957
|
-
px += Math.sin(angle) * segment;
|
|
52958
|
-
py -= Math.cos(angle) * segment;
|
|
52959
|
-
}
|
|
52960
|
-
box5(magazine, 0.056, 7e-3, 0.028, material, px, py - 2e-3, 0, angle);
|
|
52961
|
-
parts.magDrop = length2 + 0.03;
|
|
52962
|
-
} else if (o.mag === "drum") {
|
|
52963
|
-
buildDrum(kit, magazine);
|
|
52964
|
-
parts.magDrop = 0.2;
|
|
52965
|
-
} else if (o.mag === "internal") {
|
|
52966
|
-
box5(group, 0.08, 0.025, 0.03, context.isTraditional ? context.furniture : M.metal, mx, -hR / 2 - 0.012, 0);
|
|
52967
|
-
parts.mag = null;
|
|
52968
|
-
} else parts.mag = null;
|
|
52969
|
-
if (o.mag === "belt") {
|
|
52970
|
-
const belt = kit.pivot(group, mx + 0.02, -hR / 2 - 0.05, -0.045);
|
|
52971
|
-
parts.belt = belt;
|
|
52972
|
-
buildBeltBox(kit, belt);
|
|
52973
|
-
const cover = kit.pivot(group, x0 + 0.01, hR / 2, 0);
|
|
52974
|
-
parts.cover = cover;
|
|
52975
|
-
box5(cover, RL - 0.03, 0.014, wR * 1.05, M.metal, (RL - 0.03) / 2, 7e-3, 0);
|
|
52976
|
-
box5(cover, 0.02, 0.012, wR * 0.6, M.dark, RL - 0.04, 0.016, 0);
|
|
52977
|
-
}
|
|
52978
|
-
return mx;
|
|
52979
|
-
}
|
|
52980
|
-
|
|
52981
|
-
// src/models/rifle-stock.ts
|
|
52982
|
-
function buildStock(context, magazineX) {
|
|
52983
|
-
const { kit, group, options: o, furniture: furn, length: L, stockLength: S, receiverStart: x0, receiverEnd: x1, receiverHeight: hR } = context;
|
|
52984
|
-
const { M, box: box5, cylinderX } = kit;
|
|
52985
|
-
if (context.isTraditional) {
|
|
52986
|
-
buttpad(kit, group, 6e-3, -0.04, 0.13, 0.038);
|
|
52987
|
-
box5(group, 0.03, 0.13, 0.038, furn, 0.024, -0.04, 0);
|
|
52988
|
-
box5(group, S, 0.055, 0.034, furn, S / 2, -0.012, 0, 0.06);
|
|
52989
|
-
box5(group, 0.09, 0.05, 0.032, furn, x0 - 0.02, -0.035, 0, 0.25);
|
|
52990
|
-
const forendLength = x1 - x0 + (L - x1) * (o.fore ?? 0.62);
|
|
52991
|
-
if (forendLength > 0) box5(group, forendLength, 0.045, 0.04, furn, x0 + forendLength / 2, -hR / 2 + 4e-3, 0);
|
|
52992
|
-
if (o.stock === "straight") box5(group, 0.15, 0.04, 0.035, furn, x1 + 0.08, -hR / 2, 0);
|
|
52993
|
-
box5(group, 0.04, 4e-3, 0.03, M.metal, magazineX, -hR / 2 - 0.022, 0);
|
|
52994
|
-
swivel(kit, group, 0.2, -0.08);
|
|
52995
|
-
swivel(kit, group, x1 + (L - x1) * 0.45, -hR / 2 - 0.03);
|
|
52996
|
-
if (o.bands) for (const fraction of [0.35, 0.75]) cylinderX(group, 0.024, 8e-3, M.metal, x1 + (L - x1) * fraction * (o.fore || 0.62), -4e-3, 0, 16);
|
|
52997
|
-
} else if (o.stock === "fixed" || o.stock === "wood") {
|
|
52998
|
-
box5(group, S, 0.05, 0.03, furn, S / 2, -8e-3, 0, 0.05);
|
|
52999
|
-
box5(group, 0.03, 0.13, 0.036, furn, 0.022, -0.035, 0);
|
|
53000
|
-
buttpad(kit, group, 4e-3, -0.035, 0.13, 0.036);
|
|
53001
|
-
if (o.stock === "wood") box5(group, S * 0.6, 0.03, 0.028, furn, S * 0.55, -0.045, 0, 0.2);
|
|
53002
|
-
swivel(kit, group, 0.08, -0.09);
|
|
53003
|
-
} else if (o.stock === "skeleton") {
|
|
53004
|
-
box5(group, S, 0.014, 0.026, furn, S / 2, 0.012, 0, 0.03);
|
|
53005
|
-
box5(group, S, 0.014, 0.026, furn, S / 2, -0.05, 0, -0.08);
|
|
53006
|
-
box5(group, 0.03, 0.12, 0.034, furn, 0.02, -0.025, 0);
|
|
53007
|
-
buttpad(kit, group, 4e-3, -0.025, 0.12, 0.034);
|
|
53008
|
-
} else if (o.stock === "retract") {
|
|
53009
|
-
cylinderX(group, 0.013, S, M.metal, S / 2, 0, 0, 16);
|
|
53010
|
-
for (let i = 0; i < 5; i++) box5(group, 3e-3, 3e-3, 8e-3, M.dark, S * 0.2 + i * 0.015, -0.013, 0);
|
|
53011
|
-
box5(group, 0.034, 0.11, 0.036, furn, 0.02, -0.025, 0);
|
|
53012
|
-
box5(group, S * 0.55, 0.032, 0.03, furn, S * 0.35, 0, 0);
|
|
53013
|
-
buttpad(kit, group, 3e-3, -0.025, 0.11, 0.036);
|
|
53014
|
-
} else if (o.stock === "fold") {
|
|
53015
|
-
box5(group, S, 6e-3, 6e-3, M.metal, S / 2, 0.01, 0.012);
|
|
53016
|
-
box5(group, S, 6e-3, 6e-3, M.metal, S / 2, -0.04, 0.012, -0.12);
|
|
53017
|
-
box5(group, 0.012, 0.1, 0.03, M.metal, 6e-3, -0.02, 0.012);
|
|
53018
|
-
}
|
|
53019
|
-
}
|
|
53020
|
-
|
|
53021
|
-
// src/models/rifle.ts
|
|
53022
|
-
var PI11 = Math.PI;
|
|
53023
|
-
function buildReceiver(context) {
|
|
53024
|
-
const { kit, group, parts, options: o, length: L, receiverStart: x0, receiverEnd: x1, receiverHeight: hR, receiverWidth: wR, receiverLength: RL, barrelY: by } = context;
|
|
53025
|
-
const { M, box: box5, cylinderX, cylinderY, cylinderZ, sphere: sphere2 } = kit;
|
|
53026
|
-
const receiverMaterial = o.tan ? M.tan : M.metal;
|
|
53027
|
-
const middle = (x0 + x1) / 2;
|
|
53028
|
-
if (o.round) {
|
|
53029
|
-
cylinderX(group, hR * 0.36, RL, M.steel, middle, by, 0, 20);
|
|
53030
|
-
cylinderX(group, hR * 0.32, 0.05, M.steel, x0 - 0.01, by, 0, 18);
|
|
53031
|
-
} else if (o.ar) {
|
|
53032
|
-
box5(group, RL, hR * 0.5, wR, receiverMaterial, middle, hR * 0.25, 0);
|
|
53033
|
-
box5(group, RL * 0.92, hR * 0.52, wR * 0.96, receiverMaterial, middle - RL * 0.02, -hR * 0.24, 0);
|
|
53034
|
-
box5(group, 0.05, 0.03, wR * 1.15, receiverMaterial, x0 + RL * 0.62, -hR * 0.5 - 0.01, 0);
|
|
53035
|
-
cylinderZ(group, 6e-3, 0.012, M.metal, x1 - 0.03, hR * 0.28, wR / 2 + 6e-3, 12);
|
|
53036
|
-
box5(group, 0.012, 0.01, 0.012, M.metal, x1 - 0.05, hR * 0.12, wR / 2 + 6e-3);
|
|
53037
|
-
box5(group, 0.03, 8e-3, 0.012, M.dark, x0 + 0.02, hR / 2 + 4e-3, 0);
|
|
53038
|
-
box5(group, 0.012, 6e-3, 4e-3, M.dark, x0 + RL * 0.55, -hR * 0.15, -wR / 2 - 2e-3);
|
|
53039
|
-
} else box5(group, RL, hR, wR, receiverMaterial, middle, 0, 0);
|
|
53040
|
-
if (o.ak) {
|
|
53041
|
-
box5(group, RL * 0.86, hR * 0.28, wR * 0.95, M.metal, middle - 8e-3, hR / 2 + 4e-3, 0);
|
|
53042
|
-
for (let i = 0; i < 3; i++) box5(group, 4e-3, hR * 0.3, wR * 0.97, M.dark, x0 + RL * 0.25 + i * 0.02, hR / 2 + 4e-3, 0);
|
|
53043
|
-
box5(group, RL * 0.5, 0.012, 3e-3, M.metal, x0 + RL * 0.55, -hR * 0.02, wR / 2 + 15e-4, -0.05);
|
|
53044
|
-
box5(group, 0.012, 0.014, 3e-3, M.dark, x0 + RL * 0.32, -hR * 0.05, wR / 2 + 2e-3);
|
|
53045
|
-
}
|
|
53046
|
-
if (o.g3) {
|
|
53047
|
-
cylinderX(group, 9e-3, (L - x1) * 0.6, M.metal, x1 + (L - x1) * 0.28, hR * 0.48, 0, 14);
|
|
53048
|
-
box5(group, 0.012, 0.024, 8e-3, M.dark, x1 + (L - x1) * 0.5, hR * 0.48, -0.012);
|
|
53049
|
-
cylinderY(group, 0.012, 0.016, M.dark, x0 + 0.03, hR / 2 + 8e-3, 0, 12);
|
|
53050
|
-
}
|
|
53051
|
-
const ejectX = x1 - (o.ejectBack || 0.07);
|
|
53052
|
-
const ejectY = o.ar ? hR * 0.2 : by;
|
|
53053
|
-
box5(group, 0.05, hR * 0.36, 4e-3, M.hole, ejectX, ejectY, wR / 2 - 4e-4);
|
|
53054
|
-
const bolt = kit.pivot(group);
|
|
53055
|
-
parts.bolt = bolt;
|
|
53056
|
-
parts.stroke = Math.min(0.1, RL * 0.32);
|
|
53057
|
-
box5(bolt, 0.044, hR * 0.26, 6e-3, M.steelL, ejectX, ejectY, wR / 2 - 12e-4);
|
|
53058
|
-
if (o.charge) {
|
|
53059
|
-
box5(bolt, 0.012, 0.01, 0.03, M.metal, ejectX + 0.04, ejectY + 4e-3, wR / 2 + 0.012);
|
|
53060
|
-
sphere2(bolt, 65e-4, M.metal, ejectX + 0.04, ejectY + 4e-3, wR / 2 + 0.028, 1);
|
|
53061
|
-
}
|
|
53062
|
-
if (o.ar) box5(group, 0.012, 0.016, 6e-3, receiverMaterial, ejectX - 0.03, ejectY + 4e-3, wR / 2 + 4e-3);
|
|
53063
|
-
if (o.rail) rail(kit, group, x0 - 5e-3, RL + 0.07, hR / 2 + (o.ar ? 0 : 3e-3), 0, wR * 0.68);
|
|
53064
|
-
}
|
|
53065
|
-
function buildBarrel(context) {
|
|
53066
|
-
const { kit, group, parts, options: o, length: L, barrelLength: Bl, receiverEnd: x1, barrelRadius: r, barrelY: by } = context;
|
|
53067
|
-
const { M, box: box5, cylinderX } = kit;
|
|
53068
|
-
heatify(parts.glow, cylinderX(group, r, Bl, M.metal, L - Bl / 2, by, 0, 16));
|
|
53069
|
-
if (o.jacket) {
|
|
53070
|
-
cylinderX(group, r * 2, (L - x1) * 0.6, M.dark, x1 + (L - x1) * 0.3, by, 0, 16);
|
|
53071
|
-
for (let i = 0; i < 6; i++) cylinderX(group, r * 2.15, 4e-3, M.metal, x1 + (L - x1) * (0.05 + i * 0.09), by, 0, 16);
|
|
53072
|
-
}
|
|
53073
|
-
if (o.gas) cylinderX(group, r * 0.75, (L - x1) * 0.55, M.metal, x1 + (L - x1) * 0.3, by + r * 2.2, 0, 14);
|
|
53074
|
-
if (o.brake) {
|
|
53075
|
-
const kind = o.brake === 2 ? 2 : 1;
|
|
53076
|
-
recordFitting(parts, kind === 2 ? "muzzle_brake_heavy" : "muzzle_brake", group, () => buildBrake(kit, group, kind, L, by, r, (body) => void heatify(parts.glow, body)));
|
|
53077
|
-
} else if (!o.noFH) {
|
|
53078
|
-
recordFitting(parts, "muzzle_default", group, () => {
|
|
53079
|
-
heatify(parts.glow, cylinderX(group, r * 1.45, 0.042, M.dark, L - 0.021, by, 0, 16));
|
|
53080
|
-
for (let i = 0; i < 4; i++) {
|
|
53081
|
-
const angle = i * PI11 / 2 + PI11 / 4;
|
|
53082
|
-
box5(group, 0.026, 25e-4, 4e-3, M.hole, L - 0.02, by + Math.cos(angle) * r * 1.42, Math.sin(angle) * r * 1.42, 0, 0, angle);
|
|
53083
|
-
}
|
|
53084
|
-
});
|
|
53085
|
-
}
|
|
53086
|
-
cylinderX(group, r * 0.55, 4e-3, M.hole, L + 5e-4, by, 0, 12);
|
|
53087
|
-
}
|
|
53088
|
-
var familyOf = (o) => {
|
|
53089
|
-
if (o.mag === "belt") return "belt";
|
|
53090
|
-
if (o.pump) return "pump";
|
|
53091
|
-
if (o.lever) return "lever";
|
|
53092
|
-
if (o.tube) return "semi12";
|
|
53093
|
-
if (o.bolt) return o.mag === "box" ? "boltmag" : "bolt";
|
|
53094
|
-
return o.mag === "internal" ? "semiint" : "rifle";
|
|
53095
|
-
};
|
|
53096
|
-
function buildRifle(kit, options) {
|
|
53097
|
-
const { M } = kit;
|
|
53098
|
-
const group = kit.group();
|
|
53099
|
-
const parts = { family: "rifle", glow: [] };
|
|
53100
|
-
const length2 = (options.L ?? 0) / 1e3;
|
|
53101
|
-
const barrelLength = (options.B ?? 0) / 1e3;
|
|
53102
|
-
const isTraditional = options.stock === "trad" || options.stock === "straight";
|
|
53103
|
-
const stockLength = options.stock === "none" ? 0 : options.stockLen || Math.min(0.36, Math.max(0.2, 0.3 * length2));
|
|
53104
|
-
const receiverStart = stockLength;
|
|
53105
|
-
const receiverEnd = Math.max(receiverStart + 0.12, length2 - barrelLength * 0.92);
|
|
53106
|
-
const receiverHeight = options.hR || 0.06;
|
|
53107
|
-
const context = {
|
|
53108
|
-
kit,
|
|
53109
|
-
group,
|
|
53110
|
-
parts,
|
|
53111
|
-
options,
|
|
53112
|
-
furniture: options.wood ? M.wood : options.olive ? M.olive : options.tan ? M.tan : M.poly,
|
|
53113
|
-
isTraditional,
|
|
53114
|
-
length: length2,
|
|
53115
|
-
barrelLength,
|
|
53116
|
-
stockLength,
|
|
53117
|
-
receiverStart,
|
|
53118
|
-
receiverEnd,
|
|
53119
|
-
receiverHeight,
|
|
53120
|
-
receiverWidth: options.wR || 0.034,
|
|
53121
|
-
barrelRadius: options.br || 85e-4,
|
|
53122
|
-
barrelY: receiverHeight * 0.15,
|
|
53123
|
-
receiverLength: receiverEnd - receiverStart
|
|
53124
|
-
};
|
|
53125
|
-
buildReceiver(context);
|
|
53126
|
-
buildBarrel(context);
|
|
53127
|
-
buildForend(context);
|
|
53128
|
-
const gripX = buildGrip(context);
|
|
53129
|
-
const magazineX = buildMagazine(context, gripX);
|
|
53130
|
-
parts.stockMeshes = context.isTraditional ? [] : captured(group, () => buildStock(context, magazineX));
|
|
53131
|
-
if (context.isTraditional) buildStock(context, magazineX);
|
|
53132
|
-
buildFittings(context, gripX);
|
|
53133
|
-
const hasHandguard = !context.isTraditional && options.hg !== "none";
|
|
53134
|
-
parts.frames = {
|
|
53135
|
-
length: length2,
|
|
53136
|
-
barrelY: context.barrelY,
|
|
53137
|
-
barrelRadius: context.barrelRadius,
|
|
53138
|
-
receiverStart,
|
|
53139
|
-
receiverEnd,
|
|
53140
|
-
receiverHeight,
|
|
53141
|
-
receiverWidth: context.receiverWidth,
|
|
53142
|
-
handguardEnd: receiverEnd + (length2 - receiverEnd) * (hasHandguard ? options.hgFrac || 0.5 : 0.4),
|
|
53143
|
-
magazineX,
|
|
53144
|
-
gripX,
|
|
53145
|
-
hasRail: Boolean(options.rail)
|
|
53146
|
-
};
|
|
53147
|
-
const { barrelY: by, receiverWidth: wR } = context;
|
|
53148
|
-
const ejectX = receiverEnd - (options.ejectBack || 0.07);
|
|
53149
|
-
const ejectY = options.ar ? receiverHeight * 0.2 : by;
|
|
53150
|
-
parts.muzzle = kit.mark(group, length2 + 0.01, by, 0);
|
|
53151
|
-
parts.eject = kit.mark(group, ejectX, ejectY, wR / 2 + 6e-3);
|
|
53152
|
-
parts.loadPort = kit.mark(group, receiverEnd - 0.05, -receiverHeight / 2 - 4e-3, 0);
|
|
53153
|
-
parts.topLoad = kit.mark(group, ejectX, receiverHeight / 2 + 4e-3, 0);
|
|
53154
|
-
parts.family = familyOf(options);
|
|
53155
|
-
return { group, parts };
|
|
53156
|
-
}
|
|
53157
|
-
|
|
53158
54083
|
// src/models/index.ts
|
|
53159
54084
|
var MODEL_ENTRIES = models_default2;
|
|
53160
54085
|
var ARCHETYPE_MODELS = (() => {
|
|
@@ -53167,13 +54092,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
53167
54092
|
}
|
|
53168
54093
|
return chosen;
|
|
53169
54094
|
})();
|
|
53170
|
-
var
|
|
54095
|
+
var BUILDERS4 = {
|
|
53171
54096
|
pistol: buildPistol,
|
|
53172
54097
|
revolver: buildRevolver,
|
|
53173
54098
|
rifle: buildRifle,
|
|
53174
54099
|
bullpup: buildBullpup,
|
|
53175
54100
|
p90: (kit) => buildP90(kit),
|
|
53176
54101
|
break: buildBreakAction,
|
|
54102
|
+
breakLauncher: buildBreakLauncher,
|
|
53177
54103
|
m2: (kit) => buildM2(kit),
|
|
53178
54104
|
m134: (kit) => buildM134(kit),
|
|
53179
54105
|
launcher: buildLauncher
|
|
@@ -53197,7 +54123,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
53197
54123
|
const kit = modelKit(THREE);
|
|
53198
54124
|
const options = { L: entry2.length, B: entry2.barrel, cal: entry2.caliber, ...entry2.options };
|
|
53199
54125
|
if (id in ARCHETYPE_MODELS) delete options.chambers;
|
|
53200
|
-
const built2 =
|
|
54126
|
+
const built2 = BUILDERS4[entry2.builder](kit, options);
|
|
53201
54127
|
nameParts(built2.parts);
|
|
53202
54128
|
let root;
|
|
53203
54129
|
if (entry2.builder === "launcher") {
|
|
@@ -53432,9 +54358,17 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
53432
54358
|
if (kind !== "one_by_one") events.push(cue(0.7, "move_in", { from: "chambers" }), sound2(0.7, "speedloader"));
|
|
53433
54359
|
return { tweens: [turn("crane", "x", 0, 0.22, 0, -1.25), turn("crane", "x", 1.05, 0.2, -1.25, 0)], events, end: 1.3 };
|
|
53434
54360
|
}
|
|
53435
|
-
var breakReload = () => ({
|
|
54361
|
+
var breakReload = (chambers) => ({
|
|
53436
54362
|
tweens: [turn("barrels", "z", 0, 0.2, 0, -0.5), turn("barrels", "z", 1, 0.15, -0.5, 0)],
|
|
53437
|
-
events: [
|
|
54363
|
+
events: [
|
|
54364
|
+
sound2(0, "barrels_open"),
|
|
54365
|
+
cue(0.25, "eject_casing", { from: "breech", down: false }),
|
|
54366
|
+
sound2(0.25, "casings_eject"),
|
|
54367
|
+
cue(0.65, "move_in", { from: "breech" }),
|
|
54368
|
+
sound2(0.65, "shell_insert"),
|
|
54369
|
+
...chambers > 1 ? [sound2(0.8, "shell_insert")] : [],
|
|
54370
|
+
sound2(1.13, "barrels_close")
|
|
54371
|
+
],
|
|
53438
54372
|
end: 1.2
|
|
53439
54373
|
});
|
|
53440
54374
|
var beltReload = (context) => ({
|
|
@@ -53507,7 +54441,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
53507
54441
|
if (family === "rocket" || family === "flame") return heavyReload(context);
|
|
53508
54442
|
if (parts.mag) return magazineReload(context, kind);
|
|
53509
54443
|
if (family === "revolver" && parts.crane) return revolverReload(kind);
|
|
53510
|
-
if (family === "break" && parts.barrels) return breakReload();
|
|
54444
|
+
if (family === "break" && parts.barrels) return breakReload(parts.breech?.length ?? 2);
|
|
53511
54445
|
if (family === "belt" && parts.cover && parts.belt) return beltReload(context);
|
|
53512
54446
|
if (isTube(context)) return tubeReload(context, kind);
|
|
53513
54447
|
if (family === "bolt") return boltReload(context);
|
|
@@ -55642,16 +56576,16 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
55642
56576
|
if (this.spaces.delete(id)) this.list = [...this.spaces.values()];
|
|
55643
56577
|
return;
|
|
55644
56578
|
}
|
|
55645
|
-
const [hx, hy,
|
|
56579
|
+
const [hx, hy, hz2] = enclosure.halfSize;
|
|
55646
56580
|
const space = {
|
|
55647
56581
|
cx: enclosure.center[0],
|
|
55648
56582
|
cy: enclosure.center[1],
|
|
55649
56583
|
cz: enclosure.center[2],
|
|
55650
56584
|
hx: Math.abs(hx),
|
|
55651
56585
|
hy: Math.abs(hy),
|
|
55652
|
-
hz: Math.abs(
|
|
56586
|
+
hz: Math.abs(hz2),
|
|
55653
56587
|
r: rotation(enclosure.orientation),
|
|
55654
|
-
radius: Math.hypot(hx, hy,
|
|
56588
|
+
radius: Math.hypot(hx, hy, hz2),
|
|
55655
56589
|
openings: enclosure.openings ?? [],
|
|
55656
56590
|
leak: Math.max(0, enclosure.leak ?? 0)
|
|
55657
56591
|
};
|
|
@@ -59834,13 +60768,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
59834
60768
|
function composeAfterEffects(context) {
|
|
59835
60769
|
const { core, def, random, x, y, z } = context;
|
|
59836
60770
|
const mark = def.mark;
|
|
59837
|
-
|
|
60771
|
+
const keepsMarks = !core.marklessAt?.(x, z);
|
|
60772
|
+
if (keepsMarks && mark.crater && mark.dent && y < 1.2) {
|
|
59838
60773
|
core.emit({ type: "crater", x, z, radius: mark.crater, depth: mark.dent });
|
|
59839
60774
|
core.trace?.crater?.(x, z, mark.crater, mark.dent);
|
|
59840
60775
|
addCrater(core.marks, core.ground, random, { x, z, radius: mark.crater, depth: mark.dent, marks: core.layers.mark });
|
|
59841
60776
|
if (core.layers.shrapnel) composeRimDebris(context);
|
|
59842
60777
|
}
|
|
59843
|
-
if (mark.scorch && y < 1.2 && core.layers.mark) {
|
|
60778
|
+
if (keepsMarks && mark.scorch && y < 1.2 && core.layers.mark) {
|
|
59844
60779
|
core.trace?.scorch?.(x, z, mark.scorch);
|
|
59845
60780
|
addScorch(core.marks, random, x, z, mark.scorch);
|
|
59846
60781
|
}
|
|
@@ -61549,7 +62484,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
61549
62484
|
const wind = { x: DEFAULT_WIND.x, y: DEFAULT_WIND.y, z: DEFAULT_WIND.z };
|
|
61550
62485
|
if (options.wind) [wind.x, wind.y, wind.z] = options.wind;
|
|
61551
62486
|
const camera2 = { x: 0, y: 1.6, z: 0 };
|
|
61552
|
-
const layers = Object.fromEntries(VFX_LAYERS.map((
|
|
62487
|
+
const layers = Object.fromEntries(VFX_LAYERS.map((layer3) => [layer3, true]));
|
|
61553
62488
|
const ground = options.ground;
|
|
61554
62489
|
const groundAt = options.groundAt ?? (ground ? (x, z) => ground.heightAt(x, z) : () => 0);
|
|
61555
62490
|
const handles = { next: 0, events: 0 };
|
|
@@ -61591,6 +62526,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
61591
62526
|
spawned: { puffs: 0, sparks: 0, chunks: 0, lights: 0 },
|
|
61592
62527
|
clock: { time: 0, lastBlast: -1, lod: 1, forcedLod: null },
|
|
61593
62528
|
groundAt,
|
|
62529
|
+
...options.marklessAt ? { marklessAt: options.marklessAt } : {},
|
|
61594
62530
|
emit: (request) => options.onRequest?.(request)
|
|
61595
62531
|
};
|
|
61596
62532
|
function definitionOf(id) {
|
|
@@ -61617,6 +62553,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
61617
62553
|
return player ?? (player = createEffectPlayer({ engine: workshop(), effects, view }));
|
|
61618
62554
|
}
|
|
61619
62555
|
return {
|
|
62556
|
+
hostGroundAt: options.groundAt,
|
|
61620
62557
|
play(id, point, playOptions = {}) {
|
|
61621
62558
|
if (!(id in effects)) return null;
|
|
61622
62559
|
const seed = playOptions.seed ?? (randomMode === "shared" ? void 0 : Math.imul(++handles.events, AUTO_SEED) + (options.seed ?? 0));
|
|
@@ -61679,10 +62616,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
61679
62616
|
const fires = core.fires;
|
|
61680
62617
|
for (let index = fires.items.length - 1; index >= 0; index--) if (fires.items[index].handle === handle) fires.removeAt(index);
|
|
61681
62618
|
},
|
|
61682
|
-
setLayer(
|
|
61683
|
-
layers[
|
|
62619
|
+
setLayer(layer3, on) {
|
|
62620
|
+
layers[layer3] = on;
|
|
61684
62621
|
},
|
|
61685
|
-
layer: (
|
|
62622
|
+
layer: (layer3) => layers[layer3],
|
|
61686
62623
|
setCamera(position) {
|
|
61687
62624
|
camera2.x = position[0];
|
|
61688
62625
|
camera2.y = position[1];
|
|
@@ -61769,7 +62706,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
61769
62706
|
};
|
|
61770
62707
|
}
|
|
61771
62708
|
|
|
61772
|
-
// ../game-vfx-three/dist/chunk-
|
|
62709
|
+
// ../game-vfx-three/dist/chunk-CPRCWTSQ.js
|
|
61773
62710
|
var GLOW_VERTEX = `attribute vec4 aP;attribute vec4 aC;varying vec2 vU;varying vec4 vC;
|
|
61774
62711
|
void main(){vec3 R=vec3(viewMatrix[0][0],viewMatrix[1][0],viewMatrix[2][0]);vec3 Up=vec3(viewMatrix[0][1],viewMatrix[1][1],viewMatrix[2][1]);
|
|
61775
62712
|
vec3 wp=aP.xyz+(R*position.x+Up*position.y)*aP.w;vU=position.xy;vC=aC;gl_Position=projectionMatrix*viewMatrix*vec4(wp,1.);}`;
|
|
@@ -62209,7 +63146,11 @@ void main(){
|
|
|
62209
63146
|
const dirt = texture(paint(make3, (context, size) => drawDirt(context, size, random)));
|
|
62210
63147
|
return { scorch, dirt };
|
|
62211
63148
|
}
|
|
62212
|
-
var
|
|
63149
|
+
var FLAT_STEPS_PER_METRE = 8;
|
|
63150
|
+
var MAX_FLAT_STEPS = 48;
|
|
63151
|
+
var DUG_STEPS_PER_METRE = 20;
|
|
63152
|
+
var MAX_DUG_STEPS = 64;
|
|
63153
|
+
var FLAT_TOLERANCE = 2e-3;
|
|
62213
63154
|
var MIN_CONFORM_STEPS = 16;
|
|
62214
63155
|
var BLOOD_GROW_RATE = 1.2;
|
|
62215
63156
|
var BLOOD_START_GROWTH = 0.05;
|
|
@@ -62292,9 +63233,21 @@ void main(){
|
|
|
62292
63233
|
spareGeometries.push(oldest.mesh.geometry);
|
|
62293
63234
|
if (spareGeometries.length > MAX_SPARE_GROUND_GEOMETRIES) spareGeometries.shift().dispose();
|
|
62294
63235
|
}
|
|
63236
|
+
const heightAt = options.heightAt ?? ((x, z) => options.ground?.heightAt(x, z) ?? 0);
|
|
63237
|
+
function groundDipsUnder(x, z, radius) {
|
|
63238
|
+
const centre = heightAt(x, z);
|
|
63239
|
+
for (const share of [0.25, 0.5, 0.75]) {
|
|
63240
|
+
for (let ray = 0; ray < 8; ray++) {
|
|
63241
|
+
const angle = ray / 8 * Math.PI * 2;
|
|
63242
|
+
if (Math.abs(heightAt(x + Math.cos(angle) * radius * share, z + Math.sin(angle) * radius * share) - centre) > FLAT_TOLERANCE) return true;
|
|
63243
|
+
}
|
|
63244
|
+
}
|
|
63245
|
+
return false;
|
|
63246
|
+
}
|
|
62295
63247
|
function conform(mark, material) {
|
|
62296
63248
|
const radius = mark.radius;
|
|
62297
|
-
const
|
|
63249
|
+
const dug = options.heightAt !== void 0 && groundDipsUnder(mark.x, mark.z, radius);
|
|
63250
|
+
const steps = Math.max(MIN_CONFORM_STEPS, Math.min(dug ? MAX_DUG_STEPS : MAX_FLAT_STEPS, Math.round(radius * (dug ? DUG_STEPS_PER_METRE : FLAT_STEPS_PER_METRE))));
|
|
62298
63251
|
if (groundMarks.length >= maxGroundMarks) evictOldestGroundMark();
|
|
62299
63252
|
const geometry = takeSpare((steps + 1) * (steps + 1)) ?? new THREE.PlaneGeometry(2, 2, steps, steps).rotateX(-Math.PI / 2);
|
|
62300
63253
|
const grid = geometry.attributes.position;
|
|
@@ -62306,7 +63259,7 @@ void main(){
|
|
|
62306
63259
|
const localZ = Math.fround(Math.floor(index / (steps + 1)) * cell - 1) * radius;
|
|
62307
63260
|
const worldX = mark.x + localX * cos2 - localZ * sin2;
|
|
62308
63261
|
const worldZ = mark.z + localX * sin2 + localZ * cos2;
|
|
62309
|
-
grid.setXYZ(index, worldX,
|
|
63262
|
+
grid.setXYZ(index, worldX, heightAt(worldX, worldZ) + mark.lift, worldZ);
|
|
62310
63263
|
}
|
|
62311
63264
|
grid.needsUpdate = true;
|
|
62312
63265
|
geometry.computeVertexNormals();
|
|
@@ -62504,7 +63457,7 @@ void main(){
|
|
|
62504
63457
|
};
|
|
62505
63458
|
}
|
|
62506
63459
|
var clamp5 = (value, min2, max2) => value < min2 ? min2 : value > max2 ? max2 : value;
|
|
62507
|
-
function
|
|
63460
|
+
function layer2(container, name, blend) {
|
|
62508
63461
|
const element = container.ownerDocument.createElement("div");
|
|
62509
63462
|
element.dataset.vfxOverlay = name;
|
|
62510
63463
|
Object.assign(element.style, { position: "absolute", inset: "0", pointerEvents: "none", opacity: "0" });
|
|
@@ -62513,12 +63466,12 @@ void main(){
|
|
|
62513
63466
|
return element;
|
|
62514
63467
|
}
|
|
62515
63468
|
function createScreenOverlay(container) {
|
|
62516
|
-
const flash2 =
|
|
63469
|
+
const flash2 = layer2(container, "flash", "screen");
|
|
62517
63470
|
flash2.style.background = "#fff";
|
|
62518
|
-
const white =
|
|
62519
|
-
const red =
|
|
62520
|
-
const sides =
|
|
62521
|
-
const gas =
|
|
63471
|
+
const white = layer2(container, "white");
|
|
63472
|
+
const red = layer2(container, "red");
|
|
63473
|
+
const sides = layer2(container, "sides");
|
|
63474
|
+
const gas = layer2(container, "gas");
|
|
62522
63475
|
const elements = [flash2, white, red, sides, gas];
|
|
62523
63476
|
return {
|
|
62524
63477
|
update(state) {
|
|
@@ -62978,7 +63931,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
62978
63931
|
decalLayer(THREE, engine.decals),
|
|
62979
63932
|
ringLayer(THREE, engine.rings)
|
|
62980
63933
|
];
|
|
62981
|
-
for (const
|
|
63934
|
+
for (const layer22 of layers) group.add(layer22.object);
|
|
62982
63935
|
const meshes = createMeshLayer(THREE, engine.meshes);
|
|
62983
63936
|
group.add(meshes.group);
|
|
62984
63937
|
const lights = budget ? budgetedLights(engine, lightScale, budget) : legacyLights(THREE, engine, lightScale, group);
|
|
@@ -62986,13 +63939,13 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
62986
63939
|
group,
|
|
62987
63940
|
sync() {
|
|
62988
63941
|
let drawCalls = 0;
|
|
62989
|
-
for (const
|
|
63942
|
+
for (const layer22 of layers) if (layer22.sync()) drawCalls++;
|
|
62990
63943
|
drawCalls += meshes.sync();
|
|
62991
63944
|
lights.sync();
|
|
62992
63945
|
return drawCalls;
|
|
62993
63946
|
},
|
|
62994
63947
|
dispose() {
|
|
62995
|
-
for (const
|
|
63948
|
+
for (const layer22 of layers) layer22.dispose();
|
|
62996
63949
|
meshes.dispose();
|
|
62997
63950
|
lights.dispose();
|
|
62998
63951
|
group.clear();
|
|
@@ -63096,7 +64049,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
63096
64049
|
const shocks = createShockLayer(THREE, pools.shocks);
|
|
63097
64050
|
const sprites = createSpriteLayer(THREE, world.sprites(), options.pointScale ?? 700);
|
|
63098
64051
|
const lights = createLightLayer(THREE, pools.lights, options.lightScale ?? Math.PI, options.lights);
|
|
63099
|
-
const marks = createMarkLayer(THREE, { ground: pools.ground, createCanvas: options.createCanvas, rockGeometry, plateGeometry, ...options.markLimits });
|
|
64052
|
+
const marks = createMarkLayer(THREE, { ground: pools.ground, ...world.hostGroundAt ? { heightAt: world.hostGroundAt } : {}, createCanvas: options.createCanvas, rockGeometry, plateGeometry, ...options.markLimits });
|
|
63100
64053
|
root.add(puffs.mesh, sparks.mesh, glows.mesh, chunks.rocks, chunks.plates, shocks.group, lights.group, sprites.additive, sprites.normal, marks.group);
|
|
63101
64054
|
const stopMarks = world.onMarks((event) => marks.handle(event));
|
|
63102
64055
|
const overlay = options.overlay ? createScreenOverlay(options.overlay) : void 0;
|
|
@@ -63229,7 +64182,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
63229
64182
|
stopMarks();
|
|
63230
64183
|
overlay?.dispose();
|
|
63231
64184
|
workshopLayers?.dispose();
|
|
63232
|
-
for (const
|
|
64185
|
+
for (const layer22 of [puffs, sparks, glows, chunks, shocks, lights, marks, sprites]) layer22.dispose();
|
|
63233
64186
|
rockGeometry.dispose();
|
|
63234
64187
|
plateGeometry.dispose();
|
|
63235
64188
|
options.scene.remove(root);
|
|
@@ -63263,6 +64216,38 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
63263
64216
|
};
|
|
63264
64217
|
}
|
|
63265
64218
|
|
|
64219
|
+
// src/fx/view-hold.ts
|
|
64220
|
+
var VIEW_HOLD = {
|
|
64221
|
+
/** The right hand's grip, from the eye. */
|
|
64222
|
+
grip: [0.2, -0.2, -0.3],
|
|
64223
|
+
/** A handgun's grip: higher and nearer the middle, the arms out in front. */
|
|
64224
|
+
handgunGrip: [0.13, -0.15, -0.33],
|
|
64225
|
+
/** A rocket launcher's grip: its tube rides on the shoulder, so the hands are higher. */
|
|
64226
|
+
launcherGrip: [0.2, -0.14, -0.3],
|
|
64227
|
+
/** A gun with no grip anchor: the rear of its bore, from the eye. */
|
|
64228
|
+
rear: [0.2, -0.24, -0.12]
|
|
64229
|
+
};
|
|
64230
|
+
var scratch2 = { grip: null };
|
|
64231
|
+
function placeInView(placement) {
|
|
64232
|
+
const { THREE, hand, holder, camera: camera2, right } = placement;
|
|
64233
|
+
holder.scale.setScalar(1);
|
|
64234
|
+
hand.position.copy(camera2.position);
|
|
64235
|
+
hand.quaternion.copy(camera2.quaternion);
|
|
64236
|
+
hand.scale.setScalar(1);
|
|
64237
|
+
holder.position.set(0, 0, 0);
|
|
64238
|
+
hand.updateMatrixWorld(true);
|
|
64239
|
+
if (!right) {
|
|
64240
|
+
holder.position.set(VIEW_HOLD.rear[0], VIEW_HOLD.rear[1], VIEW_HOLD.rear[2] + placement.rear);
|
|
64241
|
+
hand.updateMatrixWorld(true);
|
|
64242
|
+
return;
|
|
64243
|
+
}
|
|
64244
|
+
scratch2.grip ?? (scratch2.grip = new THREE.Vector3());
|
|
64245
|
+
const grip = hand.worldToLocal(right.part.localToWorld(scratch2.grip.copy(right.offset)));
|
|
64246
|
+
const [x, y, z] = placement.kind === "handgun" ? VIEW_HOLD.handgunGrip : placement.kind === "launcher" ? VIEW_HOLD.launcherGrip : VIEW_HOLD.grip;
|
|
64247
|
+
holder.position.set(x - grip.x, y - grip.y, z - grip.z);
|
|
64248
|
+
hand.updateMatrixWorld(true);
|
|
64249
|
+
}
|
|
64250
|
+
|
|
63266
64251
|
// src/fx/heavy.ts
|
|
63267
64252
|
var PI14 = Math.PI;
|
|
63268
64253
|
var ROCKET_LIGHT_NAME = "rocket-light";
|
|
@@ -64248,6 +65233,8 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
64248
65233
|
let triggerRest = 0;
|
|
64249
65234
|
let feedCued = false;
|
|
64250
65235
|
const rootQuaternion = new THREE.Quaternion();
|
|
65236
|
+
const muzzleAt = new THREE.Vector3();
|
|
65237
|
+
const muzzleAlong = new THREE.Vector3();
|
|
64251
65238
|
const world = {
|
|
64252
65239
|
kit,
|
|
64253
65240
|
scene,
|
|
@@ -64347,6 +65334,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
64347
65334
|
if (model.parts.stockMove && onTool?.stock === "collapsed") rig.setPartPose("stock", collapsedStockPose(model.parts.stockMove));
|
|
64348
65335
|
applyCondition(kit, model, condition);
|
|
64349
65336
|
lastAmmo = options.tool?.().ammo ?? 0;
|
|
65337
|
+
void audio?.loadSamples();
|
|
64350
65338
|
hand.updateMatrixWorld(true);
|
|
64351
65339
|
hold = holdOfModel(THREE, model, 1);
|
|
64352
65340
|
hold = { ...hold, works: handWorkOf(THREE, model, weapon, hold.right) };
|
|
@@ -64399,12 +65387,22 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
64399
65387
|
if (!session) return;
|
|
64400
65388
|
const family = session.model.parts.family;
|
|
64401
65389
|
session.holderScale = 1;
|
|
65390
|
+
if (options.firstPerson?.()) {
|
|
65391
|
+
placeInView({ THREE, hand, holder, camera: camera2, right: hold?.right ?? null, rear: modelRear, kind: family === "pistol" || family === "revolver" ? "handgun" : family === "rocket" ? "launcher" : "long" });
|
|
65392
|
+
lift = 0;
|
|
65393
|
+
pullFromWall(dt);
|
|
65394
|
+
return;
|
|
65395
|
+
}
|
|
65396
|
+
hand.scale.set(1, 1, 1);
|
|
64402
65397
|
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 });
|
|
64403
65398
|
hand.updateMatrixWorld(true);
|
|
64404
65399
|
lift += (liftToKeepInView() - lift) * Math.min(1, dt * HAND_IN_VIEW.rate);
|
|
64405
65400
|
if (lift > 1e-4) hand.position.addScaledVector(up.set(0, 1, 0).applyQuaternion(camera2.quaternion), lift);
|
|
64406
65401
|
hand.updateMatrixWorld(true);
|
|
64407
|
-
|
|
65402
|
+
pullFromWall(dt);
|
|
65403
|
+
};
|
|
65404
|
+
const pullFromWall = (dt) => {
|
|
65405
|
+
if (!options.contact || !session) return;
|
|
64408
65406
|
ahead.set(0, 0, -1).applyQuaternion(camera2.quaternion);
|
|
64409
65407
|
if (reach === 0) reach = Math.max(0.01, measureReach(session));
|
|
64410
65408
|
const free = options.contact(camera2.position, ahead, WALL_PULL.probe);
|
|
@@ -64435,7 +65433,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
64435
65433
|
}
|
|
64436
65434
|
const action = current.def.action;
|
|
64437
65435
|
if (action.kind === "launcher") {
|
|
64438
|
-
launchRocket(heavy(current), options.flyRocket !== false);
|
|
65436
|
+
if (current.model.parts.family === "rocket") launchRocket(heavy(current), options.flyRocket !== false);
|
|
64439
65437
|
audio?.play("explosion", LAUNCH_VOLUME, distance3());
|
|
64440
65438
|
}
|
|
64441
65439
|
if (action.kind !== "firearm") return;
|
|
@@ -64512,6 +65510,15 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
64512
65510
|
condition = next;
|
|
64513
65511
|
if (session) applyCondition(kit, session.model, condition);
|
|
64514
65512
|
},
|
|
65513
|
+
muzzle() {
|
|
65514
|
+
const mark = session?.model.parts.muzzle;
|
|
65515
|
+
if (!session || !mark) return null;
|
|
65516
|
+
hand.updateMatrixWorld(true);
|
|
65517
|
+
const at3 = worldPositionOf(session, mark, muzzleAt);
|
|
65518
|
+
const along = muzzleAlong.set(1, 0, 0).applyQuaternion(session.model.root.getWorldQuaternion(rootQuaternion)).normalize();
|
|
65519
|
+
const kind = session.def.action.kind;
|
|
65520
|
+
return { position: [at3.x, at3.y, at3.z], direction: [along.x, along.y, along.z], drawsFlash: kind === "firearm" || kind === "launcher" };
|
|
65521
|
+
},
|
|
64515
65522
|
handTargets() {
|
|
64516
65523
|
if (!session || !hold) return null;
|
|
64517
65524
|
hand.updateMatrixWorld(true);
|
|
@@ -64566,6 +65573,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
64566
65573
|
...options.raycast ? { raycast: options.raycast } : {},
|
|
64567
65574
|
...options.contact ? { contact: options.contact } : {},
|
|
64568
65575
|
...options.bodyHold ? { bodyHold: options.bodyHold } : {},
|
|
65576
|
+
...options.firstPerson ? { firstPerson: options.firstPerson } : {},
|
|
64569
65577
|
...options.effects ? { effects: options.effects } : {},
|
|
64570
65578
|
...options.flyRocket === void 0 ? {} : { flyRocket: options.flyRocket },
|
|
64571
65579
|
...options.particleLimit ? { particleLimit: options.particleLimit } : {},
|
|
@@ -64588,6 +65596,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
64588
65596
|
},
|
|
64589
65597
|
setCondition: (condition) => model.setCondition(condition),
|
|
64590
65598
|
handTargets: () => model.handTargets() ?? box5.handTargets(),
|
|
65599
|
+
muzzle: () => model.inHand !== null ? model.muzzle() : box5.muzzle(),
|
|
64591
65600
|
layers,
|
|
64592
65601
|
get inHand() {
|
|
64593
65602
|
return model.inHand ?? box5.inHand;
|
|
@@ -64612,7 +65621,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
64612
65621
|
var MODEL_BODY = "body";
|
|
64613
65622
|
function buildModeledProp(THREE, def, name, decorate, items, props = defaultWeaponProps()) {
|
|
64614
65623
|
const model = buildWeaponModelById(THREE, def.id) ?? (() => {
|
|
64615
|
-
const root = props.buildItemModel(THREE, def, items);
|
|
65624
|
+
const root = props.buildItemModel(THREE, def, items) ?? buildThrowableModel(THREE, def);
|
|
64616
65625
|
return root ? { root } : void 0;
|
|
64617
65626
|
})();
|
|
64618
65627
|
if (!model) return void 0;
|
|
@@ -65755,7 +66764,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
65755
66764
|
};
|
|
65756
66765
|
var weaponItem = (def, name, items, props = defaultWeaponProps()) => {
|
|
65757
66766
|
const id = `${WEAPON_ITEM_PREFIX}${def.id}`;
|
|
65758
|
-
if (!hasWeaponModel(def.id) && !props.itemModelOf(def.id, items)) return asItem(id, name, weaponProp(def, name), { weapon: def.id, movable: true });
|
|
66767
|
+
if (!hasWeaponModel(def.id) && !props.itemModelOf(def.id, items) && !hasThrowableModel(def)) return asItem(id, name, weaponProp(def, name), { weapon: def.id, movable: true });
|
|
65759
66768
|
return {
|
|
65760
66769
|
id,
|
|
65761
66770
|
name,
|
|
@@ -65815,7 +66824,8 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
65815
66824
|
const seedOption = options.seed === void 0 ? {} : { seed: options.seed };
|
|
65816
66825
|
let audio;
|
|
65817
66826
|
const ownAudio = () => audio === void 0 ? audio = options.sound === false ? null : createWeaponAudio(void 0, { ...seedOption, ...options.samples ? { samples: options.samples } : {} }) : audio;
|
|
65818
|
-
const
|
|
66827
|
+
const generics = genericWeapons(arsenal);
|
|
66828
|
+
const weaponDefs = [...arsenal.weapons.values()].filter((def) => !BODY_ACTIONS.has(def.id) && !generics.has(def.id));
|
|
65819
66829
|
const thumbnailBase = options.thumbnailBase ?? DEFAULT_THUMBNAIL_BASE;
|
|
65820
66830
|
const withThumbnail = (item, key2) => {
|
|
65821
66831
|
const thumbnail = thumbnailBase === false ? void 0 : weaponThumbnailUrl(key2, thumbnailBase);
|
|
@@ -65903,7 +66913,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
65903
66913
|
engine: lentEngine,
|
|
65904
66914
|
...options.samples ? { samples: options.samples } : {},
|
|
65905
66915
|
onGunshot: (shot, input, played) => {
|
|
65906
|
-
const recorded = played.kind === "sample" && played.layers.length > 0 ? fill(text.gunshotRecorded, { takes: played.layers.map((
|
|
66916
|
+
const recorded = played.kind === "sample" && played.layers.length > 0 ? fill(text.gunshotRecorded, { takes: played.layers.map((layer3) => `${layer3.role} ${layer3.take + 1}`).join(", ") }) : "";
|
|
65907
66917
|
lent.log(
|
|
65908
66918
|
fill(text.gunshotSound, { profile: shot.profile, take: String(shot.take + 1), pitch: `${shot.pitch >= 1 ? "+" : ""}${((shot.pitch - 1) * 100).toFixed(1)} %`, space: text.spaces[input.space ?? "outdoor"], distance: String(Math.round(input.distance ?? 0)), far: shot.closeMix < 1 ? ` (${Math.round((1 - shot.closeMix) * 100)} % far)` : "" }) + recorded,
|
|
65909
66919
|
{ profile: shot.profile, take: shot.take, pitch: shot.pitch, space: input.space ?? "outdoor", distance: input.distance ?? 0, closeMix: shot.closeMix, delay: shot.delay, samples: shot.samples, played },
|
|
@@ -65932,6 +66942,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
65932
66942
|
// 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)
|
|
65933
66943
|
contact: createLaserRaycast(lent.THREE, lent.scene, lent.camera, { now: () => simulatedMs }),
|
|
65934
66944
|
...lent.holdFrame ? { bodyHold: () => lent.holdFrame?.() ?? null } : {},
|
|
66945
|
+
firstPerson: () => lent.player().cameraMode === "first",
|
|
65935
66946
|
...lent.effects ? { effects: lent.effects } : {},
|
|
65936
66947
|
...lent.particleLimit ? { particleLimit: lent.particleLimit } : {},
|
|
65937
66948
|
...isLightBudget(lent.lights) ? { lights: lent.lights } : {},
|
|
@@ -65982,6 +66993,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
65982
66993
|
});
|
|
65983
66994
|
const offFrame = lent.onFrame((dt) => created.update(dt));
|
|
65984
66995
|
const offHands = lent.setHandTargets?.(() => created.handTargets());
|
|
66996
|
+
const offMuzzle = lent.setMuzzleSource?.(() => created.muzzle());
|
|
65985
66997
|
created.handle({ type: "tool", weapon: lent.tool().weapon }, lent.tool());
|
|
65986
66998
|
return () => {
|
|
65987
66999
|
accessories.dispose();
|
|
@@ -65990,6 +67002,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
65990
67002
|
offFrame();
|
|
65991
67003
|
offClock();
|
|
65992
67004
|
offHands?.();
|
|
67005
|
+
offMuzzle?.();
|
|
65993
67006
|
created.dispose();
|
|
65994
67007
|
audio?.dispose();
|
|
65995
67008
|
fx = null;
|
|
@@ -66719,6 +67732,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
66719
67732
|
var SHELTERED_MOST = 1;
|
|
66720
67733
|
var CHEST = 1.1;
|
|
66721
67734
|
var MIDDLE = 0.3;
|
|
67735
|
+
var AIM_SEARCH = 1.5;
|
|
66722
67736
|
var HEAVY_ITEMS = ["camp_table"];
|
|
66723
67737
|
var PERSON_MASS = 70;
|
|
66724
67738
|
var GROUND_FRICTION2 = 7;
|
|
@@ -66778,6 +67792,27 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
66778
67792
|
}
|
|
66779
67793
|
const partsBefore = new Map(placed.map((body) => [body.objectId, partsOf(body.objectId)]));
|
|
66780
67794
|
expect(placed.length > 0, fillText2(text.push_found, { n: placed.length, kinds: [...new Set(placed.map((body) => body.kind))].join(", ") }), { placed: placed.map((body) => body.itemId) });
|
|
67795
|
+
const aimOf = new Map(
|
|
67796
|
+
placed.map((body) => {
|
|
67797
|
+
const from = origin.get(body.objectId) ?? body.from;
|
|
67798
|
+
if (body.kind === "zombie" || body.kind === "survivor") return [body.objectId, [from[0], from[1] + CHEST, from[2]]];
|
|
67799
|
+
const boxes = room.renderer.solidsNear?.(from[0], from[2], AIM_SEARCH).filter((box5) => box5.objectId === body.objectId) ?? [];
|
|
67800
|
+
if (boxes.length === 0) return [body.objectId, [from[0], from[1] + MIDDLE, from[2]]];
|
|
67801
|
+
const low = [0, 1, 2].map((axis2) => Math.min(...boxes.map((box5) => box5.min[axis2])));
|
|
67802
|
+
const high = [0, 1, 2].map((axis2) => Math.max(...boxes.map((box5) => box5.max[axis2])));
|
|
67803
|
+
return [body.objectId, [0, 1, 2].map((axis2) => (low[axis2] + high[axis2]) / 2)];
|
|
67804
|
+
})
|
|
67805
|
+
);
|
|
67806
|
+
const coverAt = (point) => new Map(
|
|
67807
|
+
placed.map((body) => {
|
|
67808
|
+
const ignore = source ? [source, body.objectId] : [body.objectId];
|
|
67809
|
+
return [body.objectId, room.world.blastReach?.(point, aimOf.get(body.objectId) ?? body.from, { ignore }) ?? 1];
|
|
67810
|
+
})
|
|
67811
|
+
);
|
|
67812
|
+
let coverOf;
|
|
67813
|
+
const stopListening = room.world.on("*", (event) => {
|
|
67814
|
+
if ((event.type === "explode" || event.type === "blast") && !coverOf) coverOf = coverAt(event.point);
|
|
67815
|
+
});
|
|
66781
67816
|
if (mode === "p13") bench.actions.shoot();
|
|
66782
67817
|
else {
|
|
66783
67818
|
room.setTool("frag_grenade");
|
|
@@ -66790,17 +67825,11 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
66790
67825
|
step(0.05);
|
|
66791
67826
|
waited += 0.05;
|
|
66792
67827
|
}
|
|
67828
|
+
stopListening();
|
|
66793
67829
|
const blast = bench.lastBlast();
|
|
66794
67830
|
expect(!!blast, text.push_told, { waited });
|
|
66795
67831
|
if (!blast) return;
|
|
66796
|
-
const
|
|
66797
|
-
placed.map((body) => {
|
|
66798
|
-
const from = origin.get(body.objectId) ?? body.from;
|
|
66799
|
-
const person = body.kind === "zombie" || body.kind === "survivor";
|
|
66800
|
-
const ignore = source ? [source, body.objectId] : [body.objectId];
|
|
66801
|
-
return [body.objectId, room.world.blastReach?.(blast.point, [from[0], from[1] + (person ? CHEST : MIDDLE), from[2]], { ignore }) ?? 1];
|
|
66802
|
-
})
|
|
66803
|
-
);
|
|
67832
|
+
const cover = coverOf ?? coverAt(blast.point);
|
|
66804
67833
|
step(PUSH_READ_AT);
|
|
66805
67834
|
const rows = placed.map((body) => {
|
|
66806
67835
|
const from = origin.get(body.objectId) ?? body.from;
|
|
@@ -66808,16 +67837,18 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
66808
67837
|
const distance3 = flat(from, blast.point);
|
|
66809
67838
|
const away = Math.max(1e-6, distance3);
|
|
66810
67839
|
const outward = ((now[0] - from[0]) * (from[0] - blast.point[0]) + (now[2] - from[2]) * (from[2] - blast.point[2])) / away;
|
|
66811
|
-
return { ...body, distance: distance3, outward, moved: flat(now, from), cover:
|
|
67840
|
+
return { ...body, distance: distance3, outward, moved: flat(now, from), cover: cover.get(body.objectId) ?? 1 };
|
|
66812
67841
|
});
|
|
66813
67842
|
const torn = (row) => (PUSH_KINDS.some((entry2) => entry2.kind === row.kind) || HEAVY_ITEMS.includes(row.kind)) && partsOf(row.objectId) < (partsBefore.get(row.objectId) ?? 0);
|
|
66814
67843
|
const inReach = rows.filter((row) => row.distance < blast.radius * 0.85 && !torn(row));
|
|
67844
|
+
const isPerson = (row) => row.kind === "survivor" || row.kind === "zombie";
|
|
67845
|
+
const reached = inReach.filter((row) => row.cover >= SHELTERED && !isPerson(row));
|
|
66815
67846
|
const sheltered = inReach.filter((row) => row.cover < SHELTERED);
|
|
66816
67847
|
for (const row of sheltered) {
|
|
66817
|
-
|
|
67848
|
+
const open = reached.filter((other) => other.kind === row.kind && other.distance <= row.distance).map((other) => other.outward);
|
|
67849
|
+
const most = Math.max(SHELTERED_MOST, row.cover * Math.max(0, ...open));
|
|
67850
|
+
expect(row.outward < most, fillText2(text.push_sheltered, { what: things[row.kind] ?? row.kind, distance: row.distance.toFixed(1), cover: (row.cover * 100).toFixed(0), moved: Math.max(0, row.outward).toFixed(2) }), { row: { kind: row.kind, distance: row.distance, outward: row.outward, cover: row.cover, most } });
|
|
66818
67851
|
}
|
|
66819
|
-
const isPerson = (row) => row.kind === "survivor" || row.kind === "zombie";
|
|
66820
|
-
const reached = inReach.filter((row) => row.cover >= SHELTERED && !isPerson(row));
|
|
66821
67852
|
const movedAway = reached.filter((row) => row.outward >= MOVED);
|
|
66822
67853
|
const least = reached.length === 0 ? 0 : Math.min(...reached.map((row) => row.outward));
|
|
66823
67854
|
expect(reached.length > 0 && movedAway.length === reached.length, fillText2(text.push_outward, { moved: movedAway.length, n: reached.length, least: least.toFixed(2) }), { rows: reached.map((row) => ({ kind: row.kind, distance: row.distance, outward: row.outward })), torn: rows.filter(torn).map((row) => row.objectId) });
|
|
@@ -66985,12 +68016,22 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
66985
68016
|
|
|
66986
68017
|
// src/projectile-model.ts
|
|
66987
68018
|
function projectileModel(THREE, query2) {
|
|
66988
|
-
if (query2.kind !== "rocket") return
|
|
68019
|
+
if (query2.kind !== "rocket") return explosiveProjectile(THREE, query2);
|
|
66989
68020
|
const launcher = buildWeaponModelById(THREE, query2.weapon);
|
|
66990
68021
|
if (!launcher || launcher.parts.family !== "rocket") return null;
|
|
66991
68022
|
const round5 = launcher.parts.makeRound ? launcher.parts.makeRound() : buildFlyingRocket(modelKit(THREE), launcher.parts.launcherType);
|
|
66992
68023
|
return { model: round5, axis: [1, 0, 0] };
|
|
66993
68024
|
}
|
|
68025
|
+
function explosiveProjectile(THREE, query2) {
|
|
68026
|
+
const model = query2.explosive === void 0 ? void 0 : buildExplosiveModel(THREE, query2.explosive);
|
|
68027
|
+
if (!model) return null;
|
|
68028
|
+
const centre = new THREE.Box3().setFromObject(model).getCenter(new THREE.Vector3());
|
|
68029
|
+
const holder = markKitOrigin(new THREE.Group(), { owner: "game-weapons-three", kind: "explosive", id: model.name });
|
|
68030
|
+
holder.name = model.name;
|
|
68031
|
+
model.position.sub(centre);
|
|
68032
|
+
holder.add(model);
|
|
68033
|
+
return { model: holder, axis: [0, 1, 0] };
|
|
68034
|
+
}
|
|
66994
68035
|
|
|
66995
68036
|
// src/weapon-props.ts
|
|
66996
68037
|
function createWeaponProps(options = {}) {
|