@adatechnology/game-weapons-three 0.14.1 → 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-PRC75VKC.js → chunk-GBO6L7CQ.js} +1639 -1406
- package/dist/chunk-GBO6L7CQ.js.map +1 -0
- package/dist/index.d.ts +31 -6
- package/dist/index.global.js +2146 -1043
- 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-PRC75VKC.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;
|
|
@@ -36745,6 +37357,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
36745
37357
|
camera2.updateProjectionMatrix();
|
|
36746
37358
|
};
|
|
36747
37359
|
const onKeyDown = (event) => {
|
|
37360
|
+
if (host.playerHeld?.()) return;
|
|
36748
37361
|
if (event.repeat || event.ctrlKey || event.metaKey || event.altKey || TEXT_FIELDS.has(event.target?.tagName ?? "")) return;
|
|
36749
37362
|
const handled2 = event.code === ACCESSORY_KEYS.light ? act(ACTION_IDS.light) : event.code === ACCESSORY_KEYS.laser ? act(ACTION_IDS.laser) : event.code === ACCESSORY_KEYS.underbarrel ? act(ACTION_IDS.underbarrel) : event.code === ACCESSORY_KEYS.stock && toggleStock();
|
|
36750
37363
|
if (!handled2) return;
|
|
@@ -36753,7 +37366,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
36753
37366
|
};
|
|
36754
37367
|
const isOnRoom = (event) => Boolean(document.pointerLockElement) || event.target instanceof HTMLCanvasElement;
|
|
36755
37368
|
const onMouseDown = (event) => {
|
|
36756
|
-
if (event.button !== SECONDARY_BUTTON || !isOnRoom(event) || !
|
|
37369
|
+
if (event.button !== SECONDARY_BUTTON || !isOnRoom(event) || !aims(host.tool())) return;
|
|
36757
37370
|
event.preventDefault();
|
|
36758
37371
|
event.stopImmediatePropagation();
|
|
36759
37372
|
setAim(true);
|
|
@@ -36929,7 +37542,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
36929
37542
|
};
|
|
36930
37543
|
var accessoryTextOf = (locale) => ACCESSORY_TEXT[locale] ?? ACCESSORY_TEXT.en;
|
|
36931
37544
|
|
|
36932
|
-
// ../game-audio/dist/chunk-
|
|
37545
|
+
// ../game-audio/dist/chunk-C2K7XN2K.js
|
|
36933
37546
|
var DISTANCE_CURVES = {
|
|
36934
37547
|
/** The game's `sfx`: `vol / (1 + d² × 0.004)`, cutoff `/ (1 + d × 0.01)`, silent below 0.01 (jogo L62091–62092, L62101). */
|
|
36935
37548
|
game_sfx: { model: "inverse_square", k: 4e-3, cutoffK: 0.01, minGain: 0.01 },
|
|
@@ -37191,12 +37804,46 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37191
37804
|
}
|
|
37192
37805
|
return merged2;
|
|
37193
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
|
+
}
|
|
37194
37828
|
function createSoundRegistry(banks = []) {
|
|
37195
37829
|
const sounds = /* @__PURE__ */ new Map();
|
|
37196
37830
|
const loops = /* @__PURE__ */ new Map();
|
|
37197
37831
|
const sets = /* @__PURE__ */ new Map();
|
|
37198
37832
|
const samples = /* @__PURE__ */ new Map();
|
|
37199
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
|
+
};
|
|
37200
37847
|
const registry = {
|
|
37201
37848
|
register(bank) {
|
|
37202
37849
|
for (const sound3 of bank.sounds ?? []) {
|
|
@@ -37216,6 +37863,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37216
37863
|
samples.set(sample.id, sample);
|
|
37217
37864
|
owners.set(sample.id, bank.id);
|
|
37218
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();
|
|
37219
37871
|
},
|
|
37220
37872
|
patch(id, patch) {
|
|
37221
37873
|
const sound3 = sounds.get(id);
|
|
@@ -37224,22 +37876,31 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37224
37876
|
if (loop) loops.set(id, mergeRecords(loop, patch));
|
|
37225
37877
|
const sample = samples.get(id);
|
|
37226
37878
|
if (sample) samples.set(id, mergeRecords(sample, patch));
|
|
37879
|
+
derived.clear();
|
|
37227
37880
|
},
|
|
37228
37881
|
remove(id) {
|
|
37229
37882
|
sounds.delete(id);
|
|
37230
37883
|
loops.delete(id);
|
|
37231
37884
|
sets.delete(id);
|
|
37232
37885
|
samples.delete(id);
|
|
37886
|
+
aliases.delete(id);
|
|
37233
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();
|
|
37234
37895
|
},
|
|
37235
37896
|
sound: (id) => sounds.get(id),
|
|
37236
37897
|
loop: (id) => loops.get(id),
|
|
37237
37898
|
set: (id) => sets.get(id),
|
|
37238
|
-
sample: (id) => samples.get(id),
|
|
37899
|
+
sample: (id) => samples.get(id) ?? resolveAlias(id),
|
|
37239
37900
|
soundIds: () => [...sounds.keys()],
|
|
37240
37901
|
setIds: () => [...sets.keys()],
|
|
37241
37902
|
loopIds: () => [...loops.keys()],
|
|
37242
|
-
sampleIds: () => [...samples.keys()],
|
|
37903
|
+
sampleIds: () => [...samples.keys(), ...[...aliases.keys()].filter((id) => !samples.has(id) && resolveAlias(id) !== void 0)],
|
|
37243
37904
|
bankOf: (id) => owners.get(id)
|
|
37244
37905
|
};
|
|
37245
37906
|
for (const bank of banks) registry.register(bank);
|
|
@@ -37356,16 +38017,16 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37356
38017
|
}
|
|
37357
38018
|
return pending;
|
|
37358
38019
|
}
|
|
37359
|
-
function drawLayer(
|
|
38020
|
+
function drawLayer(layer3, scope2) {
|
|
37360
38021
|
const pending = { at: 0, gain: 1, filters: [], modulators: [] };
|
|
37361
|
-
for (const key2 of Object.keys(
|
|
37362
|
-
if (key2 === "at" &&
|
|
37363
|
-
else if (key2 === "duration" &&
|
|
37364
|
-
else if (key2 === "gain" &&
|
|
37365
|
-
else if (key2 === "source" &&
|
|
37366
|
-
else if (key2 === "source" &&
|
|
37367
|
-
else if (key2 === "filters" &&
|
|
37368
|
-
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));
|
|
37369
38030
|
}
|
|
37370
38031
|
return pending;
|
|
37371
38032
|
}
|
|
@@ -37376,8 +38037,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37376
38037
|
if (source.offset === "fit") return scope2.random() * Math.max(0, noiseSeconds - duration);
|
|
37377
38038
|
return scope2.random() * (source.offsetScale ?? 1);
|
|
37378
38039
|
}
|
|
37379
|
-
function finishSource(
|
|
37380
|
-
const source =
|
|
38040
|
+
function finishSource(layer3, pending, duration, offset) {
|
|
38041
|
+
const source = layer3.source;
|
|
37381
38042
|
if (source.kind === "noise") return { kind: "noise", offset, loop: source.loop === true };
|
|
37382
38043
|
if (source.kind === "osc") return { kind: "osc", wave: source.wave, frequency: finishAutomation(pending.automation ?? {}, duration) };
|
|
37383
38044
|
const voice2 = pending.voice;
|
|
@@ -37399,23 +38060,23 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37399
38060
|
function finishEnvelope(envelope2, duration, level) {
|
|
37400
38061
|
return envelope2.map(([time, value, curve, fixed2]) => ({ time: timeOf(time, duration), value: fixed2 === "fixed" ? value : value * level, curve }));
|
|
37401
38062
|
}
|
|
37402
|
-
function planLayer(
|
|
37403
|
-
const pending = drawLayer(
|
|
38063
|
+
function planLayer(layer3, scope2, defaults, levelInEnvelope, soundLevel) {
|
|
38064
|
+
const pending = drawLayer(layer3, scope2);
|
|
37404
38065
|
const duration = pending.duration ?? defaults.duration;
|
|
37405
38066
|
if (duration === void 0) throw new Error("game-audio: a layer needs a duration (its own or the recipe\u2019s)");
|
|
37406
|
-
const offset = drawOffset(
|
|
38067
|
+
const offset = drawOffset(layer3.source, duration, scope2, defaults.noiseSeconds);
|
|
37407
38068
|
const level = pending.gain * soundLevel;
|
|
37408
|
-
const sourceFrequency =
|
|
38069
|
+
const sourceFrequency = layer3.source.kind === "noise" ? 0 : startFrequency(pending.automation ?? pending.voice?.frequency ?? {});
|
|
37409
38070
|
const planned = {
|
|
37410
38071
|
at: pending.at,
|
|
37411
38072
|
duration,
|
|
37412
|
-
tail:
|
|
38073
|
+
tail: layer3.tail ?? defaults.tail ?? DEFAULT_TAIL,
|
|
37413
38074
|
level,
|
|
37414
|
-
...
|
|
37415
|
-
source: finishSource(
|
|
37416
|
-
...
|
|
38075
|
+
...layer3.wet === void 0 ? {} : { wet: layer3.wet },
|
|
38076
|
+
source: finishSource(layer3, pending, duration, offset),
|
|
38077
|
+
...layer3.filters ? {
|
|
37417
38078
|
filters: {
|
|
37418
|
-
mode:
|
|
38079
|
+
mode: layer3.filters.mode,
|
|
37419
38080
|
bank: pending.filters.map(({ spec, frequency, q, gain, level: filterLevel }) => ({
|
|
37420
38081
|
type: spec.type,
|
|
37421
38082
|
frequency: finishAutomation(frequency, duration),
|
|
@@ -37426,10 +38087,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37426
38087
|
}
|
|
37427
38088
|
} : {},
|
|
37428
38089
|
modulators: pending.modulators.map((modulator) => finishModulator(modulator, sourceFrequency)),
|
|
37429
|
-
envelope: finishEnvelope(
|
|
38090
|
+
envelope: finishEnvelope(layer3.envelope, duration, levelInEnvelope ? level : 1)
|
|
37430
38091
|
};
|
|
37431
|
-
if (!
|
|
37432
|
-
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) }));
|
|
37433
38094
|
}
|
|
37434
38095
|
function scaleAutomation(automation, divisor) {
|
|
37435
38096
|
const scale = (value) => value === void 0 ? void 0 : value / divisor;
|
|
@@ -37437,12 +38098,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37437
38098
|
for (const key2 of ["value", "from", "to"]) if (automation[key2] !== void 0) scaled2[key2] = scale(automation[key2]);
|
|
37438
38099
|
return scaled2;
|
|
37439
38100
|
}
|
|
37440
|
-
function muffle(
|
|
37441
|
-
if (divisor === 1 || !
|
|
37442
|
-
const bank =
|
|
37443
|
-
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 } };
|
|
37444
38105
|
}
|
|
37445
|
-
var layerEnd = (
|
|
38106
|
+
var layerEnd = (layer3) => layer3.at + layer3.duration + layer3.tail;
|
|
37446
38107
|
function planSound(recipe2, input = {}) {
|
|
37447
38108
|
const listener = input.listener ?? DEFAULT_LISTENER;
|
|
37448
38109
|
const distance3 = input.distance ?? (input.position ? listenerDistance(listener, input.position, input.distanceMode) : 0);
|
|
@@ -37470,7 +38131,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37470
38131
|
noiseSeconds: input.noiseSeconds ?? DEFAULT_NOISE_SECONDS
|
|
37471
38132
|
};
|
|
37472
38133
|
const divisor = cutoffDivisor(recipe2.falloff, distance3) / (1 - OCCLUSION_CUTOFF * occlusion);
|
|
37473
|
-
const layers = recipe2.layers.flatMap((
|
|
38134
|
+
const layers = recipe2.layers.flatMap((layer3) => planLayer(layer3, scope2, defaults, order !== "layered", level)).map((layer3) => muffle(layer3, divisor));
|
|
37474
38135
|
return { ...base, silent: false, length: Math.max(0, ...layers.map(layerEnd)), layers };
|
|
37475
38136
|
}
|
|
37476
38137
|
function fillNoise(random, length2) {
|
|
@@ -37856,7 +38517,16 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37856
38517
|
const index = pickTake(refs.length, input.memory?.get(key2), input.random);
|
|
37857
38518
|
input.memory?.set(key2, index);
|
|
37858
38519
|
const ref = refs[index];
|
|
37859
|
-
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
|
+
});
|
|
37860
38530
|
};
|
|
37861
38531
|
take("close", close, gains.close, 0);
|
|
37862
38532
|
take("far", far, gains.far, 0);
|
|
@@ -37883,6 +38553,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37883
38553
|
var DEFAULT_LOOP_CROSSFADE = 0.25;
|
|
37884
38554
|
var LOOKAHEAD = 1.5;
|
|
37885
38555
|
var VOLUME_SMOOTHING = 0.05;
|
|
38556
|
+
var RATE_SMOOTHING = 0.04;
|
|
38557
|
+
var RATE_RANGE = [0.25, 4];
|
|
37886
38558
|
function loopCrossfade(sound3) {
|
|
37887
38559
|
if (!sound3.loop) return void 0;
|
|
37888
38560
|
return sound3.loop === true ? DEFAULT_LOOP_CROSSFADE : Math.max(0, sound3.loop.crossfade ?? DEFAULT_LOOP_CROSSFADE);
|
|
@@ -37894,6 +38566,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37894
38566
|
param2.setValueAtTime(value(0), at3);
|
|
37895
38567
|
for (let step = 1; step <= CROSSFADE_STEPS; step++) param2.linearRampToValueAtTime(value(step / CROSSFADE_STEPS), at3 + seconds * step / CROSSFADE_STEPS);
|
|
37896
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;
|
|
37897
38570
|
function createSampleLoopHandle(sound3, host, volume = 0) {
|
|
37898
38571
|
const crossfade = loopCrossfade(sound3) ?? DEFAULT_LOOP_CROSSFADE;
|
|
37899
38572
|
let level = volume;
|
|
@@ -37903,13 +38576,17 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37903
38576
|
let segments = [];
|
|
37904
38577
|
let last;
|
|
37905
38578
|
let timer;
|
|
38579
|
+
let panner;
|
|
38580
|
+
let rate = 1;
|
|
38581
|
+
let position;
|
|
37906
38582
|
const entry2 = {
|
|
37907
38583
|
get created() {
|
|
37908
38584
|
return master !== void 0;
|
|
37909
38585
|
},
|
|
37910
38586
|
rewire() {
|
|
37911
|
-
master
|
|
37912
|
-
|
|
38587
|
+
const out = panner ?? master;
|
|
38588
|
+
out?.disconnect();
|
|
38589
|
+
out?.connect(host.output(sound3.bus));
|
|
37913
38590
|
},
|
|
37914
38591
|
stop() {
|
|
37915
38592
|
stopped = true;
|
|
@@ -37926,23 +38603,29 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37926
38603
|
segments = [];
|
|
37927
38604
|
master?.disconnect();
|
|
37928
38605
|
master = void 0;
|
|
38606
|
+
panner?.disconnect();
|
|
38607
|
+
panner = void 0;
|
|
37929
38608
|
fallback2?.stop();
|
|
37930
38609
|
fallback2 = void 0;
|
|
37931
38610
|
host.unregister(entry2);
|
|
37932
38611
|
}
|
|
37933
38612
|
};
|
|
37934
|
-
const
|
|
38613
|
+
const nextTake = () => {
|
|
37935
38614
|
const takes2 = sound3.close;
|
|
37936
38615
|
const take = pickTake(takes2.length, last, host.random);
|
|
37937
38616
|
last = take;
|
|
37938
38617
|
const ref = takes2[take];
|
|
37939
|
-
|
|
38618
|
+
const buffer = ref ? host.buffer(ref.url) : void 0;
|
|
38619
|
+
return ref && buffer ? { buffer, ref } : void 0;
|
|
37940
38620
|
};
|
|
37941
38621
|
const schedule = (context, output, at3, first) => {
|
|
37942
|
-
const
|
|
37943
|
-
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));
|
|
37944
38626
|
const source = context.createBufferSource();
|
|
37945
38627
|
source.buffer = buffer;
|
|
38628
|
+
source.playbackRate.value = rate;
|
|
37946
38629
|
const gain = context.createGain();
|
|
37947
38630
|
source.connect(gain);
|
|
37948
38631
|
gain.connect(output);
|
|
@@ -37950,15 +38633,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37950
38633
|
if (buffer.duration < 2 * crossfade || sound3.close.length === 1) {
|
|
37951
38634
|
source.loop = true;
|
|
37952
38635
|
if (!first) ramp2(gain.gain, "in", at3, Math.max(1e-3, fade));
|
|
37953
|
-
source.start(at3);
|
|
38636
|
+
source.start(at3, offset);
|
|
37954
38637
|
segments.push({ source, gain, end: Number.POSITIVE_INFINITY });
|
|
37955
38638
|
return void 0;
|
|
37956
38639
|
}
|
|
37957
38640
|
if (first) gain.gain.setValueAtTime(1, at3);
|
|
37958
38641
|
else ramp2(gain.gain, "in", at3, fade);
|
|
37959
|
-
const end3 = at3 + buffer.duration;
|
|
38642
|
+
const end3 = at3 + (buffer.duration - offset) / rate;
|
|
37960
38643
|
ramp2(gain.gain, "out", end3 - fade, fade);
|
|
37961
|
-
source.start(at3);
|
|
38644
|
+
source.start(at3, offset);
|
|
37962
38645
|
source.stop(end3);
|
|
37963
38646
|
segments.push({ source, gain, end: end3 });
|
|
37964
38647
|
source.onended = () => {
|
|
@@ -37979,14 +38662,26 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37979
38662
|
pump(context, output, next, false);
|
|
37980
38663
|
}, wait);
|
|
37981
38664
|
};
|
|
37982
|
-
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
|
+
};
|
|
37983
38673
|
const startFiles = () => {
|
|
37984
38674
|
if (stopped || master || !host.isReady(sound3)) return master !== void 0;
|
|
37985
38675
|
const context = host.ready();
|
|
37986
38676
|
if (!context) return false;
|
|
37987
38677
|
master = context.createGain();
|
|
37988
38678
|
master.gain.setValueAtTime(fileLevel(), context.currentTime);
|
|
37989
|
-
|
|
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));
|
|
37990
38685
|
host.register(entry2);
|
|
37991
38686
|
pump(context, master, context.currentTime, true);
|
|
37992
38687
|
if (fallback2) {
|
|
@@ -38012,9 +38707,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38012
38707
|
set(next) {
|
|
38013
38708
|
if (stopped) return;
|
|
38014
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);
|
|
38015
38712
|
if (level > 0) ensure();
|
|
38016
38713
|
const context = host.ready();
|
|
38017
|
-
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
|
+
}
|
|
38018
38719
|
fallback2?.set(next.volume === void 0 ? next : { ...next, volume: level });
|
|
38019
38720
|
},
|
|
38020
38721
|
stop: entry2.stop
|
|
@@ -38117,9 +38818,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38117
38818
|
};
|
|
38118
38819
|
return queue;
|
|
38119
38820
|
}
|
|
38120
|
-
var end = (
|
|
38121
|
-
var firstFilter = (
|
|
38122
|
-
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;
|
|
38123
38824
|
function setFilter(node, filter, time) {
|
|
38124
38825
|
if (!filter) return;
|
|
38125
38826
|
node.type = filter.type;
|
|
@@ -38128,28 +38829,28 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38128
38829
|
}
|
|
38129
38830
|
function realizeBurst(plan, target) {
|
|
38130
38831
|
const { context } = target;
|
|
38131
|
-
const
|
|
38132
|
-
const time = target.time +
|
|
38832
|
+
const layer3 = plan.layers[0];
|
|
38833
|
+
const time = target.time + layer3.at;
|
|
38133
38834
|
const gain = context.createGain();
|
|
38134
38835
|
gain.connect(target.output);
|
|
38135
|
-
const source = noiseSource(target,
|
|
38836
|
+
const source = noiseSource(target, layer3.source.kind === "noise" && layer3.source.loop);
|
|
38136
38837
|
const filter = context.createBiquadFilter();
|
|
38137
38838
|
source.connect(filter);
|
|
38138
38839
|
filter.connect(gain);
|
|
38139
|
-
setFilter(filter, firstFilter(
|
|
38140
|
-
applyEnvelope(gain.gain,
|
|
38141
|
-
source.start(time, offsetOf(
|
|
38142
|
-
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));
|
|
38143
38844
|
return voiceOf([source]);
|
|
38144
38845
|
}
|
|
38145
38846
|
function realizeScream(plan, target) {
|
|
38146
38847
|
const { context } = target;
|
|
38147
|
-
const
|
|
38148
|
-
const time = target.time +
|
|
38149
|
-
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);
|
|
38150
38851
|
const gain = context.createGain();
|
|
38151
38852
|
gain.connect(target.output);
|
|
38152
|
-
for (const band of
|
|
38853
|
+
for (const band of layer3.filters?.bank ?? []) {
|
|
38153
38854
|
const filter = context.createBiquadFilter();
|
|
38154
38855
|
filter.type = band.type;
|
|
38155
38856
|
if (band.q !== void 0) filter.Q.value = band.q;
|
|
@@ -38162,7 +38863,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38162
38863
|
level.connect(gain);
|
|
38163
38864
|
}
|
|
38164
38865
|
const sources = [source];
|
|
38165
|
-
const lfos =
|
|
38866
|
+
const lfos = layer3.modulators.map((modulator) => {
|
|
38166
38867
|
const lfo = context.createOscillator();
|
|
38167
38868
|
const depth = context.createGain();
|
|
38168
38869
|
if (modulator.wave) lfo.type = modulator.wave;
|
|
@@ -38172,75 +38873,75 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38172
38873
|
depth.connect(gain.gain);
|
|
38173
38874
|
return lfo;
|
|
38174
38875
|
});
|
|
38175
|
-
applyEnvelope(gain.gain,
|
|
38176
|
-
source.start(time, offsetOf(
|
|
38177
|
-
source.stop(end(
|
|
38876
|
+
applyEnvelope(gain.gain, layer3.envelope, time);
|
|
38877
|
+
source.start(time, offsetOf(layer3));
|
|
38878
|
+
source.stop(end(layer3, time));
|
|
38178
38879
|
for (const lfo of lfos) {
|
|
38179
38880
|
lfo.start(time);
|
|
38180
|
-
lfo.stop(end(
|
|
38881
|
+
lfo.stop(end(layer3, time));
|
|
38181
38882
|
sources.push(lfo);
|
|
38182
38883
|
}
|
|
38183
38884
|
return voiceOf(sources);
|
|
38184
38885
|
}
|
|
38185
38886
|
function realizeGroan(plan, target) {
|
|
38186
38887
|
const { context } = target;
|
|
38187
|
-
const
|
|
38188
|
-
const time = target.time +
|
|
38888
|
+
const layer3 = plan.layers[0];
|
|
38889
|
+
const time = target.time + layer3.at;
|
|
38189
38890
|
const oscillator = context.createOscillator();
|
|
38190
38891
|
const gain = context.createGain();
|
|
38191
38892
|
const filter = context.createBiquadFilter();
|
|
38192
|
-
const band = firstFilter(
|
|
38193
|
-
if (
|
|
38893
|
+
const band = firstFilter(layer3);
|
|
38894
|
+
if (layer3.source.kind === "osc") oscillator.type = layer3.source.wave;
|
|
38194
38895
|
if (band) {
|
|
38195
38896
|
filter.type = band.type;
|
|
38196
38897
|
if (band.q !== void 0) filter.Q.value = band.q;
|
|
38197
38898
|
}
|
|
38198
|
-
if (
|
|
38199
|
-
assign(oscillator.frequency,
|
|
38200
|
-
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);
|
|
38201
38902
|
}
|
|
38202
38903
|
if (band) assign(filter.frequency, band.frequency, time);
|
|
38203
|
-
applyEnvelope(gain.gain,
|
|
38904
|
+
applyEnvelope(gain.gain, layer3.envelope, time);
|
|
38204
38905
|
oscillator.connect(filter);
|
|
38205
38906
|
filter.connect(gain);
|
|
38206
38907
|
gain.connect(target.output);
|
|
38207
38908
|
oscillator.start(time);
|
|
38208
|
-
oscillator.stop(end(
|
|
38909
|
+
oscillator.stop(end(layer3, time));
|
|
38209
38910
|
return voiceOf([oscillator]);
|
|
38210
38911
|
}
|
|
38211
38912
|
function realizeBoom(plan, target) {
|
|
38212
38913
|
const { context } = target;
|
|
38213
|
-
const
|
|
38214
|
-
const time = target.time +
|
|
38914
|
+
const layer3 = plan.layers[0];
|
|
38915
|
+
const time = target.time + layer3.at;
|
|
38215
38916
|
const oscillator = context.createOscillator();
|
|
38216
38917
|
const gain = context.createGain();
|
|
38217
|
-
if (
|
|
38218
|
-
oscillator.type =
|
|
38219
|
-
assign(oscillator.frequency,
|
|
38220
|
-
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);
|
|
38221
38922
|
}
|
|
38222
|
-
applyEnvelope(gain.gain,
|
|
38923
|
+
applyEnvelope(gain.gain, layer3.envelope, time);
|
|
38223
38924
|
oscillator.connect(gain);
|
|
38224
38925
|
gain.connect(target.output);
|
|
38225
38926
|
oscillator.start(time);
|
|
38226
|
-
oscillator.stop(end(
|
|
38927
|
+
oscillator.stop(end(layer3, time));
|
|
38227
38928
|
return voiceOf([oscillator]);
|
|
38228
38929
|
}
|
|
38229
38930
|
function realizeStatic(plan, target) {
|
|
38230
38931
|
const { context } = target;
|
|
38231
|
-
const
|
|
38232
|
-
const time = target.time +
|
|
38932
|
+
const layer3 = plan.layers[0];
|
|
38933
|
+
const time = target.time + layer3.at;
|
|
38233
38934
|
const gain = context.createGain();
|
|
38234
38935
|
const source = context.createBufferSource();
|
|
38235
38936
|
const filter = context.createBiquadFilter();
|
|
38236
38937
|
source.buffer = target.noise();
|
|
38237
|
-
setFilter(filter, firstFilter(
|
|
38238
|
-
applyEnvelope(gain.gain,
|
|
38938
|
+
setFilter(filter, firstFilter(layer3), time);
|
|
38939
|
+
applyEnvelope(gain.gain, layer3.envelope, time);
|
|
38239
38940
|
source.connect(filter);
|
|
38240
38941
|
filter.connect(gain);
|
|
38241
38942
|
gain.connect(target.output);
|
|
38242
|
-
source.start(time, offsetOf(
|
|
38243
|
-
source.stop(end(
|
|
38943
|
+
source.start(time, offsetOf(layer3));
|
|
38944
|
+
source.stop(end(layer3, time));
|
|
38244
38945
|
return voiceOf([source]);
|
|
38245
38946
|
}
|
|
38246
38947
|
function realizeChord(plan, target) {
|
|
@@ -38252,14 +38953,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38252
38953
|
const source = layers[index].source;
|
|
38253
38954
|
if (source.kind === "osc") oscillators[index].type = source.wave;
|
|
38254
38955
|
}
|
|
38255
|
-
layers.forEach((
|
|
38256
|
-
if (
|
|
38956
|
+
layers.forEach((layer3, index) => {
|
|
38957
|
+
if (layer3.source.kind === "osc") assign(oscillators[index].frequency, layer3.source.frequency, target.time + layer3.at);
|
|
38257
38958
|
});
|
|
38258
38959
|
applyEnvelope(gain.gain, layers[0].envelope, target.time + layers[0].at);
|
|
38259
38960
|
for (const oscillator of oscillators) oscillator.connect(gain);
|
|
38260
38961
|
gain.connect(target.output);
|
|
38261
|
-
layers.forEach((
|
|
38262
|
-
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)));
|
|
38263
38964
|
return voiceOf(oscillators);
|
|
38264
38965
|
}
|
|
38265
38966
|
function realizeCalls(plan, target) {
|
|
@@ -38271,32 +38972,32 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38271
38972
|
if (band) filter.type = band.type;
|
|
38272
38973
|
filter.connect(gain);
|
|
38273
38974
|
gain.connect(target.output);
|
|
38274
|
-
const oscillators = plan.layers.map((
|
|
38275
|
-
const time = target.time +
|
|
38975
|
+
const oscillators = plan.layers.map((layer3) => {
|
|
38976
|
+
const time = target.time + layer3.at;
|
|
38276
38977
|
const oscillator = context.createOscillator();
|
|
38277
|
-
if (
|
|
38278
|
-
oscillator.type =
|
|
38279
|
-
assign(oscillator.frequency,
|
|
38280
|
-
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);
|
|
38281
38982
|
}
|
|
38282
38983
|
if (band) {
|
|
38283
38984
|
assign(filter.frequency, band.frequency, time);
|
|
38284
38985
|
if (band.q !== void 0) filter.Q.value = band.q;
|
|
38285
38986
|
}
|
|
38286
38987
|
const envelope2 = context.createGain();
|
|
38287
|
-
applyEnvelope(envelope2.gain,
|
|
38988
|
+
applyEnvelope(envelope2.gain, layer3.envelope, time);
|
|
38288
38989
|
oscillator.connect(envelope2);
|
|
38289
38990
|
envelope2.connect(filter);
|
|
38290
38991
|
oscillator.start(time);
|
|
38291
|
-
oscillator.stop(end(
|
|
38992
|
+
oscillator.stop(end(layer3, time));
|
|
38292
38993
|
return oscillator;
|
|
38293
38994
|
});
|
|
38294
38995
|
return voiceOf(oscillators);
|
|
38295
38996
|
}
|
|
38296
|
-
var end2 = (
|
|
38297
|
-
function outputStage2(plan,
|
|
38997
|
+
var end2 = (layer3, start) => start + layer3.duration + layer3.tail;
|
|
38998
|
+
function outputStage2(plan, layer3, target) {
|
|
38298
38999
|
const { context } = target;
|
|
38299
|
-
const level = gainNode(context,
|
|
39000
|
+
const level = gainNode(context, layer3.level);
|
|
38300
39001
|
let node = level;
|
|
38301
39002
|
if (plan.pan !== void 0 && typeof context.createStereoPanner === "function") {
|
|
38302
39003
|
const panner = context.createStereoPanner();
|
|
@@ -38305,54 +39006,54 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38305
39006
|
node = panner;
|
|
38306
39007
|
}
|
|
38307
39008
|
node.connect(target.output);
|
|
38308
|
-
if (
|
|
38309
|
-
const send = gainNode(context,
|
|
39009
|
+
if (layer3.wet && target.wet) {
|
|
39010
|
+
const send = gainNode(context, layer3.wet);
|
|
38310
39011
|
node.connect(send);
|
|
38311
39012
|
send.connect(target.wet);
|
|
38312
39013
|
}
|
|
38313
39014
|
return level;
|
|
38314
39015
|
}
|
|
38315
|
-
function realizeNoiseLayer(plan,
|
|
39016
|
+
function realizeNoiseLayer(plan, layer3, target) {
|
|
38316
39017
|
const { context } = target;
|
|
38317
|
-
const time = target.time +
|
|
38318
|
-
const source = noiseSource(target,
|
|
38319
|
-
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) => {
|
|
38320
39021
|
const node = filterNode(context, filter, time);
|
|
38321
39022
|
rampTo(node.frequency, filter.frequency, time);
|
|
38322
39023
|
return node;
|
|
38323
39024
|
});
|
|
38324
39025
|
const envelope2 = context.createGain();
|
|
38325
|
-
applyEnvelope(envelope2.gain,
|
|
39026
|
+
applyEnvelope(envelope2.gain, layer3.envelope, time);
|
|
38326
39027
|
let tail = source;
|
|
38327
39028
|
for (const filter of filters) tail = tail.connect(filter);
|
|
38328
39029
|
tail.connect(envelope2);
|
|
38329
|
-
envelope2.connect(outputStage2(plan,
|
|
38330
|
-
source.start(time,
|
|
38331
|
-
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));
|
|
38332
39033
|
return [source];
|
|
38333
39034
|
}
|
|
38334
|
-
function realizeToneLayer(plan,
|
|
39035
|
+
function realizeToneLayer(plan, layer3, target) {
|
|
38335
39036
|
const { context } = target;
|
|
38336
|
-
const time = target.time +
|
|
39037
|
+
const time = target.time + layer3.at;
|
|
38337
39038
|
const oscillator = context.createOscillator();
|
|
38338
|
-
if (
|
|
38339
|
-
oscillator.type =
|
|
38340
|
-
assign(oscillator.frequency,
|
|
38341
|
-
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);
|
|
38342
39043
|
}
|
|
38343
39044
|
const envelope2 = context.createGain();
|
|
38344
|
-
applyEnvelope(envelope2.gain,
|
|
39045
|
+
applyEnvelope(envelope2.gain, layer3.envelope, time);
|
|
38345
39046
|
oscillator.connect(envelope2);
|
|
38346
|
-
envelope2.connect(outputStage2(plan,
|
|
39047
|
+
envelope2.connect(outputStage2(plan, layer3, target));
|
|
38347
39048
|
oscillator.start(time);
|
|
38348
|
-
oscillator.stop(end2(
|
|
39049
|
+
oscillator.stop(end2(layer3, time));
|
|
38349
39050
|
return [oscillator];
|
|
38350
39051
|
}
|
|
38351
|
-
function realizeVoiceLayer(plan,
|
|
38352
|
-
const source =
|
|
39052
|
+
function realizeVoiceLayer(plan, layer3, target) {
|
|
39053
|
+
const source = layer3.source;
|
|
38353
39054
|
if (source.kind !== "formant_voice") return [];
|
|
38354
39055
|
const { context } = target;
|
|
38355
|
-
const time = target.time +
|
|
39056
|
+
const time = target.time + layer3.at;
|
|
38356
39057
|
const oscillator = context.createOscillator();
|
|
38357
39058
|
oscillator.type = source.wave;
|
|
38358
39059
|
assign(oscillator.frequency, source.frequency, time);
|
|
@@ -38373,10 +39074,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38373
39074
|
for (const formant of formants) formant.connect(mix3);
|
|
38374
39075
|
breathLevel.connect(mix3);
|
|
38375
39076
|
const envelope2 = context.createGain();
|
|
38376
|
-
applyEnvelope(envelope2.gain,
|
|
39077
|
+
applyEnvelope(envelope2.gain, layer3.envelope, time);
|
|
38377
39078
|
mix3.connect(envelope2);
|
|
38378
|
-
envelope2.connect(outputStage2(plan,
|
|
38379
|
-
const stop = end2(
|
|
39079
|
+
envelope2.connect(outputStage2(plan, layer3, target));
|
|
39080
|
+
const stop = end2(layer3, time);
|
|
38380
39081
|
oscillator.start(time);
|
|
38381
39082
|
vibrato.start(time);
|
|
38382
39083
|
breath.start(time, source.breath.offset);
|
|
@@ -38386,24 +39087,24 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38386
39087
|
return [oscillator, vibrato, breath];
|
|
38387
39088
|
}
|
|
38388
39089
|
function realizeLayered(plan, target) {
|
|
38389
|
-
const sources = plan.layers.flatMap((
|
|
38390
|
-
if (
|
|
38391
|
-
if (
|
|
38392
|
-
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);
|
|
38393
39094
|
});
|
|
38394
39095
|
return voiceOf(sources);
|
|
38395
39096
|
}
|
|
38396
39097
|
function realizeSiren(plan, target) {
|
|
38397
39098
|
const { context } = target;
|
|
38398
|
-
const
|
|
38399
|
-
const time = target.time +
|
|
39099
|
+
const layer3 = plan.layers[0];
|
|
39100
|
+
const time = target.time + layer3.at;
|
|
38400
39101
|
const oscillator = context.createOscillator();
|
|
38401
|
-
if (
|
|
38402
|
-
oscillator.type =
|
|
38403
|
-
assign(oscillator.frequency,
|
|
38404
|
-
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);
|
|
38405
39106
|
}
|
|
38406
|
-
const depths =
|
|
39107
|
+
const depths = layer3.modulators.map((modulator) => {
|
|
38407
39108
|
const lfo = context.createOscillator();
|
|
38408
39109
|
if (modulator.wave) lfo.type = modulator.wave;
|
|
38409
39110
|
lfo.frequency.value = modulator.rate;
|
|
@@ -38414,57 +39115,57 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38414
39115
|
});
|
|
38415
39116
|
const lfos = depths.map(({ lfo }) => lfo);
|
|
38416
39117
|
const envelope2 = context.createGain();
|
|
38417
|
-
applyEnvelope(envelope2.gain,
|
|
39118
|
+
applyEnvelope(envelope2.gain, layer3.envelope, time);
|
|
38418
39119
|
for (const { depth, target: modulated } of depths) if (modulated === "gain") depth.connect(envelope2.gain);
|
|
38419
|
-
const filters = (
|
|
39120
|
+
const filters = (layer3.filters?.bank ?? []).map((filter) => filterNode(context, filter, time));
|
|
38420
39121
|
let tail = oscillator;
|
|
38421
39122
|
for (const filter of filters) tail = tail.connect(filter);
|
|
38422
39123
|
tail.connect(envelope2);
|
|
38423
39124
|
envelope2.connect(target.output);
|
|
38424
|
-
if (
|
|
38425
|
-
const send = gainNode(context,
|
|
39125
|
+
if (layer3.wet && target.wet) {
|
|
39126
|
+
const send = gainNode(context, layer3.wet);
|
|
38426
39127
|
envelope2.connect(send);
|
|
38427
39128
|
send.connect(target.wet);
|
|
38428
39129
|
}
|
|
38429
|
-
const stop = end2(
|
|
39130
|
+
const stop = end2(layer3, time);
|
|
38430
39131
|
oscillator.start(time);
|
|
38431
39132
|
for (const lfo of lfos) lfo.start(time);
|
|
38432
39133
|
oscillator.stop(stop);
|
|
38433
39134
|
for (const lfo of lfos) lfo.stop(stop);
|
|
38434
39135
|
return voiceOf([oscillator, ...lfos]);
|
|
38435
39136
|
}
|
|
38436
|
-
function noiseLayer(
|
|
39137
|
+
function noiseLayer(layer3, target, time) {
|
|
38437
39138
|
const { context } = target;
|
|
38438
|
-
const source = noiseSource(target,
|
|
38439
|
-
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));
|
|
38440
39141
|
const envelope2 = context.createGain();
|
|
38441
|
-
applyEnvelope(envelope2.gain,
|
|
39142
|
+
applyEnvelope(envelope2.gain, layer3.envelope, time);
|
|
38442
39143
|
let tail = source;
|
|
38443
39144
|
for (const filter of filters) tail = tail.connect(filter);
|
|
38444
39145
|
tail.connect(envelope2).connect(target.output);
|
|
38445
|
-
source.start(time,
|
|
38446
|
-
source.stop(time +
|
|
39146
|
+
source.start(time, layer3.source.kind === "noise" ? layer3.source.offset : 0);
|
|
39147
|
+
source.stop(time + layer3.duration + layer3.tail);
|
|
38447
39148
|
return source;
|
|
38448
39149
|
}
|
|
38449
|
-
function toneLayer(
|
|
39150
|
+
function toneLayer(layer3, target, time) {
|
|
38450
39151
|
const { context } = target;
|
|
38451
39152
|
const oscillator = context.createOscillator();
|
|
38452
|
-
if (
|
|
38453
|
-
oscillator.type =
|
|
38454
|
-
assign(oscillator.frequency,
|
|
38455
|
-
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);
|
|
38456
39157
|
}
|
|
38457
39158
|
const envelope2 = context.createGain();
|
|
38458
|
-
applyEnvelope(envelope2.gain,
|
|
39159
|
+
applyEnvelope(envelope2.gain, layer3.envelope, time);
|
|
38459
39160
|
oscillator.connect(envelope2).connect(target.output);
|
|
38460
39161
|
oscillator.start(time);
|
|
38461
|
-
oscillator.stop(time +
|
|
39162
|
+
oscillator.stop(time + layer3.duration + layer3.tail);
|
|
38462
39163
|
return oscillator;
|
|
38463
39164
|
}
|
|
38464
39165
|
function realizeWeapon(plan, target) {
|
|
38465
|
-
const sources = plan.layers.map((
|
|
38466
|
-
const time = target.time +
|
|
38467
|
-
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);
|
|
38468
39169
|
});
|
|
38469
39170
|
return voiceOf(sources);
|
|
38470
39171
|
}
|
|
@@ -38512,19 +39213,19 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38512
39213
|
rate: modulator.rate * rate,
|
|
38513
39214
|
...modulator.target === "frequency" ? { depth: modulator.depth * rate } : {}
|
|
38514
39215
|
});
|
|
38515
|
-
var tuneLayer = (
|
|
38516
|
-
...
|
|
38517
|
-
at:
|
|
38518
|
-
duration:
|
|
38519
|
-
tail:
|
|
38520
|
-
source: tuneSource(
|
|
38521
|
-
...
|
|
38522
|
-
modulators:
|
|
38523
|
-
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 }))
|
|
38524
39225
|
});
|
|
38525
39226
|
function retunePlan(plan, rate) {
|
|
38526
39227
|
if (rate === 1 || !(rate > 0)) return plan;
|
|
38527
|
-
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)) };
|
|
38528
39229
|
}
|
|
38529
39230
|
function createSetPicker() {
|
|
38530
39231
|
const last = /* @__PURE__ */ new Map();
|
|
@@ -38612,6 +39313,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38612
39313
|
}
|
|
38613
39314
|
};
|
|
38614
39315
|
}
|
|
39316
|
+
var TRIM_FADE = 0.04;
|
|
38615
39317
|
function realizeSample(plan, target) {
|
|
38616
39318
|
const context = target.context;
|
|
38617
39319
|
let head = target.output;
|
|
@@ -38633,16 +39335,26 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38633
39335
|
voice2.connect(head);
|
|
38634
39336
|
head = voice2;
|
|
38635
39337
|
const sources = [];
|
|
38636
|
-
for (const
|
|
38637
|
-
const buffer = target.buffer(
|
|
39338
|
+
for (const layer3 of plan.layers) {
|
|
39339
|
+
const buffer = target.buffer(layer3.url);
|
|
38638
39340
|
if (!buffer) continue;
|
|
38639
39341
|
const source = context.createBufferSource();
|
|
38640
39342
|
source.buffer = buffer;
|
|
38641
|
-
source.playbackRate.value =
|
|
38642
|
-
const gain = gainNode(context,
|
|
39343
|
+
source.playbackRate.value = layer3.rate;
|
|
39344
|
+
const gain = gainNode(context, layer3.gain);
|
|
38643
39345
|
source.connect(gain);
|
|
38644
39346
|
gain.connect(head);
|
|
38645
|
-
|
|
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
|
+
}
|
|
38646
39358
|
sources.push(source);
|
|
38647
39359
|
}
|
|
38648
39360
|
const realized = voiceOf(sources);
|
|
@@ -38662,7 +39374,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38662
39374
|
}
|
|
38663
39375
|
function sampleLength(plan, seconds) {
|
|
38664
39376
|
let length2 = 0;
|
|
38665
|
-
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
|
+
}
|
|
38666
39382
|
return length2;
|
|
38667
39383
|
}
|
|
38668
39384
|
function limiterCurve2(knee, ceiling, range3, points = 2049) {
|
|
@@ -38676,8 +39392,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38676
39392
|
}
|
|
38677
39393
|
return curve;
|
|
38678
39394
|
}
|
|
38679
|
-
var usesNoise = (recipe2) => recipe2.layers.some((
|
|
38680
|
-
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");
|
|
38681
39397
|
function createAudioEngine(options = {}) {
|
|
38682
39398
|
const seed = options.seed ?? 1;
|
|
38683
39399
|
const registry = createSoundRegistry(options.banks);
|
|
@@ -38916,7 +39632,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38916
39632
|
level: plan.level,
|
|
38917
39633
|
distance: plan.distance,
|
|
38918
39634
|
...plan.pan === void 0 ? {} : { pan: plan.pan },
|
|
38919
|
-
layers: plan.layers.map((
|
|
39635
|
+
layers: plan.layers.map((layer3) => ({ role: layer3.role, url: layer3.url, take: layer3.take, rate: layer3.rate })),
|
|
38920
39636
|
...plan.tier ? { tier: plan.tier } : {}
|
|
38921
39637
|
});
|
|
38922
39638
|
voices.setLength(voiceId, sampleLength(plan, (url2) => sampleStore.seconds(url2)) + (playOptions.delay ?? 0));
|
|
@@ -39049,7 +39765,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
39049
39765
|
random: engineRandom,
|
|
39050
39766
|
register: loopHost.register,
|
|
39051
39767
|
unregister: loopHost.unregister,
|
|
39052
|
-
muted: (bus) => busSettings.get(bus)?.muted === true
|
|
39768
|
+
muted: (bus) => busSettings.get(bus)?.muted === true,
|
|
39769
|
+
listener: () => listener,
|
|
39770
|
+
...options.distance ? { distance: options.distance } : {}
|
|
39053
39771
|
},
|
|
39054
39772
|
loopOptions.volume
|
|
39055
39773
|
);
|
|
@@ -39234,7 +39952,22 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
39234
39952
|
["smg_45_auto", 2, "sfx_pistol"],
|
|
39235
39953
|
["weapon_draw", 2],
|
|
39236
39954
|
["suppressor_attach", 3],
|
|
39237
|
-
["suppressor_detach", 3]
|
|
39955
|
+
["suppressor_detach", 3],
|
|
39956
|
+
["minigun_loop", 3],
|
|
39957
|
+
["smg_5_7x28", 3],
|
|
39958
|
+
["mg_belt_adjust", 3],
|
|
39959
|
+
["mg_belt_box_attach", 3],
|
|
39960
|
+
["mg_cover_open", 3],
|
|
39961
|
+
["mg_cover_close", 3],
|
|
39962
|
+
["weapon_holster", 3],
|
|
39963
|
+
["scope_zoom", 3]
|
|
39964
|
+
]),
|
|
39965
|
+
...entries("impactos", [
|
|
39966
|
+
["knife_hit_wall", 3],
|
|
39967
|
+
["helmet_hit", 3],
|
|
39968
|
+
["vest_hit", 3],
|
|
39969
|
+
["headshot", 3],
|
|
39970
|
+
["blood_squirt", 3]
|
|
39238
39971
|
]),
|
|
39239
39972
|
...entries("explosoes-fogo", [
|
|
39240
39973
|
["explosion_grenade", 1, "boom"],
|
|
@@ -39252,7 +39985,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
39252
39985
|
["grenade_bounce", 1],
|
|
39253
39986
|
["c4_plant", 2],
|
|
39254
39987
|
["c4_beep", 2],
|
|
39255
|
-
["c4_disarm", 2]
|
|
39988
|
+
["c4_disarm", 2],
|
|
39989
|
+
["c4_disarming_loop", 3],
|
|
39990
|
+
["c4_remote_detonate", 3],
|
|
39991
|
+
["smoke_grenade_hiss", 3],
|
|
39992
|
+
["grenade_pin_pull", 3],
|
|
39993
|
+
["electric_shock", 3],
|
|
39994
|
+
["electric_spark", 3]
|
|
39256
39995
|
]),
|
|
39257
39996
|
...entries("personagem", [
|
|
39258
39997
|
["footstep_concrete_walk", 1, "sfx_step"],
|
|
@@ -39280,7 +40019,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
39280
40019
|
["zombie_attack", 1],
|
|
39281
40020
|
["zombie_pain", 1],
|
|
39282
40021
|
["zombie_claw_hit", 1, "sfx_flesh"],
|
|
39283
|
-
["zombie_claw_miss", 2]
|
|
40022
|
+
["zombie_claw_miss", 2],
|
|
40023
|
+
["swing_whoosh", 3],
|
|
40024
|
+
["heartbeat_critical", 3],
|
|
40025
|
+
["fall_water", 3],
|
|
40026
|
+
["fall_damage", 3],
|
|
40027
|
+
["fall_scream", 3],
|
|
40028
|
+
["footstep_glass_walk", 3]
|
|
39284
40029
|
]),
|
|
39285
40030
|
...entries("veiculos", [
|
|
39286
40031
|
["engine_loop_car", 1],
|
|
@@ -39290,7 +40035,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
39290
40035
|
["car_door_open", 1, "latch"],
|
|
39291
40036
|
["car_door_close", 1, "shut_metal"],
|
|
39292
40037
|
["horn_car", 2, "horn"],
|
|
39293
|
-
["tire_skid_asphalt", 2]
|
|
40038
|
+
["tire_skid_asphalt", 2],
|
|
40039
|
+
["jet_flyby", 3],
|
|
40040
|
+
["helicopter_turbine", 3],
|
|
40041
|
+
["tire_burnout", 3],
|
|
40042
|
+
["handbrake_turn", 3],
|
|
40043
|
+
["siren_police", 3]
|
|
39294
40044
|
]),
|
|
39295
40045
|
...entries("itens-portas", [
|
|
39296
40046
|
["item_pickup_metal", 1],
|
|
@@ -39301,7 +40051,27 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
39301
40051
|
["door_creak", 1, "creak_wood"],
|
|
39302
40052
|
["door_locked_rattle", 1, "rattle"],
|
|
39303
40053
|
["drawer_open", 2, "slide"],
|
|
39304
|
-
["fridge_close", 2, "shut_metal"]
|
|
40054
|
+
["fridge_close", 2, "shut_metal"],
|
|
40055
|
+
["inventory_open", 3],
|
|
40056
|
+
["inventory_close", 3],
|
|
40057
|
+
["inventory_select", 3],
|
|
40058
|
+
["inventory_place", 3],
|
|
40059
|
+
["pickup_chime", 3],
|
|
40060
|
+
["item_pickup_coins", 3],
|
|
40061
|
+
["bandage_use", 3],
|
|
40062
|
+
["bandage_refuse", 3],
|
|
40063
|
+
["flashlight_toggle", 3],
|
|
40064
|
+
["gear_draw", 3],
|
|
40065
|
+
["gear_holster", 3],
|
|
40066
|
+
["button_press", 3],
|
|
40067
|
+
["lock_desk_open", 3],
|
|
40068
|
+
["elevator_move_loop", 3],
|
|
40069
|
+
["elevator_stop", 3],
|
|
40070
|
+
["door_sliding", 3],
|
|
40071
|
+
["door_kick", 3],
|
|
40072
|
+
["door_wood_break", 3],
|
|
40073
|
+
["gate_iron_open", 3],
|
|
40074
|
+
["gate_iron_close", 3]
|
|
39305
40075
|
]),
|
|
39306
40076
|
...entries("ambiente", [
|
|
39307
40077
|
["rain_loop", 2],
|
|
@@ -39309,7 +40079,16 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
39309
40079
|
["thunder_near", 2],
|
|
39310
40080
|
["thunder_far", 2],
|
|
39311
40081
|
["water_splash", 2],
|
|
39312
|
-
["helicopter_loop", 3]
|
|
40082
|
+
["helicopter_loop", 3],
|
|
40083
|
+
["bird_flush", 3],
|
|
40084
|
+
["dog_growl", 3],
|
|
40085
|
+
["dog_whimper", 3],
|
|
40086
|
+
["dog_howl", 3],
|
|
40087
|
+
["zombie_dog_bark", 3],
|
|
40088
|
+
["zombie_dog_howl_far", 3],
|
|
40089
|
+
["insect_squash", 3],
|
|
40090
|
+
["insect_crawl", 3],
|
|
40091
|
+
["fan_loop", 3]
|
|
39313
40092
|
])
|
|
39314
40093
|
];
|
|
39315
40094
|
var SFX_MATERIALS = [
|
|
@@ -39445,6 +40224,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
39445
40224
|
}
|
|
39446
40225
|
return { id: options.id, samples };
|
|
39447
40226
|
}
|
|
40227
|
+
var CATALOG = new Map([...SFX_CATALOG, ...SFX_IMPACTS].map((entry2) => [entry2.id, entry2]));
|
|
39448
40228
|
var PT = {
|
|
39449
40229
|
group: "Som",
|
|
39450
40230
|
name: "Painel de som (arquivos e C1\u2013C10)",
|
|
@@ -39519,9 +40299,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
39519
40299
|
strengths: { light: "leve", medium: "m\xE9dio", heavy: "forte" },
|
|
39520
40300
|
states: { file: "A", synth: "S", missing: "F" },
|
|
39521
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" },
|
|
39522
|
-
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" },
|
|
39523
40303
|
run: { idle: "parada", measuring: "medindo\u2026", done: "pronta", failed: "falhou", recording: "gravando\u2026", recorded: "grava\xE7\xE3o baixada" },
|
|
39524
|
-
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" },
|
|
39525
40305
|
sources: { sdk: "SDK", user: "seu som", synth: "sintetizado" },
|
|
39526
40306
|
probe: "Fonte do som",
|
|
39527
40307
|
wall: "Parede (oclus\xE3o)",
|
|
@@ -39592,9 +40372,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
39592
40372
|
environments: { indoor: "indoor", outdoor: "outdoor" },
|
|
39593
40373
|
strengths: { light: "light", medium: "medium", heavy: "heavy" },
|
|
39594
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" },
|
|
39595
|
-
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" },
|
|
39596
40376
|
run: { idle: "idle", measuring: "measuring\u2026", done: "done", failed: "failed", recording: "recording\u2026", recorded: "recording downloaded" },
|
|
39597
|
-
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" },
|
|
39598
40378
|
sources: { sdk: "SDK", user: "your sound", synth: "synthesized" },
|
|
39599
40379
|
probe: "Sound source",
|
|
39600
40380
|
wall: "Wall (occlusion)",
|
|
@@ -39665,6 +40445,66 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
39665
40445
|
};
|
|
39666
40446
|
}
|
|
39667
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: [] };
|
|
39668
40508
|
var FOLEY_FALLOFF = {
|
|
39669
40509
|
model: "inverse_square",
|
|
39670
40510
|
k: 0.02,
|
|
@@ -40271,11 +41111,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
40271
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 })] : []
|
|
40272
41112
|
];
|
|
40273
41113
|
}
|
|
40274
|
-
var quieter = (level, layers) => layers.map((
|
|
40275
|
-
const gain =
|
|
40276
|
-
if (typeof gain === "number") return { ...
|
|
40277
|
-
if (Array.isArray(gain)) return { ...
|
|
40278
|
-
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;
|
|
40279
41119
|
});
|
|
40280
41120
|
var recipe = (id, layers, falloff, bus = "world") => ({ id, bus, pan: true, layers, falloff, sources: ["sdk"] });
|
|
40281
41121
|
var takeId = (id, index) => `${id}_${String(index + 1).padStart(2, "0")}`;
|
|
@@ -40291,7 +41131,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
40291
41131
|
(take) => quieter(LANDING_LEVEL, [
|
|
40292
41132
|
// both feet, a hair apart, then the knees taking the weight (a low body thump) and the clothes settling
|
|
40293
41133
|
...footLayers(surface, take, GAITS.run, LANDINGS[landing2].weight),
|
|
40294
|
-
...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 })),
|
|
40295
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 }),
|
|
40296
41136
|
sceneNoise({ type: "bandpass", f: [1800, 2600], q: 0.8, d: 0.18, vol: LANDINGS[landing2].cloth * take.v, delay: 0.04 })
|
|
40297
41137
|
]),
|
|
@@ -40337,7 +41177,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
40337
41177
|
fall_damage: (take) => [
|
|
40338
41178
|
...BODY.body_fall(take),
|
|
40339
41179
|
sceneNoise({ type: "highpass", f: 2800, d: 0.02, vol: 0.35 * take.v, delay: 0.01 }),
|
|
40340
|
-
...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 }))
|
|
40341
41181
|
],
|
|
40342
41182
|
player_hurt: voice({ f0: 150, f1: 105, d: 0.26, fA: 620, fB: 1100, noise: 0.3, vol: 0.35 }),
|
|
40343
41183
|
player_breath_run: (take) => [
|
|
@@ -42410,7 +43250,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
42410
43250
|
if (base.space === "indoor") {
|
|
42411
43251
|
for (const voice2 of shot.voices) if (voice2.group === "tail") playGunshotVoice(voice2, extras);
|
|
42412
43252
|
}
|
|
42413
|
-
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 })) : [];
|
|
42414
43254
|
options.onGunshot?.(shot, { ...base, take, pitch }, { kind: "sample", id: recorded, layers });
|
|
42415
43255
|
return;
|
|
42416
43256
|
}
|
|
@@ -43232,6 +44072,19 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
43232
44072
|
"drink",
|
|
43233
44073
|
"sticky"
|
|
43234
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
|
+
]
|
|
43235
44088
|
}
|
|
43236
44089
|
];
|
|
43237
44090
|
var LIQUIDS = liquids_default;
|
|
@@ -49837,6 +50690,273 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
49837
50690
|
return group;
|
|
49838
50691
|
}
|
|
49839
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
|
+
|
|
49840
50960
|
// src/weapon-item-model.ts
|
|
49841
50961
|
var SHIPPED_WEAPON_ITEM_MODELS = [
|
|
49842
50962
|
["wrench", { item: "adjustable_wrench" }],
|
|
@@ -49845,8 +50965,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
49845
50965
|
["crossbow", { turn: 1 }],
|
|
49846
50966
|
["knife", { flip: true }],
|
|
49847
50967
|
["meat_cleaver", { flip: true }],
|
|
49848
|
-
["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" }]
|
|
49849
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;
|
|
49850
50974
|
var weaponPropsOver = (models) => {
|
|
49851
50975
|
const itemModelOf = (weaponId, items) => {
|
|
49852
50976
|
const id = models.get(weaponId)?.item ?? weaponId;
|
|
@@ -49862,7 +50986,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
49862
50986
|
get: (weaponId) => models.get(weaponId),
|
|
49863
50987
|
itemModelOf,
|
|
49864
50988
|
buildItemModel,
|
|
49865
|
-
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))
|
|
49866
50990
|
};
|
|
49867
50991
|
};
|
|
49868
50992
|
var defaultProps;
|
|
@@ -49874,6 +50998,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
49874
50998
|
|
|
49875
50999
|
// src/box-fx.ts
|
|
49876
51000
|
var EJECTS_ON_SHOT = /* @__PURE__ */ new Set(["pistol", "smg", "carbine", "rifle", "sniper", "shotgun"]);
|
|
51001
|
+
var SPOUTS = /* @__PURE__ */ new Set(["firearm", "flame", "heat", "extinguisher"]);
|
|
49877
51002
|
var DROPS_MAGAZINE = /* @__PURE__ */ new Set(["pistol", "smg", "carbine", "rifle", "sniper"]);
|
|
49878
51003
|
var CYCLES = /* @__PURE__ */ new Set(["shotgun_pump_12", "rifle_bolt_308"]);
|
|
49879
51004
|
var FALLBACK_ENERGY = 300;
|
|
@@ -49908,6 +51033,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
49908
51033
|
const q = new THREE.Quaternion();
|
|
49909
51034
|
const q2 = new THREE.Quaternion();
|
|
49910
51035
|
const pointForward = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI / 2);
|
|
51036
|
+
const frontOf = new THREE.Vector3();
|
|
49911
51037
|
const equip = (weapon) => {
|
|
49912
51038
|
if (model) hand.remove(model);
|
|
49913
51039
|
model = null;
|
|
@@ -49918,6 +51044,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
49918
51044
|
const length2 = new THREE.Box3().setFromObject(model).getSize(v).x;
|
|
49919
51045
|
rear = new THREE.Box3().setFromObject(model).min.x;
|
|
49920
51046
|
lengthMetres = length2;
|
|
51047
|
+
frontOf.copy(new THREE.Box3().setFromObject(model).getCenter(v)).setX(rear + length2);
|
|
49921
51048
|
model.quaternion.copy(pointForward);
|
|
49922
51049
|
hand.add(model);
|
|
49923
51050
|
inHand = def.id;
|
|
@@ -50018,6 +51145,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
50018
51145
|
inHand = null;
|
|
50019
51146
|
hold = null;
|
|
50020
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
|
+
},
|
|
50021
51155
|
handTargets() {
|
|
50022
51156
|
if (!model || !hold) return null;
|
|
50023
51157
|
hand.updateMatrixWorld(true);
|
|
@@ -51618,193 +52752,23 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
51618
52752
|
options: {
|
|
51619
52753
|
rpm: 3e3
|
|
51620
52754
|
}
|
|
51621
|
-
}
|
|
51622
|
-
|
|
51623
|
-
|
|
51624
|
-
|
|
51625
|
-
|
|
51626
|
-
|
|
51627
|
-
|
|
51628
|
-
|
|
51629
|
-
|
|
51630
|
-
|
|
51631
|
-
|
|
51632
|
-
|
|
51633
|
-
|
|
51634
|
-
|
|
51635
|
-
const centerUv = centerLength / (arcLength + centerLength);
|
|
51636
|
-
return centerUv + arcUvRatio + arcUvRatio * (1 - arcAngleRatio);
|
|
51637
|
-
};
|
|
51638
|
-
var FACES = [
|
|
51639
|
-
{ direction: [1, 0, 0], u: ["z", "y", false], v: ["y", "z", true] },
|
|
51640
|
-
{ direction: [-1, 0, 0], u: ["z", "y", true], v: ["y", "z", true] },
|
|
51641
|
-
{ direction: [0, 1, 0], u: ["x", "z", true], v: ["z", "x", false] },
|
|
51642
|
-
{ direction: [0, -1, 0], u: ["x", "z", true], v: ["z", "x", true] },
|
|
51643
|
-
{ direction: [0, 0, 1], u: ["x", "y", true], v: ["y", "x", true] },
|
|
51644
|
-
{ direction: [0, 0, -1], u: ["x", "y", false], v: ["y", "x", true] }
|
|
51645
|
-
];
|
|
51646
|
-
function createRoundedBoxGeometry(THREE, width, height, depth, segments, radius) {
|
|
51647
|
-
const count = segments * 2 + 1;
|
|
51648
|
-
const rounding = Math.min(width / 2, height / 2, depth / 2, radius);
|
|
51649
|
-
const geometry = new THREE.BoxGeometry(1, 1, 1, count, count, count);
|
|
51650
|
-
const flat2 = geometry.toNonIndexed();
|
|
51651
|
-
geometry.setIndex(null);
|
|
51652
|
-
geometry.setAttribute("position", flat2.attributes.position);
|
|
51653
|
-
geometry.setAttribute("normal", flat2.attributes.normal);
|
|
51654
|
-
geometry.setAttribute("uv", flat2.attributes.uv);
|
|
51655
|
-
const position = new THREE.Vector3();
|
|
51656
|
-
const normal = new THREE.Vector3();
|
|
51657
|
-
const box5 = new THREE.Vector3(width, height, depth).divideScalar(2).subScalar(rounding);
|
|
51658
|
-
const positions2 = geometry.attributes.position.array;
|
|
51659
|
-
const normals = geometry.attributes.normal.array;
|
|
51660
|
-
const uvs = geometry.attributes.uv.array;
|
|
51661
|
-
const faceTriangles = positions2.length / 6;
|
|
51662
|
-
const halfSegment = 0.5 / count;
|
|
51663
|
-
const sides = { x: width, y: height, z: depth };
|
|
51664
|
-
for (let i = 0, j = 0; i < positions2.length; i += 3, j += 2) {
|
|
51665
|
-
position.fromArray(positions2, i);
|
|
51666
|
-
normal.copy(position);
|
|
51667
|
-
normal.x -= Math.sign(normal.x) * halfSegment;
|
|
51668
|
-
normal.y -= Math.sign(normal.y) * halfSegment;
|
|
51669
|
-
normal.z -= Math.sign(normal.z) * halfSegment;
|
|
51670
|
-
normal.normalize();
|
|
51671
|
-
positions2[i] = box5.x * Math.sign(position.x) + normal.x * rounding;
|
|
51672
|
-
positions2[i + 1] = box5.y * Math.sign(position.y) + normal.y * rounding;
|
|
51673
|
-
positions2[i + 2] = box5.z * Math.sign(position.z) + normal.z * rounding;
|
|
51674
|
-
normals[i] = normal.x;
|
|
51675
|
-
normals[i + 1] = normal.y;
|
|
51676
|
-
normals[i + 2] = normal.z;
|
|
51677
|
-
const face = FACES[Math.floor(i / faceTriangles)];
|
|
51678
|
-
if (!face) continue;
|
|
51679
|
-
const direction = new THREE.Vector3(...face.direction);
|
|
51680
|
-
for (const [offset, [uvAxis, projectionAxis, mirrored]] of [[0, face.u], [1, face.v]]) {
|
|
51681
|
-
const value = uvAlong(THREE, direction, normal, uvAxis, projectionAxis, rounding, sides[uvAxis]);
|
|
51682
|
-
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
|
|
51683
52769
|
}
|
|
51684
52770
|
}
|
|
51685
|
-
return geometry;
|
|
51686
|
-
}
|
|
51687
|
-
|
|
51688
|
-
// src/models/kit.ts
|
|
51689
|
-
var PI2 = Math.PI;
|
|
51690
|
-
var createMaterials = (THREE) => {
|
|
51691
|
-
const standard = (color2, roughness = 0.7, metalness = 0.2, extra = {}) => new THREE.MeshStandardMaterial({ color: color2, roughness, metalness, ...extra });
|
|
51692
|
-
const basic = (color2, extra = {}) => new THREE.MeshBasicMaterial({ color: color2, ...extra });
|
|
51693
|
-
const additive = { transparent: true, opacity: 0.95, blending: THREE.AdditiveBlending, depthWrite: false };
|
|
51694
|
-
const materials = {
|
|
51695
|
-
metal: standard(3422010, 0.42, 0.75),
|
|
51696
|
-
steel: standard(7106418, 0.32, 0.85),
|
|
51697
|
-
steelL: standard(9080208, 0.28, 0.9),
|
|
51698
|
-
dark: standard(1711133, 0.55, 0.5),
|
|
51699
|
-
poly: standard(2369058, 0.8, 0.05),
|
|
51700
|
-
olive: standard(4936241, 0.8, 0.05),
|
|
51701
|
-
tan: standard(10259043, 0.8, 0.05),
|
|
51702
|
-
wood: standard(4860951, 0.55, 0),
|
|
51703
|
-
woodL: standard(6175263, 0.55, 0),
|
|
51704
|
-
brass: standard(12819013, 0.28, 0.9),
|
|
51705
|
-
copper: standard(11561531, 0.3, 0.85),
|
|
51706
|
-
lead: standard(7171955, 0.5, 0.5),
|
|
51707
|
-
shell: standard(10692380, 0.5, 0.05),
|
|
51708
|
-
glass: standard(8364968, 0.05, 0.1, { transparent: true, opacity: 0.42 }),
|
|
51709
|
-
lens: standard(2311770, 0.05, 0.3, { transparent: true, opacity: 0.9, emissive: 399392 }),
|
|
51710
|
-
rubber: standard(1381653, 0.85, 0),
|
|
51711
|
-
white: standard(13617332, 0.8, 0),
|
|
51712
|
-
hole: standard(526343, 1, 0),
|
|
51713
|
-
bake: standard(5911072, 0.55, 0),
|
|
51714
|
-
rust: standard(7027230, 0.95, 0.3),
|
|
51715
|
-
rustD: standard(4860440, 0.95, 0.25),
|
|
51716
|
-
worn: standard(5593178, 0.6, 0.6),
|
|
51717
|
-
fire: basic(16742946),
|
|
51718
|
-
fire2: basic(16764762),
|
|
51719
|
-
flashA: basic(16757575, additive),
|
|
51720
|
-
flashB: basic(16773568, additive),
|
|
51721
|
-
smokeP: standard(9079430, 1, 0, { transparent: true, opacity: 0.35, depthWrite: false }),
|
|
51722
|
-
/** Launcher paints. */
|
|
51723
|
-
yellow: standard(11570978, 0.6, 0),
|
|
51724
|
-
red: standard(9313300, 0.45, 0.1),
|
|
51725
|
-
redPaint: standard(10691354, 0.35, 0.2),
|
|
51726
|
-
tape: standard(9079944, 0.9, 0),
|
|
51727
|
-
pipe: standard(10115634, 0.35, 0.8),
|
|
51728
|
-
green: standard(3818536, 0.75, 0.05),
|
|
51729
|
-
/** Magazine finishes named by the options. */
|
|
51730
|
-
bakelite: standard(6958620, 0.6, 0),
|
|
51731
|
-
polyMag: standard(2763302, 0.85, 0)
|
|
51732
|
-
};
|
|
51733
|
-
markShared(...Object.values(materials));
|
|
51734
|
-
return materials;
|
|
51735
52771
|
};
|
|
51736
|
-
var kits = /* @__PURE__ */ new WeakMap();
|
|
51737
|
-
function modelKit(host) {
|
|
51738
|
-
const cached = kits.get(host);
|
|
51739
|
-
if (cached) return cached;
|
|
51740
|
-
const THREE = shapeGeometries(host);
|
|
51741
|
-
const geometries = /* @__PURE__ */ new Map();
|
|
51742
|
-
const shadowed = (mesh3) => {
|
|
51743
|
-
mesh3.castShadow = true;
|
|
51744
|
-
mesh3.receiveShadow = true;
|
|
51745
|
-
return mesh3;
|
|
51746
|
-
};
|
|
51747
|
-
const place = (parent, mesh3, x, y, z) => {
|
|
51748
|
-
mesh3.position.set(x, y, z);
|
|
51749
|
-
parent.add(mesh3);
|
|
51750
|
-
return mesh3;
|
|
51751
|
-
};
|
|
51752
|
-
const kit = {
|
|
51753
|
-
THREE,
|
|
51754
|
-
M: createMaterials(THREE),
|
|
51755
|
-
roundness: null,
|
|
51756
|
-
group: () => new THREE.Group(),
|
|
51757
|
-
box(parent, w, h, d, material, x, y, z, rz = 0, ry = 0, rx = 0) {
|
|
51758
|
-
const radius = Math.min(w, h, d) * (kit.roundness ?? 0.2);
|
|
51759
|
-
const key2 = `${w.toFixed(4)},${h.toFixed(4)},${d.toFixed(4)},${radius.toFixed(5)}`;
|
|
51760
|
-
let geometry = geometries.get(key2);
|
|
51761
|
-
if (!geometry) {
|
|
51762
|
-
geometry = radius > 25e-5 ? createRoundedBoxGeometry(THREE, w, h, d, 2, radius) : new THREE.BoxGeometry(w, h, d);
|
|
51763
|
-
markShared(geometry);
|
|
51764
|
-
geometries.set(key2, geometry);
|
|
51765
|
-
}
|
|
51766
|
-
const mesh3 = place(parent, shadowed(new THREE.Mesh(geometry, material)), x, y, z);
|
|
51767
|
-
mesh3.rotation.set(rx, ry, rz);
|
|
51768
|
-
return mesh3;
|
|
51769
|
-
},
|
|
51770
|
-
cylinderX(parent, radius, length2, material, x, y, z, segments = 16, radiusEnd) {
|
|
51771
|
-
const mesh3 = shadowed(new THREE.Mesh(new THREE.CylinderGeometry(radiusEnd ?? radius, radius, length2, segments), material));
|
|
51772
|
-
mesh3.rotation.z = -PI2 / 2;
|
|
51773
|
-
return place(parent, mesh3, x, y, z);
|
|
51774
|
-
},
|
|
51775
|
-
cylinderY(parent, radius, height, material, x, y, z, segments = 16, radiusEnd) {
|
|
51776
|
-
return place(parent, shadowed(new THREE.Mesh(new THREE.CylinderGeometry(radiusEnd ?? radius, radius, height, segments), material)), x, y, z);
|
|
51777
|
-
},
|
|
51778
|
-
cylinderZ(parent, radius, length2, material, x, y, z, segments = 16) {
|
|
51779
|
-
const mesh3 = shadowed(new THREE.Mesh(new THREE.CylinderGeometry(radius, radius, length2, segments), material));
|
|
51780
|
-
mesh3.rotation.x = PI2 / 2;
|
|
51781
|
-
return place(parent, mesh3, x, y, z);
|
|
51782
|
-
},
|
|
51783
|
-
sphere(parent, radius, material, x, y, z, detail = 1) {
|
|
51784
|
-
return place(parent, shadowed(new THREE.Mesh(new THREE.IcosahedronGeometry(radius, detail), material)), x, y, z);
|
|
51785
|
-
},
|
|
51786
|
-
torus: (parent, geometry, material, x, y, z) => place(parent, shadowed(new THREE.Mesh(geometry, material)), x, y, z),
|
|
51787
|
-
mark(parent, x, y, z) {
|
|
51788
|
-
const object2 = new THREE.Object3D();
|
|
51789
|
-
object2.position.set(x, y, z);
|
|
51790
|
-
parent.add(object2);
|
|
51791
|
-
return object2;
|
|
51792
|
-
},
|
|
51793
|
-
pivot(parent, x = 0, y = 0, z = 0) {
|
|
51794
|
-
const group = new THREE.Group();
|
|
51795
|
-
group.position.set(x, y, z);
|
|
51796
|
-
parent.add(group);
|
|
51797
|
-
return group;
|
|
51798
|
-
}
|
|
51799
|
-
};
|
|
51800
|
-
kits.set(host, kit);
|
|
51801
|
-
return kit;
|
|
51802
|
-
}
|
|
51803
|
-
function heatify(glow, mesh3) {
|
|
51804
|
-
mesh3.material = mesh3.material.clone();
|
|
51805
|
-
glow.push(mesh3);
|
|
51806
|
-
return mesh3;
|
|
51807
|
-
}
|
|
51808
52772
|
|
|
51809
52773
|
// src/models/break-action.ts
|
|
51810
52774
|
function buildBreakAction(kit, options) {
|
|
@@ -51839,6 +52803,509 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
51839
52803
|
return { group, parts };
|
|
51840
52804
|
}
|
|
51841
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
|
+
|
|
51842
53309
|
// src/models/attachments/mount-frames.ts
|
|
51843
53310
|
var DEFAULT_BARREL_RADIUS = 85e-4;
|
|
51844
53311
|
var DEFAULT_RECEIVER_WIDTH = 0.034;
|
|
@@ -51913,58 +53380,6 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
51913
53380
|
}
|
|
51914
53381
|
}
|
|
51915
53382
|
|
|
51916
|
-
// src/models/details.ts
|
|
51917
|
-
var PI3 = Math.PI;
|
|
51918
|
-
function rail(kit, parent, x, length2, y, z, width, rotationX = 0) {
|
|
51919
|
-
const { M, box: box5 } = kit;
|
|
51920
|
-
const pivot = kit.pivot(parent, 0, y, z);
|
|
51921
|
-
pivot.rotation.x = rotationX;
|
|
51922
|
-
box5(pivot, length2, 5e-3, width, M.dark, x + length2 / 2, 0, 0);
|
|
51923
|
-
const slots = Math.floor(length2 / 95e-4);
|
|
51924
|
-
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);
|
|
51925
|
-
return pivot;
|
|
51926
|
-
}
|
|
51927
|
-
function vents(kit, parent, x, length2, y, z, count, height) {
|
|
51928
|
-
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);
|
|
51929
|
-
}
|
|
51930
|
-
function scope(kit, parent, kind, cx, cy, cz = 0) {
|
|
51931
|
-
const { M, box: box5, cylinderX, cylinderY, cylinderZ, THREE } = kit;
|
|
51932
|
-
if (kind === 1) {
|
|
51933
|
-
box5(parent, 0.044, 0.01, 0.028, M.dark, cx, cy + 5e-3, cz);
|
|
51934
|
-
cylinderX(parent, 0.0155, 0.034, M.dark, cx + 4e-3, cy + 0.026, cz, 18);
|
|
51935
|
-
cylinderX(parent, 0.0125, 2e-3, M.lens, cx + 0.022, cy + 0.026, cz, 18);
|
|
51936
|
-
cylinderY(parent, 4e-3, 6e-3, M.dark, cx + 4e-3, cy + 0.044, cz, 10);
|
|
51937
|
-
return;
|
|
51938
|
-
}
|
|
51939
|
-
if (kind === 2) {
|
|
51940
|
-
box5(parent, 0.07, 0.012, 0.026, M.dark, cx, cy + 6e-3, cz);
|
|
51941
|
-
cylinderX(parent, 0.016, 0.1, M.dark, cx - 0.01, cy + 0.032, cz, 18);
|
|
51942
|
-
cylinderX(parent, 0.016, 0.035, M.dark, cx + 0.055, cy + 0.032, cz, 18, 0.02);
|
|
51943
|
-
cylinderX(parent, 0.017, 2e-3, M.lens, cx + 0.073, cy + 0.032, cz, 18);
|
|
51944
|
-
cylinderY(parent, 7e-3, 0.012, M.dark, cx, cy + 0.052, cz, 12);
|
|
51945
|
-
box5(parent, 0.03, 0.01, 0.012, M.dark, cx - 0.01, cy + 0.054, cz);
|
|
51946
|
-
return;
|
|
51947
|
-
}
|
|
51948
|
-
const sleeve = kind === 4 ? 0.2 : 0.32;
|
|
51949
|
-
cylinderX(parent, 0.0135, sleeve * 0.55, M.dark, cx, cy + 0.045, cz, 18);
|
|
51950
|
-
cylinderX(parent, 0.0135, sleeve * 0.25, M.dark, cx + sleeve * 0.36, cy + 0.045, cz, 18, 0.026);
|
|
51951
|
-
cylinderX(parent, 0.026, 0.05, M.dark, cx + sleeve * 0.5, cy + 0.045, cz, 18);
|
|
51952
|
-
cylinderX(parent, 0.024, 2e-3, M.lens, cx + sleeve * 0.5 + 0.026, cy + 0.045, cz, 18);
|
|
51953
|
-
cylinderX(parent, 0.019, 0.06, M.dark, cx - sleeve * 0.38, cy + 0.045, cz, 18, 0.0135);
|
|
51954
|
-
cylinderX(parent, 0.019, 0.035, M.rubber, cx - sleeve * 0.38 - 0.045, cy + 0.045, cz, 18);
|
|
51955
|
-
cylinderX(parent, 0.017, 2e-3, M.lens, cx - sleeve * 0.38 - 0.063, cy + 0.045, cz, 18);
|
|
51956
|
-
cylinderY(parent, 0.01, 0.022, M.dark, cx, cy + 0.066, cz, 14);
|
|
51957
|
-
cylinderY(parent, 0.011, 4e-3, M.metal, cx, cy + 0.078, cz, 14);
|
|
51958
|
-
cylinderZ(parent, 0.01, 0.022, M.dark, cx, cy + 0.045, cz + 0.022, 14);
|
|
51959
|
-
for (const offset of [-0.07, 0.07]) {
|
|
51960
|
-
const ring3 = kit.torus(parent, new THREE.TorusGeometry(0.0155, 3e-3, 8, 20), M.dark, cx + offset, cy + 0.045, cz);
|
|
51961
|
-
ring3.rotation.y = PI3 / 2;
|
|
51962
|
-
box5(parent, 0.016, 0.03, 0.022, M.dark, cx + offset, cy + 0.018, cz);
|
|
51963
|
-
}
|
|
51964
|
-
}
|
|
51965
|
-
var buttpad = (kit, parent, x, y, height, width) => void kit.box(parent, 0.012, height, width, kit.M.rubber, x, y, 0);
|
|
51966
|
-
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);
|
|
51967
|
-
|
|
51968
53383
|
// src/models/bullpup.ts
|
|
51969
53384
|
function buildBullpup(kit, options) {
|
|
51970
53385
|
const { M, box: box5, cylinderX } = kit;
|
|
@@ -52090,7 +53505,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
52090
53505
|
}
|
|
52091
53506
|
|
|
52092
53507
|
// src/models/launcher-rounds.ts
|
|
52093
|
-
var
|
|
53508
|
+
var PI7 = Math.PI;
|
|
52094
53509
|
function buildRocketGrenade(kit) {
|
|
52095
53510
|
const { M, cylinderX } = kit;
|
|
52096
53511
|
const round5 = kit.group();
|
|
@@ -52120,7 +53535,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
52120
53535
|
cylinderX(rocket, diameter, 0.12, M.olive, 0.36, 0, 0, 18, diameter * 0.25);
|
|
52121
53536
|
for (let i = 0; i < 4; i++) {
|
|
52122
53537
|
const fin = box5(rocket, 0.06, 2e-3, diameter * 1.4, M.metal, -0.17, 0, 0);
|
|
52123
|
-
fin.rotation.x = i *
|
|
53538
|
+
fin.rotation.x = i * PI7 / 4;
|
|
52124
53539
|
}
|
|
52125
53540
|
return rocket;
|
|
52126
53541
|
}
|
|
@@ -52258,7 +53673,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
52258
53673
|
}
|
|
52259
53674
|
|
|
52260
53675
|
// src/models/m134.ts
|
|
52261
|
-
var
|
|
53676
|
+
var PI8 = Math.PI;
|
|
52262
53677
|
var BARRELS = 6;
|
|
52263
53678
|
var CLUSTER_RADIUS = 0.03;
|
|
52264
53679
|
var BARREL_RADIUS = 78e-4;
|
|
@@ -52270,7 +53685,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
52270
53685
|
const length2 = BARREL_END - 0.3;
|
|
52271
53686
|
let heated;
|
|
52272
53687
|
for (let i = 0; i < BARRELS; i++) {
|
|
52273
|
-
const angle = i * 2 *
|
|
53688
|
+
const angle = i * 2 * PI8 / BARRELS;
|
|
52274
53689
|
const y = Math.cos(angle) * CLUSTER_RADIUS;
|
|
52275
53690
|
const z = Math.sin(angle) * CLUSTER_RADIUS;
|
|
52276
53691
|
const barrel = cylinderX(barrels, BARREL_RADIUS, length2, M.metal, 0.3 + length2 / 2, y, z, 14);
|
|
@@ -52419,7 +53834,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
52419
53834
|
}
|
|
52420
53835
|
|
|
52421
53836
|
// src/models/pistol-slide.ts
|
|
52422
|
-
var
|
|
53837
|
+
var PI9 = Math.PI;
|
|
52423
53838
|
function buildSlide(kit, slide2, parts, options, style, size, metal2) {
|
|
52424
53839
|
const { M, box: box5, cylinderX } = kit;
|
|
52425
53840
|
const { length: L, width: w } = size;
|
|
@@ -52447,8 +53862,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
52447
53862
|
if (style.tri) {
|
|
52448
53863
|
const tube2 = new kit.THREE.Mesh(new kit.THREE.CylinderGeometry(0.016, 0.016, L * 0.6, 3), metal2);
|
|
52449
53864
|
tube2.castShadow = tube2.receiveShadow = true;
|
|
52450
|
-
tube2.rotation.set(0, 0, -
|
|
52451
|
-
tube2.rotateY(
|
|
53865
|
+
tube2.rotation.set(0, 0, -PI9 / 2);
|
|
53866
|
+
tube2.rotateY(PI9 / 6);
|
|
52452
53867
|
tube2.position.set(L * 0.7, slideHeight * 0.08, 0);
|
|
52453
53868
|
slide2.add(tube2);
|
|
52454
53869
|
heatify(parts.glow, tube2);
|
|
@@ -52500,7 +53915,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
52500
53915
|
};
|
|
52501
53916
|
|
|
52502
53917
|
// src/models/pistol.ts
|
|
52503
|
-
var
|
|
53918
|
+
var PI10 = Math.PI;
|
|
52504
53919
|
function buildFrame2(kit, group, parts, options, style, size, materials) {
|
|
52505
53920
|
const { M, box: box5, cylinderZ, sphere: sphere2 } = kit;
|
|
52506
53921
|
const { length: L, height: h, width: w } = size;
|
|
@@ -52592,8 +54007,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
52592
54007
|
box5(group, 4e-3, 0.03, 9e-3, frameMetal, gx + 0.073, ty - 0.02, 0, 0.2);
|
|
52593
54008
|
box5(group, 8e-3, 6e-3, 9e-3, frameMetal, gx + 0.074, ty - 0.037, 0, 0.4);
|
|
52594
54009
|
} else {
|
|
52595
|
-
const guard = kit.torus(group, new kit.THREE.TorusGeometry(0.019, 22e-4, 6, 16,
|
|
52596
|
-
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;
|
|
52597
54012
|
guard.scale.set(1.2, 1, 1);
|
|
52598
54013
|
}
|
|
52599
54014
|
const isGlock = options.st === "glock" || !options.st;
|
|
@@ -52617,7 +54032,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
52617
54032
|
}
|
|
52618
54033
|
|
|
52619
54034
|
// src/models/revolver.ts
|
|
52620
|
-
var
|
|
54035
|
+
var PI11 = Math.PI;
|
|
52621
54036
|
var DEFAULT_CHAMBERS = 6;
|
|
52622
54037
|
function buildRevolver(kit, options) {
|
|
52623
54038
|
const { M, box: box5, cylinderX } = kit;
|
|
@@ -52635,12 +54050,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
52635
54050
|
parts.cylinder = cylinder2;
|
|
52636
54051
|
cylinderX(cylinder2, 0.0215, 0.042, metal2, 0, 0, 0, 24);
|
|
52637
54052
|
for (let i = 0; i < chambers; i++) {
|
|
52638
|
-
const angle = i * 2 *
|
|
54053
|
+
const angle = i * 2 * PI11 / chambers;
|
|
52639
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);
|
|
52640
54055
|
}
|
|
52641
54056
|
parts.chambers = [];
|
|
52642
54057
|
for (let i = 0; i < chambers; i++) {
|
|
52643
|
-
const angle = i * 2 *
|
|
54058
|
+
const angle = i * 2 * PI11 / chambers + PI11 / chambers;
|
|
52644
54059
|
parts.chambers.push(kit.mark(cylinder2, -0.022, Math.cos(angle) * 0.013, Math.sin(angle) * 0.013));
|
|
52645
54060
|
cylinderX(cylinder2, 46e-4, 2e-3, M.brass, -0.0215, Math.cos(angle) * 0.013, Math.sin(angle) * 0.013, 12);
|
|
52646
54061
|
}
|
|
@@ -52665,434 +54080,6 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
52665
54080
|
return { group, parts };
|
|
52666
54081
|
}
|
|
52667
54082
|
|
|
52668
|
-
// src/models/attachments/muzzle-brake.ts
|
|
52669
|
-
function buildBrake(kit, parent, kind, x, y, barrelRadius, heat = () => void 0) {
|
|
52670
|
-
const { M, box: box5, cylinderX } = kit;
|
|
52671
|
-
const scale = kind === 2 ? 3.2 : 2;
|
|
52672
|
-
const length2 = kind === 2 ? 0.12 : 0.06;
|
|
52673
|
-
heat(cylinderX(parent, barrelRadius * scale, length2, M.dark, x - length2 / 2, y, 0, kind === 2 ? 8 : 16));
|
|
52674
|
-
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);
|
|
52675
|
-
}
|
|
52676
|
-
|
|
52677
|
-
// src/models/capture.ts
|
|
52678
|
-
function captured(parent, draw2) {
|
|
52679
|
-
const before = parent.children.length;
|
|
52680
|
-
draw2();
|
|
52681
|
-
return parent.children.slice(before);
|
|
52682
|
-
}
|
|
52683
|
-
function recordFitting(parts, id, parent, draw2) {
|
|
52684
|
-
parts.fittings = { ...parts.fittings, [id]: captured(parent, draw2) };
|
|
52685
|
-
}
|
|
52686
|
-
|
|
52687
|
-
// src/models/attachments/bipod.ts
|
|
52688
|
-
function buildBipod(kit, parent, x, y) {
|
|
52689
|
-
const { M, box: box5, cylinderX } = kit;
|
|
52690
|
-
cylinderX(parent, 8e-3, 0.02, M.dark, x, y, 0, 12);
|
|
52691
|
-
for (const side of [-1, 1]) {
|
|
52692
|
-
const leg = kit.pivot(parent, x, y, side * 0.012);
|
|
52693
|
-
leg.rotation.set(side * 0.15, 0, -0.35);
|
|
52694
|
-
box5(leg, 6e-3, 0.2, 6e-3, M.dark, 0, -0.1, 0);
|
|
52695
|
-
box5(leg, 0.01, 6e-3, 0.01, M.rubber, 0, -0.2, 0);
|
|
52696
|
-
}
|
|
52697
|
-
}
|
|
52698
|
-
var buildBipodModel = ({ kit }) => {
|
|
52699
|
-
const group = kit.group();
|
|
52700
|
-
buildBipod(kit, group, 0, 0);
|
|
52701
|
-
return group;
|
|
52702
|
-
};
|
|
52703
|
-
|
|
52704
|
-
// src/models/rifle-fittings.ts
|
|
52705
|
-
var SCOPE_IDS = { 1: "red_dot", 2: "acog_4x", 3: "scope_3_9x", 4: "scope_6_24x" };
|
|
52706
|
-
function buildFittings(context, gripX) {
|
|
52707
|
-
const { kit, group, parts, options: o, furniture: furn, length: L, receiverStart: x0, receiverEnd: x1, receiverHeight: hR, receiverWidth: wR, barrelRadius: r, barrelY: by } = context;
|
|
52708
|
-
const { M, box: box5, cylinderX, cylinderZ, sphere: sphere2 } = kit;
|
|
52709
|
-
const middle = (x0 + x1) / 2;
|
|
52710
|
-
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));
|
|
52711
|
-
if (o.carry) {
|
|
52712
|
-
box5(group, 0.15, 0.026, 0.014, M.metal, middle, hR / 2 + 0.03, 0);
|
|
52713
|
-
box5(group, 0.012, 0.03, 0.014, M.metal, middle + 0.07, hR / 2 + 0.014, 0);
|
|
52714
|
-
box5(group, 0.012, 0.03, 0.014, M.metal, middle - 0.07, hR / 2 + 0.014, 0);
|
|
52715
|
-
}
|
|
52716
|
-
if (o.bipod) recordFitting(parts, "bipod", group, () => buildBipod(kit, group, x1 + (L - x1) * 0.45 + 0.04, by - 0.012));
|
|
52717
|
-
if (o.bolt) {
|
|
52718
|
-
const handle = kit.pivot(group, x1 - 0.045, by, 0);
|
|
52719
|
-
parts.boltHandle = handle;
|
|
52720
|
-
parts.boltHandleRest = handle.position.x;
|
|
52721
|
-
cylinderZ(handle, 42e-4, 0.05, M.steelL, 0, 0, wR / 2 + 0.022, 12);
|
|
52722
|
-
sphere2(handle, 95e-4, M.dark, 0, -4e-3, wR / 2 + 0.048, 1);
|
|
52723
|
-
cylinderX(group, hR * 0.3, 0.03, M.steel, x0 + 5e-3, by, 0, 16);
|
|
52724
|
-
}
|
|
52725
|
-
if (o.lever) {
|
|
52726
|
-
const lever = kit.pivot(group, gripX - 0.02, -hR / 2 - 0.01, 0);
|
|
52727
|
-
parts.lever = lever;
|
|
52728
|
-
box5(lever, 0.11, 6e-3, 0.012, M.metal, 0.055, -0.052, 0);
|
|
52729
|
-
box5(lever, 6e-3, 0.05, 0.012, M.metal, 3e-3, -0.028, 0);
|
|
52730
|
-
box5(lever, 6e-3, 0.05, 0.012, M.metal, 0.108, -0.028, 0);
|
|
52731
|
-
box5(lever, 0.04, 6e-3, 0.012, M.metal, 0.08, -2e-3, 0);
|
|
52732
|
-
box5(group, 0.03, 0.012, 3e-3, M.dark, x1 - 0.04, by, wR / 2 + 1e-3);
|
|
52733
|
-
}
|
|
52734
|
-
if (o.tube) {
|
|
52735
|
-
const tubeLength = (L - x1) * (o.tubeLen || 0.8);
|
|
52736
|
-
cylinderX(group, 0.0105, tubeLength, M.metal, x1 + tubeLength / 2, by - 0.023, 0, 16);
|
|
52737
|
-
cylinderX(group, 0.0125, 0.02, M.dark, x1 + tubeLength + 6e-3, by - 0.023, 0, 16);
|
|
52738
|
-
}
|
|
52739
|
-
if (o.pump) {
|
|
52740
|
-
const pump = kit.pivot(group);
|
|
52741
|
-
parts.pump = pump;
|
|
52742
|
-
box5(pump, 0.17, 0.042, 0.046, furn, x1 + 0.14, by - 0.022, 0);
|
|
52743
|
-
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);
|
|
52744
|
-
}
|
|
52745
|
-
if (o.heat) {
|
|
52746
|
-
cylinderX(group, r * 1.75, (L - x1) * 0.7, M.dark, x1 + (L - x1) * 0.4, by, 0, 12);
|
|
52747
|
-
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);
|
|
52748
|
-
}
|
|
52749
|
-
if (o.bayo) box5(group, 0.025, 8e-3, 0.01, M.metal, L - 0.07, by - 0.016, 0);
|
|
52750
|
-
if (o.rod) cylinderX(group, 3e-3, (L - x1) * 0.85, M.steel, x1 + (L - x1) * 0.45, by - 0.014, 0, 8);
|
|
52751
|
-
}
|
|
52752
|
-
|
|
52753
|
-
// src/models/rifle-forend.ts
|
|
52754
|
-
var PI9 = Math.PI;
|
|
52755
|
-
function buildForend(context) {
|
|
52756
|
-
const { kit, group, options: o, furniture: furn, length: L, receiverEnd: x1, receiverHeight: hR, receiverWidth: wR, barrelRadius: r, barrelY: by } = context;
|
|
52757
|
-
const { M, box: box5 } = kit;
|
|
52758
|
-
const hasLongScope = (o.scope ?? 0) >= 3;
|
|
52759
|
-
if (!context.isTraditional && o.hg !== "none") {
|
|
52760
|
-
const handguardLength = (L - x1) * (o.hgFrac || 0.5);
|
|
52761
|
-
const hx = x1 + handguardLength / 2;
|
|
52762
|
-
const hh = hR * 0.8;
|
|
52763
|
-
if (o.hg === "rail") {
|
|
52764
|
-
box5(group, handguardLength, hh, wR * 1.04, M.dark, hx, by - 2e-3, 0);
|
|
52765
|
-
rail(kit, group, x1, handguardLength, by + hh / 2, 0, wR * 0.66);
|
|
52766
|
-
rail(kit, group, x1 + 0.01, handguardLength - 0.02, by - 2e-3, wR * 0.54, wR * 0.4, PI9 / 2);
|
|
52767
|
-
rail(kit, group, x1 + 0.01, handguardLength - 0.02, by - 2e-3, -wR * 0.54, wR * 0.4, -PI9 / 2);
|
|
52768
|
-
rail(kit, group, x1 + 0.01, handguardLength - 0.02, by - hh / 2, 0, wR * 0.6, PI9);
|
|
52769
|
-
} else {
|
|
52770
|
-
const material = o.hg === "wood" ? M.wood : furn;
|
|
52771
|
-
if (o.ak) {
|
|
52772
|
-
box5(group, handguardLength, hh * 0.55, wR * 1.08, material, hx, by - hh * 0.22, 0);
|
|
52773
|
-
box5(group, handguardLength * 0.75, hh * 0.35, wR * 0.7, material, hx - handguardLength * 0.1, by + r * 2.2, 0);
|
|
52774
|
-
} else {
|
|
52775
|
-
box5(group, handguardLength, hh, wR * 1.08, material, hx, by - 2e-3, 0);
|
|
52776
|
-
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);
|
|
52777
|
-
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);
|
|
52778
|
-
}
|
|
52779
|
-
}
|
|
52780
|
-
if (!hasLongScope && !o.rail && o.ak) {
|
|
52781
|
-
box5(group, 0.03, 0.016, wR * 0.6, M.metal, x1 + 0.02, by + r * 2.5 + 0.01, 0);
|
|
52782
|
-
box5(group, 0.012, 4e-3, wR * 0.5, M.dark, x1 + 0.03, by + r * 2.5 + 0.019, 0);
|
|
52783
|
-
}
|
|
52784
|
-
}
|
|
52785
|
-
if (hasLongScope) return;
|
|
52786
|
-
const sightX = L - (o.ak ? 0.06 : 0.08);
|
|
52787
|
-
if (o.ak) {
|
|
52788
|
-
box5(group, 0.022, 0.022, wR * 0.6, M.metal, sightX, by + 8e-3, 0);
|
|
52789
|
-
box5(group, 6e-3, 0.024, 4e-3, M.metal, sightX, by + 0.026, 8e-3);
|
|
52790
|
-
box5(group, 6e-3, 0.024, 4e-3, M.metal, sightX, by + 0.026, -8e-3);
|
|
52791
|
-
box5(group, 3e-3, 0.016, 3e-3, M.dark, sightX, by + 0.022, 0);
|
|
52792
|
-
} else if (!o.rail || o.carry) {
|
|
52793
|
-
box5(group, 0.018, 0.014, wR * 0.55, M.dark, sightX, by + 8e-3, 0);
|
|
52794
|
-
box5(group, 0.012, 0.034, 8e-3, M.dark, sightX, by + 0.03, 0, -0.25);
|
|
52795
|
-
} else box5(group, 0.012, 0.024, 0.012, M.dark, sightX - 0.04, by + hR * 0.4 + 0.012, 0);
|
|
52796
|
-
}
|
|
52797
|
-
|
|
52798
|
-
// src/models/attachments/belt-box.ts
|
|
52799
|
-
function buildBeltBox(kit, belt) {
|
|
52800
|
-
const { M, box: box5, cylinderX } = kit;
|
|
52801
|
-
box5(belt, 0.11, 0.1, 0.08, M.olive, 0, 0, 0);
|
|
52802
|
-
box5(belt, 0.112, 0.012, 0.082, M.dark, 0, 0.046, 0);
|
|
52803
|
-
for (let i = 0; i < 7; i++) {
|
|
52804
|
-
cylinderX(belt, 42e-4, 0.034, M.brass, -0.04 + i * 0.012, 0.07, 0.035, 10);
|
|
52805
|
-
box5(belt, 6e-3, 6e-3, 0.012, M.metal, -0.04 + i * 0.012, 0.066, 0.035);
|
|
52806
|
-
}
|
|
52807
|
-
}
|
|
52808
|
-
|
|
52809
|
-
// src/models/attachments/drum.ts
|
|
52810
|
-
function buildDrum(kit, magazine) {
|
|
52811
|
-
const { M, box: box5, cylinderZ } = kit;
|
|
52812
|
-
cylinderZ(magazine, 0.075, 0.07, M.dark, 0.02, -0.085, 0, 22);
|
|
52813
|
-
cylinderZ(magazine, 0.05, 0.074, M.metal, 0.02, -0.085, 0, 18);
|
|
52814
|
-
box5(magazine, 0.05, 0.04, 0.03, M.dark, 0, -0.02, 0);
|
|
52815
|
-
}
|
|
52816
|
-
|
|
52817
|
-
// src/models/helical-magazine.ts
|
|
52818
|
-
var PI10 = Math.PI;
|
|
52819
|
-
var LENGTH = 0.26;
|
|
52820
|
-
var RADIUS = 0.026;
|
|
52821
|
-
var TURNS = 11;
|
|
52822
|
-
function buildHelicalMagazine(context) {
|
|
52823
|
-
const { kit, group, parts, receiverEnd, barrelY, barrelRadius } = context;
|
|
52824
|
-
const { M, cylinderX, box: box5 } = kit;
|
|
52825
|
-
const x = receiverEnd + LENGTH / 2 + 0.02;
|
|
52826
|
-
const y = barrelY - barrelRadius - RADIUS - 0.012;
|
|
52827
|
-
const magazine = kit.pivot(group, x, y, 0);
|
|
52828
|
-
parts.mag = magazine;
|
|
52829
|
-
cylinderX(magazine, RADIUS, LENGTH, M.dark, 0, 0, 0, 20);
|
|
52830
|
-
cylinderX(magazine, RADIUS * 1.06, 0.01, M.metal, -LENGTH / 2, 0, 0, 20);
|
|
52831
|
-
cylinderX(magazine, RADIUS * 1.06, 0.01, M.metal, LENGTH / 2, 0, 0, 20);
|
|
52832
|
-
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);
|
|
52833
|
-
box5(magazine, 0.05, 0.03, 0.03, M.dark, -LENGTH / 2 - 0.02, RADIUS * 0.4, 0);
|
|
52834
|
-
parts.magDrop = 0.16;
|
|
52835
|
-
return x;
|
|
52836
|
-
}
|
|
52837
|
-
|
|
52838
|
-
// src/models/rifle-controls.ts
|
|
52839
|
-
function buildGrip(context) {
|
|
52840
|
-
const { kit, group, parts, options: o, furniture: furn, receiverStart: x0, receiverHeight: hR, receiverWidth: wR } = context;
|
|
52841
|
-
const { M, box: box5 } = kit;
|
|
52842
|
-
const gx = x0 + (o.gripAt || 0.07);
|
|
52843
|
-
if (!context.isTraditional && o.grip !== "none") {
|
|
52844
|
-
const grip = kit.pivot(group, gx - 0.012, -hR / 2 - 0.046, 0);
|
|
52845
|
-
grip.rotation.z = -0.3;
|
|
52846
|
-
parts.grip = grip;
|
|
52847
|
-
box5(grip, 0.032, 0.105, 0.028, furn, 0, 0, 0);
|
|
52848
|
-
for (let i = 0; i < 3; i++) box5(grip, 6e-3, 0.012, 0.026, furn, 0.017, 0.022 - i * 0.02, 0);
|
|
52849
|
-
box5(grip, 0.034, 8e-3, 0.03, furn, 0, -0.052, 0);
|
|
52850
|
-
}
|
|
52851
|
-
box5(group, 0.06, 4e-3, 0.01, M.metal, gx + 0.03, -hR / 2 - 0.024, 0);
|
|
52852
|
-
box5(group, 4e-3, 0.022, 0.01, M.metal, gx + 0.06, -hR / 2 - 0.013, 0);
|
|
52853
|
-
parts.trigger = box5(group, 4e-3, 0.016, 4e-3, M.dark, gx + 0.024, -hR / 2 - 0.012, 0, 0.15);
|
|
52854
|
-
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);
|
|
52855
|
-
return gx;
|
|
52856
|
-
}
|
|
52857
|
-
function buildMagazine(context, gx) {
|
|
52858
|
-
const { kit, group, parts, options: o, receiverStart: x0, receiverHeight: hR, receiverWidth: wR, receiverLength: RL } = context;
|
|
52859
|
-
const { M, box: box5 } = kit;
|
|
52860
|
-
if (o.mag === "helical") return buildHelicalMagazine(context);
|
|
52861
|
-
const mx = o.magAt != null ? x0 + o.magAt : gx + 0.075;
|
|
52862
|
-
const scale = o.magLen || 1;
|
|
52863
|
-
const magazine = kit.pivot(group, mx, -hR / 2, 0);
|
|
52864
|
-
parts.mag = magazine;
|
|
52865
|
-
const finish = o.magMat === "bakelite" ? M.bakelite : o.magMat === "poly" ? M.polyMag : void 0;
|
|
52866
|
-
if (o.mag === "curved") {
|
|
52867
|
-
let px = 0;
|
|
52868
|
-
let py = 0;
|
|
52869
|
-
const material = finish ?? M.metal;
|
|
52870
|
-
for (const angle of [0.06, 0.22, 0.38]) {
|
|
52871
|
-
const length2 = 0.07 * scale;
|
|
52872
|
-
const cx = px + Math.sin(angle) * length2 / 2;
|
|
52873
|
-
const cy = py - Math.cos(angle) * length2 / 2;
|
|
52874
|
-
box5(magazine, 0.052, length2 + 4e-3, 0.024, material, cx, cy, 0, angle);
|
|
52875
|
-
box5(magazine, 0.04, length2 * 0.8, 0.026, M.dark, cx, cy, 0, angle);
|
|
52876
|
-
px += Math.sin(angle) * length2;
|
|
52877
|
-
py -= Math.cos(angle) * length2;
|
|
52878
|
-
}
|
|
52879
|
-
box5(magazine, 0.058, 8e-3, 0.028, material, px, py, 0, 0.38);
|
|
52880
|
-
parts.magDrop = 0.07 * scale * 3 + 0.04;
|
|
52881
|
-
} else if (o.mag === "box") {
|
|
52882
|
-
const length2 = 0.13 * scale;
|
|
52883
|
-
const curve = o.curve || 0;
|
|
52884
|
-
const segment = length2 / 3;
|
|
52885
|
-
const material = finish ?? M.dark;
|
|
52886
|
-
let px = 0;
|
|
52887
|
-
let py = 0;
|
|
52888
|
-
let angle = 0.08;
|
|
52889
|
-
for (let i = 0; i < 3; i++) {
|
|
52890
|
-
angle = 0.08 + curve * i;
|
|
52891
|
-
const cx = px + Math.sin(angle) * segment / 2;
|
|
52892
|
-
const cy = py - Math.cos(angle) * segment / 2;
|
|
52893
|
-
box5(magazine, 0.05, segment + 4e-3, 0.024, material, cx, cy, 0, angle);
|
|
52894
|
-
box5(magazine, 0.04, 3e-3, 0.026, M.metal, cx, cy, 0, angle);
|
|
52895
|
-
px += Math.sin(angle) * segment;
|
|
52896
|
-
py -= Math.cos(angle) * segment;
|
|
52897
|
-
}
|
|
52898
|
-
box5(magazine, 0.056, 7e-3, 0.028, material, px, py - 2e-3, 0, angle);
|
|
52899
|
-
parts.magDrop = length2 + 0.03;
|
|
52900
|
-
} else if (o.mag === "drum") {
|
|
52901
|
-
buildDrum(kit, magazine);
|
|
52902
|
-
parts.magDrop = 0.2;
|
|
52903
|
-
} else if (o.mag === "internal") {
|
|
52904
|
-
box5(group, 0.08, 0.025, 0.03, context.isTraditional ? context.furniture : M.metal, mx, -hR / 2 - 0.012, 0);
|
|
52905
|
-
parts.mag = null;
|
|
52906
|
-
} else parts.mag = null;
|
|
52907
|
-
if (o.mag === "belt") {
|
|
52908
|
-
const belt = kit.pivot(group, mx + 0.02, -hR / 2 - 0.05, -0.045);
|
|
52909
|
-
parts.belt = belt;
|
|
52910
|
-
buildBeltBox(kit, belt);
|
|
52911
|
-
const cover = kit.pivot(group, x0 + 0.01, hR / 2, 0);
|
|
52912
|
-
parts.cover = cover;
|
|
52913
|
-
box5(cover, RL - 0.03, 0.014, wR * 1.05, M.metal, (RL - 0.03) / 2, 7e-3, 0);
|
|
52914
|
-
box5(cover, 0.02, 0.012, wR * 0.6, M.dark, RL - 0.04, 0.016, 0);
|
|
52915
|
-
}
|
|
52916
|
-
return mx;
|
|
52917
|
-
}
|
|
52918
|
-
|
|
52919
|
-
// src/models/rifle-stock.ts
|
|
52920
|
-
function buildStock(context, magazineX) {
|
|
52921
|
-
const { kit, group, options: o, furniture: furn, length: L, stockLength: S, receiverStart: x0, receiverEnd: x1, receiverHeight: hR } = context;
|
|
52922
|
-
const { M, box: box5, cylinderX } = kit;
|
|
52923
|
-
if (context.isTraditional) {
|
|
52924
|
-
buttpad(kit, group, 6e-3, -0.04, 0.13, 0.038);
|
|
52925
|
-
box5(group, 0.03, 0.13, 0.038, furn, 0.024, -0.04, 0);
|
|
52926
|
-
box5(group, S, 0.055, 0.034, furn, S / 2, -0.012, 0, 0.06);
|
|
52927
|
-
box5(group, 0.09, 0.05, 0.032, furn, x0 - 0.02, -0.035, 0, 0.25);
|
|
52928
|
-
const forendLength = x1 - x0 + (L - x1) * (o.fore ?? 0.62);
|
|
52929
|
-
if (forendLength > 0) box5(group, forendLength, 0.045, 0.04, furn, x0 + forendLength / 2, -hR / 2 + 4e-3, 0);
|
|
52930
|
-
if (o.stock === "straight") box5(group, 0.15, 0.04, 0.035, furn, x1 + 0.08, -hR / 2, 0);
|
|
52931
|
-
box5(group, 0.04, 4e-3, 0.03, M.metal, magazineX, -hR / 2 - 0.022, 0);
|
|
52932
|
-
swivel(kit, group, 0.2, -0.08);
|
|
52933
|
-
swivel(kit, group, x1 + (L - x1) * 0.45, -hR / 2 - 0.03);
|
|
52934
|
-
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);
|
|
52935
|
-
} else if (o.stock === "fixed" || o.stock === "wood") {
|
|
52936
|
-
box5(group, S, 0.05, 0.03, furn, S / 2, -8e-3, 0, 0.05);
|
|
52937
|
-
box5(group, 0.03, 0.13, 0.036, furn, 0.022, -0.035, 0);
|
|
52938
|
-
buttpad(kit, group, 4e-3, -0.035, 0.13, 0.036);
|
|
52939
|
-
if (o.stock === "wood") box5(group, S * 0.6, 0.03, 0.028, furn, S * 0.55, -0.045, 0, 0.2);
|
|
52940
|
-
swivel(kit, group, 0.08, -0.09);
|
|
52941
|
-
} else if (o.stock === "skeleton") {
|
|
52942
|
-
box5(group, S, 0.014, 0.026, furn, S / 2, 0.012, 0, 0.03);
|
|
52943
|
-
box5(group, S, 0.014, 0.026, furn, S / 2, -0.05, 0, -0.08);
|
|
52944
|
-
box5(group, 0.03, 0.12, 0.034, furn, 0.02, -0.025, 0);
|
|
52945
|
-
buttpad(kit, group, 4e-3, -0.025, 0.12, 0.034);
|
|
52946
|
-
} else if (o.stock === "retract") {
|
|
52947
|
-
cylinderX(group, 0.013, S, M.metal, S / 2, 0, 0, 16);
|
|
52948
|
-
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);
|
|
52949
|
-
box5(group, 0.034, 0.11, 0.036, furn, 0.02, -0.025, 0);
|
|
52950
|
-
box5(group, S * 0.55, 0.032, 0.03, furn, S * 0.35, 0, 0);
|
|
52951
|
-
buttpad(kit, group, 3e-3, -0.025, 0.11, 0.036);
|
|
52952
|
-
} else if (o.stock === "fold") {
|
|
52953
|
-
box5(group, S, 6e-3, 6e-3, M.metal, S / 2, 0.01, 0.012);
|
|
52954
|
-
box5(group, S, 6e-3, 6e-3, M.metal, S / 2, -0.04, 0.012, -0.12);
|
|
52955
|
-
box5(group, 0.012, 0.1, 0.03, M.metal, 6e-3, -0.02, 0.012);
|
|
52956
|
-
}
|
|
52957
|
-
}
|
|
52958
|
-
|
|
52959
|
-
// src/models/rifle.ts
|
|
52960
|
-
var PI11 = Math.PI;
|
|
52961
|
-
function buildReceiver(context) {
|
|
52962
|
-
const { kit, group, parts, options: o, length: L, receiverStart: x0, receiverEnd: x1, receiverHeight: hR, receiverWidth: wR, receiverLength: RL, barrelY: by } = context;
|
|
52963
|
-
const { M, box: box5, cylinderX, cylinderY, cylinderZ, sphere: sphere2 } = kit;
|
|
52964
|
-
const receiverMaterial = o.tan ? M.tan : M.metal;
|
|
52965
|
-
const middle = (x0 + x1) / 2;
|
|
52966
|
-
if (o.round) {
|
|
52967
|
-
cylinderX(group, hR * 0.36, RL, M.steel, middle, by, 0, 20);
|
|
52968
|
-
cylinderX(group, hR * 0.32, 0.05, M.steel, x0 - 0.01, by, 0, 18);
|
|
52969
|
-
} else if (o.ar) {
|
|
52970
|
-
box5(group, RL, hR * 0.5, wR, receiverMaterial, middle, hR * 0.25, 0);
|
|
52971
|
-
box5(group, RL * 0.92, hR * 0.52, wR * 0.96, receiverMaterial, middle - RL * 0.02, -hR * 0.24, 0);
|
|
52972
|
-
box5(group, 0.05, 0.03, wR * 1.15, receiverMaterial, x0 + RL * 0.62, -hR * 0.5 - 0.01, 0);
|
|
52973
|
-
cylinderZ(group, 6e-3, 0.012, M.metal, x1 - 0.03, hR * 0.28, wR / 2 + 6e-3, 12);
|
|
52974
|
-
box5(group, 0.012, 0.01, 0.012, M.metal, x1 - 0.05, hR * 0.12, wR / 2 + 6e-3);
|
|
52975
|
-
box5(group, 0.03, 8e-3, 0.012, M.dark, x0 + 0.02, hR / 2 + 4e-3, 0);
|
|
52976
|
-
box5(group, 0.012, 6e-3, 4e-3, M.dark, x0 + RL * 0.55, -hR * 0.15, -wR / 2 - 2e-3);
|
|
52977
|
-
} else box5(group, RL, hR, wR, receiverMaterial, middle, 0, 0);
|
|
52978
|
-
if (o.ak) {
|
|
52979
|
-
box5(group, RL * 0.86, hR * 0.28, wR * 0.95, M.metal, middle - 8e-3, hR / 2 + 4e-3, 0);
|
|
52980
|
-
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);
|
|
52981
|
-
box5(group, RL * 0.5, 0.012, 3e-3, M.metal, x0 + RL * 0.55, -hR * 0.02, wR / 2 + 15e-4, -0.05);
|
|
52982
|
-
box5(group, 0.012, 0.014, 3e-3, M.dark, x0 + RL * 0.32, -hR * 0.05, wR / 2 + 2e-3);
|
|
52983
|
-
}
|
|
52984
|
-
if (o.g3) {
|
|
52985
|
-
cylinderX(group, 9e-3, (L - x1) * 0.6, M.metal, x1 + (L - x1) * 0.28, hR * 0.48, 0, 14);
|
|
52986
|
-
box5(group, 0.012, 0.024, 8e-3, M.dark, x1 + (L - x1) * 0.5, hR * 0.48, -0.012);
|
|
52987
|
-
cylinderY(group, 0.012, 0.016, M.dark, x0 + 0.03, hR / 2 + 8e-3, 0, 12);
|
|
52988
|
-
}
|
|
52989
|
-
const ejectX = x1 - (o.ejectBack || 0.07);
|
|
52990
|
-
const ejectY = o.ar ? hR * 0.2 : by;
|
|
52991
|
-
box5(group, 0.05, hR * 0.36, 4e-3, M.hole, ejectX, ejectY, wR / 2 - 4e-4);
|
|
52992
|
-
const bolt = kit.pivot(group);
|
|
52993
|
-
parts.bolt = bolt;
|
|
52994
|
-
parts.stroke = Math.min(0.1, RL * 0.32);
|
|
52995
|
-
box5(bolt, 0.044, hR * 0.26, 6e-3, M.steelL, ejectX, ejectY, wR / 2 - 12e-4);
|
|
52996
|
-
if (o.charge) {
|
|
52997
|
-
box5(bolt, 0.012, 0.01, 0.03, M.metal, ejectX + 0.04, ejectY + 4e-3, wR / 2 + 0.012);
|
|
52998
|
-
sphere2(bolt, 65e-4, M.metal, ejectX + 0.04, ejectY + 4e-3, wR / 2 + 0.028, 1);
|
|
52999
|
-
}
|
|
53000
|
-
if (o.ar) box5(group, 0.012, 0.016, 6e-3, receiverMaterial, ejectX - 0.03, ejectY + 4e-3, wR / 2 + 4e-3);
|
|
53001
|
-
if (o.rail) rail(kit, group, x0 - 5e-3, RL + 0.07, hR / 2 + (o.ar ? 0 : 3e-3), 0, wR * 0.68);
|
|
53002
|
-
}
|
|
53003
|
-
function buildBarrel(context) {
|
|
53004
|
-
const { kit, group, parts, options: o, length: L, barrelLength: Bl, receiverEnd: x1, barrelRadius: r, barrelY: by } = context;
|
|
53005
|
-
const { M, box: box5, cylinderX } = kit;
|
|
53006
|
-
heatify(parts.glow, cylinderX(group, r, Bl, M.metal, L - Bl / 2, by, 0, 16));
|
|
53007
|
-
if (o.jacket) {
|
|
53008
|
-
cylinderX(group, r * 2, (L - x1) * 0.6, M.dark, x1 + (L - x1) * 0.3, by, 0, 16);
|
|
53009
|
-
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);
|
|
53010
|
-
}
|
|
53011
|
-
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);
|
|
53012
|
-
if (o.brake) {
|
|
53013
|
-
const kind = o.brake === 2 ? 2 : 1;
|
|
53014
|
-
recordFitting(parts, kind === 2 ? "muzzle_brake_heavy" : "muzzle_brake", group, () => buildBrake(kit, group, kind, L, by, r, (body) => void heatify(parts.glow, body)));
|
|
53015
|
-
} else if (!o.noFH) {
|
|
53016
|
-
recordFitting(parts, "muzzle_default", group, () => {
|
|
53017
|
-
heatify(parts.glow, cylinderX(group, r * 1.45, 0.042, M.dark, L - 0.021, by, 0, 16));
|
|
53018
|
-
for (let i = 0; i < 4; i++) {
|
|
53019
|
-
const angle = i * PI11 / 2 + PI11 / 4;
|
|
53020
|
-
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);
|
|
53021
|
-
}
|
|
53022
|
-
});
|
|
53023
|
-
}
|
|
53024
|
-
cylinderX(group, r * 0.55, 4e-3, M.hole, L + 5e-4, by, 0, 12);
|
|
53025
|
-
}
|
|
53026
|
-
var familyOf = (o) => {
|
|
53027
|
-
if (o.mag === "belt") return "belt";
|
|
53028
|
-
if (o.pump) return "pump";
|
|
53029
|
-
if (o.lever) return "lever";
|
|
53030
|
-
if (o.tube) return "semi12";
|
|
53031
|
-
if (o.bolt) return o.mag === "box" ? "boltmag" : "bolt";
|
|
53032
|
-
return o.mag === "internal" ? "semiint" : "rifle";
|
|
53033
|
-
};
|
|
53034
|
-
function buildRifle(kit, options) {
|
|
53035
|
-
const { M } = kit;
|
|
53036
|
-
const group = kit.group();
|
|
53037
|
-
const parts = { family: "rifle", glow: [] };
|
|
53038
|
-
const length2 = (options.L ?? 0) / 1e3;
|
|
53039
|
-
const barrelLength = (options.B ?? 0) / 1e3;
|
|
53040
|
-
const isTraditional = options.stock === "trad" || options.stock === "straight";
|
|
53041
|
-
const stockLength = options.stock === "none" ? 0 : options.stockLen || Math.min(0.36, Math.max(0.2, 0.3 * length2));
|
|
53042
|
-
const receiverStart = stockLength;
|
|
53043
|
-
const receiverEnd = Math.max(receiverStart + 0.12, length2 - barrelLength * 0.92);
|
|
53044
|
-
const receiverHeight = options.hR || 0.06;
|
|
53045
|
-
const context = {
|
|
53046
|
-
kit,
|
|
53047
|
-
group,
|
|
53048
|
-
parts,
|
|
53049
|
-
options,
|
|
53050
|
-
furniture: options.wood ? M.wood : options.olive ? M.olive : options.tan ? M.tan : M.poly,
|
|
53051
|
-
isTraditional,
|
|
53052
|
-
length: length2,
|
|
53053
|
-
barrelLength,
|
|
53054
|
-
stockLength,
|
|
53055
|
-
receiverStart,
|
|
53056
|
-
receiverEnd,
|
|
53057
|
-
receiverHeight,
|
|
53058
|
-
receiverWidth: options.wR || 0.034,
|
|
53059
|
-
barrelRadius: options.br || 85e-4,
|
|
53060
|
-
barrelY: receiverHeight * 0.15,
|
|
53061
|
-
receiverLength: receiverEnd - receiverStart
|
|
53062
|
-
};
|
|
53063
|
-
buildReceiver(context);
|
|
53064
|
-
buildBarrel(context);
|
|
53065
|
-
buildForend(context);
|
|
53066
|
-
const gripX = buildGrip(context);
|
|
53067
|
-
const magazineX = buildMagazine(context, gripX);
|
|
53068
|
-
parts.stockMeshes = context.isTraditional ? [] : captured(group, () => buildStock(context, magazineX));
|
|
53069
|
-
if (context.isTraditional) buildStock(context, magazineX);
|
|
53070
|
-
buildFittings(context, gripX);
|
|
53071
|
-
const hasHandguard = !context.isTraditional && options.hg !== "none";
|
|
53072
|
-
parts.frames = {
|
|
53073
|
-
length: length2,
|
|
53074
|
-
barrelY: context.barrelY,
|
|
53075
|
-
barrelRadius: context.barrelRadius,
|
|
53076
|
-
receiverStart,
|
|
53077
|
-
receiverEnd,
|
|
53078
|
-
receiverHeight,
|
|
53079
|
-
receiverWidth: context.receiverWidth,
|
|
53080
|
-
handguardEnd: receiverEnd + (length2 - receiverEnd) * (hasHandguard ? options.hgFrac || 0.5 : 0.4),
|
|
53081
|
-
magazineX,
|
|
53082
|
-
gripX,
|
|
53083
|
-
hasRail: Boolean(options.rail)
|
|
53084
|
-
};
|
|
53085
|
-
const { barrelY: by, receiverWidth: wR } = context;
|
|
53086
|
-
const ejectX = receiverEnd - (options.ejectBack || 0.07);
|
|
53087
|
-
const ejectY = options.ar ? receiverHeight * 0.2 : by;
|
|
53088
|
-
parts.muzzle = kit.mark(group, length2 + 0.01, by, 0);
|
|
53089
|
-
parts.eject = kit.mark(group, ejectX, ejectY, wR / 2 + 6e-3);
|
|
53090
|
-
parts.loadPort = kit.mark(group, receiverEnd - 0.05, -receiverHeight / 2 - 4e-3, 0);
|
|
53091
|
-
parts.topLoad = kit.mark(group, ejectX, receiverHeight / 2 + 4e-3, 0);
|
|
53092
|
-
parts.family = familyOf(options);
|
|
53093
|
-
return { group, parts };
|
|
53094
|
-
}
|
|
53095
|
-
|
|
53096
54083
|
// src/models/index.ts
|
|
53097
54084
|
var MODEL_ENTRIES = models_default2;
|
|
53098
54085
|
var ARCHETYPE_MODELS = (() => {
|
|
@@ -53105,13 +54092,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
53105
54092
|
}
|
|
53106
54093
|
return chosen;
|
|
53107
54094
|
})();
|
|
53108
|
-
var
|
|
54095
|
+
var BUILDERS4 = {
|
|
53109
54096
|
pistol: buildPistol,
|
|
53110
54097
|
revolver: buildRevolver,
|
|
53111
54098
|
rifle: buildRifle,
|
|
53112
54099
|
bullpup: buildBullpup,
|
|
53113
54100
|
p90: (kit) => buildP90(kit),
|
|
53114
54101
|
break: buildBreakAction,
|
|
54102
|
+
breakLauncher: buildBreakLauncher,
|
|
53115
54103
|
m2: (kit) => buildM2(kit),
|
|
53116
54104
|
m134: (kit) => buildM134(kit),
|
|
53117
54105
|
launcher: buildLauncher
|
|
@@ -53135,7 +54123,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
53135
54123
|
const kit = modelKit(THREE);
|
|
53136
54124
|
const options = { L: entry2.length, B: entry2.barrel, cal: entry2.caliber, ...entry2.options };
|
|
53137
54125
|
if (id in ARCHETYPE_MODELS) delete options.chambers;
|
|
53138
|
-
const built2 =
|
|
54126
|
+
const built2 = BUILDERS4[entry2.builder](kit, options);
|
|
53139
54127
|
nameParts(built2.parts);
|
|
53140
54128
|
let root;
|
|
53141
54129
|
if (entry2.builder === "launcher") {
|
|
@@ -53370,9 +54358,17 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
53370
54358
|
if (kind !== "one_by_one") events.push(cue(0.7, "move_in", { from: "chambers" }), sound2(0.7, "speedloader"));
|
|
53371
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 };
|
|
53372
54360
|
}
|
|
53373
|
-
var breakReload = () => ({
|
|
54361
|
+
var breakReload = (chambers) => ({
|
|
53374
54362
|
tweens: [turn("barrels", "z", 0, 0.2, 0, -0.5), turn("barrels", "z", 1, 0.15, -0.5, 0)],
|
|
53375
|
-
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
|
+
],
|
|
53376
54372
|
end: 1.2
|
|
53377
54373
|
});
|
|
53378
54374
|
var beltReload = (context) => ({
|
|
@@ -53445,7 +54441,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
53445
54441
|
if (family === "rocket" || family === "flame") return heavyReload(context);
|
|
53446
54442
|
if (parts.mag) return magazineReload(context, kind);
|
|
53447
54443
|
if (family === "revolver" && parts.crane) return revolverReload(kind);
|
|
53448
|
-
if (family === "break" && parts.barrels) return breakReload();
|
|
54444
|
+
if (family === "break" && parts.barrels) return breakReload(parts.breech?.length ?? 2);
|
|
53449
54445
|
if (family === "belt" && parts.cover && parts.belt) return beltReload(context);
|
|
53450
54446
|
if (isTube(context)) return tubeReload(context, kind);
|
|
53451
54447
|
if (family === "bolt") return boltReload(context);
|
|
@@ -55580,16 +56576,16 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
55580
56576
|
if (this.spaces.delete(id)) this.list = [...this.spaces.values()];
|
|
55581
56577
|
return;
|
|
55582
56578
|
}
|
|
55583
|
-
const [hx, hy,
|
|
56579
|
+
const [hx, hy, hz2] = enclosure.halfSize;
|
|
55584
56580
|
const space = {
|
|
55585
56581
|
cx: enclosure.center[0],
|
|
55586
56582
|
cy: enclosure.center[1],
|
|
55587
56583
|
cz: enclosure.center[2],
|
|
55588
56584
|
hx: Math.abs(hx),
|
|
55589
56585
|
hy: Math.abs(hy),
|
|
55590
|
-
hz: Math.abs(
|
|
56586
|
+
hz: Math.abs(hz2),
|
|
55591
56587
|
r: rotation(enclosure.orientation),
|
|
55592
|
-
radius: Math.hypot(hx, hy,
|
|
56588
|
+
radius: Math.hypot(hx, hy, hz2),
|
|
55593
56589
|
openings: enclosure.openings ?? [],
|
|
55594
56590
|
leak: Math.max(0, enclosure.leak ?? 0)
|
|
55595
56591
|
};
|
|
@@ -59772,13 +60768,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
59772
60768
|
function composeAfterEffects(context) {
|
|
59773
60769
|
const { core, def, random, x, y, z } = context;
|
|
59774
60770
|
const mark = def.mark;
|
|
59775
|
-
|
|
60771
|
+
const keepsMarks = !core.marklessAt?.(x, z);
|
|
60772
|
+
if (keepsMarks && mark.crater && mark.dent && y < 1.2) {
|
|
59776
60773
|
core.emit({ type: "crater", x, z, radius: mark.crater, depth: mark.dent });
|
|
59777
60774
|
core.trace?.crater?.(x, z, mark.crater, mark.dent);
|
|
59778
60775
|
addCrater(core.marks, core.ground, random, { x, z, radius: mark.crater, depth: mark.dent, marks: core.layers.mark });
|
|
59779
60776
|
if (core.layers.shrapnel) composeRimDebris(context);
|
|
59780
60777
|
}
|
|
59781
|
-
if (mark.scorch && y < 1.2 && core.layers.mark) {
|
|
60778
|
+
if (keepsMarks && mark.scorch && y < 1.2 && core.layers.mark) {
|
|
59782
60779
|
core.trace?.scorch?.(x, z, mark.scorch);
|
|
59783
60780
|
addScorch(core.marks, random, x, z, mark.scorch);
|
|
59784
60781
|
}
|
|
@@ -61487,7 +62484,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
61487
62484
|
const wind = { x: DEFAULT_WIND.x, y: DEFAULT_WIND.y, z: DEFAULT_WIND.z };
|
|
61488
62485
|
if (options.wind) [wind.x, wind.y, wind.z] = options.wind;
|
|
61489
62486
|
const camera2 = { x: 0, y: 1.6, z: 0 };
|
|
61490
|
-
const layers = Object.fromEntries(VFX_LAYERS.map((
|
|
62487
|
+
const layers = Object.fromEntries(VFX_LAYERS.map((layer3) => [layer3, true]));
|
|
61491
62488
|
const ground = options.ground;
|
|
61492
62489
|
const groundAt = options.groundAt ?? (ground ? (x, z) => ground.heightAt(x, z) : () => 0);
|
|
61493
62490
|
const handles = { next: 0, events: 0 };
|
|
@@ -61529,6 +62526,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
61529
62526
|
spawned: { puffs: 0, sparks: 0, chunks: 0, lights: 0 },
|
|
61530
62527
|
clock: { time: 0, lastBlast: -1, lod: 1, forcedLod: null },
|
|
61531
62528
|
groundAt,
|
|
62529
|
+
...options.marklessAt ? { marklessAt: options.marklessAt } : {},
|
|
61532
62530
|
emit: (request) => options.onRequest?.(request)
|
|
61533
62531
|
};
|
|
61534
62532
|
function definitionOf(id) {
|
|
@@ -61555,6 +62553,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
61555
62553
|
return player ?? (player = createEffectPlayer({ engine: workshop(), effects, view }));
|
|
61556
62554
|
}
|
|
61557
62555
|
return {
|
|
62556
|
+
hostGroundAt: options.groundAt,
|
|
61558
62557
|
play(id, point, playOptions = {}) {
|
|
61559
62558
|
if (!(id in effects)) return null;
|
|
61560
62559
|
const seed = playOptions.seed ?? (randomMode === "shared" ? void 0 : Math.imul(++handles.events, AUTO_SEED) + (options.seed ?? 0));
|
|
@@ -61617,10 +62616,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
61617
62616
|
const fires = core.fires;
|
|
61618
62617
|
for (let index = fires.items.length - 1; index >= 0; index--) if (fires.items[index].handle === handle) fires.removeAt(index);
|
|
61619
62618
|
},
|
|
61620
|
-
setLayer(
|
|
61621
|
-
layers[
|
|
62619
|
+
setLayer(layer3, on) {
|
|
62620
|
+
layers[layer3] = on;
|
|
61622
62621
|
},
|
|
61623
|
-
layer: (
|
|
62622
|
+
layer: (layer3) => layers[layer3],
|
|
61624
62623
|
setCamera(position) {
|
|
61625
62624
|
camera2.x = position[0];
|
|
61626
62625
|
camera2.y = position[1];
|
|
@@ -61707,7 +62706,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
61707
62706
|
};
|
|
61708
62707
|
}
|
|
61709
62708
|
|
|
61710
|
-
// ../game-vfx-three/dist/chunk-
|
|
62709
|
+
// ../game-vfx-three/dist/chunk-CPRCWTSQ.js
|
|
61711
62710
|
var GLOW_VERTEX = `attribute vec4 aP;attribute vec4 aC;varying vec2 vU;varying vec4 vC;
|
|
61712
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]);
|
|
61713
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.);}`;
|
|
@@ -62147,7 +63146,11 @@ void main(){
|
|
|
62147
63146
|
const dirt = texture(paint(make3, (context, size) => drawDirt(context, size, random)));
|
|
62148
63147
|
return { scorch, dirt };
|
|
62149
63148
|
}
|
|
62150
|
-
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;
|
|
62151
63154
|
var MIN_CONFORM_STEPS = 16;
|
|
62152
63155
|
var BLOOD_GROW_RATE = 1.2;
|
|
62153
63156
|
var BLOOD_START_GROWTH = 0.05;
|
|
@@ -62230,9 +63233,21 @@ void main(){
|
|
|
62230
63233
|
spareGeometries.push(oldest.mesh.geometry);
|
|
62231
63234
|
if (spareGeometries.length > MAX_SPARE_GROUND_GEOMETRIES) spareGeometries.shift().dispose();
|
|
62232
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
|
+
}
|
|
62233
63247
|
function conform(mark, material) {
|
|
62234
63248
|
const radius = mark.radius;
|
|
62235
|
-
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))));
|
|
62236
63251
|
if (groundMarks.length >= maxGroundMarks) evictOldestGroundMark();
|
|
62237
63252
|
const geometry = takeSpare((steps + 1) * (steps + 1)) ?? new THREE.PlaneGeometry(2, 2, steps, steps).rotateX(-Math.PI / 2);
|
|
62238
63253
|
const grid = geometry.attributes.position;
|
|
@@ -62244,7 +63259,7 @@ void main(){
|
|
|
62244
63259
|
const localZ = Math.fround(Math.floor(index / (steps + 1)) * cell - 1) * radius;
|
|
62245
63260
|
const worldX = mark.x + localX * cos2 - localZ * sin2;
|
|
62246
63261
|
const worldZ = mark.z + localX * sin2 + localZ * cos2;
|
|
62247
|
-
grid.setXYZ(index, worldX,
|
|
63262
|
+
grid.setXYZ(index, worldX, heightAt(worldX, worldZ) + mark.lift, worldZ);
|
|
62248
63263
|
}
|
|
62249
63264
|
grid.needsUpdate = true;
|
|
62250
63265
|
geometry.computeVertexNormals();
|
|
@@ -62442,7 +63457,7 @@ void main(){
|
|
|
62442
63457
|
};
|
|
62443
63458
|
}
|
|
62444
63459
|
var clamp5 = (value, min2, max2) => value < min2 ? min2 : value > max2 ? max2 : value;
|
|
62445
|
-
function
|
|
63460
|
+
function layer2(container, name, blend) {
|
|
62446
63461
|
const element = container.ownerDocument.createElement("div");
|
|
62447
63462
|
element.dataset.vfxOverlay = name;
|
|
62448
63463
|
Object.assign(element.style, { position: "absolute", inset: "0", pointerEvents: "none", opacity: "0" });
|
|
@@ -62451,12 +63466,12 @@ void main(){
|
|
|
62451
63466
|
return element;
|
|
62452
63467
|
}
|
|
62453
63468
|
function createScreenOverlay(container) {
|
|
62454
|
-
const flash2 =
|
|
63469
|
+
const flash2 = layer2(container, "flash", "screen");
|
|
62455
63470
|
flash2.style.background = "#fff";
|
|
62456
|
-
const white =
|
|
62457
|
-
const red =
|
|
62458
|
-
const sides =
|
|
62459
|
-
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");
|
|
62460
63475
|
const elements = [flash2, white, red, sides, gas];
|
|
62461
63476
|
return {
|
|
62462
63477
|
update(state) {
|
|
@@ -62916,7 +63931,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
62916
63931
|
decalLayer(THREE, engine.decals),
|
|
62917
63932
|
ringLayer(THREE, engine.rings)
|
|
62918
63933
|
];
|
|
62919
|
-
for (const
|
|
63934
|
+
for (const layer22 of layers) group.add(layer22.object);
|
|
62920
63935
|
const meshes = createMeshLayer(THREE, engine.meshes);
|
|
62921
63936
|
group.add(meshes.group);
|
|
62922
63937
|
const lights = budget ? budgetedLights(engine, lightScale, budget) : legacyLights(THREE, engine, lightScale, group);
|
|
@@ -62924,13 +63939,13 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
62924
63939
|
group,
|
|
62925
63940
|
sync() {
|
|
62926
63941
|
let drawCalls = 0;
|
|
62927
|
-
for (const
|
|
63942
|
+
for (const layer22 of layers) if (layer22.sync()) drawCalls++;
|
|
62928
63943
|
drawCalls += meshes.sync();
|
|
62929
63944
|
lights.sync();
|
|
62930
63945
|
return drawCalls;
|
|
62931
63946
|
},
|
|
62932
63947
|
dispose() {
|
|
62933
|
-
for (const
|
|
63948
|
+
for (const layer22 of layers) layer22.dispose();
|
|
62934
63949
|
meshes.dispose();
|
|
62935
63950
|
lights.dispose();
|
|
62936
63951
|
group.clear();
|
|
@@ -63034,7 +64049,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
63034
64049
|
const shocks = createShockLayer(THREE, pools.shocks);
|
|
63035
64050
|
const sprites = createSpriteLayer(THREE, world.sprites(), options.pointScale ?? 700);
|
|
63036
64051
|
const lights = createLightLayer(THREE, pools.lights, options.lightScale ?? Math.PI, options.lights);
|
|
63037
|
-
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 });
|
|
63038
64053
|
root.add(puffs.mesh, sparks.mesh, glows.mesh, chunks.rocks, chunks.plates, shocks.group, lights.group, sprites.additive, sprites.normal, marks.group);
|
|
63039
64054
|
const stopMarks = world.onMarks((event) => marks.handle(event));
|
|
63040
64055
|
const overlay = options.overlay ? createScreenOverlay(options.overlay) : void 0;
|
|
@@ -63167,7 +64182,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
63167
64182
|
stopMarks();
|
|
63168
64183
|
overlay?.dispose();
|
|
63169
64184
|
workshopLayers?.dispose();
|
|
63170
|
-
for (const
|
|
64185
|
+
for (const layer22 of [puffs, sparks, glows, chunks, shocks, lights, marks, sprites]) layer22.dispose();
|
|
63171
64186
|
rockGeometry.dispose();
|
|
63172
64187
|
plateGeometry.dispose();
|
|
63173
64188
|
options.scene.remove(root);
|
|
@@ -63201,6 +64216,38 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
63201
64216
|
};
|
|
63202
64217
|
}
|
|
63203
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
|
+
|
|
63204
64251
|
// src/fx/heavy.ts
|
|
63205
64252
|
var PI14 = Math.PI;
|
|
63206
64253
|
var ROCKET_LIGHT_NAME = "rocket-light";
|
|
@@ -64186,6 +65233,8 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
64186
65233
|
let triggerRest = 0;
|
|
64187
65234
|
let feedCued = false;
|
|
64188
65235
|
const rootQuaternion = new THREE.Quaternion();
|
|
65236
|
+
const muzzleAt = new THREE.Vector3();
|
|
65237
|
+
const muzzleAlong = new THREE.Vector3();
|
|
64189
65238
|
const world = {
|
|
64190
65239
|
kit,
|
|
64191
65240
|
scene,
|
|
@@ -64285,6 +65334,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
64285
65334
|
if (model.parts.stockMove && onTool?.stock === "collapsed") rig.setPartPose("stock", collapsedStockPose(model.parts.stockMove));
|
|
64286
65335
|
applyCondition(kit, model, condition);
|
|
64287
65336
|
lastAmmo = options.tool?.().ammo ?? 0;
|
|
65337
|
+
void audio?.loadSamples();
|
|
64288
65338
|
hand.updateMatrixWorld(true);
|
|
64289
65339
|
hold = holdOfModel(THREE, model, 1);
|
|
64290
65340
|
hold = { ...hold, works: handWorkOf(THREE, model, weapon, hold.right) };
|
|
@@ -64337,12 +65387,22 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
64337
65387
|
if (!session) return;
|
|
64338
65388
|
const family = session.model.parts.family;
|
|
64339
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);
|
|
64340
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 });
|
|
64341
65398
|
hand.updateMatrixWorld(true);
|
|
64342
65399
|
lift += (liftToKeepInView() - lift) * Math.min(1, dt * HAND_IN_VIEW.rate);
|
|
64343
65400
|
if (lift > 1e-4) hand.position.addScaledVector(up.set(0, 1, 0).applyQuaternion(camera2.quaternion), lift);
|
|
64344
65401
|
hand.updateMatrixWorld(true);
|
|
64345
|
-
|
|
65402
|
+
pullFromWall(dt);
|
|
65403
|
+
};
|
|
65404
|
+
const pullFromWall = (dt) => {
|
|
65405
|
+
if (!options.contact || !session) return;
|
|
64346
65406
|
ahead.set(0, 0, -1).applyQuaternion(camera2.quaternion);
|
|
64347
65407
|
if (reach === 0) reach = Math.max(0.01, measureReach(session));
|
|
64348
65408
|
const free = options.contact(camera2.position, ahead, WALL_PULL.probe);
|
|
@@ -64373,7 +65433,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
64373
65433
|
}
|
|
64374
65434
|
const action = current.def.action;
|
|
64375
65435
|
if (action.kind === "launcher") {
|
|
64376
|
-
launchRocket(heavy(current), options.flyRocket !== false);
|
|
65436
|
+
if (current.model.parts.family === "rocket") launchRocket(heavy(current), options.flyRocket !== false);
|
|
64377
65437
|
audio?.play("explosion", LAUNCH_VOLUME, distance3());
|
|
64378
65438
|
}
|
|
64379
65439
|
if (action.kind !== "firearm") return;
|
|
@@ -64450,6 +65510,15 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
64450
65510
|
condition = next;
|
|
64451
65511
|
if (session) applyCondition(kit, session.model, condition);
|
|
64452
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
|
+
},
|
|
64453
65522
|
handTargets() {
|
|
64454
65523
|
if (!session || !hold) return null;
|
|
64455
65524
|
hand.updateMatrixWorld(true);
|
|
@@ -64504,6 +65573,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
64504
65573
|
...options.raycast ? { raycast: options.raycast } : {},
|
|
64505
65574
|
...options.contact ? { contact: options.contact } : {},
|
|
64506
65575
|
...options.bodyHold ? { bodyHold: options.bodyHold } : {},
|
|
65576
|
+
...options.firstPerson ? { firstPerson: options.firstPerson } : {},
|
|
64507
65577
|
...options.effects ? { effects: options.effects } : {},
|
|
64508
65578
|
...options.flyRocket === void 0 ? {} : { flyRocket: options.flyRocket },
|
|
64509
65579
|
...options.particleLimit ? { particleLimit: options.particleLimit } : {},
|
|
@@ -64526,6 +65596,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
64526
65596
|
},
|
|
64527
65597
|
setCondition: (condition) => model.setCondition(condition),
|
|
64528
65598
|
handTargets: () => model.handTargets() ?? box5.handTargets(),
|
|
65599
|
+
muzzle: () => model.inHand !== null ? model.muzzle() : box5.muzzle(),
|
|
64529
65600
|
layers,
|
|
64530
65601
|
get inHand() {
|
|
64531
65602
|
return model.inHand ?? box5.inHand;
|
|
@@ -64550,7 +65621,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
64550
65621
|
var MODEL_BODY = "body";
|
|
64551
65622
|
function buildModeledProp(THREE, def, name, decorate, items, props = defaultWeaponProps()) {
|
|
64552
65623
|
const model = buildWeaponModelById(THREE, def.id) ?? (() => {
|
|
64553
|
-
const root = props.buildItemModel(THREE, def, items);
|
|
65624
|
+
const root = props.buildItemModel(THREE, def, items) ?? buildThrowableModel(THREE, def);
|
|
64554
65625
|
return root ? { root } : void 0;
|
|
64555
65626
|
})();
|
|
64556
65627
|
if (!model) return void 0;
|
|
@@ -65693,7 +66764,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
65693
66764
|
};
|
|
65694
66765
|
var weaponItem = (def, name, items, props = defaultWeaponProps()) => {
|
|
65695
66766
|
const id = `${WEAPON_ITEM_PREFIX}${def.id}`;
|
|
65696
|
-
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 });
|
|
65697
66768
|
return {
|
|
65698
66769
|
id,
|
|
65699
66770
|
name,
|
|
@@ -65753,7 +66824,8 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
65753
66824
|
const seedOption = options.seed === void 0 ? {} : { seed: options.seed };
|
|
65754
66825
|
let audio;
|
|
65755
66826
|
const ownAudio = () => audio === void 0 ? audio = options.sound === false ? null : createWeaponAudio(void 0, { ...seedOption, ...options.samples ? { samples: options.samples } : {} }) : audio;
|
|
65756
|
-
const
|
|
66827
|
+
const generics = genericWeapons(arsenal);
|
|
66828
|
+
const weaponDefs = [...arsenal.weapons.values()].filter((def) => !BODY_ACTIONS.has(def.id) && !generics.has(def.id));
|
|
65757
66829
|
const thumbnailBase = options.thumbnailBase ?? DEFAULT_THUMBNAIL_BASE;
|
|
65758
66830
|
const withThumbnail = (item, key2) => {
|
|
65759
66831
|
const thumbnail = thumbnailBase === false ? void 0 : weaponThumbnailUrl(key2, thumbnailBase);
|
|
@@ -65841,7 +66913,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
65841
66913
|
engine: lentEngine,
|
|
65842
66914
|
...options.samples ? { samples: options.samples } : {},
|
|
65843
66915
|
onGunshot: (shot, input, played) => {
|
|
65844
|
-
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(", ") }) : "";
|
|
65845
66917
|
lent.log(
|
|
65846
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,
|
|
65847
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 },
|
|
@@ -65870,6 +66942,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
65870
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)
|
|
65871
66943
|
contact: createLaserRaycast(lent.THREE, lent.scene, lent.camera, { now: () => simulatedMs }),
|
|
65872
66944
|
...lent.holdFrame ? { bodyHold: () => lent.holdFrame?.() ?? null } : {},
|
|
66945
|
+
firstPerson: () => lent.player().cameraMode === "first",
|
|
65873
66946
|
...lent.effects ? { effects: lent.effects } : {},
|
|
65874
66947
|
...lent.particleLimit ? { particleLimit: lent.particleLimit } : {},
|
|
65875
66948
|
...isLightBudget(lent.lights) ? { lights: lent.lights } : {},
|
|
@@ -65920,6 +66993,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
65920
66993
|
});
|
|
65921
66994
|
const offFrame = lent.onFrame((dt) => created.update(dt));
|
|
65922
66995
|
const offHands = lent.setHandTargets?.(() => created.handTargets());
|
|
66996
|
+
const offMuzzle = lent.setMuzzleSource?.(() => created.muzzle());
|
|
65923
66997
|
created.handle({ type: "tool", weapon: lent.tool().weapon }, lent.tool());
|
|
65924
66998
|
return () => {
|
|
65925
66999
|
accessories.dispose();
|
|
@@ -65928,6 +67002,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
65928
67002
|
offFrame();
|
|
65929
67003
|
offClock();
|
|
65930
67004
|
offHands?.();
|
|
67005
|
+
offMuzzle?.();
|
|
65931
67006
|
created.dispose();
|
|
65932
67007
|
audio?.dispose();
|
|
65933
67008
|
fx = null;
|
|
@@ -66657,6 +67732,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
66657
67732
|
var SHELTERED_MOST = 1;
|
|
66658
67733
|
var CHEST = 1.1;
|
|
66659
67734
|
var MIDDLE = 0.3;
|
|
67735
|
+
var AIM_SEARCH = 1.5;
|
|
66660
67736
|
var HEAVY_ITEMS = ["camp_table"];
|
|
66661
67737
|
var PERSON_MASS = 70;
|
|
66662
67738
|
var GROUND_FRICTION2 = 7;
|
|
@@ -66716,6 +67792,27 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
66716
67792
|
}
|
|
66717
67793
|
const partsBefore = new Map(placed.map((body) => [body.objectId, partsOf(body.objectId)]));
|
|
66718
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
|
+
});
|
|
66719
67816
|
if (mode === "p13") bench.actions.shoot();
|
|
66720
67817
|
else {
|
|
66721
67818
|
room.setTool("frag_grenade");
|
|
@@ -66728,17 +67825,11 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
66728
67825
|
step(0.05);
|
|
66729
67826
|
waited += 0.05;
|
|
66730
67827
|
}
|
|
67828
|
+
stopListening();
|
|
66731
67829
|
const blast = bench.lastBlast();
|
|
66732
67830
|
expect(!!blast, text.push_told, { waited });
|
|
66733
67831
|
if (!blast) return;
|
|
66734
|
-
const
|
|
66735
|
-
placed.map((body) => {
|
|
66736
|
-
const from = origin.get(body.objectId) ?? body.from;
|
|
66737
|
-
const person = body.kind === "zombie" || body.kind === "survivor";
|
|
66738
|
-
const ignore = source ? [source, body.objectId] : [body.objectId];
|
|
66739
|
-
return [body.objectId, room.world.blastReach?.(blast.point, [from[0], from[1] + (person ? CHEST : MIDDLE), from[2]], { ignore }) ?? 1];
|
|
66740
|
-
})
|
|
66741
|
-
);
|
|
67832
|
+
const cover = coverOf ?? coverAt(blast.point);
|
|
66742
67833
|
step(PUSH_READ_AT);
|
|
66743
67834
|
const rows = placed.map((body) => {
|
|
66744
67835
|
const from = origin.get(body.objectId) ?? body.from;
|
|
@@ -66746,16 +67837,18 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
66746
67837
|
const distance3 = flat(from, blast.point);
|
|
66747
67838
|
const away = Math.max(1e-6, distance3);
|
|
66748
67839
|
const outward = ((now[0] - from[0]) * (from[0] - blast.point[0]) + (now[2] - from[2]) * (from[2] - blast.point[2])) / away;
|
|
66749
|
-
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 };
|
|
66750
67841
|
});
|
|
66751
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);
|
|
66752
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));
|
|
66753
67846
|
const sheltered = inReach.filter((row) => row.cover < SHELTERED);
|
|
66754
67847
|
for (const row of sheltered) {
|
|
66755
|
-
|
|
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 } });
|
|
66756
67851
|
}
|
|
66757
|
-
const isPerson = (row) => row.kind === "survivor" || row.kind === "zombie";
|
|
66758
|
-
const reached = inReach.filter((row) => row.cover >= SHELTERED && !isPerson(row));
|
|
66759
67852
|
const movedAway = reached.filter((row) => row.outward >= MOVED);
|
|
66760
67853
|
const least = reached.length === 0 ? 0 : Math.min(...reached.map((row) => row.outward));
|
|
66761
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) });
|
|
@@ -66923,12 +68016,22 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
66923
68016
|
|
|
66924
68017
|
// src/projectile-model.ts
|
|
66925
68018
|
function projectileModel(THREE, query2) {
|
|
66926
|
-
if (query2.kind !== "rocket") return
|
|
68019
|
+
if (query2.kind !== "rocket") return explosiveProjectile(THREE, query2);
|
|
66927
68020
|
const launcher = buildWeaponModelById(THREE, query2.weapon);
|
|
66928
68021
|
if (!launcher || launcher.parts.family !== "rocket") return null;
|
|
66929
68022
|
const round5 = launcher.parts.makeRound ? launcher.parts.makeRound() : buildFlyingRocket(modelKit(THREE), launcher.parts.launcherType);
|
|
66930
68023
|
return { model: round5, axis: [1, 0, 0] };
|
|
66931
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
|
+
}
|
|
66932
68035
|
|
|
66933
68036
|
// src/weapon-props.ts
|
|
66934
68037
|
function createWeaponProps(options = {}) {
|