@adatechnology/game-weapons-three 0.14.2 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/weapon-svg/generated/m79.svg +1 -1
- package/dist/{chunk-XMVSA7UT.js → chunk-KWJQO6JS.js} +1625 -1363
- package/dist/chunk-KWJQO6JS.js.map +1 -0
- package/dist/index.d.ts +31 -6
- package/dist/index.global.js +2802 -1552
- 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-CEcZ-zzz.d.ts} +44 -30
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -1
- package/package.json +9 -9
- package/dist/chunk-XMVSA7UT.js.map +0 -1
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
// src/test-area/area.ts
|
|
2
|
-
import { markKitOrigin as
|
|
3
|
-
import { createArsenal } from "@adatechnology/game-weapons";
|
|
2
|
+
import { markKitOrigin as markKitOrigin6 } from "@adatechnology/game-contracts";
|
|
3
|
+
import { createArsenal, genericWeapons } from "@adatechnology/game-weapons";
|
|
4
4
|
import { furnitureSpec } from "@adatechnology/game-floorplan-three";
|
|
5
5
|
import { isLightBudget, isRenderPools } from "@adatechnology/game-render-three";
|
|
6
6
|
|
|
7
|
+
// src/test-area/accessory-bench.ts
|
|
8
|
+
import { aimZoomOf } from "@adatechnology/game-weapons";
|
|
9
|
+
|
|
7
10
|
// src/attachments-key.ts
|
|
8
11
|
var attachmentsKey = (parts) => {
|
|
9
12
|
if (!parts) return "";
|
|
@@ -119,11 +122,11 @@ function createAccessoryBench(options) {
|
|
|
119
122
|
else return false;
|
|
120
123
|
return true;
|
|
121
124
|
};
|
|
122
|
-
const zoomOf = (tool) =>
|
|
123
|
-
|
|
124
|
-
|
|
125
|
+
const zoomOf = (tool) => aimZoomOf(arsenal, tool.weapon, tool.attachments?.map((part) => part.id));
|
|
126
|
+
const aims = (tool) => {
|
|
127
|
+
const kind = arsenal.weapons.get(tool.weapon)?.action.kind;
|
|
128
|
+
return kind === "firearm" || kind === "launcher";
|
|
125
129
|
};
|
|
126
|
-
const isFirearm = (tool) => arsenal.weapons.get(tool.weapon)?.action.kind === "firearm";
|
|
127
130
|
const setAim = (on) => {
|
|
128
131
|
if (on === aiming) return;
|
|
129
132
|
aiming = on;
|
|
@@ -150,7 +153,7 @@ function createAccessoryBench(options) {
|
|
|
150
153
|
};
|
|
151
154
|
const isOnRoom = (event) => Boolean(document.pointerLockElement) || event.target instanceof HTMLCanvasElement;
|
|
152
155
|
const onMouseDown = (event) => {
|
|
153
|
-
if (event.button !== SECONDARY_BUTTON || !isOnRoom(event) || !
|
|
156
|
+
if (event.button !== SECONDARY_BUTTON || !isOnRoom(event) || !aims(host.tool())) return;
|
|
154
157
|
event.preventDefault();
|
|
155
158
|
event.stopImmediatePropagation();
|
|
156
159
|
setAim(true);
|
|
@@ -1410,6 +1413,10 @@ function computeCasingSound(input) {
|
|
|
1410
1413
|
const surfaceName = surface === "hard" ? "concreto" : surface === "soft" ? "terra" : surface === "wood" ? "madeira" : "metal";
|
|
1411
1414
|
return { surface, kind, sample: `casing_drop_${surfaceName}_${kind}`, voices };
|
|
1412
1415
|
}
|
|
1416
|
+
function magazineDropId(material) {
|
|
1417
|
+
const surface = casingSurfaceOf(material);
|
|
1418
|
+
return `mag_drop_${surface === "hard" ? "concreto" : surface === "soft" ? "terra" : surface === "wood" ? "madeira" : "metal"}`;
|
|
1419
|
+
}
|
|
1413
1420
|
|
|
1414
1421
|
// src/audio/flyby.ts
|
|
1415
1422
|
function computeFlyby(input) {
|
|
@@ -2214,7 +2221,7 @@ var CUES_IN_SAMPLE = { mag_release: "mag_out", mag_insert: "mag_seat" };
|
|
|
2214
2221
|
var isGunshot = (id) => GUNSHOT_SAMPLE_IDS.includes(id);
|
|
2215
2222
|
function weaponSampleDefaults(sound3, overrides = {}) {
|
|
2216
2223
|
if (sound3.category !== "armas") return void 0;
|
|
2217
|
-
const base = sound3.id.startsWith("suppressed_") ? SUPPRESSED_SAMPLE : isGunshot(sound3.id) ? GUNSHOT_SAMPLE : sound3.id.startsWith("casing_drop_") ? CASING_SAMPLE : RELOAD_SAMPLE;
|
|
2224
|
+
const base = sound3.id.startsWith("suppressed_") ? SUPPRESSED_SAMPLE : isGunshot(sound3.id) ? GUNSHOT_SAMPLE : sound3.id.startsWith("casing_drop_") || sound3.id.startsWith("mag_drop_") ? CASING_SAMPLE : RELOAD_SAMPLE;
|
|
2218
2225
|
return { ...base, ...overrides[sound3.id] };
|
|
2219
2226
|
}
|
|
2220
2227
|
function weaponSampleBank(options) {
|
|
@@ -2265,6 +2272,8 @@ function createWeaponAudio(volume = 0.6, options = {}) {
|
|
|
2265
2272
|
void loadSamples();
|
|
2266
2273
|
return false;
|
|
2267
2274
|
};
|
|
2275
|
+
const fittedReady = (id) => sampleIds.has(id) && engine.registry.sound(id) === void 0 && engine.registry.set(id) !== void 0;
|
|
2276
|
+
const hostReady = (id) => sampleReady(id) || engine.registry.sound(id) === void 0 && engine.registry.set(id) !== void 0;
|
|
2268
2277
|
const burst = (config) => {
|
|
2269
2278
|
const id = config.filter === "highpass" ? BURST_IDS.highpass : BURST_IDS.lowpass;
|
|
2270
2279
|
const params = { frequency: config.frequency, q: config.q ?? 0.8, gain: Math.max(config.gain, 2e-4), seconds: config.seconds };
|
|
@@ -2319,6 +2328,11 @@ function createWeaponAudio(volume = 0.6, options = {}) {
|
|
|
2319
2328
|
options.onCasing?.(sound3, "sample");
|
|
2320
2329
|
return;
|
|
2321
2330
|
}
|
|
2331
|
+
if (recorded && fittedReady(recorded)) {
|
|
2332
|
+
if ((input.bounce ?? 0) === 0) channel.play(recorded, { volume: Math.min(1, Math.max(0.2, (input.speed ?? 1.5) / 2.5)) });
|
|
2333
|
+
options.onCasing?.(sound3, "fitted");
|
|
2334
|
+
return;
|
|
2335
|
+
}
|
|
2322
2336
|
for (const voice of sound3.voices) playCasingVoice(voice);
|
|
2323
2337
|
options.onCasing?.(sound3, "synth");
|
|
2324
2338
|
};
|
|
@@ -2343,7 +2357,9 @@ function createWeaponAudio(volume = 0.6, options = {}) {
|
|
|
2343
2357
|
const pitch = 1 + (channel.random() * 2 - 1) * pitchSpread;
|
|
2344
2358
|
const shot = computeGunshot({ ...base, take, pitch }, options.gunshot);
|
|
2345
2359
|
const recorded = shot.samples.close;
|
|
2346
|
-
|
|
2360
|
+
const sample = shot.audible && sampleReady(recorded);
|
|
2361
|
+
const fitted = shot.audible && !sample && fittedReady(recorded);
|
|
2362
|
+
if (sample || fitted) {
|
|
2347
2363
|
const occlusion = Math.min(1, Math.max(0, extras.occlusion ?? 0));
|
|
2348
2364
|
const handle = channel.play(recorded, {
|
|
2349
2365
|
volume: (extras.volume ?? 1) * (1 - 0.5 * occlusion),
|
|
@@ -2356,7 +2372,7 @@ function createWeaponAudio(volume = 0.6, options = {}) {
|
|
|
2356
2372
|
for (const voice of shot.voices) if (voice.group === "tail") playGunshotVoice(voice, extras);
|
|
2357
2373
|
}
|
|
2358
2374
|
const layers = handle?.kind === "sample" ? handle.plan.layers.map((layer) => ({ role: layer.role, take: layer.take, rate: layer.rate })) : [];
|
|
2359
|
-
options.onGunshot?.(shot, { ...base, take, pitch }, { kind: "sample", id: recorded, layers });
|
|
2375
|
+
options.onGunshot?.(shot, { ...base, take, pitch }, fitted ? { kind: "fitted", id: recorded } : { kind: "sample", id: recorded, layers });
|
|
2360
2376
|
return;
|
|
2361
2377
|
}
|
|
2362
2378
|
for (const voice of shot.voices) playGunshotVoice(voice, extras);
|
|
@@ -2377,10 +2393,11 @@ function createWeaponAudio(volume = 0.6, options = {}) {
|
|
|
2377
2393
|
mechanical,
|
|
2378
2394
|
cue(id, profile, lead = 0) {
|
|
2379
2395
|
const carriedBy = CUES_IN_SAMPLE[id];
|
|
2380
|
-
if (carriedBy && sampleReady(carriedBy)) return "carried";
|
|
2381
|
-
|
|
2396
|
+
if (carriedBy && (sampleReady(carriedBy) || fittedReady(carriedBy))) return "carried";
|
|
2397
|
+
const recorded = sampleReady(id);
|
|
2398
|
+
if (recorded || fittedReady(id)) {
|
|
2382
2399
|
channel.play(id, { intensity: WEIGHT_INTENSITY[(profile ?? DEFAULT_SOUND_PROFILE).weight] });
|
|
2383
|
-
return "sample";
|
|
2400
|
+
return recorded ? "sample" : "fitted";
|
|
2384
2401
|
}
|
|
2385
2402
|
for (const entry of reloadCueSteps(id, profile, cueTable)) step(lead > 0 ? { ...entry, at: entry.at + lead } : entry);
|
|
2386
2403
|
return "synth";
|
|
@@ -2407,7 +2424,12 @@ function createWeaponAudio(volume = 0.6, options = {}) {
|
|
|
2407
2424
|
casing,
|
|
2408
2425
|
flyby(input) {
|
|
2409
2426
|
const sound3 = computeFlyby({ ...input, pitch: input.pitch ?? 1 + (channel.random() * 2 - 1) * 0.05 });
|
|
2410
|
-
|
|
2427
|
+
if (!sound3) return;
|
|
2428
|
+
if (hostReady(sound3.sample)) {
|
|
2429
|
+
channel.play(sound3.sample, { volume: Math.min(1, 1 / (1 + input.miss / 1.5)), ...input.position ? { position: [input.position[0], input.position[1], input.position[2]] } : {} });
|
|
2430
|
+
return;
|
|
2431
|
+
}
|
|
2432
|
+
for (const voice of sound3.voices) playCasingVoice(voice, input.position);
|
|
2411
2433
|
},
|
|
2412
2434
|
clink() {
|
|
2413
2435
|
if (options.shotModel !== "game") {
|
|
@@ -2418,8 +2440,13 @@ function createWeaponAudio(volume = 0.6, options = {}) {
|
|
|
2418
2440
|
const at = 0.25 + channel.random() * 0.2;
|
|
2419
2441
|
sceneTone({ layer: "scene_tone", at, wave: "sine", f, f2: 3800, d: 0.06, vol: 0.06 });
|
|
2420
2442
|
},
|
|
2421
|
-
thud() {
|
|
2422
|
-
|
|
2443
|
+
thud(input = {}) {
|
|
2444
|
+
const id = magazineDropId(input.surface);
|
|
2445
|
+
if (hostReady(id)) {
|
|
2446
|
+
if ((input.bounce ?? 0) === 0) channel.play(id, { volume: Math.min(1, Math.max(0.2, (input.speed ?? 1.5) / 2.5)) });
|
|
2447
|
+
return;
|
|
2448
|
+
}
|
|
2449
|
+
burst({ seconds: 0.09, gain: 0.35 * (input.speed === void 0 ? 1 : Math.min(1, Math.max(0.3, input.speed / 2.5))) * ((input.bounce ?? 0) === 0 ? 1 : 0.5), filter: "lowpass", frequency: 380 });
|
|
2423
2450
|
},
|
|
2424
2451
|
setVolume(next) {
|
|
2425
2452
|
const level = Math.max(0, Math.min(1, next));
|
|
@@ -2833,6 +2860,279 @@ function drawItemWeapon({ THREE, def, items, itemId, turn: turn2, flip }) {
|
|
|
2833
2860
|
return group;
|
|
2834
2861
|
}
|
|
2835
2862
|
|
|
2863
|
+
// src/models/explosives.ts
|
|
2864
|
+
import { markKitOrigin as markKitOrigin2 } from "@adatechnology/game-contracts";
|
|
2865
|
+
|
|
2866
|
+
// src/models/kit.ts
|
|
2867
|
+
import { markShared, shapeGeometries as shapeGeometries2 } from "@adatechnology/game-shapes-three";
|
|
2868
|
+
|
|
2869
|
+
// src/models/rounded-box.ts
|
|
2870
|
+
var uvAlong = (THREE, faceDirection, normal, uvAxis, projectionAxis, radius, sideLength) => {
|
|
2871
|
+
const arcLength = 2 * Math.PI * radius / 4;
|
|
2872
|
+
const centerLength = Math.max(sideLength - 2 * radius, 0);
|
|
2873
|
+
const halfArc = Math.PI / 4;
|
|
2874
|
+
const projected = new THREE.Vector3().copy(normal);
|
|
2875
|
+
projected[projectionAxis] = 0;
|
|
2876
|
+
projected.normalize();
|
|
2877
|
+
const arcUvRatio = 0.5 * arcLength / (arcLength + centerLength);
|
|
2878
|
+
const arcAngleRatio = 1 - projected.angleTo(faceDirection) / halfArc;
|
|
2879
|
+
if (Math.sign(projected[uvAxis]) === 1) return arcAngleRatio * arcUvRatio;
|
|
2880
|
+
const centerUv = centerLength / (arcLength + centerLength);
|
|
2881
|
+
return centerUv + arcUvRatio + arcUvRatio * (1 - arcAngleRatio);
|
|
2882
|
+
};
|
|
2883
|
+
var FACES = [
|
|
2884
|
+
{ direction: [1, 0, 0], u: ["z", "y", false], v: ["y", "z", true] },
|
|
2885
|
+
{ direction: [-1, 0, 0], u: ["z", "y", true], v: ["y", "z", true] },
|
|
2886
|
+
{ direction: [0, 1, 0], u: ["x", "z", true], v: ["z", "x", false] },
|
|
2887
|
+
{ direction: [0, -1, 0], u: ["x", "z", true], v: ["z", "x", true] },
|
|
2888
|
+
{ direction: [0, 0, 1], u: ["x", "y", true], v: ["y", "x", true] },
|
|
2889
|
+
{ direction: [0, 0, -1], u: ["x", "y", false], v: ["y", "x", true] }
|
|
2890
|
+
];
|
|
2891
|
+
function createRoundedBoxGeometry(THREE, width, height, depth, segments, radius) {
|
|
2892
|
+
const count = segments * 2 + 1;
|
|
2893
|
+
const rounding = Math.min(width / 2, height / 2, depth / 2, radius);
|
|
2894
|
+
const geometry = new THREE.BoxGeometry(1, 1, 1, count, count, count);
|
|
2895
|
+
const flat2 = geometry.toNonIndexed();
|
|
2896
|
+
geometry.setIndex(null);
|
|
2897
|
+
geometry.setAttribute("position", flat2.attributes.position);
|
|
2898
|
+
geometry.setAttribute("normal", flat2.attributes.normal);
|
|
2899
|
+
geometry.setAttribute("uv", flat2.attributes.uv);
|
|
2900
|
+
const position = new THREE.Vector3();
|
|
2901
|
+
const normal = new THREE.Vector3();
|
|
2902
|
+
const box2 = new THREE.Vector3(width, height, depth).divideScalar(2).subScalar(rounding);
|
|
2903
|
+
const positions = geometry.attributes.position.array;
|
|
2904
|
+
const normals = geometry.attributes.normal.array;
|
|
2905
|
+
const uvs = geometry.attributes.uv.array;
|
|
2906
|
+
const faceTriangles = positions.length / 6;
|
|
2907
|
+
const halfSegment = 0.5 / count;
|
|
2908
|
+
const sides = { x: width, y: height, z: depth };
|
|
2909
|
+
for (let i = 0, j = 0; i < positions.length; i += 3, j += 2) {
|
|
2910
|
+
position.fromArray(positions, i);
|
|
2911
|
+
normal.copy(position);
|
|
2912
|
+
normal.x -= Math.sign(normal.x) * halfSegment;
|
|
2913
|
+
normal.y -= Math.sign(normal.y) * halfSegment;
|
|
2914
|
+
normal.z -= Math.sign(normal.z) * halfSegment;
|
|
2915
|
+
normal.normalize();
|
|
2916
|
+
positions[i] = box2.x * Math.sign(position.x) + normal.x * rounding;
|
|
2917
|
+
positions[i + 1] = box2.y * Math.sign(position.y) + normal.y * rounding;
|
|
2918
|
+
positions[i + 2] = box2.z * Math.sign(position.z) + normal.z * rounding;
|
|
2919
|
+
normals[i] = normal.x;
|
|
2920
|
+
normals[i + 1] = normal.y;
|
|
2921
|
+
normals[i + 2] = normal.z;
|
|
2922
|
+
const face = FACES[Math.floor(i / faceTriangles)];
|
|
2923
|
+
if (!face) continue;
|
|
2924
|
+
const direction = new THREE.Vector3(...face.direction);
|
|
2925
|
+
for (const [offset, [uvAxis, projectionAxis, mirrored]] of [[0, face.u], [1, face.v]]) {
|
|
2926
|
+
const value = uvAlong(THREE, direction, normal, uvAxis, projectionAxis, rounding, sides[uvAxis]);
|
|
2927
|
+
uvs[j + offset] = mirrored ? 1 - value : value;
|
|
2928
|
+
}
|
|
2929
|
+
}
|
|
2930
|
+
return geometry;
|
|
2931
|
+
}
|
|
2932
|
+
|
|
2933
|
+
// src/models/kit.ts
|
|
2934
|
+
var PI = Math.PI;
|
|
2935
|
+
var createMaterials = (THREE) => {
|
|
2936
|
+
const standard = (color, roughness = 0.7, metalness = 0.2, extra = {}) => new THREE.MeshStandardMaterial({ color, roughness, metalness, ...extra });
|
|
2937
|
+
const basic = (color, extra = {}) => new THREE.MeshBasicMaterial({ color, ...extra });
|
|
2938
|
+
const additive = { transparent: true, opacity: 0.95, blending: THREE.AdditiveBlending, depthWrite: false };
|
|
2939
|
+
const materials = {
|
|
2940
|
+
metal: standard(3422010, 0.42, 0.75),
|
|
2941
|
+
steel: standard(7106418, 0.32, 0.85),
|
|
2942
|
+
steelL: standard(9080208, 0.28, 0.9),
|
|
2943
|
+
dark: standard(1711133, 0.55, 0.5),
|
|
2944
|
+
poly: standard(2369058, 0.8, 0.05),
|
|
2945
|
+
olive: standard(4936241, 0.8, 0.05),
|
|
2946
|
+
tan: standard(10259043, 0.8, 0.05),
|
|
2947
|
+
wood: standard(4860951, 0.55, 0),
|
|
2948
|
+
woodL: standard(6175263, 0.55, 0),
|
|
2949
|
+
brass: standard(12819013, 0.28, 0.9),
|
|
2950
|
+
copper: standard(11561531, 0.3, 0.85),
|
|
2951
|
+
lead: standard(7171955, 0.5, 0.5),
|
|
2952
|
+
shell: standard(10692380, 0.5, 0.05),
|
|
2953
|
+
glass: standard(8364968, 0.05, 0.1, { transparent: true, opacity: 0.42 }),
|
|
2954
|
+
lens: standard(2311770, 0.05, 0.3, { transparent: true, opacity: 0.9, emissive: 399392 }),
|
|
2955
|
+
rubber: standard(1381653, 0.85, 0),
|
|
2956
|
+
white: standard(13617332, 0.8, 0),
|
|
2957
|
+
hole: standard(526343, 1, 0),
|
|
2958
|
+
bake: standard(5911072, 0.55, 0),
|
|
2959
|
+
rust: standard(7027230, 0.95, 0.3),
|
|
2960
|
+
rustD: standard(4860440, 0.95, 0.25),
|
|
2961
|
+
worn: standard(5593178, 0.6, 0.6),
|
|
2962
|
+
fire: basic(16742946),
|
|
2963
|
+
fire2: basic(16764762),
|
|
2964
|
+
flashA: basic(16757575, additive),
|
|
2965
|
+
flashB: basic(16773568, additive),
|
|
2966
|
+
smokeP: standard(9079430, 1, 0, { transparent: true, opacity: 0.35, depthWrite: false }),
|
|
2967
|
+
/** Launcher paints. */
|
|
2968
|
+
yellow: standard(11570978, 0.6, 0),
|
|
2969
|
+
red: standard(9313300, 0.45, 0.1),
|
|
2970
|
+
redPaint: standard(10691354, 0.35, 0.2),
|
|
2971
|
+
tape: standard(9079944, 0.9, 0),
|
|
2972
|
+
pipe: standard(10115634, 0.35, 0.8),
|
|
2973
|
+
green: standard(3818536, 0.75, 0.05),
|
|
2974
|
+
/** Explosive finishes: the molotov's bottle, the dynamite's paper, the C4's putty and the detonator's wire. */
|
|
2975
|
+
bottle: standard(3103284, 0.1, 0.1, { transparent: true, opacity: 0.72 }),
|
|
2976
|
+
dynamite: standard(10365471, 0.7, 0),
|
|
2977
|
+
c4: standard(7170636, 0.95, 0),
|
|
2978
|
+
wire: standard(11542560, 0.5, 0),
|
|
2979
|
+
/** Magazine finishes named by the options. */
|
|
2980
|
+
bakelite: standard(6958620, 0.6, 0),
|
|
2981
|
+
polyMag: standard(2763302, 0.85, 0)
|
|
2982
|
+
};
|
|
2983
|
+
markShared(...Object.values(materials));
|
|
2984
|
+
return materials;
|
|
2985
|
+
};
|
|
2986
|
+
var kits = /* @__PURE__ */ new WeakMap();
|
|
2987
|
+
function modelKit(host) {
|
|
2988
|
+
const cached = kits.get(host);
|
|
2989
|
+
if (cached) return cached;
|
|
2990
|
+
const THREE = shapeGeometries2(host);
|
|
2991
|
+
const geometries = /* @__PURE__ */ new Map();
|
|
2992
|
+
const shadowed = (mesh) => {
|
|
2993
|
+
mesh.castShadow = true;
|
|
2994
|
+
mesh.receiveShadow = true;
|
|
2995
|
+
return mesh;
|
|
2996
|
+
};
|
|
2997
|
+
const place = (parent, mesh, x, y, z) => {
|
|
2998
|
+
mesh.position.set(x, y, z);
|
|
2999
|
+
parent.add(mesh);
|
|
3000
|
+
return mesh;
|
|
3001
|
+
};
|
|
3002
|
+
const kit = {
|
|
3003
|
+
THREE,
|
|
3004
|
+
M: createMaterials(THREE),
|
|
3005
|
+
roundness: null,
|
|
3006
|
+
group: () => new THREE.Group(),
|
|
3007
|
+
box(parent, w, h, d, material, x, y, z, rz = 0, ry = 0, rx = 0) {
|
|
3008
|
+
const radius = Math.min(w, h, d) * (kit.roundness ?? 0.2);
|
|
3009
|
+
const key = `${w.toFixed(4)},${h.toFixed(4)},${d.toFixed(4)},${radius.toFixed(5)}`;
|
|
3010
|
+
let geometry = geometries.get(key);
|
|
3011
|
+
if (!geometry) {
|
|
3012
|
+
geometry = radius > 25e-5 ? createRoundedBoxGeometry(THREE, w, h, d, 2, radius) : new THREE.BoxGeometry(w, h, d);
|
|
3013
|
+
markShared(geometry);
|
|
3014
|
+
geometries.set(key, geometry);
|
|
3015
|
+
}
|
|
3016
|
+
const mesh = place(parent, shadowed(new THREE.Mesh(geometry, material)), x, y, z);
|
|
3017
|
+
mesh.rotation.set(rx, ry, rz);
|
|
3018
|
+
return mesh;
|
|
3019
|
+
},
|
|
3020
|
+
cylinderX(parent, radius, length, material, x, y, z, segments = 16, radiusEnd) {
|
|
3021
|
+
const mesh = shadowed(new THREE.Mesh(new THREE.CylinderGeometry(radiusEnd ?? radius, radius, length, segments), material));
|
|
3022
|
+
mesh.rotation.z = -PI / 2;
|
|
3023
|
+
return place(parent, mesh, x, y, z);
|
|
3024
|
+
},
|
|
3025
|
+
cylinderY(parent, radius, height, material, x, y, z, segments = 16, radiusEnd) {
|
|
3026
|
+
return place(parent, shadowed(new THREE.Mesh(new THREE.CylinderGeometry(radiusEnd ?? radius, radius, height, segments), material)), x, y, z);
|
|
3027
|
+
},
|
|
3028
|
+
cylinderZ(parent, radius, length, material, x, y, z, segments = 16) {
|
|
3029
|
+
const mesh = shadowed(new THREE.Mesh(new THREE.CylinderGeometry(radius, radius, length, segments), material));
|
|
3030
|
+
mesh.rotation.x = PI / 2;
|
|
3031
|
+
return place(parent, mesh, x, y, z);
|
|
3032
|
+
},
|
|
3033
|
+
sphere(parent, radius, material, x, y, z, detail = 1) {
|
|
3034
|
+
return place(parent, shadowed(new THREE.Mesh(new THREE.IcosahedronGeometry(radius, detail), material)), x, y, z);
|
|
3035
|
+
},
|
|
3036
|
+
torus: (parent, geometry, material, x, y, z) => place(parent, shadowed(new THREE.Mesh(geometry, material)), x, y, z),
|
|
3037
|
+
mark(parent, x, y, z) {
|
|
3038
|
+
const object = new THREE.Object3D();
|
|
3039
|
+
object.position.set(x, y, z);
|
|
3040
|
+
parent.add(object);
|
|
3041
|
+
return object;
|
|
3042
|
+
},
|
|
3043
|
+
pivot(parent, x = 0, y = 0, z = 0) {
|
|
3044
|
+
const group = new THREE.Group();
|
|
3045
|
+
group.position.set(x, y, z);
|
|
3046
|
+
parent.add(group);
|
|
3047
|
+
return group;
|
|
3048
|
+
}
|
|
3049
|
+
};
|
|
3050
|
+
kits.set(host, kit);
|
|
3051
|
+
return kit;
|
|
3052
|
+
}
|
|
3053
|
+
function heatify(glow, mesh) {
|
|
3054
|
+
mesh.material = mesh.material.clone();
|
|
3055
|
+
glow.push(mesh);
|
|
3056
|
+
return mesh;
|
|
3057
|
+
}
|
|
3058
|
+
|
|
3059
|
+
// src/models/explosives.ts
|
|
3060
|
+
var grenade = (kit, group) => {
|
|
3061
|
+
const { M, sphere, cylinderY, box: box2, torus, THREE } = kit;
|
|
3062
|
+
sphere(group, 0.032, M.olive, 0, 0.032, 0, 1);
|
|
3063
|
+
cylinderY(group, 0.011, 0.022, M.metal, 0, 0.072, 0);
|
|
3064
|
+
box2(group, 0.012, 0.07, 6e-3, M.metal, 0.016, 0.05, 0, 0.2);
|
|
3065
|
+
torus(group, new THREE.TorusGeometry(85e-4, 16e-4, 6, 12), M.steel, -0.012, 0.082, 0);
|
|
3066
|
+
kit.mark(group, 0, 0.032, 0).name = "handle";
|
|
3067
|
+
};
|
|
3068
|
+
var molotov = (kit, group) => {
|
|
3069
|
+
const { M, cylinderY, box: box2 } = kit;
|
|
3070
|
+
cylinderY(group, 0.036, 0.17, M.bottle, 0, 0.085, 0, 10);
|
|
3071
|
+
cylinderY(group, 0.012, 0.06, M.bottle, 0, 0.2, 0, 8, 0.036);
|
|
3072
|
+
box2(group, 0.03, 0.08, 0.02, M.white, 5e-3, 0.25, 0, 0.3);
|
|
3073
|
+
cylinderY(group, 0.02, 0.07, M.fire, 0.01, 0.31, 0, 6, 0).userData.flame = true;
|
|
3074
|
+
kit.mark(group, 0, 0.085, 0).name = "handle";
|
|
3075
|
+
};
|
|
3076
|
+
var pipeBomb = (kit, group) => {
|
|
3077
|
+
const { M, cylinderX, cylinderY } = kit;
|
|
3078
|
+
cylinderX(group, 0.025, 0.2, M.metal, 0, 0.03, 0, 8);
|
|
3079
|
+
cylinderX(group, 0.031, 0.025, M.dark, -0.1, 0.03, 0, 6);
|
|
3080
|
+
cylinderX(group, 0.031, 0.025, M.dark, 0.1, 0.03, 0, 6);
|
|
3081
|
+
cylinderY(group, 2e-3, 0.06, M.white, 0.1, 0.07, 0);
|
|
3082
|
+
kit.mark(group, 0, 0.03, 0).name = "handle";
|
|
3083
|
+
};
|
|
3084
|
+
var dynamite = (kit, group) => {
|
|
3085
|
+
const { M, cylinderX } = kit;
|
|
3086
|
+
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);
|
|
3087
|
+
cylinderX(group, 0.031, 0.03, M.dark, -0.04, 0.025, 0, 8);
|
|
3088
|
+
cylinderX(group, 0.031, 0.03, M.dark, 0.05, 0.025, 0, 8);
|
|
3089
|
+
cylinderX(group, 2e-3, 0.1, M.white, 0.14, 0.03, 0, 4);
|
|
3090
|
+
kit.mark(group, 0, 0.025, 0).name = "handle";
|
|
3091
|
+
};
|
|
3092
|
+
var c4 = (kit, group) => {
|
|
3093
|
+
const { M, box: box2, cylinderY } = kit;
|
|
3094
|
+
box2(group, 0.28, 0.05, 0.11, M.c4, 0, 0.025, 0);
|
|
3095
|
+
box2(group, 0.05, 0.03, 0.04, M.dark, 0.06, 0.065, 0);
|
|
3096
|
+
cylinderY(group, 4e-3, 0.05, M.metal, 0.03, 0.07, 0);
|
|
3097
|
+
box2(group, 0.24, 3e-3, 3e-3, M.wire, 0.18, 0.055, 0.02);
|
|
3098
|
+
box2(group, 0.24, 3e-3, 3e-3, M.metal, 0.18, 0.055, 0.03);
|
|
3099
|
+
kit.mark(group, 0, 0.025, 0).name = "handle";
|
|
3100
|
+
};
|
|
3101
|
+
var claymore = (kit, group) => {
|
|
3102
|
+
const { M, box: box2 } = kit;
|
|
3103
|
+
for (const i of [-1, 0, 1]) box2(group, 0.075, 0.083, 0.035, M.olive, i * 0.072, 0.12, Math.abs(i) * 0.012, 0, -i * 0.25);
|
|
3104
|
+
for (const [x, z] of [[-0.07, 0.03], [-0.07, -0.03], [0.07, 0.03], [0.07, -0.03]]) box2(group, 4e-3, 0.09, 4e-3, M.metal, x, 0.04, z, x > 0 ? -0.25 : 0.25);
|
|
3105
|
+
kit.mark(group, 0, 0.12, 0).name = "handle";
|
|
3106
|
+
};
|
|
3107
|
+
var flashbang = (kit, group) => {
|
|
3108
|
+
const { M, cylinderY, box: box2 } = kit;
|
|
3109
|
+
cylinderY(group, 0.022, 0.13, M.olive, 0, 0.065, 0, 10);
|
|
3110
|
+
for (let i = 0; i < 4; i++) cylinderY(group, 0.023, 8e-3, M.dark, 0, 0.025 + i * 0.028, 0, 10);
|
|
3111
|
+
cylinderY(group, 0.012, 0.02, M.metal, 0, 0.14, 0);
|
|
3112
|
+
box2(group, 0.01, 0.08, 5e-3, M.metal, 0.024, 0.1, 0, 0.15);
|
|
3113
|
+
kit.mark(group, 0, 0.065, 0).name = "handle";
|
|
3114
|
+
};
|
|
3115
|
+
var BUILDERS = {
|
|
3116
|
+
m67: grenade,
|
|
3117
|
+
molotov,
|
|
3118
|
+
pipe_bomb: pipeBomb,
|
|
3119
|
+
dynamite,
|
|
3120
|
+
c4,
|
|
3121
|
+
claymore,
|
|
3122
|
+
flashbang
|
|
3123
|
+
};
|
|
3124
|
+
var EXPLOSIVE_MODEL_IDS = Object.keys(BUILDERS);
|
|
3125
|
+
var hasExplosiveModel = (explosiveId) => explosiveId in BUILDERS;
|
|
3126
|
+
function buildExplosiveModel(THREE, explosiveId) {
|
|
3127
|
+
const builder = BUILDERS[explosiveId];
|
|
3128
|
+
if (!builder) return void 0;
|
|
3129
|
+
const kit = modelKit(THREE);
|
|
3130
|
+
const group = markKitOrigin2(kit.group(), { owner: "game-weapons-three", kind: "explosive", id: explosiveId });
|
|
3131
|
+
group.name = explosiveId;
|
|
3132
|
+
builder(kit, group);
|
|
3133
|
+
return group;
|
|
3134
|
+
}
|
|
3135
|
+
|
|
2836
3136
|
// src/weapon-item-model.ts
|
|
2837
3137
|
var SHIPPED_WEAPON_ITEM_MODELS = [
|
|
2838
3138
|
["wrench", { item: "adjustable_wrench" }],
|
|
@@ -2841,8 +3141,12 @@ var SHIPPED_WEAPON_ITEM_MODELS = [
|
|
|
2841
3141
|
["crossbow", { turn: 1 }],
|
|
2842
3142
|
["knife", { flip: true }],
|
|
2843
3143
|
["meat_cleaver", { flip: true }],
|
|
2844
|
-
["screwdriver", { flip: true }]
|
|
3144
|
+
["screwdriver", { flip: true }],
|
|
3145
|
+
// the Itens do Vale Cinzento hammer is a claw hammer: the head and the two-pronged claw
|
|
3146
|
+
["claw_hammer", { item: "hammer" }]
|
|
2845
3147
|
];
|
|
3148
|
+
var hasThrowableModel = (def) => def.action?.kind === "throwable" && def.action.explosive !== void 0 && hasExplosiveModel(def.action.explosive);
|
|
3149
|
+
var buildThrowableModel = (THREE, def) => def.action?.kind === "throwable" && def.action.explosive !== void 0 ? buildExplosiveModel(THREE, def.action.explosive) : void 0;
|
|
2846
3150
|
var weaponPropsOver = (models) => {
|
|
2847
3151
|
const itemModelOf = (weaponId, items) => {
|
|
2848
3152
|
const id = models.get(weaponId)?.item ?? weaponId;
|
|
@@ -2858,7 +3162,7 @@ var weaponPropsOver = (models) => {
|
|
|
2858
3162
|
get: (weaponId) => models.get(weaponId),
|
|
2859
3163
|
itemModelOf,
|
|
2860
3164
|
buildItemModel,
|
|
2861
|
-
buildModel: (THREE, def, items) => buildItemModel(THREE, def, items) ?? buildProp(THREE, weaponProp(def))
|
|
3165
|
+
buildModel: (THREE, def, items) => buildItemModel(THREE, def, items) ?? buildThrowableModel(THREE, def) ?? buildProp(THREE, weaponProp(def))
|
|
2862
3166
|
};
|
|
2863
3167
|
};
|
|
2864
3168
|
var defaultProps;
|
|
@@ -2870,6 +3174,7 @@ var buildWeaponModel = (THREE, def, items) => defaultWeaponProps().buildModel(TH
|
|
|
2870
3174
|
|
|
2871
3175
|
// src/box-fx.ts
|
|
2872
3176
|
var EJECTS_ON_SHOT = /* @__PURE__ */ new Set(["pistol", "smg", "carbine", "rifle", "sniper", "shotgun"]);
|
|
3177
|
+
var SPOUTS = /* @__PURE__ */ new Set(["firearm", "flame", "heat", "extinguisher"]);
|
|
2873
3178
|
var DROPS_MAGAZINE = /* @__PURE__ */ new Set(["pistol", "smg", "carbine", "rifle", "sniper"]);
|
|
2874
3179
|
var CYCLES = /* @__PURE__ */ new Set(["shotgun_pump_12", "rifle_bolt_308"]);
|
|
2875
3180
|
var FALLBACK_ENERGY = 300;
|
|
@@ -2904,6 +3209,7 @@ function createBoxFx(options) {
|
|
|
2904
3209
|
const q = new THREE.Quaternion();
|
|
2905
3210
|
const q2 = new THREE.Quaternion();
|
|
2906
3211
|
const pointForward = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI / 2);
|
|
3212
|
+
const frontOf = new THREE.Vector3();
|
|
2907
3213
|
const equip = (weapon) => {
|
|
2908
3214
|
if (model) hand.remove(model);
|
|
2909
3215
|
model = null;
|
|
@@ -2914,6 +3220,7 @@ function createBoxFx(options) {
|
|
|
2914
3220
|
const length = new THREE.Box3().setFromObject(model).getSize(v).x;
|
|
2915
3221
|
rear = new THREE.Box3().setFromObject(model).min.x;
|
|
2916
3222
|
lengthMetres = length;
|
|
3223
|
+
frontOf.copy(new THREE.Box3().setFromObject(model).getCenter(v)).setX(rear + length);
|
|
2917
3224
|
model.quaternion.copy(pointForward);
|
|
2918
3225
|
hand.add(model);
|
|
2919
3226
|
inHand = def.id;
|
|
@@ -3014,6 +3321,13 @@ function createBoxFx(options) {
|
|
|
3014
3321
|
inHand = null;
|
|
3015
3322
|
hold = null;
|
|
3016
3323
|
},
|
|
3324
|
+
muzzle() {
|
|
3325
|
+
if (!model || !def || !SPOUTS.has(def.action.kind)) return null;
|
|
3326
|
+
hand.updateMatrixWorld(true);
|
|
3327
|
+
const at = model.localToWorld(v.copy(frontOf));
|
|
3328
|
+
const along = v2.set(1, 0, 0).applyQuaternion(model.getWorldQuaternion(q2)).normalize();
|
|
3329
|
+
return { position: [at.x, at.y, at.z], direction: [along.x, along.y, along.z], drawsFlash: false };
|
|
3330
|
+
},
|
|
3017
3331
|
handTargets() {
|
|
3018
3332
|
if (!model || !hold) return null;
|
|
3019
3333
|
hand.updateMatrixWorld(true);
|
|
@@ -3065,7 +3379,7 @@ function createBoxFx(options) {
|
|
|
3065
3379
|
}
|
|
3066
3380
|
|
|
3067
3381
|
// src/models/index.ts
|
|
3068
|
-
import { markKitOrigin as
|
|
3382
|
+
import { markKitOrigin as markKitOrigin3 } from "@adatechnology/game-contracts";
|
|
3069
3383
|
import { WEAPONS } from "@adatechnology/game-weapons";
|
|
3070
3384
|
|
|
3071
3385
|
// src/data/models.json
|
|
@@ -4618,197 +4932,24 @@ var models_default = {
|
|
|
4618
4932
|
options: {
|
|
4619
4933
|
rpm: 3e3
|
|
4620
4934
|
}
|
|
4935
|
+
},
|
|
4936
|
+
m79: {
|
|
4937
|
+
builder: "breakLauncher",
|
|
4938
|
+
caliber: "40\xD746",
|
|
4939
|
+
length: 730,
|
|
4940
|
+
barrel: 356,
|
|
4941
|
+
options: {
|
|
4942
|
+
stock: "fixed",
|
|
4943
|
+
wood: 1,
|
|
4944
|
+
mag: "none",
|
|
4945
|
+
hg: "wood",
|
|
4946
|
+
hgFrac: 0.4,
|
|
4947
|
+
br: 0.022,
|
|
4948
|
+
hR: 0.05
|
|
4949
|
+
}
|
|
4621
4950
|
}
|
|
4622
4951
|
};
|
|
4623
4952
|
|
|
4624
|
-
// src/models/kit.ts
|
|
4625
|
-
import { markShared, shapeGeometries as shapeGeometries2 } from "@adatechnology/game-shapes-three";
|
|
4626
|
-
|
|
4627
|
-
// src/models/rounded-box.ts
|
|
4628
|
-
var uvAlong = (THREE, faceDirection, normal, uvAxis, projectionAxis, radius, sideLength) => {
|
|
4629
|
-
const arcLength = 2 * Math.PI * radius / 4;
|
|
4630
|
-
const centerLength = Math.max(sideLength - 2 * radius, 0);
|
|
4631
|
-
const halfArc = Math.PI / 4;
|
|
4632
|
-
const projected = new THREE.Vector3().copy(normal);
|
|
4633
|
-
projected[projectionAxis] = 0;
|
|
4634
|
-
projected.normalize();
|
|
4635
|
-
const arcUvRatio = 0.5 * arcLength / (arcLength + centerLength);
|
|
4636
|
-
const arcAngleRatio = 1 - projected.angleTo(faceDirection) / halfArc;
|
|
4637
|
-
if (Math.sign(projected[uvAxis]) === 1) return arcAngleRatio * arcUvRatio;
|
|
4638
|
-
const centerUv = centerLength / (arcLength + centerLength);
|
|
4639
|
-
return centerUv + arcUvRatio + arcUvRatio * (1 - arcAngleRatio);
|
|
4640
|
-
};
|
|
4641
|
-
var FACES = [
|
|
4642
|
-
{ direction: [1, 0, 0], u: ["z", "y", false], v: ["y", "z", true] },
|
|
4643
|
-
{ direction: [-1, 0, 0], u: ["z", "y", true], v: ["y", "z", true] },
|
|
4644
|
-
{ direction: [0, 1, 0], u: ["x", "z", true], v: ["z", "x", false] },
|
|
4645
|
-
{ direction: [0, -1, 0], u: ["x", "z", true], v: ["z", "x", true] },
|
|
4646
|
-
{ direction: [0, 0, 1], u: ["x", "y", true], v: ["y", "x", true] },
|
|
4647
|
-
{ direction: [0, 0, -1], u: ["x", "y", false], v: ["y", "x", true] }
|
|
4648
|
-
];
|
|
4649
|
-
function createRoundedBoxGeometry(THREE, width, height, depth, segments, radius) {
|
|
4650
|
-
const count = segments * 2 + 1;
|
|
4651
|
-
const rounding = Math.min(width / 2, height / 2, depth / 2, radius);
|
|
4652
|
-
const geometry = new THREE.BoxGeometry(1, 1, 1, count, count, count);
|
|
4653
|
-
const flat2 = geometry.toNonIndexed();
|
|
4654
|
-
geometry.setIndex(null);
|
|
4655
|
-
geometry.setAttribute("position", flat2.attributes.position);
|
|
4656
|
-
geometry.setAttribute("normal", flat2.attributes.normal);
|
|
4657
|
-
geometry.setAttribute("uv", flat2.attributes.uv);
|
|
4658
|
-
const position = new THREE.Vector3();
|
|
4659
|
-
const normal = new THREE.Vector3();
|
|
4660
|
-
const box2 = new THREE.Vector3(width, height, depth).divideScalar(2).subScalar(rounding);
|
|
4661
|
-
const positions = geometry.attributes.position.array;
|
|
4662
|
-
const normals = geometry.attributes.normal.array;
|
|
4663
|
-
const uvs = geometry.attributes.uv.array;
|
|
4664
|
-
const faceTriangles = positions.length / 6;
|
|
4665
|
-
const halfSegment = 0.5 / count;
|
|
4666
|
-
const sides = { x: width, y: height, z: depth };
|
|
4667
|
-
for (let i = 0, j = 0; i < positions.length; i += 3, j += 2) {
|
|
4668
|
-
position.fromArray(positions, i);
|
|
4669
|
-
normal.copy(position);
|
|
4670
|
-
normal.x -= Math.sign(normal.x) * halfSegment;
|
|
4671
|
-
normal.y -= Math.sign(normal.y) * halfSegment;
|
|
4672
|
-
normal.z -= Math.sign(normal.z) * halfSegment;
|
|
4673
|
-
normal.normalize();
|
|
4674
|
-
positions[i] = box2.x * Math.sign(position.x) + normal.x * rounding;
|
|
4675
|
-
positions[i + 1] = box2.y * Math.sign(position.y) + normal.y * rounding;
|
|
4676
|
-
positions[i + 2] = box2.z * Math.sign(position.z) + normal.z * rounding;
|
|
4677
|
-
normals[i] = normal.x;
|
|
4678
|
-
normals[i + 1] = normal.y;
|
|
4679
|
-
normals[i + 2] = normal.z;
|
|
4680
|
-
const face = FACES[Math.floor(i / faceTriangles)];
|
|
4681
|
-
if (!face) continue;
|
|
4682
|
-
const direction = new THREE.Vector3(...face.direction);
|
|
4683
|
-
for (const [offset, [uvAxis, projectionAxis, mirrored]] of [[0, face.u], [1, face.v]]) {
|
|
4684
|
-
const value = uvAlong(THREE, direction, normal, uvAxis, projectionAxis, rounding, sides[uvAxis]);
|
|
4685
|
-
uvs[j + offset] = mirrored ? 1 - value : value;
|
|
4686
|
-
}
|
|
4687
|
-
}
|
|
4688
|
-
return geometry;
|
|
4689
|
-
}
|
|
4690
|
-
|
|
4691
|
-
// src/models/kit.ts
|
|
4692
|
-
var PI = Math.PI;
|
|
4693
|
-
var createMaterials = (THREE) => {
|
|
4694
|
-
const standard = (color, roughness = 0.7, metalness = 0.2, extra = {}) => new THREE.MeshStandardMaterial({ color, roughness, metalness, ...extra });
|
|
4695
|
-
const basic = (color, extra = {}) => new THREE.MeshBasicMaterial({ color, ...extra });
|
|
4696
|
-
const additive = { transparent: true, opacity: 0.95, blending: THREE.AdditiveBlending, depthWrite: false };
|
|
4697
|
-
const materials = {
|
|
4698
|
-
metal: standard(3422010, 0.42, 0.75),
|
|
4699
|
-
steel: standard(7106418, 0.32, 0.85),
|
|
4700
|
-
steelL: standard(9080208, 0.28, 0.9),
|
|
4701
|
-
dark: standard(1711133, 0.55, 0.5),
|
|
4702
|
-
poly: standard(2369058, 0.8, 0.05),
|
|
4703
|
-
olive: standard(4936241, 0.8, 0.05),
|
|
4704
|
-
tan: standard(10259043, 0.8, 0.05),
|
|
4705
|
-
wood: standard(4860951, 0.55, 0),
|
|
4706
|
-
woodL: standard(6175263, 0.55, 0),
|
|
4707
|
-
brass: standard(12819013, 0.28, 0.9),
|
|
4708
|
-
copper: standard(11561531, 0.3, 0.85),
|
|
4709
|
-
lead: standard(7171955, 0.5, 0.5),
|
|
4710
|
-
shell: standard(10692380, 0.5, 0.05),
|
|
4711
|
-
glass: standard(8364968, 0.05, 0.1, { transparent: true, opacity: 0.42 }),
|
|
4712
|
-
lens: standard(2311770, 0.05, 0.3, { transparent: true, opacity: 0.9, emissive: 399392 }),
|
|
4713
|
-
rubber: standard(1381653, 0.85, 0),
|
|
4714
|
-
white: standard(13617332, 0.8, 0),
|
|
4715
|
-
hole: standard(526343, 1, 0),
|
|
4716
|
-
bake: standard(5911072, 0.55, 0),
|
|
4717
|
-
rust: standard(7027230, 0.95, 0.3),
|
|
4718
|
-
rustD: standard(4860440, 0.95, 0.25),
|
|
4719
|
-
worn: standard(5593178, 0.6, 0.6),
|
|
4720
|
-
fire: basic(16742946),
|
|
4721
|
-
fire2: basic(16764762),
|
|
4722
|
-
flashA: basic(16757575, additive),
|
|
4723
|
-
flashB: basic(16773568, additive),
|
|
4724
|
-
smokeP: standard(9079430, 1, 0, { transparent: true, opacity: 0.35, depthWrite: false }),
|
|
4725
|
-
/** Launcher paints. */
|
|
4726
|
-
yellow: standard(11570978, 0.6, 0),
|
|
4727
|
-
red: standard(9313300, 0.45, 0.1),
|
|
4728
|
-
redPaint: standard(10691354, 0.35, 0.2),
|
|
4729
|
-
tape: standard(9079944, 0.9, 0),
|
|
4730
|
-
pipe: standard(10115634, 0.35, 0.8),
|
|
4731
|
-
green: standard(3818536, 0.75, 0.05),
|
|
4732
|
-
/** Magazine finishes named by the options. */
|
|
4733
|
-
bakelite: standard(6958620, 0.6, 0),
|
|
4734
|
-
polyMag: standard(2763302, 0.85, 0)
|
|
4735
|
-
};
|
|
4736
|
-
markShared(...Object.values(materials));
|
|
4737
|
-
return materials;
|
|
4738
|
-
};
|
|
4739
|
-
var kits = /* @__PURE__ */ new WeakMap();
|
|
4740
|
-
function modelKit(host) {
|
|
4741
|
-
const cached = kits.get(host);
|
|
4742
|
-
if (cached) return cached;
|
|
4743
|
-
const THREE = shapeGeometries2(host);
|
|
4744
|
-
const geometries = /* @__PURE__ */ new Map();
|
|
4745
|
-
const shadowed = (mesh) => {
|
|
4746
|
-
mesh.castShadow = true;
|
|
4747
|
-
mesh.receiveShadow = true;
|
|
4748
|
-
return mesh;
|
|
4749
|
-
};
|
|
4750
|
-
const place = (parent, mesh, x, y, z) => {
|
|
4751
|
-
mesh.position.set(x, y, z);
|
|
4752
|
-
parent.add(mesh);
|
|
4753
|
-
return mesh;
|
|
4754
|
-
};
|
|
4755
|
-
const kit = {
|
|
4756
|
-
THREE,
|
|
4757
|
-
M: createMaterials(THREE),
|
|
4758
|
-
roundness: null,
|
|
4759
|
-
group: () => new THREE.Group(),
|
|
4760
|
-
box(parent, w, h, d, material, x, y, z, rz = 0, ry = 0, rx = 0) {
|
|
4761
|
-
const radius = Math.min(w, h, d) * (kit.roundness ?? 0.2);
|
|
4762
|
-
const key = `${w.toFixed(4)},${h.toFixed(4)},${d.toFixed(4)},${radius.toFixed(5)}`;
|
|
4763
|
-
let geometry = geometries.get(key);
|
|
4764
|
-
if (!geometry) {
|
|
4765
|
-
geometry = radius > 25e-5 ? createRoundedBoxGeometry(THREE, w, h, d, 2, radius) : new THREE.BoxGeometry(w, h, d);
|
|
4766
|
-
markShared(geometry);
|
|
4767
|
-
geometries.set(key, geometry);
|
|
4768
|
-
}
|
|
4769
|
-
const mesh = place(parent, shadowed(new THREE.Mesh(geometry, material)), x, y, z);
|
|
4770
|
-
mesh.rotation.set(rx, ry, rz);
|
|
4771
|
-
return mesh;
|
|
4772
|
-
},
|
|
4773
|
-
cylinderX(parent, radius, length, material, x, y, z, segments = 16, radiusEnd) {
|
|
4774
|
-
const mesh = shadowed(new THREE.Mesh(new THREE.CylinderGeometry(radiusEnd ?? radius, radius, length, segments), material));
|
|
4775
|
-
mesh.rotation.z = -PI / 2;
|
|
4776
|
-
return place(parent, mesh, x, y, z);
|
|
4777
|
-
},
|
|
4778
|
-
cylinderY(parent, radius, height, material, x, y, z, segments = 16, radiusEnd) {
|
|
4779
|
-
return place(parent, shadowed(new THREE.Mesh(new THREE.CylinderGeometry(radiusEnd ?? radius, radius, height, segments), material)), x, y, z);
|
|
4780
|
-
},
|
|
4781
|
-
cylinderZ(parent, radius, length, material, x, y, z, segments = 16) {
|
|
4782
|
-
const mesh = shadowed(new THREE.Mesh(new THREE.CylinderGeometry(radius, radius, length, segments), material));
|
|
4783
|
-
mesh.rotation.x = PI / 2;
|
|
4784
|
-
return place(parent, mesh, x, y, z);
|
|
4785
|
-
},
|
|
4786
|
-
sphere(parent, radius, material, x, y, z, detail = 1) {
|
|
4787
|
-
return place(parent, shadowed(new THREE.Mesh(new THREE.IcosahedronGeometry(radius, detail), material)), x, y, z);
|
|
4788
|
-
},
|
|
4789
|
-
torus: (parent, geometry, material, x, y, z) => place(parent, shadowed(new THREE.Mesh(geometry, material)), x, y, z),
|
|
4790
|
-
mark(parent, x, y, z) {
|
|
4791
|
-
const object = new THREE.Object3D();
|
|
4792
|
-
object.position.set(x, y, z);
|
|
4793
|
-
parent.add(object);
|
|
4794
|
-
return object;
|
|
4795
|
-
},
|
|
4796
|
-
pivot(parent, x = 0, y = 0, z = 0) {
|
|
4797
|
-
const group = new THREE.Group();
|
|
4798
|
-
group.position.set(x, y, z);
|
|
4799
|
-
parent.add(group);
|
|
4800
|
-
return group;
|
|
4801
|
-
}
|
|
4802
|
-
};
|
|
4803
|
-
kits.set(host, kit);
|
|
4804
|
-
return kit;
|
|
4805
|
-
}
|
|
4806
|
-
function heatify(glow, mesh) {
|
|
4807
|
-
mesh.material = mesh.material.clone();
|
|
4808
|
-
glow.push(mesh);
|
|
4809
|
-
return mesh;
|
|
4810
|
-
}
|
|
4811
|
-
|
|
4812
4953
|
// src/models/break-action.ts
|
|
4813
4954
|
function buildBreakAction(kit, options) {
|
|
4814
4955
|
const { M, box: box2, cylinderX, sphere } = kit;
|
|
@@ -4842,78 +4983,23 @@ function buildBreakAction(kit, options) {
|
|
|
4842
4983
|
return { group, parts };
|
|
4843
4984
|
}
|
|
4844
4985
|
|
|
4845
|
-
// src/models/attachments/
|
|
4846
|
-
|
|
4847
|
-
|
|
4848
|
-
|
|
4849
|
-
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
var HANDGUARD_FRACTION = 0.5;
|
|
4853
|
-
function deriveFrames(THREE, model) {
|
|
4854
|
-
const { root, inner, parts } = model;
|
|
4855
|
-
root.updateMatrixWorld(true);
|
|
4856
|
-
const box2 = new THREE.Box3().setFromObject(root);
|
|
4857
|
-
const span = box2.max.x - box2.min.x;
|
|
4858
|
-
const toInnerX = (x) => (x - inner.position.x) / inner.scale.x;
|
|
4859
|
-
const muzzle = parts.muzzle?.position;
|
|
4860
|
-
const length = muzzle ? muzzle.x - 0.01 : toInnerX(box2.max.x);
|
|
4861
|
-
const receiverStart = toInnerX(box2.min.x + span * RECEIVER_START_FRACTION);
|
|
4862
|
-
const receiverEnd = toInnerX(box2.min.x + span * RECEIVER_END_FRACTION);
|
|
4863
|
-
return {
|
|
4864
|
-
length,
|
|
4865
|
-
barrelY: muzzle?.y ?? (box2.max.y + box2.min.y) / 2,
|
|
4866
|
-
barrelRadius: DEFAULT_BARREL_RADIUS,
|
|
4867
|
-
receiverStart,
|
|
4868
|
-
receiverEnd,
|
|
4869
|
-
receiverHeight: (box2.max.y - box2.min.y) * RECEIVER_HEIGHT_FRACTION,
|
|
4870
|
-
receiverWidth: Math.min(DEFAULT_RECEIVER_WIDTH, box2.max.z - box2.min.z),
|
|
4871
|
-
handguardEnd: receiverEnd + (length - receiverEnd) * HANDGUARD_FRACTION,
|
|
4872
|
-
magazineX: parts.mag ? parts.mag.position.x : (receiverStart + receiverEnd) / 2,
|
|
4873
|
-
gripX: receiverStart + DEFAULT_GRIP_OFFSET,
|
|
4874
|
-
hasRail: false
|
|
4875
|
-
};
|
|
4986
|
+
// src/models/attachments/muzzle-brake.ts
|
|
4987
|
+
function buildBrake(kit, parent, kind, x, y, barrelRadius, heat = () => void 0) {
|
|
4988
|
+
const { M, box: box2, cylinderX } = kit;
|
|
4989
|
+
const scale = kind === 2 ? 3.2 : 2;
|
|
4990
|
+
const length = kind === 2 ? 0.12 : 0.06;
|
|
4991
|
+
heat(cylinderX(parent, barrelRadius * scale, length, M.dark, x - length / 2, y, 0, kind === 2 ? 8 : 16));
|
|
4992
|
+
for (let i = 0; i < 3; i++) box2(parent, length * 0.16, barrelRadius * scale * 1.3, barrelRadius * scale * 2.2, M.hole, x - length * 0.25 - i * length * 0.25, y, 0);
|
|
4876
4993
|
}
|
|
4877
|
-
|
|
4878
|
-
|
|
4879
|
-
|
|
4880
|
-
const
|
|
4881
|
-
|
|
4882
|
-
|
|
4883
|
-
|
|
4884
|
-
|
|
4885
|
-
|
|
4886
|
-
switch (mount) {
|
|
4887
|
-
case "muzzle":
|
|
4888
|
-
return { ...base, position: toRoot(frames.length, frames.barrelY, 0), side: 0 };
|
|
4889
|
-
case "rail_top":
|
|
4890
|
-
return { ...base, position: toRoot((frames.receiverStart + frames.receiverEnd) / 2 + 0.03, railTopY, 0), side: 0 };
|
|
4891
|
-
case "rail_bottom":
|
|
4892
|
-
return { ...base, position: toRoot(forendMiddle, frames.barrelY - handguardHeight / 2, 0), side: 0 };
|
|
4893
|
-
case "rail_left":
|
|
4894
|
-
return { ...base, position: toRoot(forendMiddle, frames.barrelY, -(frames.receiverWidth * 0.54 + 4e-3)), side: -1 };
|
|
4895
|
-
case "rail_right":
|
|
4896
|
-
return { ...base, position: toRoot(forendMiddle, frames.barrelY, frames.receiverWidth * 0.54 + 4e-3), side: 1 };
|
|
4897
|
-
case "underbarrel": {
|
|
4898
|
-
const [x, y] = frames.underbarrel ?? [frames.receiverEnd + (frames.handguardEnd - frames.receiverEnd) * 0.25, frames.barrelY - handguardHeight / 2 - 0.02];
|
|
4899
|
-
return { ...base, position: toRoot(x, y, 0), side: 0 };
|
|
4900
|
-
}
|
|
4901
|
-
case "magazine":
|
|
4902
|
-
return { ...base, position: toRoot(frames.magazineX, -frames.receiverHeight / 2, 0), side: 0 };
|
|
4903
|
-
case "feed": {
|
|
4904
|
-
const belt = model.parts.belt?.position;
|
|
4905
|
-
return { ...base, position: belt ? toRoot(belt.x, belt.y, belt.z) : toRoot(frames.magazineX + 0.02, -frames.receiverHeight / 2 - 0.05, -0.045), side: -1 };
|
|
4906
|
-
}
|
|
4907
|
-
case "sling":
|
|
4908
|
-
return {
|
|
4909
|
-
...base,
|
|
4910
|
-
position: toRoot(frames.receiverEnd + (frames.length - frames.receiverEnd) * 0.45, -frames.receiverHeight / 2 - 0.03, 0),
|
|
4911
|
-
secondary: toRoot(0.08, -0.09, 0),
|
|
4912
|
-
side: 0
|
|
4913
|
-
};
|
|
4914
|
-
default:
|
|
4915
|
-
return void 0;
|
|
4916
|
-
}
|
|
4994
|
+
|
|
4995
|
+
// src/models/capture.ts
|
|
4996
|
+
function captured(parent, draw) {
|
|
4997
|
+
const before = parent.children.length;
|
|
4998
|
+
draw();
|
|
4999
|
+
return parent.children.slice(before);
|
|
5000
|
+
}
|
|
5001
|
+
function recordFitting(parts, id, parent, draw) {
|
|
5002
|
+
parts.fittings = { ...parts.fittings, [id]: captured(parent, draw) };
|
|
4917
5003
|
}
|
|
4918
5004
|
|
|
4919
5005
|
// src/models/details.ts
|
|
@@ -4968,1131 +5054,1209 @@ function scope(kit, parent, kind, cx, cy, cz = 0) {
|
|
|
4968
5054
|
var buttpad = (kit, parent, x, y, height, width) => void kit.box(parent, 0.012, height, width, kit.M.rubber, x, y, 0);
|
|
4969
5055
|
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);
|
|
4970
5056
|
|
|
4971
|
-
// src/models/
|
|
4972
|
-
function
|
|
5057
|
+
// src/models/attachments/bipod.ts
|
|
5058
|
+
function buildBipod(kit, parent, x, y) {
|
|
4973
5059
|
const { M, box: box2, cylinderX } = kit;
|
|
4974
|
-
|
|
4975
|
-
const
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
|
|
4980
|
-
box2(group, bodyLength, 0.075, 0.042, body, bodyLength / 2, 0, 0);
|
|
4981
|
-
box2(group, bodyLength * 0.9, 0.02, 0.044, M.dark, bodyLength * 0.5, -0.02, 0);
|
|
4982
|
-
box2(group, 0.032, 0.13, 0.044, M.rubber, 0.016, -0.025, 0);
|
|
4983
|
-
const gx = bodyLength * 0.8;
|
|
4984
|
-
const grip = kit.pivot(group, gx, -0.085, 0);
|
|
4985
|
-
grip.rotation.z = -0.25;
|
|
4986
|
-
parts.grip = grip;
|
|
4987
|
-
box2(grip, 0.03, 0.1, 0.03, M.poly, 0, 0, 0);
|
|
4988
|
-
box2(group, 0.1, 6e-3, 0.03, body, gx + 0.01, -0.06, 0);
|
|
4989
|
-
parts.trigger = box2(group, 4e-3, 0.016, 4e-3, M.dark, gx + 0.02, -0.05, 0, 0.15);
|
|
4990
|
-
heatify(parts.glow, cylinderX(group, options.shot ? 0.0105 : 85e-4, barrel, M.metal, L - barrel / 2, 0.012, 0, 16));
|
|
4991
|
-
cylinderX(group, 6e-3, 4e-3, M.hole, L + 1e-3, 0.012, 0, 12);
|
|
4992
|
-
box2(group, 0.05, 0.024, 4e-3, M.hole, bodyLength * 0.25, 5e-3, 0.0212);
|
|
4993
|
-
const bolt = kit.pivot(group);
|
|
4994
|
-
parts.bolt = bolt;
|
|
4995
|
-
box2(bolt, 0.044, 0.02, 6e-3, M.steelL, bodyLength * 0.25, 5e-3, 0.02);
|
|
4996
|
-
if (options.shot) {
|
|
4997
|
-
cylinderX(group, 0.012, bodyLength * 0.75, M.metal, bodyLength * 0.55, -0.025, 0.014, 14);
|
|
4998
|
-
cylinderX(group, 0.012, bodyLength * 0.75, M.metal, bodyLength * 0.55, -0.025, -0.014, 14);
|
|
4999
|
-
const pump = kit.pivot(group);
|
|
5000
|
-
parts.pump = pump;
|
|
5001
|
-
box2(pump, 0.15, 0.045, 0.052, M.poly, bodyLength + 0.06, -0.015, 0);
|
|
5002
|
-
for (let i = 0; i < 6; i++) box2(pump, 6e-3, 0.047, 0.054, M.dark, bodyLength + 5e-3 + i * 0.022, -0.015, 0);
|
|
5003
|
-
rail(kit, group, bodyLength * 0.15, bodyLength * 0.8, 0.04, 0, 0.02);
|
|
5004
|
-
parts.loadPort = kit.mark(group, bodyLength * 0.2, -0.04, 0);
|
|
5005
|
-
} else {
|
|
5006
|
-
const magazine = kit.pivot(group, gx - 0.11, -0.03, 0);
|
|
5007
|
-
magazine.rotation.z = 0.14;
|
|
5008
|
-
parts.mag = magazine;
|
|
5009
|
-
box2(magazine, 0.05, 0.14, 0.026, M.glass, 0, -0.07, 0);
|
|
5010
|
-
for (let i = 0; i < 6; i++) cylinderX(magazine, 3e-3, 0.04, M.brass, 0, -0.01 - i * 0.02, 0, 6);
|
|
5011
|
-
parts.magDrop = 0.18;
|
|
5012
|
-
scope(kit, group, 2, bodyLength * 0.5, 0.04, 0);
|
|
5013
|
-
box2(group, 0.2, 0.03, 0.02, body, bodyLength * 0.62, 0.048, 0);
|
|
5014
|
-
box2(group, 0.026, 0.075, 0.026, body, bodyLength + 0.05, -0.05, 0, 0.1);
|
|
5060
|
+
cylinderX(parent, 8e-3, 0.02, M.dark, x, y, 0, 12);
|
|
5061
|
+
for (const side of [-1, 1]) {
|
|
5062
|
+
const leg = kit.pivot(parent, x, y, side * 0.012);
|
|
5063
|
+
leg.rotation.set(side * 0.15, 0, -0.35);
|
|
5064
|
+
box2(leg, 6e-3, 0.2, 6e-3, M.dark, 0, -0.1, 0);
|
|
5065
|
+
box2(leg, 0.01, 6e-3, 0.01, M.rubber, 0, -0.2, 0);
|
|
5015
5066
|
}
|
|
5016
|
-
parts.muzzle = kit.mark(group, L + 0.01, 0.012, 0);
|
|
5017
|
-
parts.eject = kit.mark(group, bodyLength * 0.25, 5e-3, 0.03);
|
|
5018
|
-
return { group, parts };
|
|
5019
5067
|
}
|
|
5020
|
-
|
|
5021
|
-
|
|
5022
|
-
|
|
5023
|
-
|
|
5024
|
-
const curve = new THREE.CatmullRomCurve3(points.map((point) => new THREE.Vector3(...point)));
|
|
5025
|
-
const tube = new THREE.Mesh(new THREE.TubeGeometry(curve, 40, radius, 8, false), material);
|
|
5026
|
-
tube.castShadow = tube.receiveShadow = true;
|
|
5027
|
-
group.add(tube);
|
|
5028
|
-
};
|
|
5029
|
-
var pilot = (kit, group, x, y) => {
|
|
5030
|
-
const { M, cylinderX } = kit;
|
|
5031
|
-
cylinderX(group, 6e-3, 0.03, M.fire2, x + 0.015, y, 0, 6, 0).userData.flame = 1;
|
|
5032
|
-
cylinderX(group, 4e-3, 0.022, M.fire, x + 0.012, y, 0, 6, 0).userData.flame = 1;
|
|
5068
|
+
var buildBipodModel = ({ kit }) => {
|
|
5069
|
+
const group = kit.group();
|
|
5070
|
+
buildBipod(kit, group, 0, 0);
|
|
5071
|
+
return group;
|
|
5033
5072
|
};
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
|
|
5046
|
-
const lever = kit.pivot(group, 0.62, -0.02, 0);
|
|
5047
|
-
parts.trigger = box2(lever, 8e-3, 0.05, 6e-3, M.metal, 0.02, -0.03, 0, 0.3);
|
|
5048
|
-
const rearGrip = kit.pivot(group, 0.17, -0.02, 0);
|
|
5049
|
-
rearGrip.rotation.z = -0.28;
|
|
5050
|
-
box2(rearGrip, 0.03, 0.1, 0.03, M.wood, 0, -0.05, 0);
|
|
5051
|
-
box2(group, 0.05, 4e-3, 0.012, M.metal, 0.2, -0.035, 0);
|
|
5052
|
-
cylinderX(group, 0.02, 0.04, M.metal, 0.1, 0, 0, 12);
|
|
5053
|
-
hose(kit, group, [[0.08, 0, 0], [0, -0.04, 0], [-0.08, -0.2, 0.05], [-0.18, -0.32, 0.08], [-0.25, -0.33, 0.08]], 0.011, M.rubber);
|
|
5054
|
-
for (const z of [-0.1, 0.1]) {
|
|
5055
|
-
cylinderY(group, 0.085, 0.5, M.olive, -0.3, -0.05, z, 20);
|
|
5056
|
-
sphere(group, 0.085, M.olive, -0.3, 0.2, z, 2).scale.y = 0.45;
|
|
5057
|
-
sphere(group, 0.085, M.olive, -0.3, -0.3, z, 2).scale.y = 0.45;
|
|
5058
|
-
cylinderY(group, 0.03, 0.03, M.metal, -0.3, 0.24, z, 12);
|
|
5073
|
+
|
|
5074
|
+
// src/models/rifle-fittings.ts
|
|
5075
|
+
var SCOPE_IDS = { 1: "red_dot", 2: "acog_4x", 3: "scope_3_9x", 4: "scope_6_24x" };
|
|
5076
|
+
function buildFittings(context, gripX) {
|
|
5077
|
+
const { kit, group, parts, options: o, furniture: furn, length: L, receiverStart: x0, receiverEnd: x1, receiverHeight: hR, receiverWidth: wR, barrelRadius: r, barrelY: by } = context;
|
|
5078
|
+
const { M, box: box2, cylinderX, cylinderZ, sphere } = kit;
|
|
5079
|
+
const middle = (x0 + x1) / 2;
|
|
5080
|
+
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));
|
|
5081
|
+
if (o.carry) {
|
|
5082
|
+
box2(group, 0.15, 0.026, 0.014, M.metal, middle, hR / 2 + 0.03, 0);
|
|
5083
|
+
box2(group, 0.012, 0.03, 0.014, M.metal, middle + 0.07, hR / 2 + 0.014, 0);
|
|
5084
|
+
box2(group, 0.012, 0.03, 0.014, M.metal, middle - 0.07, hR / 2 + 0.014, 0);
|
|
5059
5085
|
}
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
|
|
5067
|
-
|
|
5068
|
-
}
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5086
|
+
if (o.bipod) recordFitting(parts, "bipod", group, () => buildBipod(kit, group, x1 + (L - x1) * 0.45 + 0.04, by - 0.012));
|
|
5087
|
+
if (o.bolt) {
|
|
5088
|
+
const handle = kit.pivot(group, x1 - 0.045, by, 0);
|
|
5089
|
+
parts.boltHandle = handle;
|
|
5090
|
+
parts.boltHandleRest = handle.position.x;
|
|
5091
|
+
cylinderZ(handle, 42e-4, 0.05, M.steelL, 0, 0, wR / 2 + 0.022, 12);
|
|
5092
|
+
sphere(handle, 95e-4, M.dark, 0, -4e-3, wR / 2 + 0.048, 1);
|
|
5093
|
+
cylinderX(group, hR * 0.3, 0.03, M.steel, x0 + 5e-3, by, 0, 16);
|
|
5094
|
+
}
|
|
5095
|
+
if (o.lever) {
|
|
5096
|
+
const lever = kit.pivot(group, gripX - 0.02, -hR / 2 - 0.01, 0);
|
|
5097
|
+
parts.lever = lever;
|
|
5098
|
+
box2(lever, 0.11, 6e-3, 0.012, M.metal, 0.055, -0.052, 0);
|
|
5099
|
+
box2(lever, 6e-3, 0.05, 0.012, M.metal, 3e-3, -0.028, 0);
|
|
5100
|
+
box2(lever, 6e-3, 0.05, 0.012, M.metal, 0.108, -0.028, 0);
|
|
5101
|
+
box2(lever, 0.04, 6e-3, 0.012, M.metal, 0.08, -2e-3, 0);
|
|
5102
|
+
box2(group, 0.03, 0.012, 3e-3, M.dark, x1 - 0.04, by, wR / 2 + 1e-3);
|
|
5103
|
+
}
|
|
5104
|
+
if (o.tube) {
|
|
5105
|
+
const tubeLength = (L - x1) * (o.tubeLen || 0.8);
|
|
5106
|
+
cylinderX(group, 0.0105, tubeLength, M.metal, x1 + tubeLength / 2, by - 0.023, 0, 16);
|
|
5107
|
+
cylinderX(group, 0.0125, 0.02, M.dark, x1 + tubeLength + 6e-3, by - 0.023, 0, 16);
|
|
5108
|
+
}
|
|
5109
|
+
if (o.pump) {
|
|
5110
|
+
const pump = kit.pivot(group);
|
|
5111
|
+
parts.pump = pump;
|
|
5112
|
+
box2(pump, 0.17, 0.042, 0.046, furn, x1 + 0.14, by - 0.022, 0);
|
|
5113
|
+
for (let i = 0; i < 8; i++) box2(pump, 6e-3, 0.044, 0.048, M.dark, x1 + 0.07 + i * 0.02, by - 0.022, 0);
|
|
5114
|
+
}
|
|
5115
|
+
if (o.heat) {
|
|
5116
|
+
cylinderX(group, r * 1.75, (L - x1) * 0.7, M.dark, x1 + (L - x1) * 0.4, by, 0, 12);
|
|
5117
|
+
for (let i = 0; i < 10; i++) box2(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);
|
|
5118
|
+
}
|
|
5119
|
+
if (o.bayo) box2(group, 0.025, 8e-3, 0.01, M.metal, L - 0.07, by - 0.016, 0);
|
|
5120
|
+
if (o.rod) cylinderX(group, 3e-3, (L - x1) * 0.85, M.steel, x1 + (L - x1) * 0.45, by - 0.014, 0, 8);
|
|
5093
5121
|
}
|
|
5094
5122
|
|
|
5095
|
-
// src/models/
|
|
5123
|
+
// src/models/rifle-forend.ts
|
|
5096
5124
|
var PI3 = Math.PI;
|
|
5097
|
-
function
|
|
5098
|
-
const {
|
|
5099
|
-
const
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
|
|
5106
|
-
|
|
5107
|
-
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
|
|
5113
|
-
|
|
5114
|
-
|
|
5115
|
-
|
|
5125
|
+
function buildForend(context) {
|
|
5126
|
+
const { kit, group, options: o, furniture: furn, length: L, receiverEnd: x1, receiverHeight: hR, receiverWidth: wR, barrelRadius: r, barrelY: by } = context;
|
|
5127
|
+
const { M, box: box2 } = kit;
|
|
5128
|
+
const hasLongScope = (o.scope ?? 0) >= 3;
|
|
5129
|
+
if (!context.isTraditional && o.hg !== "none") {
|
|
5130
|
+
const handguardLength = (L - x1) * (o.hgFrac || 0.5);
|
|
5131
|
+
const hx = x1 + handguardLength / 2;
|
|
5132
|
+
const hh = hR * 0.8;
|
|
5133
|
+
if (o.hg === "rail") {
|
|
5134
|
+
box2(group, handguardLength, hh, wR * 1.04, M.dark, hx, by - 2e-3, 0);
|
|
5135
|
+
rail(kit, group, x1, handguardLength, by + hh / 2, 0, wR * 0.66);
|
|
5136
|
+
rail(kit, group, x1 + 0.01, handguardLength - 0.02, by - 2e-3, wR * 0.54, wR * 0.4, PI3 / 2);
|
|
5137
|
+
rail(kit, group, x1 + 0.01, handguardLength - 0.02, by - 2e-3, -wR * 0.54, wR * 0.4, -PI3 / 2);
|
|
5138
|
+
rail(kit, group, x1 + 0.01, handguardLength - 0.02, by - hh / 2, 0, wR * 0.6, PI3);
|
|
5139
|
+
} else {
|
|
5140
|
+
const material = o.hg === "wood" ? M.wood : furn;
|
|
5141
|
+
if (o.ak) {
|
|
5142
|
+
box2(group, handguardLength, hh * 0.55, wR * 1.08, material, hx, by - hh * 0.22, 0);
|
|
5143
|
+
box2(group, handguardLength * 0.75, hh * 0.35, wR * 0.7, material, hx - handguardLength * 0.1, by + r * 2.2, 0);
|
|
5144
|
+
} else {
|
|
5145
|
+
box2(group, handguardLength, hh, wR * 1.08, material, hx, by - 2e-3, 0);
|
|
5146
|
+
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);
|
|
5147
|
+
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);
|
|
5148
|
+
}
|
|
5149
|
+
}
|
|
5150
|
+
if (!hasLongScope && !o.rail && o.ak) {
|
|
5151
|
+
box2(group, 0.03, 0.016, wR * 0.6, M.metal, x1 + 0.02, by + r * 2.5 + 0.01, 0);
|
|
5152
|
+
box2(group, 0.012, 4e-3, wR * 0.5, M.dark, x1 + 0.03, by + r * 2.5 + 0.019, 0);
|
|
5153
|
+
}
|
|
5154
|
+
}
|
|
5155
|
+
if (hasLongScope) return;
|
|
5156
|
+
const sightX = L - (o.ak ? 0.06 : 0.08);
|
|
5157
|
+
if (o.ak) {
|
|
5158
|
+
box2(group, 0.022, 0.022, wR * 0.6, M.metal, sightX, by + 8e-3, 0);
|
|
5159
|
+
box2(group, 6e-3, 0.024, 4e-3, M.metal, sightX, by + 0.026, 8e-3);
|
|
5160
|
+
box2(group, 6e-3, 0.024, 4e-3, M.metal, sightX, by + 0.026, -8e-3);
|
|
5161
|
+
box2(group, 3e-3, 0.016, 3e-3, M.dark, sightX, by + 0.022, 0);
|
|
5162
|
+
} else if (!o.rail || o.carry) {
|
|
5163
|
+
box2(group, 0.018, 0.014, wR * 0.55, M.dark, sightX, by + 8e-3, 0);
|
|
5164
|
+
box2(group, 0.012, 0.034, 8e-3, M.dark, sightX, by + 0.03, 0, -0.25);
|
|
5165
|
+
} else box2(group, 0.012, 0.024, 0.012, M.dark, sightX - 0.04, by + hR * 0.4 + 0.012, 0);
|
|
5116
5166
|
}
|
|
5117
|
-
|
|
5167
|
+
|
|
5168
|
+
// src/models/attachments/belt-box.ts
|
|
5169
|
+
function buildBeltBox(kit, belt) {
|
|
5118
5170
|
const { M, box: box2, cylinderX } = kit;
|
|
5119
|
-
|
|
5120
|
-
|
|
5121
|
-
|
|
5122
|
-
|
|
5123
|
-
|
|
5124
|
-
for (let i = 0; i < 4; i++) {
|
|
5125
|
-
const fin = box2(rocket, 0.06, 2e-3, diameter * 1.4, M.metal, -0.17, 0, 0);
|
|
5126
|
-
fin.rotation.x = i * PI3 / 4;
|
|
5171
|
+
box2(belt, 0.11, 0.1, 0.08, M.olive, 0, 0, 0);
|
|
5172
|
+
box2(belt, 0.112, 0.012, 0.082, M.dark, 0, 0.046, 0);
|
|
5173
|
+
for (let i = 0; i < 7; i++) {
|
|
5174
|
+
cylinderX(belt, 42e-4, 0.034, M.brass, -0.04 + i * 0.012, 0.07, 0.035, 10);
|
|
5175
|
+
box2(belt, 6e-3, 6e-3, 0.012, M.metal, -0.04 + i * 0.012, 0.066, 0.035);
|
|
5127
5176
|
}
|
|
5128
|
-
return rocket;
|
|
5129
5177
|
}
|
|
5130
5178
|
|
|
5131
|
-
// src/models/
|
|
5132
|
-
function
|
|
5133
|
-
const { M, box: box2,
|
|
5134
|
-
|
|
5135
|
-
|
|
5136
|
-
|
|
5137
|
-
heatify(parts.glow, cylinderX(group, 0.021, 0.83, M.steel, 0.545, 0, 0, 18));
|
|
5138
|
-
cylinderX(group, 0.03, 0.3, M.wood, 0.47, 0, 0, 16);
|
|
5139
|
-
cylinderX(group, 0.031, 0.012, M.metal, 0.32, 0, 0, 16);
|
|
5140
|
-
cylinderX(group, 0.031, 0.012, M.metal, 0.62, 0, 0, 16);
|
|
5141
|
-
cylinderX(group, 0.024, 0.02, M.metal, 0.94, 0, 0, 16);
|
|
5142
|
-
box2(group, 0.09, 0.03, 0.032, M.metal, 0.46, -0.028, 0);
|
|
5143
|
-
const frontGrip = kit.pivot(group, 0.4, -0.04, 0);
|
|
5144
|
-
frontGrip.rotation.z = -0.22;
|
|
5145
|
-
box2(frontGrip, 0.03, 0.1, 0.03, M.wood, 0, -0.05, 0);
|
|
5146
|
-
const rearGrip = kit.pivot(group, 0.5, -0.04, 0);
|
|
5147
|
-
rearGrip.rotation.z = -0.18;
|
|
5148
|
-
box2(rearGrip, 0.03, 0.1, 0.03, M.wood, 0, -0.05, 0);
|
|
5149
|
-
box2(group, 0.06, 4e-3, 0.012, M.metal, 0.53, -0.05, 0);
|
|
5150
|
-
box2(group, 4e-3, 0.025, 0.012, M.metal, 0.56, -0.04, 0);
|
|
5151
|
-
parts.trigger = box2(group, 4e-3, 0.018, 4e-3, M.dark, 0.535, -0.045, 0, 0.15);
|
|
5152
|
-
const hammer = kit.pivot(group, 0.44, -0.012, 0);
|
|
5153
|
-
parts.hammer = hammer;
|
|
5154
|
-
box2(hammer, 0.012, 0.02, 0.01, M.dark, 0, 0, 0);
|
|
5155
|
-
box2(group, 6e-3, 0.03, 6e-3, M.dark, 0.78, 0.032, 0);
|
|
5156
|
-
box2(group, 0.02, 0.022, 0.014, M.dark, 0.46, 0.032, 0);
|
|
5157
|
-
box2(group, 0.12, 0.042, 0.032, M.dark, 0.5, 0.04, -0.04);
|
|
5158
|
-
cylinderX(group, 0.013, 0.05, M.rubber, 0.42, 0.048, -0.04, 14);
|
|
5159
|
-
cylinderX(group, 0.016, 4e-3, M.lens, 0.565, 0.048, -0.04, 14);
|
|
5160
|
-
box2(group, 0.04, 0.012, 0.012, M.metal, 0.5, 0.016, -0.03);
|
|
5161
|
-
const round2 = buildRocketGrenade(kit);
|
|
5162
|
-
round2.position.x = 0.95;
|
|
5163
|
-
group.add(round2);
|
|
5164
|
-
parts.round = round2;
|
|
5165
|
-
parts.roundRest = 0.95;
|
|
5166
|
-
parts.makeRound = () => buildRocketGrenade(kit);
|
|
5167
|
-
parts.muzzle = kit.pivot(group, 0.95, 0, 0);
|
|
5168
|
-
parts.rear = kit.pivot(group, 0, 0, 0);
|
|
5169
|
-
}
|
|
5170
|
-
function buildM72(kit, group, parts) {
|
|
5171
|
-
const { M, box: box2, cylinderX, cylinderY } = kit;
|
|
5172
|
-
parts.kick = 1.1;
|
|
5173
|
-
parts.disposable = true;
|
|
5174
|
-
heatify(parts.glow, cylinderX(group, 0.0365, 0.6, M.olive, 0.58, 0, 0, 20));
|
|
5175
|
-
cylinderX(group, 0.032, 0.32, M.olive, 0.16, 0, 0, 20);
|
|
5176
|
-
cylinderX(group, 0.039, 0.03, M.rubber, 0.866, 0, 0, 20);
|
|
5177
|
-
cylinderX(group, 0.035, 0.025, M.rubber, 0.012, 0, 0, 20);
|
|
5178
|
-
cylinderX(group, 0.037, 0.015, M.yellow, 0.8, 0, 0, 20);
|
|
5179
|
-
cylinderX(group, 0.037, 0.012, M.dark, 0.3, 0, 0, 20);
|
|
5180
|
-
box2(group, 4e-3, 0.05, 0.05, M.dark, 0.79, 0.055, 0);
|
|
5181
|
-
box2(group, 4e-3, 6e-3, 0.04, M.dark, 0.79, 0.078, 0);
|
|
5182
|
-
box2(group, 4e-3, 0.035, 0.024, M.dark, 0.38, 0.05, 0);
|
|
5183
|
-
cylinderY(group, 4e-3, 6e-3, M.lens, 0.38, 0.064, 0, 8);
|
|
5184
|
-
parts.trigger = box2(group, 0.05, 0.016, 0.024, M.rubber, 0.5, 0.042, 0);
|
|
5185
|
-
box2(group, 0.1, 0.01, 0.03, M.dark, 0.47, 0.036, 0);
|
|
5186
|
-
box2(group, 0.02, 0.03, 0.01, M.dark, 0.66, -0.035, 0.03);
|
|
5187
|
-
box2(group, 8e-3, 0.03, 8e-3, M.metal, 0.25, -0.04, 0.03);
|
|
5188
|
-
parts.muzzle = kit.pivot(group, 0.881, 0, 0);
|
|
5189
|
-
parts.rear = kit.pivot(group, 0, 0, 0);
|
|
5190
|
-
}
|
|
5191
|
-
function buildAt4(kit, group, parts) {
|
|
5192
|
-
const { M, box: box2, cylinderX } = kit;
|
|
5193
|
-
parts.kick = 1.3;
|
|
5194
|
-
parts.disposable = true;
|
|
5195
|
-
heatify(parts.glow, cylinderX(group, 0.05, 0.86, M.olive, 0.51, 0, 0, 24));
|
|
5196
|
-
cylinderX(group, 0.056, 0.08, M.dark, 0.98, 0, 0, 24);
|
|
5197
|
-
cylinderX(group, 0.058, 0.07, M.dark, 0.04, 0, 0, 24, 0.05);
|
|
5198
|
-
cylinderX(group, 0.051, 0.015, M.yellow, 0.86, 0, 0, 24);
|
|
5199
|
-
box2(group, 0.16, 0.026, 0.05, M.dark, 0.42, 0.058, 0);
|
|
5200
|
-
box2(group, 0.03, 0.012, 0.016, M.red, 0.47, 0.075, 0);
|
|
5201
|
-
parts.trigger = box2(group, 0.022, 0.012, 0.018, M.rubber, 0.5, 0.074, 0);
|
|
5202
|
-
box2(group, 0.012, 0.07, 0.02, M.dark, 0.35, 0.09, -0.035);
|
|
5203
|
-
box2(group, 0.012, 0.05, 0.02, M.dark, 0.71, 0.08, -0.035);
|
|
5204
|
-
const grip = kit.pivot(group, 0.68, -0.05, 0);
|
|
5205
|
-
grip.rotation.z = -0.15;
|
|
5206
|
-
parts.grip = grip;
|
|
5207
|
-
box2(grip, 0.035, 0.11, 0.032, M.dark, 0, -0.05, 0);
|
|
5208
|
-
box2(group, 0.14, 0.035, 0.06, M.rubber, 0.32, -0.06, 0);
|
|
5209
|
-
box2(group, 0.3, 0.012, 0.055, M.dark, 0.5, -0.05, 0);
|
|
5210
|
-
parts.muzzle = kit.pivot(group, 1.02, 0, 0);
|
|
5211
|
-
parts.rear = kit.pivot(group, 0, 0, 0);
|
|
5212
|
-
}
|
|
5213
|
-
function buildCarlGustaf(kit, group, parts) {
|
|
5214
|
-
const { M, box: box2, cylinderX } = kit;
|
|
5215
|
-
parts.kick = 1.4;
|
|
5216
|
-
heatify(parts.glow, cylinderX(group, 0.045, 0.72, M.dark, 0.59, 0, 0, 24));
|
|
5217
|
-
cylinderX(group, 0.05, 0.04, M.rubber, 0.93, 0, 0, 24);
|
|
5218
|
-
const breech = kit.pivot(group, 0.21, 0, 0.05);
|
|
5219
|
-
parts.breech = [breech];
|
|
5220
|
-
cylinderX(breech, 0.06, 0.16, M.dark, -0.1, 0, -0.05, 24, 0.046);
|
|
5221
|
-
cylinderX(breech, 0.062, 0.015, M.metal, -0.18, 0, -0.05, 24);
|
|
5222
|
-
box2(group, 0.025, 0.03, 0.02, M.metal, 0.22, 0, 0.052);
|
|
5223
|
-
const foreGrip = kit.pivot(group, 0.62, -0.05, 0);
|
|
5224
|
-
foreGrip.rotation.z = -0.2;
|
|
5225
|
-
box2(foreGrip, 0.035, 0.11, 0.034, M.dark, 0, -0.05, 0);
|
|
5226
|
-
parts.trigger = box2(group, 4e-3, 0.018, 4e-3, M.dark, 0.66, -0.06, 0, 0.15);
|
|
5227
|
-
box2(group, 0.06, 4e-3, 0.012, M.metal, 0.66, -0.07, 0);
|
|
5228
|
-
const rearGrip = kit.pivot(group, 0.4, -0.05, 0);
|
|
5229
|
-
rearGrip.rotation.z = -0.25;
|
|
5230
|
-
box2(rearGrip, 0.035, 0.1, 0.034, M.dark, 0, -0.05, 0);
|
|
5231
|
-
box2(group, 0.13, 0.04, 0.07, M.rubber, 0.28, -0.065, 0);
|
|
5232
|
-
box2(group, 0.16, 0.05, 0.045, M.dark, 0.56, 0.07, -0.035);
|
|
5233
|
-
cylinderX(group, 0.016, 0.05, M.rubber, 0.46, 0.075, -0.035, 14);
|
|
5234
|
-
cylinderX(group, 0.02, 4e-3, M.lens, 0.645, 0.075, -0.035, 14);
|
|
5235
|
-
box2(group, 0.06, 0.02, 0.02, M.metal, 0.56, 0.04, -0.03);
|
|
5236
|
-
box2(group, 0.22, 0.01, 0.02, M.dark, 0.6, 0.06, 0.03);
|
|
5237
|
-
box2(group, 0.01, 0.03, 0.02, M.dark, 0.5, 0.05, 0.03);
|
|
5238
|
-
box2(group, 0.01, 0.03, 0.02, M.dark, 0.7, 0.05, 0.03);
|
|
5239
|
-
parts.makeRound = () => buildRecoillessRound(kit);
|
|
5240
|
-
parts.muzzle = kit.pivot(group, 0.95, 0, 0);
|
|
5241
|
-
parts.rear = kit.pivot(group, 0.05, 0, 0);
|
|
5179
|
+
// src/models/attachments/drum.ts
|
|
5180
|
+
function buildDrum(kit, magazine) {
|
|
5181
|
+
const { M, box: box2, cylinderZ } = kit;
|
|
5182
|
+
cylinderZ(magazine, 0.075, 0.07, M.dark, 0.02, -0.085, 0, 22);
|
|
5183
|
+
cylinderZ(magazine, 0.05, 0.074, M.metal, 0.02, -0.085, 0, 18);
|
|
5184
|
+
box2(magazine, 0.05, 0.04, 0.03, M.dark, 0, -0.02, 0);
|
|
5242
5185
|
}
|
|
5243
|
-
var ROCKET_BUILDERS = {
|
|
5244
|
-
rpg: buildRpg,
|
|
5245
|
-
m72: buildM72,
|
|
5246
|
-
at4: buildAt4,
|
|
5247
|
-
carl: buildCarlGustaf
|
|
5248
|
-
};
|
|
5249
5186
|
|
|
5250
|
-
// src/models/
|
|
5251
|
-
|
|
5252
|
-
|
|
5253
|
-
|
|
5254
|
-
|
|
5255
|
-
|
|
5256
|
-
|
|
5257
|
-
|
|
5258
|
-
|
|
5259
|
-
|
|
5260
|
-
|
|
5187
|
+
// src/models/helical-magazine.ts
|
|
5188
|
+
var PI4 = Math.PI;
|
|
5189
|
+
var LENGTH = 0.26;
|
|
5190
|
+
var RADIUS = 0.026;
|
|
5191
|
+
var TURNS = 11;
|
|
5192
|
+
function buildHelicalMagazine(context) {
|
|
5193
|
+
const { kit, group, parts, receiverEnd, barrelY, barrelRadius } = context;
|
|
5194
|
+
const { M, cylinderX, box: box2 } = kit;
|
|
5195
|
+
const x = receiverEnd + LENGTH / 2 + 0.02;
|
|
5196
|
+
const y = barrelY - barrelRadius - RADIUS - 0.012;
|
|
5197
|
+
const magazine = kit.pivot(group, x, y, 0);
|
|
5198
|
+
parts.mag = magazine;
|
|
5199
|
+
cylinderX(magazine, RADIUS, LENGTH, M.dark, 0, 0, 0, 20);
|
|
5200
|
+
cylinderX(magazine, RADIUS * 1.06, 0.01, M.metal, -LENGTH / 2, 0, 0, 20);
|
|
5201
|
+
cylinderX(magazine, RADIUS * 1.06, 0.01, M.metal, LENGTH / 2, 0, 0, 20);
|
|
5202
|
+
for (let i = 0; i < TURNS; i++) box2(magazine, 0.012, RADIUS * 2.15, 0.014, M.metal, -LENGTH / 2 + (i + 0.5) * LENGTH / TURNS, 0, 0, 0, 0, i * PI4 / 4);
|
|
5203
|
+
box2(magazine, 0.05, 0.03, 0.03, M.dark, -LENGTH / 2 - 0.02, RADIUS * 0.4, 0);
|
|
5204
|
+
parts.magDrop = 0.16;
|
|
5205
|
+
return x;
|
|
5261
5206
|
}
|
|
5262
5207
|
|
|
5263
|
-
// src/models/
|
|
5264
|
-
|
|
5265
|
-
|
|
5266
|
-
|
|
5267
|
-
|
|
5268
|
-
|
|
5269
|
-
|
|
5270
|
-
|
|
5271
|
-
|
|
5272
|
-
|
|
5273
|
-
|
|
5274
|
-
|
|
5275
|
-
for (let i = 0; i < BARRELS; i++) {
|
|
5276
|
-
const angle = i * 2 * PI4 / BARRELS;
|
|
5277
|
-
const y = Math.cos(angle) * CLUSTER_RADIUS;
|
|
5278
|
-
const z = Math.sin(angle) * CLUSTER_RADIUS;
|
|
5279
|
-
const barrel = cylinderX(barrels, BARREL_RADIUS, length, M.metal, 0.3 + length / 2, y, z, 14);
|
|
5280
|
-
if (heated) barrel.material = heated;
|
|
5281
|
-
else heated = heatify(parts.glow, barrel).material;
|
|
5282
|
-
cylinderX(barrels, BARREL_RADIUS * 0.55, 4e-3, M.hole, BARREL_END + 5e-4, y, z, 10);
|
|
5208
|
+
// src/models/rifle-controls.ts
|
|
5209
|
+
function buildGrip(context) {
|
|
5210
|
+
const { kit, group, parts, options: o, furniture: furn, receiverStart: x0, receiverHeight: hR, receiverWidth: wR } = context;
|
|
5211
|
+
const { M, box: box2 } = kit;
|
|
5212
|
+
const gx = x0 + (o.gripAt || 0.07);
|
|
5213
|
+
if (!context.isTraditional && o.grip !== "none") {
|
|
5214
|
+
const grip = kit.pivot(group, gx - 0.012, -hR / 2 - 0.046, 0);
|
|
5215
|
+
grip.rotation.z = -0.3;
|
|
5216
|
+
parts.grip = grip;
|
|
5217
|
+
box2(grip, 0.032, 0.105, 0.028, furn, 0, 0, 0);
|
|
5218
|
+
for (let i = 0; i < 3; i++) box2(grip, 6e-3, 0.012, 0.026, furn, 0.017, 0.022 - i * 0.02, 0);
|
|
5219
|
+
box2(grip, 0.034, 8e-3, 0.03, furn, 0, -0.052, 0);
|
|
5283
5220
|
}
|
|
5284
|
-
|
|
5285
|
-
|
|
5286
|
-
|
|
5221
|
+
box2(group, 0.06, 4e-3, 0.01, M.metal, gx + 0.03, -hR / 2 - 0.024, 0);
|
|
5222
|
+
box2(group, 4e-3, 0.022, 0.01, M.metal, gx + 0.06, -hR / 2 - 0.013, 0);
|
|
5223
|
+
parts.trigger = box2(group, 4e-3, 0.016, 4e-3, M.dark, gx + 0.024, -hR / 2 - 0.012, 0, 0.15);
|
|
5224
|
+
if (o.sel) parts.safety = box2(group, 0.016, 5e-3, 3e-3, M.dark, gx + 5e-3, -hR * 0.15, -wR / 2 - 2e-3, 0.4);
|
|
5225
|
+
return gx;
|
|
5287
5226
|
}
|
|
5288
|
-
function
|
|
5289
|
-
const {
|
|
5290
|
-
|
|
5291
|
-
|
|
5292
|
-
|
|
5293
|
-
|
|
5294
|
-
|
|
5295
|
-
|
|
5296
|
-
|
|
5297
|
-
|
|
5298
|
-
|
|
5299
|
-
|
|
5300
|
-
|
|
5227
|
+
function buildMagazine(context, gx) {
|
|
5228
|
+
const { kit, group, parts, options: o, receiverStart: x0, receiverHeight: hR, receiverWidth: wR, receiverLength: RL } = context;
|
|
5229
|
+
const { M, box: box2 } = kit;
|
|
5230
|
+
if (o.mag === "helical") return buildHelicalMagazine(context);
|
|
5231
|
+
const mx = o.magAt != null ? x0 + o.magAt : gx + 0.075;
|
|
5232
|
+
const scale = o.magLen || 1;
|
|
5233
|
+
const magazine = kit.pivot(group, mx, -hR / 2, 0);
|
|
5234
|
+
parts.mag = magazine;
|
|
5235
|
+
const finish = o.magMat === "bakelite" ? M.bakelite : o.magMat === "poly" ? M.polyMag : void 0;
|
|
5236
|
+
if (o.mag === "curved") {
|
|
5237
|
+
let px = 0;
|
|
5238
|
+
let py = 0;
|
|
5239
|
+
const material = finish ?? M.metal;
|
|
5240
|
+
for (const angle of [0.06, 0.22, 0.38]) {
|
|
5241
|
+
const length = 0.07 * scale;
|
|
5242
|
+
const cx = px + Math.sin(angle) * length / 2;
|
|
5243
|
+
const cy = py - Math.cos(angle) * length / 2;
|
|
5244
|
+
box2(magazine, 0.052, length + 4e-3, 0.024, material, cx, cy, 0, angle);
|
|
5245
|
+
box2(magazine, 0.04, length * 0.8, 0.026, M.dark, cx, cy, 0, angle);
|
|
5246
|
+
px += Math.sin(angle) * length;
|
|
5247
|
+
py -= Math.cos(angle) * length;
|
|
5248
|
+
}
|
|
5249
|
+
box2(magazine, 0.058, 8e-3, 0.028, material, px, py, 0, 0.38);
|
|
5250
|
+
parts.magDrop = 0.07 * scale * 3 + 0.04;
|
|
5251
|
+
} else if (o.mag === "box") {
|
|
5252
|
+
const length = 0.13 * scale;
|
|
5253
|
+
const curve = o.curve || 0;
|
|
5254
|
+
const segment = length / 3;
|
|
5255
|
+
const material = finish ?? M.dark;
|
|
5256
|
+
let px = 0;
|
|
5257
|
+
let py = 0;
|
|
5258
|
+
let angle = 0.08;
|
|
5259
|
+
for (let i = 0; i < 3; i++) {
|
|
5260
|
+
angle = 0.08 + curve * i;
|
|
5261
|
+
const cx = px + Math.sin(angle) * segment / 2;
|
|
5262
|
+
const cy = py - Math.cos(angle) * segment / 2;
|
|
5263
|
+
box2(magazine, 0.05, segment + 4e-3, 0.024, material, cx, cy, 0, angle);
|
|
5264
|
+
box2(magazine, 0.04, 3e-3, 0.026, M.metal, cx, cy, 0, angle);
|
|
5265
|
+
px += Math.sin(angle) * segment;
|
|
5266
|
+
py -= Math.cos(angle) * segment;
|
|
5267
|
+
}
|
|
5268
|
+
box2(magazine, 0.056, 7e-3, 0.028, material, px, py - 2e-3, 0, angle);
|
|
5269
|
+
parts.magDrop = length + 0.03;
|
|
5270
|
+
} else if (o.mag === "drum") {
|
|
5271
|
+
buildDrum(kit, magazine);
|
|
5272
|
+
parts.magDrop = 0.2;
|
|
5273
|
+
} else if (o.mag === "internal") {
|
|
5274
|
+
box2(group, 0.08, 0.025, 0.03, context.isTraditional ? context.furniture : M.metal, mx, -hR / 2 - 0.012, 0);
|
|
5275
|
+
parts.mag = null;
|
|
5276
|
+
} else parts.mag = null;
|
|
5277
|
+
if (o.mag === "belt") {
|
|
5278
|
+
const belt = kit.pivot(group, mx + 0.02, -hR / 2 - 0.05, -0.045);
|
|
5279
|
+
parts.belt = belt;
|
|
5280
|
+
buildBeltBox(kit, belt);
|
|
5281
|
+
const cover = kit.pivot(group, x0 + 0.01, hR / 2, 0);
|
|
5282
|
+
parts.cover = cover;
|
|
5283
|
+
box2(cover, RL - 0.03, 0.014, wR * 1.05, M.metal, (RL - 0.03) / 2, 7e-3, 0);
|
|
5284
|
+
box2(cover, 0.02, 0.012, wR * 0.6, M.dark, RL - 0.04, 0.016, 0);
|
|
5301
5285
|
}
|
|
5302
|
-
|
|
5303
|
-
parts.safety = box2(group, 0.014, 6e-3, 0.01, M.dark, 0.2, 0.073, -0.076, 0.4);
|
|
5286
|
+
return mx;
|
|
5304
5287
|
}
|
|
5305
|
-
|
|
5288
|
+
|
|
5289
|
+
// src/models/rifle-stock.ts
|
|
5290
|
+
function buildStock(context, magazineX) {
|
|
5291
|
+
const { kit, group, options: o, furniture: furn, length: L, stockLength: S, receiverStart: x0, receiverEnd: x1, receiverHeight: hR } = context;
|
|
5306
5292
|
const { M, box: box2, cylinderX } = kit;
|
|
5307
|
-
|
|
5308
|
-
|
|
5309
|
-
|
|
5310
|
-
|
|
5311
|
-
|
|
5312
|
-
|
|
5313
|
-
|
|
5314
|
-
|
|
5315
|
-
|
|
5316
|
-
|
|
5317
|
-
|
|
5318
|
-
|
|
5319
|
-
|
|
5320
|
-
|
|
5321
|
-
|
|
5322
|
-
|
|
5323
|
-
|
|
5324
|
-
|
|
5325
|
-
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
|
|
5332
|
-
|
|
5333
|
-
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
};
|
|
5342
|
-
parts.muzzle = kit.mark(group, BARREL_END + 0.01, 0, 0);
|
|
5343
|
-
parts.eject = kit.mark(group, 0.3, -0.07, 0.08);
|
|
5344
|
-
return { group, parts };
|
|
5293
|
+
if (context.isTraditional) {
|
|
5294
|
+
buttpad(kit, group, 6e-3, -0.04, 0.13, 0.038);
|
|
5295
|
+
box2(group, 0.03, 0.13, 0.038, furn, 0.024, -0.04, 0);
|
|
5296
|
+
box2(group, S, 0.055, 0.034, furn, S / 2, -0.012, 0, 0.06);
|
|
5297
|
+
box2(group, 0.09, 0.05, 0.032, furn, x0 - 0.02, -0.035, 0, 0.25);
|
|
5298
|
+
const forendLength = x1 - x0 + (L - x1) * (o.fore ?? 0.62);
|
|
5299
|
+
if (forendLength > 0) box2(group, forendLength, 0.045, 0.04, furn, x0 + forendLength / 2, -hR / 2 + 4e-3, 0);
|
|
5300
|
+
if (o.stock === "straight") box2(group, 0.15, 0.04, 0.035, furn, x1 + 0.08, -hR / 2, 0);
|
|
5301
|
+
box2(group, 0.04, 4e-3, 0.03, M.metal, magazineX, -hR / 2 - 0.022, 0);
|
|
5302
|
+
swivel(kit, group, 0.2, -0.08);
|
|
5303
|
+
swivel(kit, group, x1 + (L - x1) * 0.45, -hR / 2 - 0.03);
|
|
5304
|
+
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);
|
|
5305
|
+
} else if (o.stock === "fixed" || o.stock === "wood") {
|
|
5306
|
+
box2(group, S, 0.05, 0.03, furn, S / 2, -8e-3, 0, 0.05);
|
|
5307
|
+
box2(group, 0.03, 0.13, 0.036, furn, 0.022, -0.035, 0);
|
|
5308
|
+
buttpad(kit, group, 4e-3, -0.035, 0.13, 0.036);
|
|
5309
|
+
if (o.stock === "wood") box2(group, S * 0.6, 0.03, 0.028, furn, S * 0.55, -0.045, 0, 0.2);
|
|
5310
|
+
swivel(kit, group, 0.08, -0.09);
|
|
5311
|
+
} else if (o.stock === "skeleton") {
|
|
5312
|
+
box2(group, S, 0.014, 0.026, furn, S / 2, 0.012, 0, 0.03);
|
|
5313
|
+
box2(group, S, 0.014, 0.026, furn, S / 2, -0.05, 0, -0.08);
|
|
5314
|
+
box2(group, 0.03, 0.12, 0.034, furn, 0.02, -0.025, 0);
|
|
5315
|
+
buttpad(kit, group, 4e-3, -0.025, 0.12, 0.034);
|
|
5316
|
+
} else if (o.stock === "retract") {
|
|
5317
|
+
cylinderX(group, 0.013, S, M.metal, S / 2, 0, 0, 16);
|
|
5318
|
+
for (let i = 0; i < 5; i++) box2(group, 3e-3, 3e-3, 8e-3, M.dark, S * 0.2 + i * 0.015, -0.013, 0);
|
|
5319
|
+
box2(group, 0.034, 0.11, 0.036, furn, 0.02, -0.025, 0);
|
|
5320
|
+
box2(group, S * 0.55, 0.032, 0.03, furn, S * 0.35, 0, 0);
|
|
5321
|
+
buttpad(kit, group, 3e-3, -0.025, 0.11, 0.036);
|
|
5322
|
+
} else if (o.stock === "fold") {
|
|
5323
|
+
box2(group, S, 6e-3, 6e-3, M.metal, S / 2, 0.01, 0.012);
|
|
5324
|
+
box2(group, S, 6e-3, 6e-3, M.metal, S / 2, -0.04, 0.012, -0.12);
|
|
5325
|
+
box2(group, 0.012, 0.1, 0.03, M.metal, 6e-3, -0.02, 0.012);
|
|
5326
|
+
}
|
|
5345
5327
|
}
|
|
5346
5328
|
|
|
5347
|
-
// src/models/
|
|
5348
|
-
|
|
5349
|
-
|
|
5350
|
-
const group =
|
|
5351
|
-
const
|
|
5352
|
-
|
|
5353
|
-
|
|
5354
|
-
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
|
|
5362
|
-
|
|
5363
|
-
|
|
5364
|
-
|
|
5365
|
-
|
|
5366
|
-
|
|
5367
|
-
|
|
5368
|
-
|
|
5329
|
+
// src/models/rifle.ts
|
|
5330
|
+
var PI5 = Math.PI;
|
|
5331
|
+
function buildReceiver(context) {
|
|
5332
|
+
const { kit, group, parts, options: o, length: L, receiverStart: x0, receiverEnd: x1, receiverHeight: hR, receiverWidth: wR, receiverLength: RL, barrelY: by } = context;
|
|
5333
|
+
const { M, box: box2, cylinderX, cylinderY, cylinderZ, sphere } = kit;
|
|
5334
|
+
const receiverMaterial = o.tan ? M.tan : M.metal;
|
|
5335
|
+
const middle = (x0 + x1) / 2;
|
|
5336
|
+
if (o.round) {
|
|
5337
|
+
cylinderX(group, hR * 0.36, RL, M.steel, middle, by, 0, 20);
|
|
5338
|
+
cylinderX(group, hR * 0.32, 0.05, M.steel, x0 - 0.01, by, 0, 18);
|
|
5339
|
+
} else if (o.ar) {
|
|
5340
|
+
box2(group, RL, hR * 0.5, wR, receiverMaterial, middle, hR * 0.25, 0);
|
|
5341
|
+
box2(group, RL * 0.92, hR * 0.52, wR * 0.96, receiverMaterial, middle - RL * 0.02, -hR * 0.24, 0);
|
|
5342
|
+
box2(group, 0.05, 0.03, wR * 1.15, receiverMaterial, x0 + RL * 0.62, -hR * 0.5 - 0.01, 0);
|
|
5343
|
+
cylinderZ(group, 6e-3, 0.012, M.metal, x1 - 0.03, hR * 0.28, wR / 2 + 6e-3, 12);
|
|
5344
|
+
box2(group, 0.012, 0.01, 0.012, M.metal, x1 - 0.05, hR * 0.12, wR / 2 + 6e-3);
|
|
5345
|
+
box2(group, 0.03, 8e-3, 0.012, M.dark, x0 + 0.02, hR / 2 + 4e-3, 0);
|
|
5346
|
+
box2(group, 0.012, 6e-3, 4e-3, M.dark, x0 + RL * 0.55, -hR * 0.15, -wR / 2 - 2e-3);
|
|
5347
|
+
} else box2(group, RL, hR, wR, receiverMaterial, middle, 0, 0);
|
|
5348
|
+
if (o.ak) {
|
|
5349
|
+
box2(group, RL * 0.86, hR * 0.28, wR * 0.95, M.metal, middle - 8e-3, hR / 2 + 4e-3, 0);
|
|
5350
|
+
for (let i = 0; i < 3; i++) box2(group, 4e-3, hR * 0.3, wR * 0.97, M.dark, x0 + RL * 0.25 + i * 0.02, hR / 2 + 4e-3, 0);
|
|
5351
|
+
box2(group, RL * 0.5, 0.012, 3e-3, M.metal, x0 + RL * 0.55, -hR * 0.02, wR / 2 + 15e-4, -0.05);
|
|
5352
|
+
box2(group, 0.012, 0.014, 3e-3, M.dark, x0 + RL * 0.32, -hR * 0.05, wR / 2 + 2e-3);
|
|
5353
|
+
}
|
|
5354
|
+
if (o.g3) {
|
|
5355
|
+
cylinderX(group, 9e-3, (L - x1) * 0.6, M.metal, x1 + (L - x1) * 0.28, hR * 0.48, 0, 14);
|
|
5356
|
+
box2(group, 0.012, 0.024, 8e-3, M.dark, x1 + (L - x1) * 0.5, hR * 0.48, -0.012);
|
|
5357
|
+
cylinderY(group, 0.012, 0.016, M.dark, x0 + 0.03, hR / 2 + 8e-3, 0, 12);
|
|
5358
|
+
}
|
|
5359
|
+
const ejectX = x1 - (o.ejectBack || 0.07);
|
|
5360
|
+
const ejectY = o.ar ? hR * 0.2 : by;
|
|
5361
|
+
box2(group, 0.05, hR * 0.36, 4e-3, M.hole, ejectX, ejectY, wR / 2 - 4e-4);
|
|
5369
5362
|
const bolt = kit.pivot(group);
|
|
5370
5363
|
parts.bolt = bolt;
|
|
5371
|
-
|
|
5372
|
-
|
|
5373
|
-
|
|
5374
|
-
|
|
5375
|
-
|
|
5376
|
-
|
|
5377
|
-
box2(
|
|
5378
|
-
|
|
5379
|
-
parts.muzzle = kit.mark(group, 1.72, 0.01, 0);
|
|
5380
|
-
parts.eject = kit.mark(group, 0.3, -0.07, 0);
|
|
5381
|
-
return { group, parts };
|
|
5364
|
+
parts.stroke = Math.min(0.1, RL * 0.32);
|
|
5365
|
+
box2(bolt, 0.044, hR * 0.26, 6e-3, M.steelL, ejectX, ejectY, wR / 2 - 12e-4);
|
|
5366
|
+
if (o.charge) {
|
|
5367
|
+
box2(bolt, 0.012, 0.01, 0.03, M.metal, ejectX + 0.04, ejectY + 4e-3, wR / 2 + 0.012);
|
|
5368
|
+
sphere(bolt, 65e-4, M.metal, ejectX + 0.04, ejectY + 4e-3, wR / 2 + 0.028, 1);
|
|
5369
|
+
}
|
|
5370
|
+
if (o.ar) box2(group, 0.012, 0.016, 6e-3, receiverMaterial, ejectX - 0.03, ejectY + 4e-3, wR / 2 + 4e-3);
|
|
5371
|
+
if (o.rail) rail(kit, group, x0 - 5e-3, RL + 0.07, hR / 2 + (o.ar ? 0 : 3e-3), 0, wR * 0.68);
|
|
5382
5372
|
}
|
|
5383
|
-
|
|
5384
|
-
|
|
5385
|
-
function buildP90(kit) {
|
|
5373
|
+
function buildBarrel(context) {
|
|
5374
|
+
const { kit, group, parts, options: o, length: L, barrelLength: Bl, receiverEnd: x1, barrelRadius: r, barrelY: by } = context;
|
|
5386
5375
|
const { M, box: box2, cylinderX } = kit;
|
|
5376
|
+
heatify(parts.glow, cylinderX(group, r, Bl, M.metal, L - Bl / 2, by, 0, 16));
|
|
5377
|
+
if (o.jacket) {
|
|
5378
|
+
cylinderX(group, r * 2, (L - x1) * 0.6, M.dark, x1 + (L - x1) * 0.3, by, 0, 16);
|
|
5379
|
+
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);
|
|
5380
|
+
}
|
|
5381
|
+
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);
|
|
5382
|
+
if (o.brake) {
|
|
5383
|
+
const kind = o.brake === 2 ? 2 : 1;
|
|
5384
|
+
recordFitting(parts, kind === 2 ? "muzzle_brake_heavy" : "muzzle_brake", group, () => buildBrake(kit, group, kind, L, by, r, (body) => void heatify(parts.glow, body)));
|
|
5385
|
+
} else if (!o.noFH) {
|
|
5386
|
+
recordFitting(parts, "muzzle_default", group, () => {
|
|
5387
|
+
heatify(parts.glow, cylinderX(group, r * 1.45, 0.042, M.dark, L - 0.021, by, 0, 16));
|
|
5388
|
+
for (let i = 0; i < 4; i++) {
|
|
5389
|
+
const angle = i * PI5 / 2 + PI5 / 4;
|
|
5390
|
+
box2(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);
|
|
5391
|
+
}
|
|
5392
|
+
});
|
|
5393
|
+
}
|
|
5394
|
+
cylinderX(group, r * 0.55, 4e-3, M.hole, L + 5e-4, by, 0, 12);
|
|
5395
|
+
}
|
|
5396
|
+
var familyOf = (o) => {
|
|
5397
|
+
if (o.mag === "belt") return "belt";
|
|
5398
|
+
if (o.pump) return "pump";
|
|
5399
|
+
if (o.lever) return "lever";
|
|
5400
|
+
if (o.tube) return "semi12";
|
|
5401
|
+
if (o.bolt) return o.mag === "box" ? "boltmag" : "bolt";
|
|
5402
|
+
return o.mag === "internal" ? "semiint" : "rifle";
|
|
5403
|
+
};
|
|
5404
|
+
function buildRifle(kit, options) {
|
|
5405
|
+
const { M } = kit;
|
|
5387
5406
|
const group = kit.group();
|
|
5388
|
-
const parts = { family: "
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
const
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
|
|
5407
|
+
const parts = { family: "rifle", glow: [] };
|
|
5408
|
+
const length = (options.L ?? 0) / 1e3;
|
|
5409
|
+
const barrelLength = (options.B ?? 0) / 1e3;
|
|
5410
|
+
const isTraditional = options.stock === "trad" || options.stock === "straight";
|
|
5411
|
+
const stockLength = options.stock === "none" ? 0 : options.stockLen || Math.min(0.36, Math.max(0.2, 0.3 * length));
|
|
5412
|
+
const receiverStart = stockLength;
|
|
5413
|
+
const receiverEnd = Math.max(receiverStart + 0.12, length - barrelLength * 0.92);
|
|
5414
|
+
const receiverHeight = options.hR || 0.06;
|
|
5415
|
+
const context = {
|
|
5416
|
+
kit,
|
|
5417
|
+
group,
|
|
5418
|
+
parts,
|
|
5419
|
+
options,
|
|
5420
|
+
furniture: options.wood ? M.wood : options.olive ? M.olive : options.tan ? M.tan : M.poly,
|
|
5421
|
+
isTraditional,
|
|
5422
|
+
length,
|
|
5423
|
+
barrelLength,
|
|
5424
|
+
stockLength,
|
|
5425
|
+
receiverStart,
|
|
5426
|
+
receiverEnd,
|
|
5427
|
+
receiverHeight,
|
|
5428
|
+
receiverWidth: options.wR || 0.034,
|
|
5429
|
+
barrelRadius: options.br || 85e-4,
|
|
5430
|
+
barrelY: receiverHeight * 0.15,
|
|
5431
|
+
receiverLength: receiverEnd - receiverStart
|
|
5432
|
+
};
|
|
5433
|
+
buildReceiver(context);
|
|
5434
|
+
buildBarrel(context);
|
|
5435
|
+
buildForend(context);
|
|
5436
|
+
const gripX = buildGrip(context);
|
|
5437
|
+
const magazineX = buildMagazine(context, gripX);
|
|
5438
|
+
parts.stockMeshes = context.isTraditional ? [] : captured(group, () => buildStock(context, magazineX));
|
|
5439
|
+
if (context.isTraditional) buildStock(context, magazineX);
|
|
5440
|
+
buildFittings(context, gripX);
|
|
5441
|
+
const hasHandguard = !context.isTraditional && options.hg !== "none";
|
|
5442
|
+
parts.frames = {
|
|
5443
|
+
length,
|
|
5444
|
+
barrelY: context.barrelY,
|
|
5445
|
+
barrelRadius: context.barrelRadius,
|
|
5446
|
+
receiverStart,
|
|
5447
|
+
receiverEnd,
|
|
5448
|
+
receiverHeight,
|
|
5449
|
+
receiverWidth: context.receiverWidth,
|
|
5450
|
+
handguardEnd: receiverEnd + (length - receiverEnd) * (hasHandguard ? options.hgFrac || 0.5 : 0.4),
|
|
5451
|
+
magazineX,
|
|
5452
|
+
gripX,
|
|
5453
|
+
hasRail: Boolean(options.rail)
|
|
5454
|
+
};
|
|
5455
|
+
const { barrelY: by, receiverWidth: wR } = context;
|
|
5456
|
+
const ejectX = receiverEnd - (options.ejectBack || 0.07);
|
|
5457
|
+
const ejectY = options.ar ? receiverHeight * 0.2 : by;
|
|
5458
|
+
parts.muzzle = kit.mark(group, length + 0.01, by, 0);
|
|
5459
|
+
parts.eject = kit.mark(group, ejectX, ejectY, wR / 2 + 6e-3);
|
|
5460
|
+
parts.loadPort = kit.mark(group, receiverEnd - 0.05, -receiverHeight / 2 - 4e-3, 0);
|
|
5461
|
+
parts.topLoad = kit.mark(group, ejectX, receiverHeight / 2 + 4e-3, 0);
|
|
5462
|
+
parts.family = familyOf(options);
|
|
5408
5463
|
return { group, parts };
|
|
5409
5464
|
}
|
|
5410
5465
|
|
|
5411
|
-
// src/models/
|
|
5412
|
-
|
|
5413
|
-
|
|
5414
|
-
const
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
|
|
5466
|
+
// src/models/break-launcher.ts
|
|
5467
|
+
function buildBreakLauncher(kit, options) {
|
|
5468
|
+
const built = buildRifle(kit, options);
|
|
5469
|
+
const { group, parts } = built;
|
|
5470
|
+
const frames = parts.frames;
|
|
5471
|
+
if (!frames) return built;
|
|
5472
|
+
const hingeY = frames.barrelY - frames.barrelRadius;
|
|
5473
|
+
const barrels = kit.pivot(group, frames.receiverEnd, hingeY, 0);
|
|
5474
|
+
group.updateMatrixWorld(true);
|
|
5475
|
+
const centre = new kit.THREE.Vector3();
|
|
5476
|
+
for (const child of [...group.children]) {
|
|
5477
|
+
if (child === barrels) continue;
|
|
5478
|
+
const mesh = child;
|
|
5479
|
+
const isAhead = mesh.isMesh ? new kit.THREE.Box3().setFromObject(mesh).getCenter(centre).x > frames.receiverEnd : child === parts.muzzle;
|
|
5480
|
+
if (isAhead) barrels.attach(child);
|
|
5418
5481
|
}
|
|
5419
|
-
parts.
|
|
5420
|
-
parts.
|
|
5421
|
-
|
|
5482
|
+
parts.barrels = barrels;
|
|
5483
|
+
parts.breech = [kit.mark(barrels, 4e-3, frames.barrelY - hingeY, 0)];
|
|
5484
|
+
parts.eject = parts.breech[0];
|
|
5485
|
+
parts.family = "break";
|
|
5486
|
+
return built;
|
|
5422
5487
|
}
|
|
5423
5488
|
|
|
5424
|
-
// src/models/
|
|
5425
|
-
var
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
5446
|
-
|
|
5447
|
-
|
|
5448
|
-
box2
|
|
5449
|
-
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
|
|
5456
|
-
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
|
|
5463
|
-
|
|
5489
|
+
// src/models/attachments/mount-frames.ts
|
|
5490
|
+
var DEFAULT_BARREL_RADIUS = 85e-4;
|
|
5491
|
+
var DEFAULT_RECEIVER_WIDTH = 0.034;
|
|
5492
|
+
var RECEIVER_START_FRACTION = 0.25;
|
|
5493
|
+
var RECEIVER_END_FRACTION = 0.55;
|
|
5494
|
+
var RECEIVER_HEIGHT_FRACTION = 0.4;
|
|
5495
|
+
var DEFAULT_GRIP_OFFSET = 0.07;
|
|
5496
|
+
var HANDGUARD_FRACTION = 0.5;
|
|
5497
|
+
function deriveFrames(THREE, model) {
|
|
5498
|
+
const { root, inner, parts } = model;
|
|
5499
|
+
root.updateMatrixWorld(true);
|
|
5500
|
+
const box2 = new THREE.Box3().setFromObject(root);
|
|
5501
|
+
const span = box2.max.x - box2.min.x;
|
|
5502
|
+
const toInnerX = (x) => (x - inner.position.x) / inner.scale.x;
|
|
5503
|
+
const muzzle = parts.muzzle?.position;
|
|
5504
|
+
const length = muzzle ? muzzle.x - 0.01 : toInnerX(box2.max.x);
|
|
5505
|
+
const receiverStart = toInnerX(box2.min.x + span * RECEIVER_START_FRACTION);
|
|
5506
|
+
const receiverEnd = toInnerX(box2.min.x + span * RECEIVER_END_FRACTION);
|
|
5507
|
+
return {
|
|
5508
|
+
length,
|
|
5509
|
+
barrelY: muzzle?.y ?? (box2.max.y + box2.min.y) / 2,
|
|
5510
|
+
barrelRadius: DEFAULT_BARREL_RADIUS,
|
|
5511
|
+
receiverStart,
|
|
5512
|
+
receiverEnd,
|
|
5513
|
+
receiverHeight: (box2.max.y - box2.min.y) * RECEIVER_HEIGHT_FRACTION,
|
|
5514
|
+
receiverWidth: Math.min(DEFAULT_RECEIVER_WIDTH, box2.max.z - box2.min.z),
|
|
5515
|
+
handguardEnd: receiverEnd + (length - receiverEnd) * HANDGUARD_FRACTION,
|
|
5516
|
+
magazineX: parts.mag ? parts.mag.position.x : (receiverStart + receiverEnd) / 2,
|
|
5517
|
+
gripX: receiverStart + DEFAULT_GRIP_OFFSET,
|
|
5518
|
+
hasRail: false
|
|
5519
|
+
};
|
|
5520
|
+
}
|
|
5521
|
+
function mountFrame(model, mount) {
|
|
5522
|
+
const frames = model.parts.frames;
|
|
5523
|
+
if (!frames) return void 0;
|
|
5524
|
+
const { inner } = model;
|
|
5525
|
+
const toRoot = (x, y, z) => [inner.position.x + x * inner.scale.x, y, z];
|
|
5526
|
+
const handguardHeight = frames.receiverHeight * 0.8;
|
|
5527
|
+
const railTopY = frames.receiverHeight / 2 + (frames.hasRail ? 6e-3 : 0);
|
|
5528
|
+
const forendMiddle = (frames.receiverEnd + frames.handguardEnd) / 2;
|
|
5529
|
+
const base = { mount, barrelRadius: frames.barrelRadius, receiverWidth: frames.receiverWidth, receiverHeight: frames.receiverHeight, hasRail: frames.hasRail };
|
|
5530
|
+
switch (mount) {
|
|
5531
|
+
case "muzzle":
|
|
5532
|
+
return { ...base, position: toRoot(frames.length, frames.barrelY, 0), side: 0 };
|
|
5533
|
+
case "rail_top":
|
|
5534
|
+
return { ...base, position: toRoot((frames.receiverStart + frames.receiverEnd) / 2 + 0.03, railTopY, 0), side: 0 };
|
|
5535
|
+
case "rail_bottom":
|
|
5536
|
+
return { ...base, position: toRoot(forendMiddle, frames.barrelY - handguardHeight / 2, 0), side: 0 };
|
|
5537
|
+
case "rail_left":
|
|
5538
|
+
return { ...base, position: toRoot(forendMiddle, frames.barrelY, -(frames.receiverWidth * 0.54 + 4e-3)), side: -1 };
|
|
5539
|
+
case "rail_right":
|
|
5540
|
+
return { ...base, position: toRoot(forendMiddle, frames.barrelY, frames.receiverWidth * 0.54 + 4e-3), side: 1 };
|
|
5541
|
+
case "underbarrel": {
|
|
5542
|
+
const [x, y] = frames.underbarrel ?? [frames.receiverEnd + (frames.handguardEnd - frames.receiverEnd) * 0.25, frames.barrelY - handguardHeight / 2 - 0.02];
|
|
5543
|
+
return { ...base, position: toRoot(x, y, 0), side: 0 };
|
|
5544
|
+
}
|
|
5545
|
+
case "magazine":
|
|
5546
|
+
return { ...base, position: toRoot(frames.magazineX, -frames.receiverHeight / 2, 0), side: 0 };
|
|
5547
|
+
case "feed": {
|
|
5548
|
+
const belt = model.parts.belt?.position;
|
|
5549
|
+
return { ...base, position: belt ? toRoot(belt.x, belt.y, belt.z) : toRoot(frames.magazineX + 0.02, -frames.receiverHeight / 2 - 0.05, -0.045), side: -1 };
|
|
5550
|
+
}
|
|
5551
|
+
case "sling":
|
|
5552
|
+
return {
|
|
5553
|
+
...base,
|
|
5554
|
+
position: toRoot(frames.receiverEnd + (frames.length - frames.receiverEnd) * 0.45, -frames.receiverHeight / 2 - 0.03, 0),
|
|
5555
|
+
secondary: toRoot(0.08, -0.09, 0),
|
|
5556
|
+
side: 0
|
|
5557
|
+
};
|
|
5558
|
+
default:
|
|
5559
|
+
return void 0;
|
|
5464
5560
|
}
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5469
|
-
|
|
5470
|
-
|
|
5471
|
-
|
|
5472
|
-
|
|
5473
|
-
|
|
5474
|
-
|
|
5561
|
+
}
|
|
5562
|
+
|
|
5563
|
+
// src/models/bullpup.ts
|
|
5564
|
+
function buildBullpup(kit, options) {
|
|
5565
|
+
const { M, box: box2, cylinderX } = kit;
|
|
5566
|
+
const group = kit.group();
|
|
5567
|
+
const L = (options.L ?? 0) / 1e3;
|
|
5568
|
+
const barrel = (options.B ?? 0) / 1e3;
|
|
5569
|
+
const bodyLength = Math.max(0.32, L - barrel * 0.72);
|
|
5570
|
+
const body = options.shot ? M.poly : M.olive;
|
|
5571
|
+
const parts = { family: options.shot ? "pump" : "rifle", stroke: 0.06, glow: [] };
|
|
5572
|
+
box2(group, bodyLength, 0.075, 0.042, body, bodyLength / 2, 0, 0);
|
|
5573
|
+
box2(group, bodyLength * 0.9, 0.02, 0.044, M.dark, bodyLength * 0.5, -0.02, 0);
|
|
5574
|
+
box2(group, 0.032, 0.13, 0.044, M.rubber, 0.016, -0.025, 0);
|
|
5575
|
+
const gx = bodyLength * 0.8;
|
|
5576
|
+
const grip = kit.pivot(group, gx, -0.085, 0);
|
|
5577
|
+
grip.rotation.z = -0.25;
|
|
5578
|
+
parts.grip = grip;
|
|
5579
|
+
box2(grip, 0.03, 0.1, 0.03, M.poly, 0, 0, 0);
|
|
5580
|
+
box2(group, 0.1, 6e-3, 0.03, body, gx + 0.01, -0.06, 0);
|
|
5581
|
+
parts.trigger = box2(group, 4e-3, 0.016, 4e-3, M.dark, gx + 0.02, -0.05, 0, 0.15);
|
|
5582
|
+
heatify(parts.glow, cylinderX(group, options.shot ? 0.0105 : 85e-4, barrel, M.metal, L - barrel / 2, 0.012, 0, 16));
|
|
5583
|
+
cylinderX(group, 6e-3, 4e-3, M.hole, L + 1e-3, 0.012, 0, 12);
|
|
5584
|
+
box2(group, 0.05, 0.024, 4e-3, M.hole, bodyLength * 0.25, 5e-3, 0.0212);
|
|
5585
|
+
const bolt = kit.pivot(group);
|
|
5586
|
+
parts.bolt = bolt;
|
|
5587
|
+
box2(bolt, 0.044, 0.02, 6e-3, M.steelL, bodyLength * 0.25, 5e-3, 0.02);
|
|
5588
|
+
if (options.shot) {
|
|
5589
|
+
cylinderX(group, 0.012, bodyLength * 0.75, M.metal, bodyLength * 0.55, -0.025, 0.014, 14);
|
|
5590
|
+
cylinderX(group, 0.012, bodyLength * 0.75, M.metal, bodyLength * 0.55, -0.025, -0.014, 14);
|
|
5591
|
+
const pump = kit.pivot(group);
|
|
5592
|
+
parts.pump = pump;
|
|
5593
|
+
box2(pump, 0.15, 0.045, 0.052, M.poly, bodyLength + 0.06, -0.015, 0);
|
|
5594
|
+
for (let i = 0; i < 6; i++) box2(pump, 6e-3, 0.047, 0.054, M.dark, bodyLength + 5e-3 + i * 0.022, -0.015, 0);
|
|
5595
|
+
rail(kit, group, bodyLength * 0.15, bodyLength * 0.8, 0.04, 0, 0.02);
|
|
5596
|
+
parts.loadPort = kit.mark(group, bodyLength * 0.2, -0.04, 0);
|
|
5475
5597
|
} else {
|
|
5476
|
-
|
|
5477
|
-
|
|
5478
|
-
|
|
5479
|
-
|
|
5480
|
-
|
|
5481
|
-
|
|
5482
|
-
|
|
5483
|
-
|
|
5484
|
-
|
|
5485
|
-
const selector = box2(slide2, 0.01, 8e-3, 3e-3, M.dark, 0.014, -slideHeight * 0.2, slideWidth / 2 + 14e-4);
|
|
5486
|
-
parts.safety ?? (parts.safety = selector);
|
|
5598
|
+
const magazine = kit.pivot(group, gx - 0.11, -0.03, 0);
|
|
5599
|
+
magazine.rotation.z = 0.14;
|
|
5600
|
+
parts.mag = magazine;
|
|
5601
|
+
box2(magazine, 0.05, 0.14, 0.026, M.glass, 0, -0.07, 0);
|
|
5602
|
+
for (let i = 0; i < 6; i++) cylinderX(magazine, 3e-3, 0.04, M.brass, 0, -0.01 - i * 0.02, 0, 6);
|
|
5603
|
+
parts.magDrop = 0.18;
|
|
5604
|
+
scope(kit, group, 2, bodyLength * 0.5, 0.04, 0);
|
|
5605
|
+
box2(group, 0.2, 0.03, 0.02, body, bodyLength * 0.62, 0.048, 0);
|
|
5606
|
+
box2(group, 0.026, 0.075, 0.026, body, bodyLength + 0.05, -0.05, 0, 0.1);
|
|
5487
5607
|
}
|
|
5608
|
+
parts.muzzle = kit.mark(group, L + 0.01, 0.012, 0);
|
|
5609
|
+
parts.eject = kit.mark(group, bodyLength * 0.25, 5e-3, 0.03);
|
|
5610
|
+
return { group, parts };
|
|
5488
5611
|
}
|
|
5489
5612
|
|
|
5490
|
-
// src/models/
|
|
5491
|
-
var
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
|
|
5497
|
-
sig: { rf: 0.14, ga: -0.3, grip: "rubber", guard: "hook", hammer: "spur", sight: "3dot", port: 0.19, decock: "frame", rail: 1, tall: 1.12, frame: "metal" },
|
|
5498
|
-
cz: { rf: 0.32, ga: -0.3, grip: "rubber", guard: "round", hammer: "spur", sight: "3dot", port: 0.15, inset: 1, safety: "thumb", frame: "metal" },
|
|
5499
|
-
m1911: { rf: 0.24, ga: -0.2, grip: "wood", guard: "round", hammer: "ring", sight: "small", port: 0.12, bushing: 1, beaver: 1, safety: "thumb", slideStop: 1, frame: "metal" },
|
|
5500
|
-
makarov: { rf: 0.48, ga: -0.24, grip: "star", guard: "round", hammer: "ring", sight: "small", port: 0.14, flush: 1, safety: "slide", lanyard: 1, frame: "metal" },
|
|
5501
|
-
fiveseven: { rf: 0.2, ga: -0.4, grip: "chunky", guard: "square", rail: 1, sight: "3dot", port: 0.18, slope: 1, frame: "poly" },
|
|
5502
|
-
deagle: { rf: 0.08, ga: -0.28, grip: "rubber", guard: "round", hammer: "big", sight: "small", port: 0.16, tri: 1, safety: "slide", frame: "metal" }
|
|
5613
|
+
// src/models/launcher-flame.ts
|
|
5614
|
+
var hose = (kit, group, points, radius, material) => {
|
|
5615
|
+
const { THREE } = kit;
|
|
5616
|
+
const curve = new THREE.CatmullRomCurve3(points.map((point) => new THREE.Vector3(...point)));
|
|
5617
|
+
const tube = new THREE.Mesh(new THREE.TubeGeometry(curve, 40, radius, 8, false), material);
|
|
5618
|
+
tube.castShadow = tube.receiveShadow = true;
|
|
5619
|
+
group.add(tube);
|
|
5503
5620
|
};
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
|
|
5508
|
-
|
|
5509
|
-
|
|
5510
|
-
const
|
|
5511
|
-
|
|
5512
|
-
|
|
5513
|
-
|
|
5514
|
-
|
|
5515
|
-
|
|
5516
|
-
|
|
5517
|
-
|
|
5518
|
-
kit.
|
|
5519
|
-
|
|
5520
|
-
|
|
5521
|
-
|
|
5522
|
-
|
|
5523
|
-
|
|
5524
|
-
|
|
5525
|
-
|
|
5526
|
-
|
|
5527
|
-
|
|
5528
|
-
|
|
5529
|
-
|
|
5530
|
-
|
|
5531
|
-
|
|
5532
|
-
|
|
5533
|
-
|
|
5534
|
-
const grip = kit.pivot(group, gx, gy, 0);
|
|
5535
|
-
grip.rotation.z = style.ga;
|
|
5536
|
-
parts.grip = grip;
|
|
5537
|
-
const gripWidth = style.grip === "chunky" ? w * 1.18 : w * 1.06;
|
|
5538
|
-
const gripDepth = style.grip === "chunky" ? 0.036 : 0.032;
|
|
5539
|
-
kit.roundness = 0.3;
|
|
5540
|
-
if (style.grip === "wood" || style.grip === "star") {
|
|
5541
|
-
box2(grip, gripDepth * 0.86, gripLength, w * 0.9, fm, 0, 0, 0);
|
|
5542
|
-
box2(grip, gripDepth * 0.8, gripLength * 0.86, 4e-3, materials.grip, 1e-3, -2e-3, w * 0.47);
|
|
5543
|
-
box2(grip, gripDepth * 0.8, gripLength * 0.86, 4e-3, materials.grip, 1e-3, -2e-3, -w * 0.47);
|
|
5544
|
-
if (style.grip === "wood") {
|
|
5545
|
-
for (let i = 0; i < 6; i++) for (let j = 0; j < 2; j++) box2(grip, 3e-3, 3e-3, 12e-4, M.woodL, -6e-3 + j * 0.012, -gripLength * 0.3 + i * 0.012, w * 0.495, 0, 0, 0);
|
|
5546
|
-
cylinderZ(grip, 35e-4, 15e-4, M.brass, 0, gripLength * 0.25, w * 0.5, 10);
|
|
5547
|
-
cylinderZ(grip, 35e-4, 15e-4, M.brass, 0, -gripLength * 0.3, w * 0.5, 10);
|
|
5548
|
-
} else cylinderZ(grip, 8e-3, 15e-4, M.dark, 0, gripLength * 0.1, w * 0.5, 5);
|
|
5549
|
-
} else box2(grip, gripDepth, gripLength, gripWidth, materials.grip, 0, 0, 0);
|
|
5550
|
-
kit.roundness = null;
|
|
5551
|
-
if (style.grip === "finger") {
|
|
5552
|
-
for (let i = 0; i < 3; i++) box2(grip, 6e-3, 0.012, gripWidth * 0.98, materials.grip, gripDepth / 2 + 2e-3, gripLength * 0.18 - i * 0.022, 0);
|
|
5553
|
-
for (let i = 0; i < 5; i++) for (let j = 0; j < 3; j++) box2(grip, 3e-3, 3e-3, 12e-4, M.dark, -8e-3 + j * 8e-3, -gripLength * 0.25 + i * 0.012, gripWidth / 2 + 4e-4);
|
|
5554
|
-
}
|
|
5555
|
-
if (style.grip === "panel" || style.grip === "rubber" || style.grip === "chunky") for (let i = 0; i < 6; i++) box2(grip, gripDepth * 0.75, 25e-4, gripWidth + 1e-3, M.dark, 2e-3, -gripLength / 2 + 0.018 + i * 0.013, 0);
|
|
5556
|
-
if (style.grip === "chunky") box2(grip, 8e-3, gripLength * 0.8, gripWidth * 0.9, materials.grip, gripDepth / 2 + 2e-3, -4e-3, 0);
|
|
5557
|
-
if (style.beaver) {
|
|
5558
|
-
box2(group, 0.026, 8e-3, w * 0.9, fm, -4e-3, -h / 2 - 4e-3, 0, 0.25);
|
|
5559
|
-
box2(grip, 6e-3, gripLength * 0.55, w * 0.9, fm, -gripDepth * 0.5 - 2e-3, gripLength * 0.18, 0);
|
|
5560
|
-
} else box2(group, 0.02, 9e-3, w * 0.9, fm, 4e-3, -h / 2 - 6e-3, 0);
|
|
5561
|
-
if (style.lanyard) {
|
|
5562
|
-
const ring = kit.torus(grip, new kit.THREE.TorusGeometry(5e-3, 13e-4, 6, 12), M.dark, -0.012, -gripLength / 2 + 4e-3, 0);
|
|
5563
|
-
ring.position.set(-0.012, -gripLength / 2 + 4e-3, 0);
|
|
5621
|
+
var pilot = (kit, group, x, y) => {
|
|
5622
|
+
const { M, cylinderX } = kit;
|
|
5623
|
+
cylinderX(group, 6e-3, 0.03, M.fire2, x + 0.015, y, 0, 6, 0).userData.flame = 1;
|
|
5624
|
+
cylinderX(group, 4e-3, 0.022, M.fire, x + 0.012, y, 0, 6, 0).userData.flame = 1;
|
|
5625
|
+
};
|
|
5626
|
+
function buildFlamethrower(kit, group, parts) {
|
|
5627
|
+
const { M, box: box2, cylinderX, cylinderY, sphere } = kit;
|
|
5628
|
+
parts.kick = 0.15;
|
|
5629
|
+
heatify(parts.glow, cylinderX(group, 0.016, 0.62, M.steel, 0.42, 0, 0, 14));
|
|
5630
|
+
cylinderX(group, 0.022, 0.1, M.dark, 0.78, 0, 0, 14);
|
|
5631
|
+
heatify(parts.glow, cylinderX(group, 0.013, 0.1, M.steel, 0.88, 0, 0, 12, 9e-3));
|
|
5632
|
+
cylinderX(group, 0.018, 0.02, M.metal, 0.73, 0, 0, 14);
|
|
5633
|
+
cylinderX(group, 0.012, 0.06, M.metal, 0.84, -0.025, 0, 10);
|
|
5634
|
+
pilot(kit, group, 0.92, -0.012);
|
|
5635
|
+
const foreGrip = kit.pivot(group, 0.6, -0.02, 0);
|
|
5636
|
+
foreGrip.rotation.z = -0.1;
|
|
5637
|
+
box2(foreGrip, 0.03, 0.1, 0.03, M.wood, 0, -0.05, 0);
|
|
5638
|
+
const lever = kit.pivot(group, 0.62, -0.02, 0);
|
|
5639
|
+
parts.trigger = box2(lever, 8e-3, 0.05, 6e-3, M.metal, 0.02, -0.03, 0, 0.3);
|
|
5640
|
+
const rearGrip = kit.pivot(group, 0.17, -0.02, 0);
|
|
5641
|
+
rearGrip.rotation.z = -0.28;
|
|
5642
|
+
box2(rearGrip, 0.03, 0.1, 0.03, M.wood, 0, -0.05, 0);
|
|
5643
|
+
box2(group, 0.05, 4e-3, 0.012, M.metal, 0.2, -0.035, 0);
|
|
5644
|
+
cylinderX(group, 0.02, 0.04, M.metal, 0.1, 0, 0, 12);
|
|
5645
|
+
hose(kit, group, [[0.08, 0, 0], [0, -0.04, 0], [-0.08, -0.2, 0.05], [-0.18, -0.32, 0.08], [-0.25, -0.33, 0.08]], 0.011, M.rubber);
|
|
5646
|
+
for (const z of [-0.1, 0.1]) {
|
|
5647
|
+
cylinderY(group, 0.085, 0.5, M.olive, -0.3, -0.05, z, 20);
|
|
5648
|
+
sphere(group, 0.085, M.olive, -0.3, 0.2, z, 2).scale.y = 0.45;
|
|
5649
|
+
sphere(group, 0.085, M.olive, -0.3, -0.3, z, 2).scale.y = 0.45;
|
|
5650
|
+
cylinderY(group, 0.03, 0.03, M.metal, -0.3, 0.24, z, 12);
|
|
5564
5651
|
}
|
|
5565
|
-
|
|
5566
|
-
|
|
5567
|
-
|
|
5568
|
-
|
|
5569
|
-
|
|
5570
|
-
|
|
5571
|
-
|
|
5572
|
-
|
|
5652
|
+
sphere(group, 0.075, M.olive, -0.3, 0.1, 0, 2).position.x = -0.39;
|
|
5653
|
+
box2(group, 0.03, 0.6, 0.24, M.dark, -0.4, -0.05, 0);
|
|
5654
|
+
cylinderY(group, 0.03, 0.012, M.metal, -0.39, 0.18, 0, 14);
|
|
5655
|
+
const gauge = kit.pivot(group, -0.39, 0.18, 3e-3);
|
|
5656
|
+
parts.gauge = gauge;
|
|
5657
|
+
box2(gauge, 2e-3, 0.022, 2e-3, M.red, 0, 8e-3, 0.012);
|
|
5658
|
+
parts.muzzle = kit.pivot(group, 0.94, 0, 0);
|
|
5659
|
+
parts.rear = kit.pivot(group, 0.1, 0, 0);
|
|
5573
5660
|
}
|
|
5574
|
-
function
|
|
5575
|
-
const { M, box: box2 } = kit;
|
|
5576
|
-
|
|
5577
|
-
|
|
5578
|
-
|
|
5579
|
-
|
|
5580
|
-
|
|
5581
|
-
|
|
5582
|
-
|
|
5583
|
-
|
|
5584
|
-
|
|
5585
|
-
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
const
|
|
5589
|
-
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
|
|
5593
|
-
|
|
5594
|
-
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
const guard = kit.torus(group, new kit.THREE.TorusGeometry(0.019, 22e-4, 6, 16, PI6), frameMetal, gx + 0.05, ty - 0.014, 0);
|
|
5599
|
-
guard.rotation.z = PI6;
|
|
5600
|
-
guard.scale.set(1.2, 1, 1);
|
|
5601
|
-
}
|
|
5602
|
-
const isGlock = options.st === "glock" || !options.st;
|
|
5603
|
-
parts.trigger = box2(group, 4e-3, 0.014, 4e-3, isGlock ? M.dark : M.steel, gx + 0.042, ty - 0.022, 0, 0.2);
|
|
5604
|
-
if (isGlock) box2(parts.trigger, 15e-4, 8e-3, 45e-4, M.metal, 0, -1e-3, 0);
|
|
5605
|
-
if (style.hammer) {
|
|
5606
|
-
const hammer = kit.pivot(group, 3e-3, h / 2 - 8e-3, 0);
|
|
5607
|
-
parts.hammer = hammer;
|
|
5608
|
-
if (style.hammer === "ring") {
|
|
5609
|
-
box2(hammer, 6e-3, 0.012, 6e-3, M.dark, -2e-3, 4e-3, 0, 0.3);
|
|
5610
|
-
kit.torus(hammer, new kit.THREE.TorusGeometry(45e-4, 16e-4, 6, 12), M.dark, -4e-3, 0.012, 0);
|
|
5611
|
-
} else if (style.hammer === "big") box2(hammer, 0.014, 0.02, 9e-3, M.dark, -4e-3, 7e-3, 0, 0.35);
|
|
5612
|
-
else {
|
|
5613
|
-
box2(hammer, 8e-3, 0.016, 7e-3, M.dark, -2e-3, 6e-3, 0, 0.3);
|
|
5614
|
-
box2(hammer, 8e-3, 4e-3, 8e-3, M.dark, -6e-3, 0.013, 0, 0.3);
|
|
5615
|
-
}
|
|
5616
|
-
}
|
|
5617
|
-
parts.muzzle = kit.mark(group, L + 6e-3, style.tri ? h * 0.08 : 2e-3, 0);
|
|
5618
|
-
parts.eject = kit.mark(group, L * 0.6, h / 2, w * 0.25);
|
|
5619
|
-
return { group, parts };
|
|
5661
|
+
function buildImprovisedFlamethrower(kit, group, parts) {
|
|
5662
|
+
const { M, box: box2, cylinderX, cylinderY, sphere } = kit;
|
|
5663
|
+
parts.kick = 0.12;
|
|
5664
|
+
heatify(parts.glow, cylinderX(group, 0.011, 0.66, M.pipe, 0.38, 0, 0, 12));
|
|
5665
|
+
heatify(parts.glow, cylinderX(group, 0.015, 0.06, M.steel, 0.74, 0, 0, 12, 0.01));
|
|
5666
|
+
cylinderX(group, 6e-3, 0.05, M.metal, 0.735, -0.02, 0, 8);
|
|
5667
|
+
pilot(kit, group, 0.77, -0.02);
|
|
5668
|
+
cylinderY(group, 0.012, 0.04, M.redPaint, 0.72, -0.055, 0, 10);
|
|
5669
|
+
box2(group, 0.02, 0.03, 0.012, M.dark, 0.72, -0.085, 0);
|
|
5670
|
+
cylinderX(group, 0.06, 0.42, M.redPaint, 0.3, -0.09, 0, 22);
|
|
5671
|
+
sphere(group, 0.06, M.redPaint, 0.51, -0.09, 0, 2).scale.x = 0.5;
|
|
5672
|
+
sphere(group, 0.06, M.redPaint, 0.09, -0.09, 0, 2).scale.x = 0.5;
|
|
5673
|
+
cylinderX(group, 0.02, 0.04, M.dark, 0.04, -0.09, 0, 12);
|
|
5674
|
+
box2(group, 0.02, 0.06, 5e-3, M.white, 0.3, -0.09, 0.06);
|
|
5675
|
+
for (const x of [0.15, 0.3, 0.45]) cylinderX(group, 0.063, 0.03, M.tape, x, -0.09, 0, 22);
|
|
5676
|
+
cylinderX(group, 0.016, 0.03, M.tape, 0.3, 0, 0, 12);
|
|
5677
|
+
hose(kit, group, [[0.04, -0.09, 0], [-0.02, -0.06, 0.02], [0, 0, 0.02], [0.05, 0, 0]], 7e-3, M.rubber);
|
|
5678
|
+
const rearGrip = kit.pivot(group, 0.12, -0.01, 0);
|
|
5679
|
+
rearGrip.rotation.z = -0.3;
|
|
5680
|
+
box2(rearGrip, 0.03, 0.1, 0.03, M.wood, 0, -0.05, 0);
|
|
5681
|
+
const lever = kit.pivot(group, 0.17, -0.02, 0);
|
|
5682
|
+
parts.trigger = box2(lever, 8e-3, 0.04, 6e-3, M.metal, 0, -0.02, 0, 0.2);
|
|
5683
|
+
parts.muzzle = kit.pivot(group, 0.78, 0, 0);
|
|
5684
|
+
parts.rear = kit.pivot(group, 0.05, 0, 0);
|
|
5620
5685
|
}
|
|
5621
5686
|
|
|
5622
|
-
// src/models/
|
|
5623
|
-
var
|
|
5624
|
-
|
|
5625
|
-
|
|
5687
|
+
// src/models/launcher-rounds.ts
|
|
5688
|
+
var PI6 = Math.PI;
|
|
5689
|
+
function buildRocketGrenade(kit) {
|
|
5690
|
+
const { M, cylinderX } = kit;
|
|
5691
|
+
const round2 = kit.group();
|
|
5692
|
+
cylinderX(round2, 0.018, 0.15, M.olive, -0.05, 0, 0, 14);
|
|
5693
|
+
cylinderX(round2, 0.02, 0.07, M.olive, 0.035, 0, 0, 18, 0.0425);
|
|
5694
|
+
cylinderX(round2, 0.0425, 0.12, M.olive, 0.13, 0, 0, 20);
|
|
5695
|
+
cylinderX(round2, 0.0428, 0.012, M.dark, 0.09, 0, 0, 20);
|
|
5696
|
+
cylinderX(round2, 0.0425, 0.13, M.olive, 0.255, 0, 0, 20, 0.011);
|
|
5697
|
+
cylinderX(round2, 0.011, 0.03, M.metal, 0.335, 0, 0, 10, 4e-3);
|
|
5698
|
+
return round2;
|
|
5699
|
+
}
|
|
5700
|
+
function buildRecoillessRound(kit) {
|
|
5701
|
+
const { M, cylinderX } = kit;
|
|
5702
|
+
const round2 = kit.group();
|
|
5703
|
+
cylinderX(round2, 0.041, 0.32, M.green, -0.16, 0, 0, 20);
|
|
5704
|
+
cylinderX(round2, 0.0415, 0.02, M.yellow, -0.05, 0, 0, 20);
|
|
5705
|
+
cylinderX(round2, 0.041, 0.12, M.green, 0.06, 0, 0, 20, 0.012);
|
|
5706
|
+
cylinderX(round2, 0.043, 0.03, M.brass, -0.33, 0, 0, 20);
|
|
5707
|
+
return round2;
|
|
5708
|
+
}
|
|
5709
|
+
function buildFlyingRocket(kit, launcherType) {
|
|
5626
5710
|
const { M, box: box2, cylinderX } = kit;
|
|
5627
|
-
const
|
|
5628
|
-
const
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
const crane = kit.pivot(group, 0.077, -0.024, 0);
|
|
5636
|
-
parts.crane = crane;
|
|
5637
|
-
const cylinder = kit.pivot(crane, 0, 0.022, 0);
|
|
5638
|
-
parts.cylinder = cylinder;
|
|
5639
|
-
cylinderX(cylinder, 0.0215, 0.042, metal2, 0, 0, 0, 24);
|
|
5640
|
-
for (let i = 0; i < chambers; i++) {
|
|
5641
|
-
const angle = i * 2 * PI7 / chambers;
|
|
5642
|
-
box2(cylinder, 0.026, 5e-3, 5e-3, M.dark, 0, Math.cos(angle) * 0.0205, Math.sin(angle) * 0.0205, 0, 0, angle);
|
|
5643
|
-
}
|
|
5644
|
-
parts.chambers = [];
|
|
5645
|
-
for (let i = 0; i < chambers; i++) {
|
|
5646
|
-
const angle = i * 2 * PI7 / chambers + PI7 / chambers;
|
|
5647
|
-
parts.chambers.push(kit.mark(cylinder, -0.022, Math.cos(angle) * 0.013, Math.sin(angle) * 0.013));
|
|
5648
|
-
cylinderX(cylinder, 46e-4, 2e-3, M.brass, -0.0215, Math.cos(angle) * 0.013, Math.sin(angle) * 0.013, 12);
|
|
5711
|
+
const rocket = kit.group();
|
|
5712
|
+
const diameter = launcherType === "at4" || launcherType === "carl" ? 0.041 : 0.032;
|
|
5713
|
+
cylinderX(rocket, diameter * 0.5, 0.2, M.dark, -0.1, 0, 0, 10);
|
|
5714
|
+
cylinderX(rocket, diameter, 0.3, M.olive, 0.15, 0, 0, 18);
|
|
5715
|
+
cylinderX(rocket, diameter, 0.12, M.olive, 0.36, 0, 0, 18, diameter * 0.25);
|
|
5716
|
+
for (let i = 0; i < 4; i++) {
|
|
5717
|
+
const fin = box2(rocket, 0.06, 2e-3, diameter * 1.4, M.metal, -0.17, 0, 0);
|
|
5718
|
+
fin.rotation.x = i * PI6 / 4;
|
|
5649
5719
|
}
|
|
5650
|
-
|
|
5651
|
-
box2(group, barrel * 0.92, 0.015, 0.013, metal2, 0.112 + barrel * 0.46, -5e-3, 0);
|
|
5652
|
-
cylinderX(group, 4e-3, 5e-3, M.hole, 0.112 + barrel + 15e-4, 9e-3, 0, 12);
|
|
5653
|
-
box2(group, 0.012, 9e-3, 4e-3, M.dark, 0.112 + barrel - 8e-3, 0.021, 0, -0.3);
|
|
5654
|
-
box2(group, 0.012, 6e-3, 0.012, M.dark, 0.105, 0.031, 0);
|
|
5655
|
-
const hammer = kit.pivot(group, 0.036, 0.018, 0);
|
|
5656
|
-
box2(hammer, 0.01, 0.02, 8e-3, M.dark, -4e-3, 8e-3, 0, 0.45);
|
|
5657
|
-
parts.hammer = hammer;
|
|
5658
|
-
const grip = kit.pivot(group, 0.024, -0.062, 0);
|
|
5659
|
-
grip.rotation.z = -0.38;
|
|
5660
|
-
parts.grip = grip;
|
|
5661
|
-
box2(grip, 0.034, 0.1, 0.031, options.wood ? M.wood : M.rubber, 0, 0, 0);
|
|
5662
|
-
if (!options.wood) for (let i = 0; i < 4; i++) box2(grip, 6e-3, 0.07, 0.033, M.dark, -0.012 + i * 8e-3, 0, 0);
|
|
5663
|
-
box2(group, 0.038, 4e-3, 8e-3, metal2, 0.062, -0.036, 0);
|
|
5664
|
-
box2(group, 4e-3, 0.022, 8e-3, metal2, 0.08, -0.026, 0, 0.2);
|
|
5665
|
-
parts.trigger = box2(group, 4e-3, 0.015, 4e-3, M.dark, 0.06, -0.027, 0, 0.2);
|
|
5666
|
-
parts.muzzle = kit.mark(group, 0.112 + barrel + 6e-3, 9e-3, 0);
|
|
5667
|
-
parts.eject = kit.mark(group, 0.077, 0, 0);
|
|
5668
|
-
return { group, parts };
|
|
5720
|
+
return rocket;
|
|
5669
5721
|
}
|
|
5670
5722
|
|
|
5671
|
-
// src/models/
|
|
5672
|
-
function
|
|
5723
|
+
// src/models/launcher-rocket.ts
|
|
5724
|
+
function buildRpg(kit, group, parts) {
|
|
5673
5725
|
const { M, box: box2, cylinderX } = kit;
|
|
5674
|
-
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
5684
|
-
|
|
5726
|
+
parts.kick = 1.6;
|
|
5727
|
+
cylinderX(group, 0.036, 0.13, M.dark, 0.065, 0, 0, 20, 0.021);
|
|
5728
|
+
cylinderX(group, 0.038, 0.012, M.metal, 0, 0, 0, 20);
|
|
5729
|
+
heatify(parts.glow, cylinderX(group, 0.021, 0.83, M.steel, 0.545, 0, 0, 18));
|
|
5730
|
+
cylinderX(group, 0.03, 0.3, M.wood, 0.47, 0, 0, 16);
|
|
5731
|
+
cylinderX(group, 0.031, 0.012, M.metal, 0.32, 0, 0, 16);
|
|
5732
|
+
cylinderX(group, 0.031, 0.012, M.metal, 0.62, 0, 0, 16);
|
|
5733
|
+
cylinderX(group, 0.024, 0.02, M.metal, 0.94, 0, 0, 16);
|
|
5734
|
+
box2(group, 0.09, 0.03, 0.032, M.metal, 0.46, -0.028, 0);
|
|
5735
|
+
const frontGrip = kit.pivot(group, 0.4, -0.04, 0);
|
|
5736
|
+
frontGrip.rotation.z = -0.22;
|
|
5737
|
+
box2(frontGrip, 0.03, 0.1, 0.03, M.wood, 0, -0.05, 0);
|
|
5738
|
+
const rearGrip = kit.pivot(group, 0.5, -0.04, 0);
|
|
5739
|
+
rearGrip.rotation.z = -0.18;
|
|
5740
|
+
box2(rearGrip, 0.03, 0.1, 0.03, M.wood, 0, -0.05, 0);
|
|
5741
|
+
box2(group, 0.06, 4e-3, 0.012, M.metal, 0.53, -0.05, 0);
|
|
5742
|
+
box2(group, 4e-3, 0.025, 0.012, M.metal, 0.56, -0.04, 0);
|
|
5743
|
+
parts.trigger = box2(group, 4e-3, 0.018, 4e-3, M.dark, 0.535, -0.045, 0, 0.15);
|
|
5744
|
+
const hammer = kit.pivot(group, 0.44, -0.012, 0);
|
|
5745
|
+
parts.hammer = hammer;
|
|
5746
|
+
box2(hammer, 0.012, 0.02, 0.01, M.dark, 0, 0, 0);
|
|
5747
|
+
box2(group, 6e-3, 0.03, 6e-3, M.dark, 0.78, 0.032, 0);
|
|
5748
|
+
box2(group, 0.02, 0.022, 0.014, M.dark, 0.46, 0.032, 0);
|
|
5749
|
+
box2(group, 0.12, 0.042, 0.032, M.dark, 0.5, 0.04, -0.04);
|
|
5750
|
+
cylinderX(group, 0.013, 0.05, M.rubber, 0.42, 0.048, -0.04, 14);
|
|
5751
|
+
cylinderX(group, 0.016, 4e-3, M.lens, 0.565, 0.048, -0.04, 14);
|
|
5752
|
+
box2(group, 0.04, 0.012, 0.012, M.metal, 0.5, 0.016, -0.03);
|
|
5753
|
+
const round2 = buildRocketGrenade(kit);
|
|
5754
|
+
round2.position.x = 0.95;
|
|
5755
|
+
group.add(round2);
|
|
5756
|
+
parts.round = round2;
|
|
5757
|
+
parts.roundRest = 0.95;
|
|
5758
|
+
parts.makeRound = () => buildRocketGrenade(kit);
|
|
5759
|
+
parts.muzzle = kit.pivot(group, 0.95, 0, 0);
|
|
5760
|
+
parts.rear = kit.pivot(group, 0, 0, 0);
|
|
5685
5761
|
}
|
|
5686
|
-
function
|
|
5687
|
-
|
|
5762
|
+
function buildM72(kit, group, parts) {
|
|
5763
|
+
const { M, box: box2, cylinderX, cylinderY } = kit;
|
|
5764
|
+
parts.kick = 1.1;
|
|
5765
|
+
parts.disposable = true;
|
|
5766
|
+
heatify(parts.glow, cylinderX(group, 0.0365, 0.6, M.olive, 0.58, 0, 0, 20));
|
|
5767
|
+
cylinderX(group, 0.032, 0.32, M.olive, 0.16, 0, 0, 20);
|
|
5768
|
+
cylinderX(group, 0.039, 0.03, M.rubber, 0.866, 0, 0, 20);
|
|
5769
|
+
cylinderX(group, 0.035, 0.025, M.rubber, 0.012, 0, 0, 20);
|
|
5770
|
+
cylinderX(group, 0.037, 0.015, M.yellow, 0.8, 0, 0, 20);
|
|
5771
|
+
cylinderX(group, 0.037, 0.012, M.dark, 0.3, 0, 0, 20);
|
|
5772
|
+
box2(group, 4e-3, 0.05, 0.05, M.dark, 0.79, 0.055, 0);
|
|
5773
|
+
box2(group, 4e-3, 6e-3, 0.04, M.dark, 0.79, 0.078, 0);
|
|
5774
|
+
box2(group, 4e-3, 0.035, 0.024, M.dark, 0.38, 0.05, 0);
|
|
5775
|
+
cylinderY(group, 4e-3, 6e-3, M.lens, 0.38, 0.064, 0, 8);
|
|
5776
|
+
parts.trigger = box2(group, 0.05, 0.016, 0.024, M.rubber, 0.5, 0.042, 0);
|
|
5777
|
+
box2(group, 0.1, 0.01, 0.03, M.dark, 0.47, 0.036, 0);
|
|
5778
|
+
box2(group, 0.02, 0.03, 0.01, M.dark, 0.66, -0.035, 0.03);
|
|
5779
|
+
box2(group, 8e-3, 0.03, 8e-3, M.metal, 0.25, -0.04, 0.03);
|
|
5780
|
+
parts.muzzle = kit.pivot(group, 0.881, 0, 0);
|
|
5781
|
+
parts.rear = kit.pivot(group, 0, 0, 0);
|
|
5688
5782
|
}
|
|
5689
|
-
|
|
5690
|
-
// src/models/attachments/bipod.ts
|
|
5691
|
-
function buildBipod(kit, parent, x, y) {
|
|
5783
|
+
function buildAt4(kit, group, parts) {
|
|
5692
5784
|
const { M, box: box2, cylinderX } = kit;
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
|
|
5697
|
-
|
|
5698
|
-
|
|
5699
|
-
|
|
5785
|
+
parts.kick = 1.3;
|
|
5786
|
+
parts.disposable = true;
|
|
5787
|
+
heatify(parts.glow, cylinderX(group, 0.05, 0.86, M.olive, 0.51, 0, 0, 24));
|
|
5788
|
+
cylinderX(group, 0.056, 0.08, M.dark, 0.98, 0, 0, 24);
|
|
5789
|
+
cylinderX(group, 0.058, 0.07, M.dark, 0.04, 0, 0, 24, 0.05);
|
|
5790
|
+
cylinderX(group, 0.051, 0.015, M.yellow, 0.86, 0, 0, 24);
|
|
5791
|
+
box2(group, 0.16, 0.026, 0.05, M.dark, 0.42, 0.058, 0);
|
|
5792
|
+
box2(group, 0.03, 0.012, 0.016, M.red, 0.47, 0.075, 0);
|
|
5793
|
+
parts.trigger = box2(group, 0.022, 0.012, 0.018, M.rubber, 0.5, 0.074, 0);
|
|
5794
|
+
box2(group, 0.012, 0.07, 0.02, M.dark, 0.35, 0.09, -0.035);
|
|
5795
|
+
box2(group, 0.012, 0.05, 0.02, M.dark, 0.71, 0.08, -0.035);
|
|
5796
|
+
const grip = kit.pivot(group, 0.68, -0.05, 0);
|
|
5797
|
+
grip.rotation.z = -0.15;
|
|
5798
|
+
parts.grip = grip;
|
|
5799
|
+
box2(grip, 0.035, 0.11, 0.032, M.dark, 0, -0.05, 0);
|
|
5800
|
+
box2(group, 0.14, 0.035, 0.06, M.rubber, 0.32, -0.06, 0);
|
|
5801
|
+
box2(group, 0.3, 0.012, 0.055, M.dark, 0.5, -0.05, 0);
|
|
5802
|
+
parts.muzzle = kit.pivot(group, 1.02, 0, 0);
|
|
5803
|
+
parts.rear = kit.pivot(group, 0, 0, 0);
|
|
5700
5804
|
}
|
|
5701
|
-
|
|
5702
|
-
const
|
|
5703
|
-
|
|
5704
|
-
|
|
5705
|
-
|
|
5706
|
-
|
|
5707
|
-
|
|
5708
|
-
|
|
5709
|
-
|
|
5710
|
-
|
|
5711
|
-
const
|
|
5712
|
-
|
|
5713
|
-
|
|
5714
|
-
|
|
5715
|
-
|
|
5716
|
-
|
|
5717
|
-
|
|
5718
|
-
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
|
|
5725
|
-
|
|
5726
|
-
|
|
5727
|
-
|
|
5728
|
-
|
|
5729
|
-
|
|
5730
|
-
parts.lever = lever;
|
|
5731
|
-
box2(lever, 0.11, 6e-3, 0.012, M.metal, 0.055, -0.052, 0);
|
|
5732
|
-
box2(lever, 6e-3, 0.05, 0.012, M.metal, 3e-3, -0.028, 0);
|
|
5733
|
-
box2(lever, 6e-3, 0.05, 0.012, M.metal, 0.108, -0.028, 0);
|
|
5734
|
-
box2(lever, 0.04, 6e-3, 0.012, M.metal, 0.08, -2e-3, 0);
|
|
5735
|
-
box2(group, 0.03, 0.012, 3e-3, M.dark, x1 - 0.04, by, wR / 2 + 1e-3);
|
|
5736
|
-
}
|
|
5737
|
-
if (o.tube) {
|
|
5738
|
-
const tubeLength = (L - x1) * (o.tubeLen || 0.8);
|
|
5739
|
-
cylinderX(group, 0.0105, tubeLength, M.metal, x1 + tubeLength / 2, by - 0.023, 0, 16);
|
|
5740
|
-
cylinderX(group, 0.0125, 0.02, M.dark, x1 + tubeLength + 6e-3, by - 0.023, 0, 16);
|
|
5741
|
-
}
|
|
5742
|
-
if (o.pump) {
|
|
5743
|
-
const pump = kit.pivot(group);
|
|
5744
|
-
parts.pump = pump;
|
|
5745
|
-
box2(pump, 0.17, 0.042, 0.046, furn, x1 + 0.14, by - 0.022, 0);
|
|
5746
|
-
for (let i = 0; i < 8; i++) box2(pump, 6e-3, 0.044, 0.048, M.dark, x1 + 0.07 + i * 0.02, by - 0.022, 0);
|
|
5747
|
-
}
|
|
5748
|
-
if (o.heat) {
|
|
5749
|
-
cylinderX(group, r * 1.75, (L - x1) * 0.7, M.dark, x1 + (L - x1) * 0.4, by, 0, 12);
|
|
5750
|
-
for (let i = 0; i < 10; i++) box2(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);
|
|
5751
|
-
}
|
|
5752
|
-
if (o.bayo) box2(group, 0.025, 8e-3, 0.01, M.metal, L - 0.07, by - 0.016, 0);
|
|
5753
|
-
if (o.rod) cylinderX(group, 3e-3, (L - x1) * 0.85, M.steel, x1 + (L - x1) * 0.45, by - 0.014, 0, 8);
|
|
5805
|
+
function buildCarlGustaf(kit, group, parts) {
|
|
5806
|
+
const { M, box: box2, cylinderX } = kit;
|
|
5807
|
+
parts.kick = 1.4;
|
|
5808
|
+
heatify(parts.glow, cylinderX(group, 0.045, 0.72, M.dark, 0.59, 0, 0, 24));
|
|
5809
|
+
cylinderX(group, 0.05, 0.04, M.rubber, 0.93, 0, 0, 24);
|
|
5810
|
+
const breech = kit.pivot(group, 0.21, 0, 0.05);
|
|
5811
|
+
parts.breech = [breech];
|
|
5812
|
+
cylinderX(breech, 0.06, 0.16, M.dark, -0.1, 0, -0.05, 24, 0.046);
|
|
5813
|
+
cylinderX(breech, 0.062, 0.015, M.metal, -0.18, 0, -0.05, 24);
|
|
5814
|
+
box2(group, 0.025, 0.03, 0.02, M.metal, 0.22, 0, 0.052);
|
|
5815
|
+
const foreGrip = kit.pivot(group, 0.62, -0.05, 0);
|
|
5816
|
+
foreGrip.rotation.z = -0.2;
|
|
5817
|
+
box2(foreGrip, 0.035, 0.11, 0.034, M.dark, 0, -0.05, 0);
|
|
5818
|
+
parts.trigger = box2(group, 4e-3, 0.018, 4e-3, M.dark, 0.66, -0.06, 0, 0.15);
|
|
5819
|
+
box2(group, 0.06, 4e-3, 0.012, M.metal, 0.66, -0.07, 0);
|
|
5820
|
+
const rearGrip = kit.pivot(group, 0.4, -0.05, 0);
|
|
5821
|
+
rearGrip.rotation.z = -0.25;
|
|
5822
|
+
box2(rearGrip, 0.035, 0.1, 0.034, M.dark, 0, -0.05, 0);
|
|
5823
|
+
box2(group, 0.13, 0.04, 0.07, M.rubber, 0.28, -0.065, 0);
|
|
5824
|
+
box2(group, 0.16, 0.05, 0.045, M.dark, 0.56, 0.07, -0.035);
|
|
5825
|
+
cylinderX(group, 0.016, 0.05, M.rubber, 0.46, 0.075, -0.035, 14);
|
|
5826
|
+
cylinderX(group, 0.02, 4e-3, M.lens, 0.645, 0.075, -0.035, 14);
|
|
5827
|
+
box2(group, 0.06, 0.02, 0.02, M.metal, 0.56, 0.04, -0.03);
|
|
5828
|
+
box2(group, 0.22, 0.01, 0.02, M.dark, 0.6, 0.06, 0.03);
|
|
5829
|
+
box2(group, 0.01, 0.03, 0.02, M.dark, 0.5, 0.05, 0.03);
|
|
5830
|
+
box2(group, 0.01, 0.03, 0.02, M.dark, 0.7, 0.05, 0.03);
|
|
5831
|
+
parts.makeRound = () => buildRecoillessRound(kit);
|
|
5832
|
+
parts.muzzle = kit.pivot(group, 0.95, 0, 0);
|
|
5833
|
+
parts.rear = kit.pivot(group, 0.05, 0, 0);
|
|
5754
5834
|
}
|
|
5835
|
+
var ROCKET_BUILDERS = {
|
|
5836
|
+
rpg: buildRpg,
|
|
5837
|
+
m72: buildM72,
|
|
5838
|
+
at4: buildAt4,
|
|
5839
|
+
carl: buildCarlGustaf
|
|
5840
|
+
};
|
|
5755
5841
|
|
|
5756
|
-
// src/models/
|
|
5757
|
-
|
|
5758
|
-
|
|
5759
|
-
const
|
|
5760
|
-
const
|
|
5761
|
-
const
|
|
5762
|
-
if (
|
|
5763
|
-
|
|
5764
|
-
|
|
5765
|
-
|
|
5766
|
-
|
|
5767
|
-
box2(group, handguardLength, hh, wR * 1.04, M.dark, hx, by - 2e-3, 0);
|
|
5768
|
-
rail(kit, group, x1, handguardLength, by + hh / 2, 0, wR * 0.66);
|
|
5769
|
-
rail(kit, group, x1 + 0.01, handguardLength - 0.02, by - 2e-3, wR * 0.54, wR * 0.4, PI8 / 2);
|
|
5770
|
-
rail(kit, group, x1 + 0.01, handguardLength - 0.02, by - 2e-3, -wR * 0.54, wR * 0.4, -PI8 / 2);
|
|
5771
|
-
rail(kit, group, x1 + 0.01, handguardLength - 0.02, by - hh / 2, 0, wR * 0.6, PI8);
|
|
5772
|
-
} else {
|
|
5773
|
-
const material = o.hg === "wood" ? M.wood : furn;
|
|
5774
|
-
if (o.ak) {
|
|
5775
|
-
box2(group, handguardLength, hh * 0.55, wR * 1.08, material, hx, by - hh * 0.22, 0);
|
|
5776
|
-
box2(group, handguardLength * 0.75, hh * 0.35, wR * 0.7, material, hx - handguardLength * 0.1, by + r * 2.2, 0);
|
|
5777
|
-
} else {
|
|
5778
|
-
box2(group, handguardLength, hh, wR * 1.08, material, hx, by - 2e-3, 0);
|
|
5779
|
-
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);
|
|
5780
|
-
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);
|
|
5781
|
-
}
|
|
5782
|
-
}
|
|
5783
|
-
if (!hasLongScope && !o.rail && o.ak) {
|
|
5784
|
-
box2(group, 0.03, 0.016, wR * 0.6, M.metal, x1 + 0.02, by + r * 2.5 + 0.01, 0);
|
|
5785
|
-
box2(group, 0.012, 4e-3, wR * 0.5, M.dark, x1 + 0.03, by + r * 2.5 + 0.019, 0);
|
|
5786
|
-
}
|
|
5787
|
-
}
|
|
5788
|
-
if (hasLongScope) return;
|
|
5789
|
-
const sightX = L - (o.ak ? 0.06 : 0.08);
|
|
5790
|
-
if (o.ak) {
|
|
5791
|
-
box2(group, 0.022, 0.022, wR * 0.6, M.metal, sightX, by + 8e-3, 0);
|
|
5792
|
-
box2(group, 6e-3, 0.024, 4e-3, M.metal, sightX, by + 0.026, 8e-3);
|
|
5793
|
-
box2(group, 6e-3, 0.024, 4e-3, M.metal, sightX, by + 0.026, -8e-3);
|
|
5794
|
-
box2(group, 3e-3, 0.016, 3e-3, M.dark, sightX, by + 0.022, 0);
|
|
5795
|
-
} else if (!o.rail || o.carry) {
|
|
5796
|
-
box2(group, 0.018, 0.014, wR * 0.55, M.dark, sightX, by + 8e-3, 0);
|
|
5797
|
-
box2(group, 0.012, 0.034, 8e-3, M.dark, sightX, by + 0.03, 0, -0.25);
|
|
5798
|
-
} else box2(group, 0.012, 0.024, 0.012, M.dark, sightX - 0.04, by + hR * 0.4 + 0.012, 0);
|
|
5842
|
+
// src/models/launcher.ts
|
|
5843
|
+
function buildLauncher(kit, options) {
|
|
5844
|
+
const group = kit.group();
|
|
5845
|
+
const type = options.lt ?? "";
|
|
5846
|
+
const isFlame = type === "flame" || type === "flameDIY";
|
|
5847
|
+
const parts = { family: isFlame ? "flame" : "rocket", launcherType: type, glow: [] };
|
|
5848
|
+
if (type === "flame") buildFlamethrower(kit, group, parts);
|
|
5849
|
+
else if (type === "flameDIY") buildImprovisedFlamethrower(kit, group, parts);
|
|
5850
|
+
else ROCKET_BUILDERS[type]?.(kit, group, parts);
|
|
5851
|
+
parts.eject = parts.muzzle;
|
|
5852
|
+
return { group, parts };
|
|
5799
5853
|
}
|
|
5800
5854
|
|
|
5801
|
-
// src/models/
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
|
|
5805
|
-
|
|
5806
|
-
|
|
5807
|
-
|
|
5808
|
-
|
|
5855
|
+
// src/models/m134.ts
|
|
5856
|
+
var PI7 = Math.PI;
|
|
5857
|
+
var BARRELS = 6;
|
|
5858
|
+
var CLUSTER_RADIUS = 0.03;
|
|
5859
|
+
var BARREL_RADIUS = 78e-4;
|
|
5860
|
+
var BARREL_END = 0.8;
|
|
5861
|
+
function buildBarrelCluster(kit, parts, group) {
|
|
5862
|
+
const { M, cylinderX } = kit;
|
|
5863
|
+
const barrels = kit.pivot(group, 0, 0, 0);
|
|
5864
|
+
parts.barrels = barrels;
|
|
5865
|
+
const length = BARREL_END - 0.3;
|
|
5866
|
+
let heated;
|
|
5867
|
+
for (let i = 0; i < BARRELS; i++) {
|
|
5868
|
+
const angle = i * 2 * PI7 / BARRELS;
|
|
5869
|
+
const y = Math.cos(angle) * CLUSTER_RADIUS;
|
|
5870
|
+
const z = Math.sin(angle) * CLUSTER_RADIUS;
|
|
5871
|
+
const barrel = cylinderX(barrels, BARREL_RADIUS, length, M.metal, 0.3 + length / 2, y, z, 14);
|
|
5872
|
+
if (heated) barrel.material = heated;
|
|
5873
|
+
else heated = heatify(parts.glow, barrel).material;
|
|
5874
|
+
cylinderX(barrels, BARREL_RADIUS * 0.55, 4e-3, M.hole, BARREL_END + 5e-4, y, z, 10);
|
|
5809
5875
|
}
|
|
5876
|
+
cylinderX(barrels, 0.012, length, M.steel, 0.3 + length / 2, 0, 0, 12);
|
|
5877
|
+
for (const x of [0.42, 0.58, 0.74]) cylinderX(barrels, CLUSTER_RADIUS + BARREL_RADIUS * 1.6, 0.014, M.steel, x, 0, 0, 24);
|
|
5878
|
+
cylinderX(barrels, CLUSTER_RADIUS + BARREL_RADIUS * 1.8, 0.03, M.dark, BARREL_END - 0.015, 0, 0, 24);
|
|
5810
5879
|
}
|
|
5811
|
-
|
|
5812
|
-
|
|
5813
|
-
|
|
5814
|
-
|
|
5815
|
-
|
|
5816
|
-
|
|
5817
|
-
box2(
|
|
5880
|
+
function buildHousing(kit, parts, group) {
|
|
5881
|
+
const { M, box: box2, cylinderX, cylinderZ } = kit;
|
|
5882
|
+
box2(group, 0.3, 0.14, 0.15, M.metal, 0.18, 0, 0);
|
|
5883
|
+
cylinderX(group, 0.052, 0.12, M.dark, 0.06, 0, 0, 20);
|
|
5884
|
+
cylinderX(group, 0.062, 0.2, M.dark, 0.38, 0, 0, 22);
|
|
5885
|
+
for (let i = 0; i < 4; i++) cylinderX(group, 0.064, 8e-3, M.steel, 0.3 + i * 0.05, 0, 0, 22);
|
|
5886
|
+
box2(group, 0.04, 0.05, 0.2, M.dark, 0.1, 0.095, 0);
|
|
5887
|
+
box2(group, 0.2, 0.012, 0.045, M.dark, 0.22, 0.158, 0);
|
|
5888
|
+
box2(group, 0.012, 0.05, 0.045, M.dark, 0.13, 0.13, 0);
|
|
5889
|
+
box2(group, 0.012, 0.05, 0.045, M.dark, 0.31, 0.13, 0);
|
|
5890
|
+
for (const side of [-1, 1]) {
|
|
5891
|
+
box2(group, 0.03, 0.03, 0.1, M.poly, 0.06, -0.01, side * 0.14);
|
|
5892
|
+
cylinderZ(group, 0.016, 0.07, M.poly, 0.06, -0.01, side * 0.2, 14);
|
|
5893
|
+
}
|
|
5894
|
+
parts.trigger = box2(group, 0.012, 0.02, 0.016, M.dark, 0.1, 0.085, 0.14, 0.3);
|
|
5895
|
+
parts.safety = box2(group, 0.014, 6e-3, 0.01, M.dark, 0.2, 0.073, -0.076, 0.4);
|
|
5818
5896
|
}
|
|
5819
|
-
|
|
5820
|
-
|
|
5821
|
-
|
|
5822
|
-
|
|
5823
|
-
|
|
5824
|
-
|
|
5825
|
-
|
|
5826
|
-
|
|
5827
|
-
const
|
|
5828
|
-
|
|
5829
|
-
|
|
5830
|
-
const
|
|
5831
|
-
parts.
|
|
5832
|
-
|
|
5833
|
-
|
|
5834
|
-
|
|
5835
|
-
|
|
5836
|
-
|
|
5837
|
-
parts
|
|
5838
|
-
|
|
5897
|
+
function buildFeed(kit, parts, group) {
|
|
5898
|
+
const { M, box: box2, cylinderX } = kit;
|
|
5899
|
+
const belt = kit.pivot(group, 0.2, -0.13, -0.16);
|
|
5900
|
+
parts.belt = belt;
|
|
5901
|
+
box2(belt, 0.16, 0.12, 0.1, M.olive, 0, 0, 0);
|
|
5902
|
+
box2(belt, 0.162, 0.012, 0.102, M.dark, 0, 0.056, 0);
|
|
5903
|
+
for (let i = 0; i < 8; i++) cylinderX(belt, 46e-4, 0.04, M.brass, -0.07 + i * 0.02, 0.075, 0.04, 10);
|
|
5904
|
+
box2(group, 0.1, 0.03, 0.1, M.metal, 0.22, -0.06, -0.1, 0, 0, 0.5);
|
|
5905
|
+
const cover = kit.pivot(group, 0.1, 0.075, 0);
|
|
5906
|
+
parts.cover = cover;
|
|
5907
|
+
box2(cover, 0.24, 0.012, 0.15, M.metal, 0.12, 6e-3, 0);
|
|
5908
|
+
const bolt = kit.pivot(group);
|
|
5909
|
+
parts.bolt = bolt;
|
|
5910
|
+
parts.stroke = 0.03;
|
|
5911
|
+
box2(bolt, 0.03, 0.012, 0.012, M.steelL, 0.28, 0.02, 0.078);
|
|
5912
|
+
}
|
|
5913
|
+
function buildM134(kit) {
|
|
5914
|
+
const group = kit.group();
|
|
5915
|
+
const parts = { family: "belt", kick: 0.9, glow: [] };
|
|
5916
|
+
buildHousing(kit, parts, group);
|
|
5917
|
+
buildBarrelCluster(kit, parts, group);
|
|
5918
|
+
buildFeed(kit, parts, group);
|
|
5919
|
+
parts.frames = {
|
|
5920
|
+
length: BARREL_END,
|
|
5921
|
+
barrelY: 0,
|
|
5922
|
+
barrelRadius: BARREL_RADIUS,
|
|
5923
|
+
receiverStart: 0.06,
|
|
5924
|
+
receiverEnd: 0.48,
|
|
5925
|
+
receiverHeight: 0.14,
|
|
5926
|
+
receiverWidth: 0.15,
|
|
5927
|
+
handguardEnd: 0.6,
|
|
5928
|
+
magazineX: 0.2,
|
|
5929
|
+
gripX: 0.06,
|
|
5930
|
+
hasRail: false,
|
|
5931
|
+
// the tripod head, where the gun balances (the tripod of the counters joins here too)
|
|
5932
|
+
underbarrel: [0.4, -0.1]
|
|
5933
|
+
};
|
|
5934
|
+
parts.muzzle = kit.mark(group, BARREL_END + 0.01, 0, 0);
|
|
5935
|
+
parts.eject = kit.mark(group, 0.3, -0.07, 0.08);
|
|
5936
|
+
return { group, parts };
|
|
5839
5937
|
}
|
|
5840
5938
|
|
|
5841
|
-
// src/models/
|
|
5842
|
-
function
|
|
5843
|
-
const {
|
|
5844
|
-
const
|
|
5845
|
-
const
|
|
5846
|
-
|
|
5847
|
-
|
|
5848
|
-
|
|
5849
|
-
|
|
5850
|
-
|
|
5851
|
-
|
|
5852
|
-
|
|
5853
|
-
|
|
5854
|
-
box2(group, 0.06,
|
|
5855
|
-
|
|
5856
|
-
parts.
|
|
5857
|
-
|
|
5858
|
-
|
|
5939
|
+
// src/models/m2.ts
|
|
5940
|
+
function buildM2(kit) {
|
|
5941
|
+
const { M, box: box2, cylinderX, cylinderZ } = kit;
|
|
5942
|
+
const group = kit.group();
|
|
5943
|
+
const parts = { family: "belt", kick: 2.2, stroke: 0.08, glow: [] };
|
|
5944
|
+
box2(group, 0.52, 0.13, 0.12, M.metal, 0.36, 0, 0);
|
|
5945
|
+
for (let i = 0; i < 5; i++) cylinderZ(group, 6e-3, 0.124, M.dark, 0.15 + i * 0.1, -0.03, 0, 10);
|
|
5946
|
+
heatify(parts.glow, cylinderX(group, 0.016, 1.14, M.metal, 1.14, 0.01, 0, 16));
|
|
5947
|
+
cylinderX(group, 0.034, 0.24, M.dark, 0.74, 0.01, 0, 16);
|
|
5948
|
+
for (let i = 0; i < 6; i++) cylinderX(group, 0.036, 0.012, M.metal, 0.66 + i * 0.035, 0.01, 0, 16);
|
|
5949
|
+
cylinderX(group, 0.022, 0.05, M.dark, 1.69, 0.01, 0, 16);
|
|
5950
|
+
box2(group, 0.04, 0.09, 0.03, M.wood, 0.05, -0.02, 0.05);
|
|
5951
|
+
box2(group, 0.04, 0.09, 0.03, M.wood, 0.05, -0.02, -0.05);
|
|
5952
|
+
box2(group, 0.06, 0.02, 0.12, M.metal, 0.09, -0.02, 0);
|
|
5953
|
+
const belt = kit.pivot(group, 0.38, -0.05, -0.12);
|
|
5954
|
+
parts.belt = belt;
|
|
5955
|
+
box2(belt, 0.16, 0.12, 0.09, M.olive, 0, 0, 0);
|
|
5956
|
+
for (let i = 0; i < 8; i++) cylinderX(belt, 6e-3, 0.05, M.brass, -0.08 + i * 0.02, 0.08, 0.04, 8);
|
|
5957
|
+
const cover = kit.pivot(group, 0.12, 0.065, 0);
|
|
5958
|
+
parts.cover = cover;
|
|
5959
|
+
box2(cover, 0.4, 0.012, 0.12, M.metal, 0.2, 6e-3, 0);
|
|
5960
|
+
box2(group, 0.04, 0.05, 0.04, M.dark, 0.66, 0.1, 0);
|
|
5961
|
+
const bolt = kit.pivot(group);
|
|
5962
|
+
parts.bolt = bolt;
|
|
5963
|
+
box2(bolt, 0.03, 0.03, 0.02, M.metal, 0.5, 0, 0.07);
|
|
5964
|
+
const tripod = kit.group();
|
|
5965
|
+
tripod.position.set(0.42, -0.1, 0);
|
|
5966
|
+
group.add(tripod);
|
|
5967
|
+
box2(tripod, 0.03, 0.06, 0.03, M.metal, 0, 0, 0);
|
|
5968
|
+
box2(tripod, 0.012, 0.62, 0.012, M.metal, -0.2, -0.25, 0, 0.75);
|
|
5969
|
+
box2(tripod, 0.012, 0.62, 0.012, M.metal, 0.22, -0.25, 0.16, -0.75, 0, 0.3);
|
|
5970
|
+
box2(tripod, 0.012, 0.62, 0.012, M.metal, 0.22, -0.25, -0.16, -0.75, 0, -0.3);
|
|
5971
|
+
parts.muzzle = kit.mark(group, 1.72, 0.01, 0);
|
|
5972
|
+
parts.eject = kit.mark(group, 0.3, -0.07, 0);
|
|
5973
|
+
return { group, parts };
|
|
5859
5974
|
}
|
|
5860
|
-
|
|
5861
|
-
|
|
5862
|
-
|
|
5863
|
-
|
|
5864
|
-
const
|
|
5865
|
-
const
|
|
5866
|
-
|
|
5975
|
+
|
|
5976
|
+
// src/models/p90.ts
|
|
5977
|
+
function buildP90(kit) {
|
|
5978
|
+
const { M, box: box2, cylinderX } = kit;
|
|
5979
|
+
const group = kit.group();
|
|
5980
|
+
const parts = { family: "p90", stroke: 0.04, kick: 0.6, glow: [] };
|
|
5981
|
+
box2(group, 0.4, 0.07, 0.055, M.poly, 0.2, 0, 0);
|
|
5982
|
+
box2(group, 0.12, 0.075, 0.05, M.poly, 0.2, -0.07, 0);
|
|
5983
|
+
box2(group, 0.08, 0.04, 0.03, M.hole, 0.21, -0.06, 0);
|
|
5984
|
+
box2(group, 0.06, 0.13, 0.056, M.poly, 0.03, -0.03, 0);
|
|
5985
|
+
box2(group, 0.05, 0.03, 0.056, M.poly, 0.33, -0.04, 0);
|
|
5986
|
+
heatify(parts.glow, cylinderX(group, 8e-3, 0.09, M.metal, 0.43, 0, 0, 16));
|
|
5987
|
+
const magazine = kit.pivot(group, 0.22, 0.047, 0);
|
|
5867
5988
|
parts.mag = magazine;
|
|
5868
|
-
|
|
5869
|
-
|
|
5870
|
-
|
|
5871
|
-
|
|
5872
|
-
|
|
5873
|
-
|
|
5874
|
-
|
|
5875
|
-
|
|
5876
|
-
|
|
5877
|
-
|
|
5878
|
-
|
|
5879
|
-
|
|
5880
|
-
|
|
5881
|
-
|
|
5882
|
-
|
|
5883
|
-
|
|
5884
|
-
|
|
5885
|
-
|
|
5886
|
-
|
|
5887
|
-
const
|
|
5888
|
-
|
|
5889
|
-
let px = 0;
|
|
5890
|
-
let py = 0;
|
|
5891
|
-
let angle = 0.08;
|
|
5892
|
-
for (let i = 0; i < 3; i++) {
|
|
5893
|
-
angle = 0.08 + curve * i;
|
|
5894
|
-
const cx = px + Math.sin(angle) * segment / 2;
|
|
5895
|
-
const cy = py - Math.cos(angle) * segment / 2;
|
|
5896
|
-
box2(magazine, 0.05, segment + 4e-3, 0.024, material, cx, cy, 0, angle);
|
|
5897
|
-
box2(magazine, 0.04, 3e-3, 0.026, M.metal, cx, cy, 0, angle);
|
|
5898
|
-
px += Math.sin(angle) * segment;
|
|
5899
|
-
py -= Math.cos(angle) * segment;
|
|
5900
|
-
}
|
|
5901
|
-
box2(magazine, 0.056, 7e-3, 0.028, material, px, py - 2e-3, 0, angle);
|
|
5902
|
-
parts.magDrop = length + 0.03;
|
|
5903
|
-
} else if (o.mag === "drum") {
|
|
5904
|
-
buildDrum(kit, magazine);
|
|
5905
|
-
parts.magDrop = 0.2;
|
|
5906
|
-
} else if (o.mag === "internal") {
|
|
5907
|
-
box2(group, 0.08, 0.025, 0.03, context.isTraditional ? context.furniture : M.metal, mx, -hR / 2 - 0.012, 0);
|
|
5908
|
-
parts.mag = null;
|
|
5909
|
-
} else parts.mag = null;
|
|
5910
|
-
if (o.mag === "belt") {
|
|
5911
|
-
const belt = kit.pivot(group, mx + 0.02, -hR / 2 - 0.05, -0.045);
|
|
5912
|
-
parts.belt = belt;
|
|
5913
|
-
buildBeltBox(kit, belt);
|
|
5914
|
-
const cover = kit.pivot(group, x0 + 0.01, hR / 2, 0);
|
|
5915
|
-
parts.cover = cover;
|
|
5916
|
-
box2(cover, RL - 0.03, 0.014, wR * 1.05, M.metal, (RL - 0.03) / 2, 7e-3, 0);
|
|
5917
|
-
box2(cover, 0.02, 0.012, wR * 0.6, M.dark, RL - 0.04, 0.016, 0);
|
|
5989
|
+
parts.magDir = 1;
|
|
5990
|
+
parts.magDrop = 0.08;
|
|
5991
|
+
box2(magazine, 0.3, 0.022, 0.05, M.glass, 0, 0, 0);
|
|
5992
|
+
for (let i = 0; i < 12; i++) cylinderX(magazine, 28e-4, 0.02, M.brass, -0.12 + i * 0.022, 0, 0, 6);
|
|
5993
|
+
scope(kit, group, 1, 0.24, 0.06, 0);
|
|
5994
|
+
const bolt = kit.pivot(group);
|
|
5995
|
+
parts.bolt = bolt;
|
|
5996
|
+
box2(bolt, 0.02, 0.012, 0.012, M.dark, 0.3, 0.02, 0.03);
|
|
5997
|
+
parts.trigger = box2(group, 4e-3, 0.016, 4e-3, M.dark, 0.24, -0.045, 0);
|
|
5998
|
+
parts.muzzle = kit.mark(group, 0.48, 0, 0);
|
|
5999
|
+
parts.eject = kit.mark(group, 0.2, -0.07, 0);
|
|
6000
|
+
return { group, parts };
|
|
6001
|
+
}
|
|
6002
|
+
|
|
6003
|
+
// src/models/part-registry.ts
|
|
6004
|
+
var SINGLE_PARTS = ["slide", "bolt", "boltHandle", "mag", "trigger", "hammer", "lever", "pump", "belt", "cover", "crane", "cylinder", "barrels", "safety", "muzzle", "eject", "loadPort", "topLoad", "rear", "round", "gauge", "stock", "ugl"];
|
|
6005
|
+
function partRegistry(parts) {
|
|
6006
|
+
const registry = /* @__PURE__ */ new Map();
|
|
6007
|
+
for (const key of SINGLE_PARTS) {
|
|
6008
|
+
const part = parts[key];
|
|
6009
|
+
if (part) registry.set(key, part);
|
|
5918
6010
|
}
|
|
5919
|
-
|
|
6011
|
+
parts.breech?.forEach((part, index) => registry.set(`breech_${index}`, part));
|
|
6012
|
+
parts.chambers?.forEach((part, index) => registry.set(`chamber_${index}`, part));
|
|
6013
|
+
return registry;
|
|
5920
6014
|
}
|
|
5921
6015
|
|
|
5922
|
-
// src/models/
|
|
5923
|
-
|
|
5924
|
-
|
|
6016
|
+
// src/models/pistol-slide.ts
|
|
6017
|
+
var PI8 = Math.PI;
|
|
6018
|
+
function buildSlide(kit, slide2, parts, options, style, size, metal2) {
|
|
5925
6019
|
const { M, box: box2, cylinderX } = kit;
|
|
5926
|
-
|
|
5927
|
-
|
|
5928
|
-
|
|
5929
|
-
|
|
5930
|
-
|
|
5931
|
-
|
|
5932
|
-
|
|
5933
|
-
|
|
5934
|
-
|
|
5935
|
-
|
|
5936
|
-
|
|
5937
|
-
|
|
5938
|
-
|
|
5939
|
-
|
|
5940
|
-
box2(
|
|
5941
|
-
|
|
5942
|
-
|
|
5943
|
-
|
|
5944
|
-
|
|
5945
|
-
|
|
5946
|
-
box2(
|
|
5947
|
-
|
|
5948
|
-
|
|
5949
|
-
|
|
5950
|
-
|
|
5951
|
-
|
|
5952
|
-
|
|
5953
|
-
|
|
5954
|
-
|
|
5955
|
-
|
|
5956
|
-
box2(
|
|
5957
|
-
box2(
|
|
5958
|
-
|
|
6020
|
+
const { length: L, width: w } = size;
|
|
6021
|
+
const slideHeight = style.inset ? size.height * 0.92 : size.height;
|
|
6022
|
+
const slideWidth = style.inset ? w * 0.86 : w;
|
|
6023
|
+
kit.roundness = style.rf;
|
|
6024
|
+
if (style.tri) box2(slide2, L * 0.42, slideHeight, slideWidth, metal2, L * 0.21, 0, 0);
|
|
6025
|
+
else if (style.open) {
|
|
6026
|
+
box2(slide2, L * 0.45, slideHeight, slideWidth, metal2, L * 0.225, 0, 0);
|
|
6027
|
+
box2(slide2, L * 0.55, slideHeight * 0.62, slideWidth, metal2, L * 0.72, -slideHeight * 0.19, 0);
|
|
6028
|
+
} else box2(slide2, L, slideHeight, slideWidth, metal2, L / 2, 0, 0);
|
|
6029
|
+
if (style.slope) box2(slide2, L * 0.25, slideHeight * 0.5, slideWidth * 0.98, metal2, L * 0.86, slideHeight * 0.35, 0, -0.22);
|
|
6030
|
+
kit.roundness = null;
|
|
6031
|
+
for (let i = 0; i < (style.flush ? 9 : 7); i++) box2(slide2, 22e-4, slideHeight * 0.72, slideWidth + 14e-4, M.dark, 7e-3 + i * 52e-4, -2e-3, 0, 0);
|
|
6032
|
+
if (style.frontSer) for (let i = 0; i < 5; i++) box2(slide2, 22e-4, slideHeight * 0.6, slideWidth + 14e-4, M.dark, L * 0.76 + i * 52e-4, -3e-3, 0);
|
|
6033
|
+
if (style.port) {
|
|
6034
|
+
box2(slide2, L * style.port, 4e-3, slideWidth * 0.55, M.hole, L * 0.6, slideHeight / 2 - 1e-3, slideWidth * 0.12);
|
|
6035
|
+
box2(slide2, L * style.port * 0.85, 3e-3, slideWidth * 0.4, M.steelL, L * 0.6, slideHeight / 2 - 4e-4, slideWidth * 0.1);
|
|
6036
|
+
box2(slide2, 0.012, 4e-3, 2e-3, M.dark, L * 0.55, slideHeight * 0.15, slideWidth / 2 + 8e-4);
|
|
6037
|
+
}
|
|
6038
|
+
if (style.open) {
|
|
6039
|
+
heatify(parts.glow, cylinderX(slide2, 62e-4, L * 0.56, M.steelL, L * 0.7, slideHeight * 0.12, 0, 18));
|
|
6040
|
+
box2(slide2, 0.03, 4e-3, slideWidth * 0.6, M.hole, L * 0.48, slideHeight / 2 - 1e-3, 0);
|
|
6041
|
+
}
|
|
6042
|
+
if (style.tri) {
|
|
6043
|
+
const tube = new kit.THREE.Mesh(new kit.THREE.CylinderGeometry(0.016, 0.016, L * 0.6, 3), metal2);
|
|
6044
|
+
tube.castShadow = tube.receiveShadow = true;
|
|
6045
|
+
tube.rotation.set(0, 0, -PI8 / 2);
|
|
6046
|
+
tube.rotateY(PI8 / 6);
|
|
6047
|
+
tube.position.set(L * 0.7, slideHeight * 0.08, 0);
|
|
6048
|
+
slide2.add(tube);
|
|
6049
|
+
heatify(parts.glow, tube);
|
|
6050
|
+
box2(slide2, L * 0.6, 6e-3, 0.012, metal2, L * 0.7, slideHeight * 0.38, 0);
|
|
6051
|
+
for (let i = 0; i < 6; i++) box2(slide2, 8e-3, 3e-3, 0.013, M.hole, L * 0.45 + i * 0.04, slideHeight * 0.41, 0);
|
|
6052
|
+
}
|
|
6053
|
+
if (style.bushing) {
|
|
6054
|
+
heatify(parts.glow, cylinderX(slide2, 78e-4, 6e-3, M.steelL, L + 2e-3, 1e-3, 0, 18));
|
|
6055
|
+
cylinderX(slide2, 45e-4, 4e-3, M.steel, L + 2e-3, -0.012, 0, 12);
|
|
6056
|
+
}
|
|
6057
|
+
const muzzleY = style.tri ? slideHeight * 0.08 : 2e-3;
|
|
6058
|
+
heatify(parts.glow, cylinderX(slide2, style.tri ? 72e-4 : 62e-4, 4e-3, M.dark, L + 15e-4, muzzleY, 0, 18));
|
|
6059
|
+
cylinderX(slide2, 34e-4, 5e-3, M.hole, L + 25e-4, muzzleY, 0, 12);
|
|
6060
|
+
const top = slideHeight / 2;
|
|
6061
|
+
if (style.sight === "u" || style.sight === "3dot") {
|
|
6062
|
+
box2(slide2, 4e-3, 7e-3, 4e-3, M.dark, L - 8e-3, top + 35e-4, 0);
|
|
6063
|
+
box2(slide2, 22e-4, 22e-4, 46e-4, M.white, L - 8e-3, top + 58e-4, 0);
|
|
6064
|
+
box2(slide2, 8e-3, 7e-3, 0.016, M.dark, 9e-3, top + 35e-4, 0);
|
|
6065
|
+
if (style.sight === "u") box2(slide2, 4e-3, 2e-3, 0.0122, M.white, 9e-3, top + 6e-3, 0);
|
|
6066
|
+
else box2(slide2, 22e-4, 22e-4, 0.0166, M.white, 9e-3, top + 58e-4, 0);
|
|
6067
|
+
} else {
|
|
6068
|
+
box2(slide2, 6e-3, 4e-3, 3e-3, M.dark, L - 6e-3, top + 2e-3, 0);
|
|
6069
|
+
box2(slide2, 6e-3, 4e-3, 0.012, M.dark, 8e-3, top + 2e-3, 0);
|
|
6070
|
+
}
|
|
6071
|
+
if (style.decock === "slide") {
|
|
6072
|
+
box2(slide2, 0.012, 8e-3, 4e-3, M.dark, 0.02, slideHeight * 0.15, slideWidth / 2 + 2e-3, 0.3);
|
|
6073
|
+
box2(slide2, 0.012, 8e-3, 4e-3, M.dark, 0.02, slideHeight * 0.15, -slideWidth / 2 - 2e-3, 0.3);
|
|
6074
|
+
}
|
|
6075
|
+
if (style.safety === "slide") parts.safety = box2(slide2, 0.012, 8e-3, 4e-3, M.dark, 0.018, slideHeight * 0.1, -slideWidth / 2 - 2e-3, 0.2);
|
|
6076
|
+
if (options.sel) {
|
|
6077
|
+
const selector = box2(slide2, 0.01, 8e-3, 3e-3, M.dark, 0.014, -slideHeight * 0.2, slideWidth / 2 + 14e-4);
|
|
6078
|
+
parts.safety ?? (parts.safety = selector);
|
|
5959
6079
|
}
|
|
5960
6080
|
}
|
|
5961
6081
|
|
|
5962
|
-
// src/models/
|
|
5963
|
-
var
|
|
5964
|
-
|
|
5965
|
-
|
|
5966
|
-
|
|
5967
|
-
|
|
5968
|
-
|
|
5969
|
-
|
|
5970
|
-
|
|
5971
|
-
|
|
5972
|
-
|
|
5973
|
-
|
|
5974
|
-
|
|
5975
|
-
|
|
5976
|
-
|
|
5977
|
-
|
|
5978
|
-
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
|
|
5982
|
-
|
|
5983
|
-
|
|
5984
|
-
box2(group,
|
|
5985
|
-
box2(group, 0.
|
|
6082
|
+
// src/models/pistol-style.ts
|
|
6083
|
+
var STYLES = {
|
|
6084
|
+
glock: { rf: 0.07, ga: -0.36, grip: "finger", guard: "square", rail: 1, sight: "u", port: 0.2, slideM: "metal", frame: "poly" },
|
|
6085
|
+
taurus: { rf: 0.16, ga: -0.3, grip: "panel", guard: "square", rail: 1, sight: "3dot", port: 0.18, frontSer: 1, frame: "poly" },
|
|
6086
|
+
g2c: { rf: 0.2, ga: -0.3, grip: "panel", guard: "round", rail: 0, sight: "3dot", port: 0.17, frame: "poly", safety: "thumb" },
|
|
6087
|
+
beretta: { rf: 0.28, ga: -0.27, grip: "wood", guard: "round", hammer: "spur", sight: "3dot", open: 1, decock: "slide", port: 0, frame: "metal" },
|
|
6088
|
+
pt100: { rf: 0.25, ga: -0.27, grip: "rubber", guard: "round", hammer: "spur", sight: "3dot", port: 0.17, decock: "frame", frame: "metal" },
|
|
6089
|
+
sig: { rf: 0.14, ga: -0.3, grip: "rubber", guard: "hook", hammer: "spur", sight: "3dot", port: 0.19, decock: "frame", rail: 1, tall: 1.12, frame: "metal" },
|
|
6090
|
+
cz: { rf: 0.32, ga: -0.3, grip: "rubber", guard: "round", hammer: "spur", sight: "3dot", port: 0.15, inset: 1, safety: "thumb", frame: "metal" },
|
|
6091
|
+
m1911: { rf: 0.24, ga: -0.2, grip: "wood", guard: "round", hammer: "ring", sight: "small", port: 0.12, bushing: 1, beaver: 1, safety: "thumb", slideStop: 1, frame: "metal" },
|
|
6092
|
+
makarov: { rf: 0.48, ga: -0.24, grip: "star", guard: "round", hammer: "ring", sight: "small", port: 0.14, flush: 1, safety: "slide", lanyard: 1, frame: "metal" },
|
|
6093
|
+
fiveseven: { rf: 0.2, ga: -0.4, grip: "chunky", guard: "square", rail: 1, sight: "3dot", port: 0.18, slope: 1, frame: "poly" },
|
|
6094
|
+
deagle: { rf: 0.08, ga: -0.28, grip: "rubber", guard: "round", hammer: "big", sight: "small", port: 0.16, tri: 1, safety: "slide", frame: "metal" }
|
|
6095
|
+
};
|
|
6096
|
+
|
|
6097
|
+
// src/models/pistol.ts
|
|
6098
|
+
var PI9 = Math.PI;
|
|
6099
|
+
function buildFrame(kit, group, parts, options, style, size, materials) {
|
|
6100
|
+
const { M, box: box2, cylinderZ, sphere } = kit;
|
|
6101
|
+
const { length: L, height: h, width: w } = size;
|
|
6102
|
+
const fm = materials.frame;
|
|
6103
|
+
if (style.inset) {
|
|
6104
|
+
box2(group, L * 0.9, h * 0.35, w * 0.12, fm, L * 0.47, -h * 0.32, w * 0.47);
|
|
6105
|
+
box2(group, L * 0.9, h * 0.35, w * 0.12, fm, L * 0.47, -h * 0.32, -w * 0.47);
|
|
5986
6106
|
}
|
|
5987
|
-
|
|
5988
|
-
|
|
5989
|
-
|
|
5990
|
-
|
|
6107
|
+
const frameLength = style.tri ? L * 0.66 : L * 0.8;
|
|
6108
|
+
kit.roundness = style.rf;
|
|
6109
|
+
box2(group, frameLength, 0.016, w * 0.92, fm, frameLength / 2 + L * 0.06, -h / 2 - 8e-3, 0);
|
|
6110
|
+
kit.roundness = null;
|
|
6111
|
+
if (style.rail) for (let i = 0; i < (style.slope ? 5 : 3); i++) box2(group, 4e-3, 3e-3, w * 0.96, M.dark, L * 0.62 + i * 9e-3, -h / 2 - 0.017, 0);
|
|
6112
|
+
const isGlock = options.st === "glock" || !options.st;
|
|
6113
|
+
if (isGlock) {
|
|
6114
|
+
box2(group, 8e-3, 4e-3, 3e-3, M.dark, L * 0.5, -h / 2 - 3e-3, -w / 2 - 12e-4);
|
|
6115
|
+
box2(group, 8e-3, 4e-3, 3e-3, M.dark, L * 0.5, -h / 2 - 3e-3, w / 2 + 12e-4);
|
|
6116
|
+
}
|
|
6117
|
+
if (style.slideStop) {
|
|
6118
|
+
box2(group, 0.03, 6e-3, 3e-3, M.dark, L * 0.42, -h / 2 - 2e-3, -w / 2 - 14e-4);
|
|
6119
|
+
sphere(group, 28e-4, M.dark, L * 0.55, -h / 2 - 3e-3, w / 2 + 1e-3, 1);
|
|
6120
|
+
} else box2(group, 0.012, 4e-3, 3e-3, M.dark, L * 0.45, -h / 2 - 3e-3, -w / 2 - 12e-4);
|
|
6121
|
+
if (style.decock === "frame") box2(group, 0.01, 0.012, 3e-3, M.dark, L * 0.38, -h / 2 - 0.012, -w / 2 - 14e-4, 0.6);
|
|
6122
|
+
if (style.safety === "thumb") parts.safety = box2(group, 0.014, 6e-3, 4e-3, M.dark, 0.02, -h / 2 - 2e-3, -w / 2 - 16e-4);
|
|
6123
|
+
const gripLength = options.gl ?? 0.105;
|
|
6124
|
+
const gx = 0.034 + (L - 0.2) * 0.15;
|
|
6125
|
+
const gy = -h / 2 - gripLength / 2 + 6e-3;
|
|
6126
|
+
const grip = kit.pivot(group, gx, gy, 0);
|
|
6127
|
+
grip.rotation.z = style.ga;
|
|
6128
|
+
parts.grip = grip;
|
|
6129
|
+
const gripWidth = style.grip === "chunky" ? w * 1.18 : w * 1.06;
|
|
6130
|
+
const gripDepth = style.grip === "chunky" ? 0.036 : 0.032;
|
|
6131
|
+
kit.roundness = 0.3;
|
|
6132
|
+
if (style.grip === "wood" || style.grip === "star") {
|
|
6133
|
+
box2(grip, gripDepth * 0.86, gripLength, w * 0.9, fm, 0, 0, 0);
|
|
6134
|
+
box2(grip, gripDepth * 0.8, gripLength * 0.86, 4e-3, materials.grip, 1e-3, -2e-3, w * 0.47);
|
|
6135
|
+
box2(grip, gripDepth * 0.8, gripLength * 0.86, 4e-3, materials.grip, 1e-3, -2e-3, -w * 0.47);
|
|
6136
|
+
if (style.grip === "wood") {
|
|
6137
|
+
for (let i = 0; i < 6; i++) for (let j = 0; j < 2; j++) box2(grip, 3e-3, 3e-3, 12e-4, M.woodL, -6e-3 + j * 0.012, -gripLength * 0.3 + i * 0.012, w * 0.495, 0, 0, 0);
|
|
6138
|
+
cylinderZ(grip, 35e-4, 15e-4, M.brass, 0, gripLength * 0.25, w * 0.5, 10);
|
|
6139
|
+
cylinderZ(grip, 35e-4, 15e-4, M.brass, 0, -gripLength * 0.3, w * 0.5, 10);
|
|
6140
|
+
} else cylinderZ(grip, 8e-3, 15e-4, M.dark, 0, gripLength * 0.1, w * 0.5, 5);
|
|
6141
|
+
} else box2(grip, gripDepth, gripLength, gripWidth, materials.grip, 0, 0, 0);
|
|
6142
|
+
kit.roundness = null;
|
|
6143
|
+
if (style.grip === "finger") {
|
|
6144
|
+
for (let i = 0; i < 3; i++) box2(grip, 6e-3, 0.012, gripWidth * 0.98, materials.grip, gripDepth / 2 + 2e-3, gripLength * 0.18 - i * 0.022, 0);
|
|
6145
|
+
for (let i = 0; i < 5; i++) for (let j = 0; j < 3; j++) box2(grip, 3e-3, 3e-3, 12e-4, M.dark, -8e-3 + j * 8e-3, -gripLength * 0.25 + i * 0.012, gripWidth / 2 + 4e-4);
|
|
5991
6146
|
}
|
|
5992
|
-
|
|
5993
|
-
|
|
5994
|
-
|
|
5995
|
-
|
|
5996
|
-
|
|
5997
|
-
|
|
5998
|
-
|
|
5999
|
-
|
|
6000
|
-
|
|
6001
|
-
sphere(bolt, 65e-4, M.metal, ejectX + 0.04, ejectY + 4e-3, wR / 2 + 0.028, 1);
|
|
6147
|
+
if (style.grip === "panel" || style.grip === "rubber" || style.grip === "chunky") for (let i = 0; i < 6; i++) box2(grip, gripDepth * 0.75, 25e-4, gripWidth + 1e-3, M.dark, 2e-3, -gripLength / 2 + 0.018 + i * 0.013, 0);
|
|
6148
|
+
if (style.grip === "chunky") box2(grip, 8e-3, gripLength * 0.8, gripWidth * 0.9, materials.grip, gripDepth / 2 + 2e-3, -4e-3, 0);
|
|
6149
|
+
if (style.beaver) {
|
|
6150
|
+
box2(group, 0.026, 8e-3, w * 0.9, fm, -4e-3, -h / 2 - 4e-3, 0, 0.25);
|
|
6151
|
+
box2(grip, 6e-3, gripLength * 0.55, w * 0.9, fm, -gripDepth * 0.5 - 2e-3, gripLength * 0.18, 0);
|
|
6152
|
+
} else box2(group, 0.02, 9e-3, w * 0.9, fm, 4e-3, -h / 2 - 6e-3, 0);
|
|
6153
|
+
if (style.lanyard) {
|
|
6154
|
+
const ring = kit.torus(grip, new kit.THREE.TorusGeometry(5e-3, 13e-4, 6, 12), M.dark, -0.012, -gripLength / 2 + 4e-3, 0);
|
|
6155
|
+
ring.position.set(-0.012, -gripLength / 2 + 4e-3, 0);
|
|
6002
6156
|
}
|
|
6003
|
-
|
|
6004
|
-
|
|
6157
|
+
const magazine = kit.pivot(grip);
|
|
6158
|
+
parts.mag = magazine;
|
|
6159
|
+
parts.magDrop = gripLength * 1.15;
|
|
6160
|
+
box2(magazine, 0.022, gripLength * 0.94, w * 0.72, M.dark, 3e-3, -4e-3, 0);
|
|
6161
|
+
if (style.grip === "chunky") box2(magazine, 0.04, 0.01, gripWidth * 1.02, M.poly, 3e-3, -gripLength / 2 - 4e-3, 0);
|
|
6162
|
+
else if (style.flush || style.grip === "wood") box2(magazine, 0.028, 4e-3, w * 0.9, M.steel, 3e-3, -gripLength / 2 - 1e-3, 0);
|
|
6163
|
+
else box2(magazine, 0.031, 6e-3, gripWidth * 1.02, M.dark, 3e-3, -gripLength / 2 - 2e-3, 0);
|
|
6164
|
+
return { gx, ty: -h / 2 };
|
|
6005
6165
|
}
|
|
6006
|
-
function
|
|
6007
|
-
const {
|
|
6008
|
-
const {
|
|
6009
|
-
|
|
6010
|
-
|
|
6011
|
-
|
|
6012
|
-
|
|
6166
|
+
function buildPistol(kit, options) {
|
|
6167
|
+
const { M, box: box2 } = kit;
|
|
6168
|
+
const style = { ...STYLES[options.st ?? "glock"] };
|
|
6169
|
+
const group = kit.group();
|
|
6170
|
+
const parts = { family: "pistol", kick: options.deagle ? 1.8 : 0.6, glow: [] };
|
|
6171
|
+
const size = { length: (options.L ?? 0) / 1e3 * 0.97, height: (options.h ?? 0.031) * (style.tall ?? 1), width: options.deagle ? 0.032 : style.flush ? 0.024 : 0.025 };
|
|
6172
|
+
const { length: L, height: h, width: w } = size;
|
|
6173
|
+
const slideMetal = options.steel ? M.steel : options.stain ? M.steelL : M.metal;
|
|
6174
|
+
const frameMetal = style.frame === "poly" ? M.poly : slideMetal;
|
|
6175
|
+
const gripMaterial = style.grip === "wood" ? M.wood : style.grip === "star" ? M.bake : style.grip === "rubber" ? M.rubber : M.poly;
|
|
6176
|
+
const slide2 = kit.pivot(group);
|
|
6177
|
+
parts.slide = slide2;
|
|
6178
|
+
parts.stroke = L * 0.15;
|
|
6179
|
+
buildSlide(kit, slide2, parts, options, style, size, slideMetal);
|
|
6180
|
+
const { gx, ty } = buildFrame(kit, group, parts, options, style, size, { frame: frameMetal, grip: gripMaterial });
|
|
6181
|
+
if (style.guard === "square") {
|
|
6182
|
+
box2(group, 0.046, 4e-3, 9e-3, frameMetal, gx + 0.05, ty - 0.034, 0);
|
|
6183
|
+
box2(group, 4e-3, 0.03, 9e-3, frameMetal, gx + 0.074, ty - 0.02, 0);
|
|
6184
|
+
box2(group, 6e-3, 4e-3, 9e-3, frameMetal, gx + 0.075, ty - 0.034, 0);
|
|
6185
|
+
} else if (style.guard === "hook") {
|
|
6186
|
+
box2(group, 0.046, 4e-3, 9e-3, frameMetal, gx + 0.05, ty - 0.034, 0);
|
|
6187
|
+
box2(group, 4e-3, 0.03, 9e-3, frameMetal, gx + 0.073, ty - 0.02, 0, 0.2);
|
|
6188
|
+
box2(group, 8e-3, 6e-3, 9e-3, frameMetal, gx + 0.074, ty - 0.037, 0, 0.4);
|
|
6189
|
+
} else {
|
|
6190
|
+
const guard = kit.torus(group, new kit.THREE.TorusGeometry(0.019, 22e-4, 6, 16, PI9), frameMetal, gx + 0.05, ty - 0.014, 0);
|
|
6191
|
+
guard.rotation.z = PI9;
|
|
6192
|
+
guard.scale.set(1.2, 1, 1);
|
|
6013
6193
|
}
|
|
6014
|
-
|
|
6015
|
-
|
|
6016
|
-
|
|
6017
|
-
|
|
6018
|
-
|
|
6019
|
-
|
|
6020
|
-
|
|
6021
|
-
|
|
6022
|
-
|
|
6023
|
-
|
|
6024
|
-
|
|
6025
|
-
|
|
6194
|
+
const isGlock = options.st === "glock" || !options.st;
|
|
6195
|
+
parts.trigger = box2(group, 4e-3, 0.014, 4e-3, isGlock ? M.dark : M.steel, gx + 0.042, ty - 0.022, 0, 0.2);
|
|
6196
|
+
if (isGlock) box2(parts.trigger, 15e-4, 8e-3, 45e-4, M.metal, 0, -1e-3, 0);
|
|
6197
|
+
if (style.hammer) {
|
|
6198
|
+
const hammer = kit.pivot(group, 3e-3, h / 2 - 8e-3, 0);
|
|
6199
|
+
parts.hammer = hammer;
|
|
6200
|
+
if (style.hammer === "ring") {
|
|
6201
|
+
box2(hammer, 6e-3, 0.012, 6e-3, M.dark, -2e-3, 4e-3, 0, 0.3);
|
|
6202
|
+
kit.torus(hammer, new kit.THREE.TorusGeometry(45e-4, 16e-4, 6, 12), M.dark, -4e-3, 0.012, 0);
|
|
6203
|
+
} else if (style.hammer === "big") box2(hammer, 0.014, 0.02, 9e-3, M.dark, -4e-3, 7e-3, 0, 0.35);
|
|
6204
|
+
else {
|
|
6205
|
+
box2(hammer, 8e-3, 0.016, 7e-3, M.dark, -2e-3, 6e-3, 0, 0.3);
|
|
6206
|
+
box2(hammer, 8e-3, 4e-3, 8e-3, M.dark, -6e-3, 0.013, 0, 0.3);
|
|
6207
|
+
}
|
|
6026
6208
|
}
|
|
6027
|
-
|
|
6209
|
+
parts.muzzle = kit.mark(group, L + 6e-3, style.tri ? h * 0.08 : 2e-3, 0);
|
|
6210
|
+
parts.eject = kit.mark(group, L * 0.6, h / 2, w * 0.25);
|
|
6211
|
+
return { group, parts };
|
|
6028
6212
|
}
|
|
6029
|
-
|
|
6030
|
-
|
|
6031
|
-
|
|
6032
|
-
|
|
6033
|
-
|
|
6034
|
-
|
|
6035
|
-
return o.mag === "internal" ? "semiint" : "rifle";
|
|
6036
|
-
};
|
|
6037
|
-
function buildRifle(kit, options) {
|
|
6038
|
-
const { M } = kit;
|
|
6213
|
+
|
|
6214
|
+
// src/models/revolver.ts
|
|
6215
|
+
var PI10 = Math.PI;
|
|
6216
|
+
var DEFAULT_CHAMBERS = 6;
|
|
6217
|
+
function buildRevolver(kit, options) {
|
|
6218
|
+
const { M, box: box2, cylinderX } = kit;
|
|
6039
6219
|
const group = kit.group();
|
|
6040
|
-
const parts = { family: "
|
|
6041
|
-
const
|
|
6042
|
-
const
|
|
6043
|
-
const
|
|
6044
|
-
|
|
6045
|
-
|
|
6046
|
-
|
|
6047
|
-
const
|
|
6048
|
-
|
|
6049
|
-
|
|
6050
|
-
|
|
6051
|
-
|
|
6052
|
-
|
|
6053
|
-
|
|
6054
|
-
|
|
6055
|
-
|
|
6056
|
-
|
|
6057
|
-
|
|
6058
|
-
|
|
6059
|
-
|
|
6060
|
-
|
|
6061
|
-
|
|
6062
|
-
|
|
6063
|
-
|
|
6064
|
-
|
|
6065
|
-
|
|
6066
|
-
|
|
6067
|
-
|
|
6068
|
-
|
|
6069
|
-
|
|
6070
|
-
const
|
|
6071
|
-
|
|
6072
|
-
|
|
6073
|
-
|
|
6074
|
-
|
|
6075
|
-
|
|
6076
|
-
|
|
6077
|
-
|
|
6078
|
-
|
|
6079
|
-
|
|
6080
|
-
receiverEnd,
|
|
6081
|
-
receiverHeight,
|
|
6082
|
-
receiverWidth: context.receiverWidth,
|
|
6083
|
-
handguardEnd: receiverEnd + (length - receiverEnd) * (hasHandguard ? options.hgFrac || 0.5 : 0.4),
|
|
6084
|
-
magazineX,
|
|
6085
|
-
gripX,
|
|
6086
|
-
hasRail: Boolean(options.rail)
|
|
6087
|
-
};
|
|
6088
|
-
const { barrelY: by, receiverWidth: wR } = context;
|
|
6089
|
-
const ejectX = receiverEnd - (options.ejectBack || 0.07);
|
|
6090
|
-
const ejectY = options.ar ? receiverHeight * 0.2 : by;
|
|
6091
|
-
parts.muzzle = kit.mark(group, length + 0.01, by, 0);
|
|
6092
|
-
parts.eject = kit.mark(group, ejectX, ejectY, wR / 2 + 6e-3);
|
|
6093
|
-
parts.loadPort = kit.mark(group, receiverEnd - 0.05, -receiverHeight / 2 - 4e-3, 0);
|
|
6094
|
-
parts.topLoad = kit.mark(group, ejectX, receiverHeight / 2 + 4e-3, 0);
|
|
6095
|
-
parts.family = familyOf(options);
|
|
6220
|
+
const parts = { family: "revolver", kick: options.cal === ".44 Magnum" ? 1.5 : 0.9, glow: [] };
|
|
6221
|
+
const barrel = (options.B ?? 0) / 1e3;
|
|
6222
|
+
const chambers = options.chambers ?? DEFAULT_CHAMBERS;
|
|
6223
|
+
const metal2 = options.steel ? M.steel : M.metal;
|
|
6224
|
+
box2(group, 0.08, 0.044, 0.024, metal2, 0.07, 0, 0);
|
|
6225
|
+
box2(group, 0.036, 0.012, 0.022, metal2, 0.096, 0.022, 0);
|
|
6226
|
+
box2(group, 0.024, 0.012, 4e-3, M.dark, 0.055, 6e-3, -0.013);
|
|
6227
|
+
const crane = kit.pivot(group, 0.077, -0.024, 0);
|
|
6228
|
+
parts.crane = crane;
|
|
6229
|
+
const cylinder = kit.pivot(crane, 0, 0.022, 0);
|
|
6230
|
+
parts.cylinder = cylinder;
|
|
6231
|
+
cylinderX(cylinder, 0.0215, 0.042, metal2, 0, 0, 0, 24);
|
|
6232
|
+
for (let i = 0; i < chambers; i++) {
|
|
6233
|
+
const angle = i * 2 * PI10 / chambers;
|
|
6234
|
+
box2(cylinder, 0.026, 5e-3, 5e-3, M.dark, 0, Math.cos(angle) * 0.0205, Math.sin(angle) * 0.0205, 0, 0, angle);
|
|
6235
|
+
}
|
|
6236
|
+
parts.chambers = [];
|
|
6237
|
+
for (let i = 0; i < chambers; i++) {
|
|
6238
|
+
const angle = i * 2 * PI10 / chambers + PI10 / chambers;
|
|
6239
|
+
parts.chambers.push(kit.mark(cylinder, -0.022, Math.cos(angle) * 0.013, Math.sin(angle) * 0.013));
|
|
6240
|
+
cylinderX(cylinder, 46e-4, 2e-3, M.brass, -0.0215, Math.cos(angle) * 0.013, Math.sin(angle) * 0.013, 12);
|
|
6241
|
+
}
|
|
6242
|
+
heatify(parts.glow, cylinderX(group, 88e-4, barrel, metal2, 0.112 + barrel / 2, 9e-3, 0, 18));
|
|
6243
|
+
box2(group, barrel * 0.92, 0.015, 0.013, metal2, 0.112 + barrel * 0.46, -5e-3, 0);
|
|
6244
|
+
cylinderX(group, 4e-3, 5e-3, M.hole, 0.112 + barrel + 15e-4, 9e-3, 0, 12);
|
|
6245
|
+
box2(group, 0.012, 9e-3, 4e-3, M.dark, 0.112 + barrel - 8e-3, 0.021, 0, -0.3);
|
|
6246
|
+
box2(group, 0.012, 6e-3, 0.012, M.dark, 0.105, 0.031, 0);
|
|
6247
|
+
const hammer = kit.pivot(group, 0.036, 0.018, 0);
|
|
6248
|
+
box2(hammer, 0.01, 0.02, 8e-3, M.dark, -4e-3, 8e-3, 0, 0.45);
|
|
6249
|
+
parts.hammer = hammer;
|
|
6250
|
+
const grip = kit.pivot(group, 0.024, -0.062, 0);
|
|
6251
|
+
grip.rotation.z = -0.38;
|
|
6252
|
+
parts.grip = grip;
|
|
6253
|
+
box2(grip, 0.034, 0.1, 0.031, options.wood ? M.wood : M.rubber, 0, 0, 0);
|
|
6254
|
+
if (!options.wood) for (let i = 0; i < 4; i++) box2(grip, 6e-3, 0.07, 0.033, M.dark, -0.012 + i * 8e-3, 0, 0);
|
|
6255
|
+
box2(group, 0.038, 4e-3, 8e-3, metal2, 0.062, -0.036, 0);
|
|
6256
|
+
box2(group, 4e-3, 0.022, 8e-3, metal2, 0.08, -0.026, 0, 0.2);
|
|
6257
|
+
parts.trigger = box2(group, 4e-3, 0.015, 4e-3, M.dark, 0.06, -0.027, 0, 0.2);
|
|
6258
|
+
parts.muzzle = kit.mark(group, 0.112 + barrel + 6e-3, 9e-3, 0);
|
|
6259
|
+
parts.eject = kit.mark(group, 0.077, 0, 0);
|
|
6096
6260
|
return { group, parts };
|
|
6097
6261
|
}
|
|
6098
6262
|
|
|
@@ -6108,13 +6272,14 @@ var ARCHETYPE_MODELS = (() => {
|
|
|
6108
6272
|
}
|
|
6109
6273
|
return chosen;
|
|
6110
6274
|
})();
|
|
6111
|
-
var
|
|
6275
|
+
var BUILDERS2 = {
|
|
6112
6276
|
pistol: buildPistol,
|
|
6113
6277
|
revolver: buildRevolver,
|
|
6114
6278
|
rifle: buildRifle,
|
|
6115
6279
|
bullpup: buildBullpup,
|
|
6116
6280
|
p90: (kit) => buildP90(kit),
|
|
6117
6281
|
break: buildBreakAction,
|
|
6282
|
+
breakLauncher: buildBreakLauncher,
|
|
6118
6283
|
m2: (kit) => buildM2(kit),
|
|
6119
6284
|
m134: (kit) => buildM134(kit),
|
|
6120
6285
|
launcher: buildLauncher
|
|
@@ -6138,7 +6303,7 @@ function buildWeaponModelById(THREE, id) {
|
|
|
6138
6303
|
const kit = modelKit(THREE);
|
|
6139
6304
|
const options = { L: entry.length, B: entry.barrel, cal: entry.caliber, ...entry.options };
|
|
6140
6305
|
if (id in ARCHETYPE_MODELS) delete options.chambers;
|
|
6141
|
-
const built =
|
|
6306
|
+
const built = BUILDERS2[entry.builder](kit, options);
|
|
6142
6307
|
nameParts(built.parts);
|
|
6143
6308
|
let root;
|
|
6144
6309
|
if (entry.builder === "launcher") {
|
|
@@ -6147,7 +6312,7 @@ function buildWeaponModelById(THREE, id) {
|
|
|
6147
6312
|
built.group.position.x = -new THREE.Box3().setFromObject(built.group).min.x;
|
|
6148
6313
|
} else root = fitLength(kit, built.group, entry.length / 1e3);
|
|
6149
6314
|
root.name = id;
|
|
6150
|
-
|
|
6315
|
+
markKitOrigin3(root, { owner: "game-weapons-three", kind: "weapon", id });
|
|
6151
6316
|
const model = { id, root, inner: built.group, parts: built.parts };
|
|
6152
6317
|
if (!built.parts.frames) built.parts.frames = deriveFrames(THREE, model);
|
|
6153
6318
|
return model;
|
|
@@ -6380,9 +6545,17 @@ function revolverReload(kind) {
|
|
|
6380
6545
|
if (kind !== "one_by_one") events.push(cue(0.7, "move_in", { from: "chambers" }), sound2(0.7, "speedloader"));
|
|
6381
6546
|
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 };
|
|
6382
6547
|
}
|
|
6383
|
-
var breakReload = () => ({
|
|
6548
|
+
var breakReload = (chambers) => ({
|
|
6384
6549
|
tweens: [turn("barrels", "z", 0, 0.2, 0, -0.5), turn("barrels", "z", 1, 0.15, -0.5, 0)],
|
|
6385
|
-
events: [
|
|
6550
|
+
events: [
|
|
6551
|
+
sound2(0, "barrels_open"),
|
|
6552
|
+
cue(0.25, "eject_casing", { from: "breech", down: false }),
|
|
6553
|
+
sound2(0.25, "casings_eject"),
|
|
6554
|
+
cue(0.65, "move_in", { from: "breech" }),
|
|
6555
|
+
sound2(0.65, "shell_insert"),
|
|
6556
|
+
...chambers > 1 ? [sound2(0.8, "shell_insert")] : [],
|
|
6557
|
+
sound2(1.13, "barrels_close")
|
|
6558
|
+
],
|
|
6386
6559
|
end: 1.2
|
|
6387
6560
|
});
|
|
6388
6561
|
var beltReload = (context) => ({
|
|
@@ -6455,7 +6628,7 @@ function draftFor(context, kind) {
|
|
|
6455
6628
|
if (family === "rocket" || family === "flame") return heavyReload(context);
|
|
6456
6629
|
if (parts.mag) return magazineReload(context, kind);
|
|
6457
6630
|
if (family === "revolver" && parts.crane) return revolverReload(kind);
|
|
6458
|
-
if (family === "break" && parts.barrels) return breakReload();
|
|
6631
|
+
if (family === "break" && parts.barrels) return breakReload(parts.breech?.length ?? 2);
|
|
6459
6632
|
if (family === "belt" && parts.cover && parts.belt) return beltReload(context);
|
|
6460
6633
|
if (isTube(context)) return tubeReload(context, kind);
|
|
6461
6634
|
if (family === "bolt") return boltReload(context);
|
|
@@ -7155,7 +7328,7 @@ function applyCondition(kit, model, condition) {
|
|
|
7155
7328
|
}
|
|
7156
7329
|
|
|
7157
7330
|
// src/models/cartridge.ts
|
|
7158
|
-
import { markKitOrigin as
|
|
7331
|
+
import { markKitOrigin as markKitOrigin4 } from "@adatechnology/game-contracts";
|
|
7159
7332
|
var BOTTLENECK_RATIO = 0.8;
|
|
7160
7333
|
function cartridgeShape(caliber, dims) {
|
|
7161
7334
|
if (caliber.caseType === "shell" || caliber.rim === "shell") return "shell";
|
|
@@ -7167,7 +7340,7 @@ function cartridgeShape(caliber, dims) {
|
|
|
7167
7340
|
}
|
|
7168
7341
|
function buildCartridge(kit, dims, shape) {
|
|
7169
7342
|
const { M, cylinderY } = kit;
|
|
7170
|
-
const group =
|
|
7343
|
+
const group = markKitOrigin4(kit.group(), { owner: "game-weapons-three", kind: "ammunition", id: shape });
|
|
7171
7344
|
const radius = dims.caseDiameter / 2;
|
|
7172
7345
|
const bulletRadius = dims.projectileDiameter / 2;
|
|
7173
7346
|
const caseLength = dims.caseLength;
|
|
@@ -7199,7 +7372,7 @@ function buildCartridge(kit, dims, shape) {
|
|
|
7199
7372
|
}
|
|
7200
7373
|
function buildCasing(kit, dims, shape) {
|
|
7201
7374
|
const { M, cylinderX } = kit;
|
|
7202
|
-
const group =
|
|
7375
|
+
const group = markKitOrigin4(kit.group(), { owner: "game-weapons-three", kind: "ammunition", id: shape });
|
|
7203
7376
|
const radius = dims.caseDiameter / 2e3;
|
|
7204
7377
|
const length = dims.caseLength / 1e3;
|
|
7205
7378
|
if (shape === "shell") {
|
|
@@ -7215,7 +7388,7 @@ function buildCasing(kit, dims, shape) {
|
|
|
7215
7388
|
return { group, radius, length };
|
|
7216
7389
|
}
|
|
7217
7390
|
function buildRound(kit, dims, shape) {
|
|
7218
|
-
const group =
|
|
7391
|
+
const group = markKitOrigin4(kit.group(), { owner: "game-weapons-three", kind: "ammunition", id: shape });
|
|
7219
7392
|
const cartridge = buildCartridge(kit, dims, shape);
|
|
7220
7393
|
cartridge.scale.setScalar(1e-3);
|
|
7221
7394
|
cartridge.rotation.z = -Math.PI / 2;
|
|
@@ -7252,6 +7425,38 @@ function createEffects(THREE, sink, random) {
|
|
|
7252
7425
|
};
|
|
7253
7426
|
}
|
|
7254
7427
|
|
|
7428
|
+
// src/fx/view-hold.ts
|
|
7429
|
+
var VIEW_HOLD = {
|
|
7430
|
+
/** The right hand's grip, from the eye. */
|
|
7431
|
+
grip: [0.2, -0.2, -0.3],
|
|
7432
|
+
/** A handgun's grip: higher and nearer the middle, the arms out in front. */
|
|
7433
|
+
handgunGrip: [0.13, -0.15, -0.33],
|
|
7434
|
+
/** A rocket launcher's grip: its tube rides on the shoulder, so the hands are higher. */
|
|
7435
|
+
launcherGrip: [0.2, -0.14, -0.3],
|
|
7436
|
+
/** A gun with no grip anchor: the rear of its bore, from the eye. */
|
|
7437
|
+
rear: [0.2, -0.24, -0.12]
|
|
7438
|
+
};
|
|
7439
|
+
var scratch2 = { grip: null };
|
|
7440
|
+
function placeInView(placement) {
|
|
7441
|
+
const { THREE, hand, holder, camera, right } = placement;
|
|
7442
|
+
holder.scale.setScalar(1);
|
|
7443
|
+
hand.position.copy(camera.position);
|
|
7444
|
+
hand.quaternion.copy(camera.quaternion);
|
|
7445
|
+
hand.scale.setScalar(1);
|
|
7446
|
+
holder.position.set(0, 0, 0);
|
|
7447
|
+
hand.updateMatrixWorld(true);
|
|
7448
|
+
if (!right) {
|
|
7449
|
+
holder.position.set(VIEW_HOLD.rear[0], VIEW_HOLD.rear[1], VIEW_HOLD.rear[2] + placement.rear);
|
|
7450
|
+
hand.updateMatrixWorld(true);
|
|
7451
|
+
return;
|
|
7452
|
+
}
|
|
7453
|
+
scratch2.grip ?? (scratch2.grip = new THREE.Vector3());
|
|
7454
|
+
const grip = hand.worldToLocal(right.part.localToWorld(scratch2.grip.copy(right.offset)));
|
|
7455
|
+
const [x, y, z] = placement.kind === "handgun" ? VIEW_HOLD.handgunGrip : placement.kind === "launcher" ? VIEW_HOLD.launcherGrip : VIEW_HOLD.grip;
|
|
7456
|
+
holder.position.set(x - grip.x, y - grip.y, z - grip.z);
|
|
7457
|
+
hand.updateMatrixWorld(true);
|
|
7458
|
+
}
|
|
7459
|
+
|
|
7255
7460
|
// src/fx/heavy.ts
|
|
7256
7461
|
import { LIGHT_PRIORITY as LIGHT_PRIORITY2, geometryKey, materialKey } from "@adatechnology/game-render-three";
|
|
7257
7462
|
import { discardObject3D } from "@adatechnology/game-shapes-three";
|
|
@@ -8212,10 +8417,13 @@ function createViewmodel(options) {
|
|
|
8212
8417
|
const distance = () => options.soundDistance?.() ?? 0;
|
|
8213
8418
|
const particles = createParticles(THREE, scene, groundAt, options.particleLimit);
|
|
8214
8419
|
particles.onBounce = (kind, hit) => {
|
|
8215
|
-
if (kind
|
|
8216
|
-
if (kind !== "casing" || !audio) return;
|
|
8217
|
-
const caseType = hit?.object.userData["caseType"];
|
|
8420
|
+
if (!audio || kind !== "casing" && kind !== "magazine") return;
|
|
8218
8421
|
const surface = hit ? options.surfaceAt?.(hit.object.position.x, hit.object.position.z) : void 0;
|
|
8422
|
+
if (kind === "magazine") {
|
|
8423
|
+
audio.thud({ ...surface ? { surface } : {}, ...hit ? { speed: hit.speed, bounce: hit.bounce } : {} });
|
|
8424
|
+
return;
|
|
8425
|
+
}
|
|
8426
|
+
const caseType = hit?.object.userData["caseType"];
|
|
8219
8427
|
audio.casing({ ...caseType ? { caseType } : {}, ...surface ? { surface } : {}, ...hit ? { speed: hit.speed, bounce: hit.bounce } : {} });
|
|
8220
8428
|
};
|
|
8221
8429
|
if (!options.effects) warnOnce2("game-weapons-three.own-effects-world", "game-weapons-three made an effects world of its own because the host lent none (options.effects); pass the host effects so the effects share one budget");
|
|
@@ -8244,6 +8452,8 @@ function createViewmodel(options) {
|
|
|
8244
8452
|
let triggerRest = 0;
|
|
8245
8453
|
let feedCued = false;
|
|
8246
8454
|
const rootQuaternion = new THREE.Quaternion();
|
|
8455
|
+
const muzzleAt = new THREE.Vector3();
|
|
8456
|
+
const muzzleAlong = new THREE.Vector3();
|
|
8247
8457
|
const world = {
|
|
8248
8458
|
kit,
|
|
8249
8459
|
scene,
|
|
@@ -8343,6 +8553,7 @@ function createViewmodel(options) {
|
|
|
8343
8553
|
if (model.parts.stockMove && onTool?.stock === "collapsed") rig.setPartPose("stock", collapsedStockPose(model.parts.stockMove));
|
|
8344
8554
|
applyCondition(kit, model, condition);
|
|
8345
8555
|
lastAmmo = options.tool?.().ammo ?? 0;
|
|
8556
|
+
void audio?.loadSamples();
|
|
8346
8557
|
hand.updateMatrixWorld(true);
|
|
8347
8558
|
hold = holdOfModel(THREE, model, 1);
|
|
8348
8559
|
hold = { ...hold, works: handWorkOf(THREE, model, weapon, hold.right) };
|
|
@@ -8395,12 +8606,22 @@ function createViewmodel(options) {
|
|
|
8395
8606
|
if (!session) return;
|
|
8396
8607
|
const family = session.model.parts.family;
|
|
8397
8608
|
session.holderScale = 1;
|
|
8609
|
+
if (options.firstPerson?.()) {
|
|
8610
|
+
placeInView({ THREE, hand, holder, camera, right: hold?.right ?? null, rear: modelRear, kind: family === "pistol" || family === "revolver" ? "handgun" : family === "rocket" ? "launcher" : "long" });
|
|
8611
|
+
lift = 0;
|
|
8612
|
+
pullFromWall(dt);
|
|
8613
|
+
return;
|
|
8614
|
+
}
|
|
8615
|
+
hand.scale.set(1, 1, 1);
|
|
8398
8616
|
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 });
|
|
8399
8617
|
hand.updateMatrixWorld(true);
|
|
8400
8618
|
lift += (liftToKeepInView() - lift) * Math.min(1, dt * HAND_IN_VIEW.rate);
|
|
8401
8619
|
if (lift > 1e-4) hand.position.addScaledVector(up.set(0, 1, 0).applyQuaternion(camera.quaternion), lift);
|
|
8402
8620
|
hand.updateMatrixWorld(true);
|
|
8403
|
-
|
|
8621
|
+
pullFromWall(dt);
|
|
8622
|
+
};
|
|
8623
|
+
const pullFromWall = (dt) => {
|
|
8624
|
+
if (!options.contact || !session) return;
|
|
8404
8625
|
ahead.set(0, 0, -1).applyQuaternion(camera.quaternion);
|
|
8405
8626
|
if (reach === 0) reach = Math.max(0.01, measureReach(session));
|
|
8406
8627
|
const free = options.contact(camera.position, ahead, WALL_PULL.probe);
|
|
@@ -8431,7 +8652,7 @@ function createViewmodel(options) {
|
|
|
8431
8652
|
}
|
|
8432
8653
|
const action = current.def.action;
|
|
8433
8654
|
if (action.kind === "launcher") {
|
|
8434
|
-
launchRocket(heavy(current), options.flyRocket !== false);
|
|
8655
|
+
if (current.model.parts.family === "rocket") launchRocket(heavy(current), options.flyRocket !== false);
|
|
8435
8656
|
audio?.play("explosion", LAUNCH_VOLUME, distance());
|
|
8436
8657
|
}
|
|
8437
8658
|
if (action.kind !== "firearm") return;
|
|
@@ -8508,6 +8729,15 @@ function createViewmodel(options) {
|
|
|
8508
8729
|
condition = next;
|
|
8509
8730
|
if (session) applyCondition(kit, session.model, condition);
|
|
8510
8731
|
},
|
|
8732
|
+
muzzle() {
|
|
8733
|
+
const mark = session?.model.parts.muzzle;
|
|
8734
|
+
if (!session || !mark) return null;
|
|
8735
|
+
hand.updateMatrixWorld(true);
|
|
8736
|
+
const at = worldPositionOf(session, mark, muzzleAt);
|
|
8737
|
+
const along = muzzleAlong.set(1, 0, 0).applyQuaternion(session.model.root.getWorldQuaternion(rootQuaternion)).normalize();
|
|
8738
|
+
const kind = session.def.action.kind;
|
|
8739
|
+
return { position: [at.x, at.y, at.z], direction: [along.x, along.y, along.z], drawsFlash: kind === "firearm" || kind === "launcher" };
|
|
8740
|
+
},
|
|
8511
8741
|
handTargets() {
|
|
8512
8742
|
if (!session || !hold) return null;
|
|
8513
8743
|
hand.updateMatrixWorld(true);
|
|
@@ -8562,6 +8792,7 @@ function createWeaponFx(options) {
|
|
|
8562
8792
|
...options.raycast ? { raycast: options.raycast } : {},
|
|
8563
8793
|
...options.contact ? { contact: options.contact } : {},
|
|
8564
8794
|
...options.bodyHold ? { bodyHold: options.bodyHold } : {},
|
|
8795
|
+
...options.firstPerson ? { firstPerson: options.firstPerson } : {},
|
|
8565
8796
|
...options.effects ? { effects: options.effects } : {},
|
|
8566
8797
|
...options.flyRocket === void 0 ? {} : { flyRocket: options.flyRocket },
|
|
8567
8798
|
...options.particleLimit ? { particleLimit: options.particleLimit } : {},
|
|
@@ -8584,6 +8815,7 @@ function createWeaponFx(options) {
|
|
|
8584
8815
|
},
|
|
8585
8816
|
setCondition: (condition) => model.setCondition(condition),
|
|
8586
8817
|
handTargets: () => model.handTargets() ?? box2.handTargets(),
|
|
8818
|
+
muzzle: () => model.inHand !== null ? model.muzzle() : box2.muzzle(),
|
|
8587
8819
|
layers,
|
|
8588
8820
|
get inHand() {
|
|
8589
8821
|
return model.inHand ?? box2.inHand;
|
|
@@ -8605,17 +8837,17 @@ function createWeaponFx(options) {
|
|
|
8605
8837
|
}
|
|
8606
8838
|
|
|
8607
8839
|
// src/modeled-prop.ts
|
|
8608
|
-
import { markKitOrigin as
|
|
8840
|
+
import { markKitOrigin as markKitOrigin5 } from "@adatechnology/game-contracts";
|
|
8609
8841
|
import { mergeByMaterial } from "@adatechnology/game-shapes-three";
|
|
8610
8842
|
var MODEL_BODY = "body";
|
|
8611
8843
|
function buildModeledProp(THREE, def, name, decorate, items, props = defaultWeaponProps()) {
|
|
8612
8844
|
const model = buildWeaponModelById(THREE, def.id) ?? (() => {
|
|
8613
|
-
const root = props.buildItemModel(THREE, def, items);
|
|
8845
|
+
const root = props.buildItemModel(THREE, def, items) ?? buildThrowableModel(THREE, def);
|
|
8614
8846
|
return root ? { root } : void 0;
|
|
8615
8847
|
})();
|
|
8616
8848
|
if (!model) return void 0;
|
|
8617
8849
|
decorate?.(model.root);
|
|
8618
|
-
const group =
|
|
8850
|
+
const group = markKitOrigin5(new THREE.Group(), { owner: "game-weapons-three", kind: "weapon", id: def.id });
|
|
8619
8851
|
group.name = name;
|
|
8620
8852
|
const box2 = new THREE.Box3().setFromObject(model.root);
|
|
8621
8853
|
const center = box2.getCenter(new THREE.Vector3());
|
|
@@ -9653,6 +9885,7 @@ var TEXT = {
|
|
|
9653
9885
|
reloadClip: "Reload of {weapon}: {kind}, clip {clip} ({seconds} s)",
|
|
9654
9886
|
soundCue: "Sound: {cue} ({weapon})",
|
|
9655
9887
|
cueRecorded: " \xB7 recorded",
|
|
9888
|
+
cueFitted: " \xB7 fitted copy of the recording",
|
|
9656
9889
|
cueCarried: " \xB7 inside the next recording",
|
|
9657
9890
|
gunshotSound: "Shot sound: {profile}, take {take}/4, pitch {pitch}, {space}, {distance} m{far}",
|
|
9658
9891
|
gunshotRecorded: " \xB7 recorded take {takes}",
|
|
@@ -9688,6 +9921,7 @@ var TEXT = {
|
|
|
9688
9921
|
reloadClip: "Recarga de {weapon}: {kind}, clipe {clip} ({seconds} s)",
|
|
9689
9922
|
soundCue: "Som: {cue} ({weapon})",
|
|
9690
9923
|
cueRecorded: " \xB7 grava\xE7\xE3o",
|
|
9924
|
+
cueFitted: " \xB7 c\xF3pia medida da grava\xE7\xE3o",
|
|
9691
9925
|
cueCarried: " \xB7 dentro da grava\xE7\xE3o seguinte",
|
|
9692
9926
|
gunshotSound: "Som do tiro: {profile}, tomada {take}/4, tom {pitch}, {space}, {distance} m{far}",
|
|
9693
9927
|
gunshotRecorded: " \xB7 grava\xE7\xE3o, tomada {takes}",
|
|
@@ -9753,7 +9987,7 @@ var targetProp = (id, name) => {
|
|
|
9753
9987
|
};
|
|
9754
9988
|
var weaponItem = (def, name, items, props = defaultWeaponProps()) => {
|
|
9755
9989
|
const id = `${WEAPON_ITEM_PREFIX}${def.id}`;
|
|
9756
|
-
if (!hasWeaponModel(def.id) && !props.itemModelOf(def.id, items)) return asItem(id, name, weaponProp(def, name), { weapon: def.id, movable: true });
|
|
9990
|
+
if (!hasWeaponModel(def.id) && !props.itemModelOf(def.id, items) && !hasThrowableModel(def)) return asItem(id, name, weaponProp(def, name), { weapon: def.id, movable: true });
|
|
9757
9991
|
return {
|
|
9758
9992
|
id,
|
|
9759
9993
|
name,
|
|
@@ -9773,7 +10007,7 @@ var mountedM134Item = (def, name, items, props) => ({
|
|
|
9773
10007
|
});
|
|
9774
10008
|
var targetItem = (id, name) => {
|
|
9775
10009
|
const prop = targetProp(id, name);
|
|
9776
|
-
return { id, name, build: (THREE) =>
|
|
10010
|
+
return { id, name, build: (THREE) => markKitOrigin6(buildProp(THREE, prop), { owner: "game-weapons-three", kind: "target", id }), spec: prop.spec, movable: false };
|
|
9777
10011
|
};
|
|
9778
10012
|
var asItem = (id, name, prop, extra = {}) => ({
|
|
9779
10013
|
id,
|
|
@@ -9813,7 +10047,8 @@ function createWeaponsTestModule(options = {}) {
|
|
|
9813
10047
|
const seedOption = options.seed === void 0 ? {} : { seed: options.seed };
|
|
9814
10048
|
let audio;
|
|
9815
10049
|
const ownAudio = () => audio === void 0 ? audio = options.sound === false ? null : createWeaponAudio(void 0, { ...seedOption, ...options.samples ? { samples: options.samples } : {} }) : audio;
|
|
9816
|
-
const
|
|
10050
|
+
const generics = genericWeapons(arsenal);
|
|
10051
|
+
const weaponDefs = [...arsenal.weapons.values()].filter((def) => !BODY_ACTIONS.has(def.id) && !generics.has(def.id));
|
|
9817
10052
|
const thumbnailBase = options.thumbnailBase ?? DEFAULT_THUMBNAIL_BASE;
|
|
9818
10053
|
const withThumbnail = (item, key) => {
|
|
9819
10054
|
const thumbnail = thumbnailBase === false ? void 0 : weaponThumbnailUrl(key, thumbnailBase);
|
|
@@ -9901,20 +10136,20 @@ function createWeaponsTestModule(options = {}) {
|
|
|
9901
10136
|
engine: lentEngine,
|
|
9902
10137
|
...options.samples ? { samples: options.samples } : {},
|
|
9903
10138
|
onGunshot: (shot, input, played) => {
|
|
9904
|
-
const recorded = played.kind === "sample" && played.layers.length > 0 ? fill(text.gunshotRecorded, { takes: played.layers.map((layer) => `${layer.role} ${layer.take + 1}`).join(", ") }) : "";
|
|
10139
|
+
const recorded = played.kind === "sample" && played.layers.length > 0 ? fill(text.gunshotRecorded, { takes: played.layers.map((layer) => `${layer.role} ${layer.take + 1}`).join(", ") }) : played.kind === "fitted" ? text.cueFitted : "";
|
|
9905
10140
|
lent.log(
|
|
9906
10141
|
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,
|
|
9907
10142
|
{ 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 },
|
|
9908
10143
|
"sound"
|
|
9909
10144
|
);
|
|
9910
10145
|
},
|
|
9911
|
-
onCasing: (sound3, played) => lent.log(fill(text.casingSound, { case: sound3.kind, surface: text.surfaces[sound3.surface] }) + (played === "sample" ? text.cueRecorded : ""), { case: sound3.kind, surface: sound3.surface, sample: sound3.sample, played }, "sound")
|
|
10146
|
+
onCasing: (sound3, played) => lent.log(fill(text.casingSound, { case: sound3.kind, surface: text.surfaces[sound3.surface] }) + (played === "sample" ? text.cueRecorded : played === "fitted" ? text.cueFitted : ""), { case: sound3.kind, surface: sound3.surface, sample: sound3.sample, played }, "sound")
|
|
9912
10147
|
});
|
|
9913
10148
|
}
|
|
9914
10149
|
let simulatedMs = 0;
|
|
9915
10150
|
const offClock = lent.onFrame((dt) => simulatedMs += dt * 1e3);
|
|
9916
10151
|
const created = createWeaponFx({
|
|
9917
|
-
onSound: ({ weapon, cue: cue2, profile, played }) => lent.log(fill(text.soundCue, { weapon: arsenal.name(weapon), cue: text.soundCues[cue2] ?? cue2 }) + (played === "sample" ? text.cueRecorded : played === "carried" ? text.cueCarried : ""), { weapon, cue: cue2, weight: profile.weight, material: profile.material, ...played ? { played } : {} }, "sound"),
|
|
10152
|
+
onSound: ({ weapon, cue: cue2, profile, played }) => lent.log(fill(text.soundCue, { weapon: arsenal.name(weapon), cue: text.soundCues[cue2] ?? cue2 }) + (played === "sample" ? text.cueRecorded : played === "fitted" ? text.cueFitted : played === "carried" ? text.cueCarried : ""), { weapon, cue: cue2, weight: profile.weight, material: profile.material, ...played ? { played } : {} }, "sound"),
|
|
9918
10153
|
THREE: lent.THREE,
|
|
9919
10154
|
scene: lent.scene,
|
|
9920
10155
|
camera: lent.camera,
|
|
@@ -9930,6 +10165,7 @@ function createWeaponsTestModule(options = {}) {
|
|
|
9930
10165
|
// 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)
|
|
9931
10166
|
contact: createLaserRaycast(lent.THREE, lent.scene, lent.camera, { now: () => simulatedMs }),
|
|
9932
10167
|
...lent.holdFrame ? { bodyHold: () => lent.holdFrame?.() ?? null } : {},
|
|
10168
|
+
firstPerson: () => lent.player().cameraMode === "first",
|
|
9933
10169
|
...lent.effects ? { effects: lent.effects } : {},
|
|
9934
10170
|
...lent.particleLimit ? { particleLimit: lent.particleLimit } : {},
|
|
9935
10171
|
...isLightBudget(lent.lights) ? { lights: lent.lights } : {},
|
|
@@ -9963,6 +10199,7 @@ function createWeaponsTestModule(options = {}) {
|
|
|
9963
10199
|
const offEvents = lent.on((event) => {
|
|
9964
10200
|
worldEffects.handle(event, lent.effects);
|
|
9965
10201
|
if (event.type === "explosion") {
|
|
10202
|
+
if (lentEngine) return;
|
|
9966
10203
|
const away = Math.hypot(event.point[0] - camera.position.x, event.point[1] - camera.position.y, event.point[2] - camera.position.z);
|
|
9967
10204
|
ownAudio()?.play("explosion", Math.min(1, EXPLOSION_VOLUME_BASE + event.radius * EXPLOSION_VOLUME_PER_METRE), away);
|
|
9968
10205
|
return;
|
|
@@ -9980,6 +10217,7 @@ function createWeaponsTestModule(options = {}) {
|
|
|
9980
10217
|
});
|
|
9981
10218
|
const offFrame = lent.onFrame((dt) => created.update(dt));
|
|
9982
10219
|
const offHands = lent.setHandTargets?.(() => created.handTargets());
|
|
10220
|
+
const offMuzzle = lent.setMuzzleSource?.(() => created.muzzle());
|
|
9983
10221
|
created.handle({ type: "tool", weapon: lent.tool().weapon }, lent.tool());
|
|
9984
10222
|
return () => {
|
|
9985
10223
|
accessories.dispose();
|
|
@@ -9988,6 +10226,7 @@ function createWeaponsTestModule(options = {}) {
|
|
|
9988
10226
|
offFrame();
|
|
9989
10227
|
offClock();
|
|
9990
10228
|
offHands?.();
|
|
10229
|
+
offMuzzle?.();
|
|
9991
10230
|
created.dispose();
|
|
9992
10231
|
audio?.dispose();
|
|
9993
10232
|
fx = null;
|
|
@@ -10003,7 +10242,7 @@ import { createArsenal as createArsenal2 } from "@adatechnology/game-weapons";
|
|
|
10003
10242
|
|
|
10004
10243
|
// src/test-area/explosives-bench.ts
|
|
10005
10244
|
import { discardObject3D as discardObject3D4 } from "@adatechnology/game-shapes-three";
|
|
10006
|
-
import { markKitOrigin as
|
|
10245
|
+
import { markKitOrigin as markKitOrigin7 } from "@adatechnology/game-contracts";
|
|
10007
10246
|
|
|
10008
10247
|
// src/test-area/explosives-text.ts
|
|
10009
10248
|
var EXPLOSIVES_TEXT = {
|
|
@@ -10266,7 +10505,7 @@ function createExplosivesBench(options) {
|
|
|
10266
10505
|
return new (T()).LineLoop(geometry, new (T()).LineBasicMaterial({ color: colour }));
|
|
10267
10506
|
};
|
|
10268
10507
|
const drawRings = (vessel) => {
|
|
10269
|
-
const group =
|
|
10508
|
+
const group = markKitOrigin7(new (T()).Group(), { owner: "game-weapons-three", kind: "aid" });
|
|
10270
10509
|
group.name = "blast_rings";
|
|
10271
10510
|
const lethal = lethalOf(vessel);
|
|
10272
10511
|
const injury = injuryOf(vessel);
|
|
@@ -10726,6 +10965,7 @@ var SHELTERED = 0.5;
|
|
|
10726
10965
|
var SHELTERED_MOST = 1;
|
|
10727
10966
|
var CHEST = 1.1;
|
|
10728
10967
|
var MIDDLE = 0.3;
|
|
10968
|
+
var AIM_SEARCH = 1.5;
|
|
10729
10969
|
var HEAVY_ITEMS = ["camp_table"];
|
|
10730
10970
|
var PERSON_MASS = 70;
|
|
10731
10971
|
var GROUND_FRICTION = 7;
|
|
@@ -10785,6 +11025,27 @@ function pushScenario(all, bench, mode) {
|
|
|
10785
11025
|
}
|
|
10786
11026
|
const partsBefore = new Map(placed.map((body) => [body.objectId, partsOf(body.objectId)]));
|
|
10787
11027
|
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) });
|
|
11028
|
+
const aimOf = new Map(
|
|
11029
|
+
placed.map((body) => {
|
|
11030
|
+
const from = origin.get(body.objectId) ?? body.from;
|
|
11031
|
+
if (body.kind === "zombie" || body.kind === "survivor") return [body.objectId, [from[0], from[1] + CHEST, from[2]]];
|
|
11032
|
+
const boxes = room.renderer.solidsNear?.(from[0], from[2], AIM_SEARCH).filter((box2) => box2.objectId === body.objectId) ?? [];
|
|
11033
|
+
if (boxes.length === 0) return [body.objectId, [from[0], from[1] + MIDDLE, from[2]]];
|
|
11034
|
+
const low = [0, 1, 2].map((axis) => Math.min(...boxes.map((box2) => box2.min[axis])));
|
|
11035
|
+
const high = [0, 1, 2].map((axis) => Math.max(...boxes.map((box2) => box2.max[axis])));
|
|
11036
|
+
return [body.objectId, [0, 1, 2].map((axis) => (low[axis] + high[axis]) / 2)];
|
|
11037
|
+
})
|
|
11038
|
+
);
|
|
11039
|
+
const coverAt = (point) => new Map(
|
|
11040
|
+
placed.map((body) => {
|
|
11041
|
+
const ignore = source ? [source, body.objectId] : [body.objectId];
|
|
11042
|
+
return [body.objectId, room.world.blastReach?.(point, aimOf.get(body.objectId) ?? body.from, { ignore }) ?? 1];
|
|
11043
|
+
})
|
|
11044
|
+
);
|
|
11045
|
+
let coverOf;
|
|
11046
|
+
const stopListening = room.world.on("*", (event) => {
|
|
11047
|
+
if ((event.type === "explode" || event.type === "blast") && !coverOf) coverOf = coverAt(event.point);
|
|
11048
|
+
});
|
|
10788
11049
|
if (mode === "p13") bench.actions.shoot();
|
|
10789
11050
|
else {
|
|
10790
11051
|
room.setTool("frag_grenade");
|
|
@@ -10797,17 +11058,11 @@ function pushScenario(all, bench, mode) {
|
|
|
10797
11058
|
step(0.05);
|
|
10798
11059
|
waited += 0.05;
|
|
10799
11060
|
}
|
|
11061
|
+
stopListening();
|
|
10800
11062
|
const blast = bench.lastBlast();
|
|
10801
11063
|
expect(!!blast, text.push_told, { waited });
|
|
10802
11064
|
if (!blast) return;
|
|
10803
|
-
const
|
|
10804
|
-
placed.map((body) => {
|
|
10805
|
-
const from = origin.get(body.objectId) ?? body.from;
|
|
10806
|
-
const person = body.kind === "zombie" || body.kind === "survivor";
|
|
10807
|
-
const ignore = source ? [source, body.objectId] : [body.objectId];
|
|
10808
|
-
return [body.objectId, room.world.blastReach?.(blast.point, [from[0], from[1] + (person ? CHEST : MIDDLE), from[2]], { ignore }) ?? 1];
|
|
10809
|
-
})
|
|
10810
|
-
);
|
|
11065
|
+
const cover = coverOf ?? coverAt(blast.point);
|
|
10811
11066
|
step(PUSH_READ_AT);
|
|
10812
11067
|
const rows = placed.map((body) => {
|
|
10813
11068
|
const from = origin.get(body.objectId) ?? body.from;
|
|
@@ -10815,16 +11070,18 @@ function pushScenario(all, bench, mode) {
|
|
|
10815
11070
|
const distance = flat(from, blast.point);
|
|
10816
11071
|
const away = Math.max(1e-6, distance);
|
|
10817
11072
|
const outward = ((now[0] - from[0]) * (from[0] - blast.point[0]) + (now[2] - from[2]) * (from[2] - blast.point[2])) / away;
|
|
10818
|
-
return { ...body, distance, outward, moved: flat(now, from), cover:
|
|
11073
|
+
return { ...body, distance, outward, moved: flat(now, from), cover: cover.get(body.objectId) ?? 1 };
|
|
10819
11074
|
});
|
|
10820
11075
|
const torn = (row) => (PUSH_KINDS.some((entry) => entry.kind === row.kind) || HEAVY_ITEMS.includes(row.kind)) && partsOf(row.objectId) < (partsBefore.get(row.objectId) ?? 0);
|
|
10821
11076
|
const inReach = rows.filter((row) => row.distance < blast.radius * 0.85 && !torn(row));
|
|
11077
|
+
const isPerson = (row) => row.kind === "survivor" || row.kind === "zombie";
|
|
11078
|
+
const reached = inReach.filter((row) => row.cover >= SHELTERED && !isPerson(row));
|
|
10822
11079
|
const sheltered = inReach.filter((row) => row.cover < SHELTERED);
|
|
10823
11080
|
for (const row of sheltered) {
|
|
10824
|
-
|
|
11081
|
+
const open = reached.filter((other) => other.kind === row.kind && other.distance <= row.distance).map((other) => other.outward);
|
|
11082
|
+
const most = Math.max(SHELTERED_MOST, row.cover * Math.max(0, ...open));
|
|
11083
|
+
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 } });
|
|
10825
11084
|
}
|
|
10826
|
-
const isPerson = (row) => row.kind === "survivor" || row.kind === "zombie";
|
|
10827
|
-
const reached = inReach.filter((row) => row.cover >= SHELTERED && !isPerson(row));
|
|
10828
11085
|
const movedAway = reached.filter((row) => row.outward >= MOVED);
|
|
10829
11086
|
const least = reached.length === 0 ? 0 : Math.min(...reached.map((row) => row.outward));
|
|
10830
11087
|
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) });
|
|
@@ -11014,14 +11271,19 @@ export {
|
|
|
11014
11271
|
BODY_ACTIONS,
|
|
11015
11272
|
weaponProp,
|
|
11016
11273
|
buildProp,
|
|
11274
|
+
modelKit,
|
|
11275
|
+
EXPLOSIVE_MODEL_IDS,
|
|
11276
|
+
hasExplosiveModel,
|
|
11277
|
+
buildExplosiveModel,
|
|
11017
11278
|
SHIPPED_WEAPON_ITEM_MODELS,
|
|
11279
|
+
hasThrowableModel,
|
|
11280
|
+
buildThrowableModel,
|
|
11018
11281
|
weaponPropsOver,
|
|
11019
11282
|
defaultWeaponProps,
|
|
11020
11283
|
registerWeaponItemModel,
|
|
11021
11284
|
itemModelOfWeapon,
|
|
11022
11285
|
buildItemWeaponModel,
|
|
11023
11286
|
buildWeaponModel,
|
|
11024
|
-
modelKit,
|
|
11025
11287
|
deriveFrames,
|
|
11026
11288
|
mountFrame,
|
|
11027
11289
|
buildFlyingRocket,
|
|
@@ -11067,4 +11329,4 @@ export {
|
|
|
11067
11329
|
DEFAULT_EXPLOSIVES_SCENE,
|
|
11068
11330
|
createExplosivesTestModule
|
|
11069
11331
|
};
|
|
11070
|
-
//# sourceMappingURL=chunk-
|
|
11332
|
+
//# sourceMappingURL=chunk-KWJQO6JS.js.map
|