@adatechnology/game-destruction-three 0.12.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +10 -2
- package/dist/index.global.js +954 -219
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +65 -14
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
package/dist/index.global.js
CHANGED
|
@@ -55,6 +55,39 @@ var GameDestructionThree = (() => {
|
|
|
55
55
|
const length = Math.hypot(direction[0], direction[1], direction[2]);
|
|
56
56
|
return { speed, direction: [direction[0] / length, direction[1] / length, direction[2] / length], distance, falloff };
|
|
57
57
|
}
|
|
58
|
+
var DEFAULT_COST_ALLOCATION_BYTES = 1024 * 1024;
|
|
59
|
+
var DEFERRED_QUEUE_ID = {
|
|
60
|
+
DESTRUCTION_EVENTS: "destruction.events",
|
|
61
|
+
BREACH_PAINT: "floorplan.breach-paint",
|
|
62
|
+
AUDIO_VOICES: "audio.voices",
|
|
63
|
+
VEHICLE_CREASE: "vehicles.crease"
|
|
64
|
+
};
|
|
65
|
+
var DEFERRED_PRIORITY = {
|
|
66
|
+
[DEFERRED_QUEUE_ID.DESTRUCTION_EVENTS]: { priority: 300, phase: "present" },
|
|
67
|
+
[DEFERRED_QUEUE_ID.BREACH_PAINT]: { priority: 250, phase: "present" },
|
|
68
|
+
[DEFERRED_QUEUE_ID.AUDIO_VOICES]: { priority: 200, phase: "idle", reserveMs: 1 },
|
|
69
|
+
[DEFERRED_QUEUE_ID.VEHICLE_CREASE]: { priority: 100, phase: "idle" }
|
|
70
|
+
};
|
|
71
|
+
var WARNED_KEY = /* @__PURE__ */ Symbol.for("@adatechnology/game-contracts.warned");
|
|
72
|
+
var warnedKeys = () => {
|
|
73
|
+
const holder = globalThis;
|
|
74
|
+
return holder[WARNED_KEY] ?? (holder[WARNED_KEY] = /* @__PURE__ */ new Set());
|
|
75
|
+
};
|
|
76
|
+
var isProduction = () => {
|
|
77
|
+
try {
|
|
78
|
+
return process.env.NODE_ENV === "production";
|
|
79
|
+
} catch {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
var isQuiet = () => globalThis.__GAME_KIT_QUIET__ === true;
|
|
84
|
+
var warnOnce = (key, message) => {
|
|
85
|
+
if (isQuiet() || isProduction()) return;
|
|
86
|
+
const seen = warnedKeys();
|
|
87
|
+
if (seen.has(key)) return;
|
|
88
|
+
seen.add(key);
|
|
89
|
+
console.warn(`[game-kit] ${message}`);
|
|
90
|
+
};
|
|
58
91
|
var KIT_ORIGIN_KEY = "kitOrigin";
|
|
59
92
|
function markKitOrigin(object, origin) {
|
|
60
93
|
const node = object;
|
|
@@ -69,6 +102,43 @@ var GameDestructionThree = (() => {
|
|
|
69
102
|
}
|
|
70
103
|
return null;
|
|
71
104
|
}
|
|
105
|
+
var SURFACE_IDS = ["concrete", "asphalt", "wood", "tile", "dirt", "grass", "gravel", "sand", "metal", "water", "glass", "carpet"];
|
|
106
|
+
var GAIT_IDS = ["walk", "run"];
|
|
107
|
+
var LANDING_IDS = ["light", "heavy"];
|
|
108
|
+
var BODY_SOUND_IDS = [
|
|
109
|
+
"jump",
|
|
110
|
+
"cloth_rustle",
|
|
111
|
+
"body_fall",
|
|
112
|
+
"fall_damage",
|
|
113
|
+
"player_hurt",
|
|
114
|
+
"player_breath_run",
|
|
115
|
+
"player_death",
|
|
116
|
+
"bite",
|
|
117
|
+
"grab",
|
|
118
|
+
"punch_swing",
|
|
119
|
+
"punch_hit_body",
|
|
120
|
+
"punch_hit_face",
|
|
121
|
+
"punch_hit_object",
|
|
122
|
+
"kick_swing",
|
|
123
|
+
"kick_hit",
|
|
124
|
+
"kick_hit_object",
|
|
125
|
+
"shove_two_hands",
|
|
126
|
+
"knife_swing",
|
|
127
|
+
"knife_stab",
|
|
128
|
+
"knife_slash",
|
|
129
|
+
"knife_hit_object",
|
|
130
|
+
"blunt_swing",
|
|
131
|
+
"blunt_hit",
|
|
132
|
+
"blunt_hit_object",
|
|
133
|
+
"axe_swing",
|
|
134
|
+
"axe_chop",
|
|
135
|
+
"axe_hit_object"
|
|
136
|
+
];
|
|
137
|
+
var footstepSoundId = (surface, gait) => `footstep_${surface}_${gait}`;
|
|
138
|
+
var FOOTSTEP_SOUND_IDS = SURFACE_IDS.flatMap((surface) => GAIT_IDS.map((gait) => footstepSoundId(surface, gait)));
|
|
139
|
+
var LAND_SOUND_IDS = SURFACE_IDS.flatMap((surface) => LANDING_IDS.map((landing2) => `land_${surface}_${landing2}`));
|
|
140
|
+
var BODY_FOLEY_IDS = [...FOOTSTEP_SOUND_IDS, ...LAND_SOUND_IDS, ...BODY_SOUND_IDS];
|
|
141
|
+
var SWING_LEAD_SECONDS = { punch: 0.07, kick: 0.09, shove: 0, blade: 0.05, blunt: 0.1, chop: 0.11 };
|
|
72
142
|
|
|
73
143
|
// ../game-vfx/dist/index.js
|
|
74
144
|
var __defProp2 = Object.defineProperty;
|
|
@@ -1357,11 +1427,231 @@ var GameDestructionThree = (() => {
|
|
|
1357
1427
|
glow.outIntensity = glow.i * Math.pow(1 - age, glow.curve) * flicker;
|
|
1358
1428
|
}
|
|
1359
1429
|
}
|
|
1430
|
+
var LEHMER_MULTIPLIER = 16807;
|
|
1431
|
+
var LEHMER_MODULUS = 2147483647;
|
|
1432
|
+
var HASH_MIX = 2654435761;
|
|
1433
|
+
function normalizeLehmerSeed(seed) {
|
|
1434
|
+
const whole = Math.floor(Math.abs(seed)) % (LEHMER_MODULUS - 1);
|
|
1435
|
+
return whole === 0 ? 1 : whole;
|
|
1436
|
+
}
|
|
1437
|
+
function lehmer(seed) {
|
|
1438
|
+
let state = normalizeLehmerSeed(seed);
|
|
1439
|
+
const next = () => {
|
|
1440
|
+
state = state * LEHMER_MULTIPLIER % LEHMER_MODULUS;
|
|
1441
|
+
return (state - 1) / (LEHMER_MODULUS - 1);
|
|
1442
|
+
};
|
|
1443
|
+
return {
|
|
1444
|
+
next,
|
|
1445
|
+
between: (min2, max2) => min2 + (max2 - min2) * next(),
|
|
1446
|
+
direction(out) {
|
|
1447
|
+
const up = next() * 2 - 1;
|
|
1448
|
+
const angle = next() * Math.PI * 2;
|
|
1449
|
+
const ring2 = Math.sqrt(1 - up * up);
|
|
1450
|
+
out.x = ring2 * Math.cos(angle);
|
|
1451
|
+
out.y = up;
|
|
1452
|
+
out.z = ring2 * Math.sin(angle);
|
|
1453
|
+
return out;
|
|
1454
|
+
},
|
|
1455
|
+
get state() {
|
|
1456
|
+
return state;
|
|
1457
|
+
}
|
|
1458
|
+
};
|
|
1459
|
+
}
|
|
1460
|
+
function mixEventSeed(eventSeed) {
|
|
1461
|
+
let mixed = Math.imul((eventSeed | 0) ^ HASH_MIX, 2246822507);
|
|
1462
|
+
mixed ^= mixed >>> 13;
|
|
1463
|
+
mixed = Math.imul(mixed, 3266489909);
|
|
1464
|
+
mixed ^= mixed >>> 16;
|
|
1465
|
+
return (mixed >>> 0) % (LEHMER_MODULUS - 1) + 1;
|
|
1466
|
+
}
|
|
1467
|
+
function streamFor(eventSeed) {
|
|
1468
|
+
return lehmer(mixEventSeed(eventSeed));
|
|
1469
|
+
}
|
|
1470
|
+
var SKIN = 5e-3;
|
|
1471
|
+
var MAX_PAD = 0.45;
|
|
1472
|
+
function rotation(q) {
|
|
1473
|
+
const [x, y, z, w] = q ?? [0, 0, 0, 1];
|
|
1474
|
+
const n = Math.hypot(x, y, z, w) || 1;
|
|
1475
|
+
const qx = x / n;
|
|
1476
|
+
const qy = y / n;
|
|
1477
|
+
const qz = z / n;
|
|
1478
|
+
const qw = w / n;
|
|
1479
|
+
return new Float64Array([
|
|
1480
|
+
1 - 2 * (qy * qy + qz * qz),
|
|
1481
|
+
2 * (qx * qy - qz * qw),
|
|
1482
|
+
2 * (qx * qz + qy * qw),
|
|
1483
|
+
2 * (qx * qy + qz * qw),
|
|
1484
|
+
1 - 2 * (qx * qx + qz * qz),
|
|
1485
|
+
2 * (qy * qz - qx * qw),
|
|
1486
|
+
2 * (qx * qz - qy * qw),
|
|
1487
|
+
2 * (qy * qz + qx * qw),
|
|
1488
|
+
1 - 2 * (qx * qx + qy * qy)
|
|
1489
|
+
]);
|
|
1490
|
+
}
|
|
1491
|
+
var Enclosures = class {
|
|
1492
|
+
constructor(seed = 20973) {
|
|
1493
|
+
__publicField2(this, "spaces", /* @__PURE__ */ new Map());
|
|
1494
|
+
__publicField2(this, "list", []);
|
|
1495
|
+
__publicField2(this, "random");
|
|
1496
|
+
__publicField2(this, "out", { x: 0, y: 0, z: 0, nx: 0, ny: 0, nz: 0 });
|
|
1497
|
+
__publicField2(this, "l0", new Float64Array(3));
|
|
1498
|
+
__publicField2(this, "l1", new Float64Array(3));
|
|
1499
|
+
__publicField2(this, "q", new Float64Array(3));
|
|
1500
|
+
this.random = lehmer(seed);
|
|
1501
|
+
}
|
|
1502
|
+
get empty() {
|
|
1503
|
+
return this.list.length === 0;
|
|
1504
|
+
}
|
|
1505
|
+
get size() {
|
|
1506
|
+
return this.list.length;
|
|
1507
|
+
}
|
|
1508
|
+
/** Declares, moves or (with `null`) ends the space `id`. */
|
|
1509
|
+
set(id, enclosure) {
|
|
1510
|
+
if (!enclosure) {
|
|
1511
|
+
if (this.spaces.delete(id)) this.list = [...this.spaces.values()];
|
|
1512
|
+
return;
|
|
1513
|
+
}
|
|
1514
|
+
const [hx, hy, hz] = enclosure.halfSize;
|
|
1515
|
+
const space = {
|
|
1516
|
+
cx: enclosure.center[0],
|
|
1517
|
+
cy: enclosure.center[1],
|
|
1518
|
+
cz: enclosure.center[2],
|
|
1519
|
+
hx: Math.abs(hx),
|
|
1520
|
+
hy: Math.abs(hy),
|
|
1521
|
+
hz: Math.abs(hz),
|
|
1522
|
+
r: rotation(enclosure.orientation),
|
|
1523
|
+
radius: Math.hypot(hx, hy, hz),
|
|
1524
|
+
openings: enclosure.openings ?? [],
|
|
1525
|
+
leak: Math.max(0, enclosure.leak ?? 0)
|
|
1526
|
+
};
|
|
1527
|
+
const old = this.spaces.get(id);
|
|
1528
|
+
this.spaces.set(id, space);
|
|
1529
|
+
const at3 = old ? this.list.indexOf(old) : -1;
|
|
1530
|
+
if (at3 >= 0) this.list[at3] = space;
|
|
1531
|
+
else this.list.push(space);
|
|
1532
|
+
}
|
|
1533
|
+
get(id) {
|
|
1534
|
+
const s = this.spaces.get(id);
|
|
1535
|
+
if (!s) return void 0;
|
|
1536
|
+
return { center: [s.cx, s.cy, s.cz], halfSize: [s.hx, s.hy, s.hz], openings: s.openings, leak: s.leak };
|
|
1537
|
+
}
|
|
1538
|
+
ids() {
|
|
1539
|
+
return [...this.spaces.keys()];
|
|
1540
|
+
}
|
|
1541
|
+
clear() {
|
|
1542
|
+
this.spaces.clear();
|
|
1543
|
+
this.list = [];
|
|
1544
|
+
}
|
|
1545
|
+
/** Whether a point is inside any space (on the inside of its walls). */
|
|
1546
|
+
inside(x, y, z) {
|
|
1547
|
+
for (const s of this.list) {
|
|
1548
|
+
this.toLocal(s, x, y, z, this.l0);
|
|
1549
|
+
if (Math.abs(this.l0[0]) <= s.hx && Math.abs(this.l0[1]) <= s.hy && Math.abs(this.l0[2]) <= s.hz) return true;
|
|
1550
|
+
}
|
|
1551
|
+
return false;
|
|
1552
|
+
}
|
|
1553
|
+
toLocal(s, x, y, z, out) {
|
|
1554
|
+
const dx = x - s.cx;
|
|
1555
|
+
const dy = y - s.cy;
|
|
1556
|
+
const dz = z - s.cz;
|
|
1557
|
+
const r = s.r;
|
|
1558
|
+
out[0] = r[0] * dx + r[3] * dy + r[6] * dz;
|
|
1559
|
+
out[1] = r[1] * dx + r[4] * dy + r[7] * dz;
|
|
1560
|
+
out[2] = r[2] * dx + r[5] * dy + r[8] * dz;
|
|
1561
|
+
}
|
|
1562
|
+
/** Passes at `rate` per second. */
|
|
1563
|
+
chance(rate, dt) {
|
|
1564
|
+
return rate > 0 && this.random.next() < 1 - Math.exp(-rate * dt);
|
|
1565
|
+
}
|
|
1566
|
+
/** The opening the wall point `q` (local) is in lets it through now. */
|
|
1567
|
+
through(s, q, dt) {
|
|
1568
|
+
for (const o of s.openings) {
|
|
1569
|
+
if (Math.abs(q[0] - o.center[0]) > o.halfSize[0] || Math.abs(q[1] - o.center[1]) > o.halfSize[1] || Math.abs(q[2] - o.center[2]) > o.halfSize[2]) continue;
|
|
1570
|
+
if (o.rate === void 0 || this.chance(o.rate, dt)) return true;
|
|
1571
|
+
}
|
|
1572
|
+
return this.chance(s.leak, dt);
|
|
1573
|
+
}
|
|
1574
|
+
confine(x0, y0, z0, x1, y1, z1, pad, dt) {
|
|
1575
|
+
const list = this.list;
|
|
1576
|
+
if (list.length === 0) return false;
|
|
1577
|
+
const p = Math.min(Math.max(0, pad), MAX_PAD);
|
|
1578
|
+
const l0 = this.l0;
|
|
1579
|
+
const l1 = this.l1;
|
|
1580
|
+
const q = this.q;
|
|
1581
|
+
for (const s of list) {
|
|
1582
|
+
const reach = s.radius + p + 0.05;
|
|
1583
|
+
const dx = x1 - s.cx;
|
|
1584
|
+
const dy = y1 - s.cy;
|
|
1585
|
+
const dz = z1 - s.cz;
|
|
1586
|
+
if (dx * dx + dy * dy + dz * dz > reach * reach) {
|
|
1587
|
+
const ex = x0 - s.cx;
|
|
1588
|
+
const ey = y0 - s.cy;
|
|
1589
|
+
const ez = z0 - s.cz;
|
|
1590
|
+
if (ex * ex + ey * ey + ez * ez > reach * reach) continue;
|
|
1591
|
+
}
|
|
1592
|
+
this.toLocal(s, x0, y0, z0, l0);
|
|
1593
|
+
this.toLocal(s, x1, y1, z1, l1);
|
|
1594
|
+
const h = [s.hx, s.hy, s.hz];
|
|
1595
|
+
const in0 = Math.abs(l0[0]) <= s.hx && Math.abs(l0[1]) <= s.hy && Math.abs(l0[2]) <= s.hz;
|
|
1596
|
+
let axis2 = 0;
|
|
1597
|
+
let sign = 1;
|
|
1598
|
+
if (in0) {
|
|
1599
|
+
if (Math.abs(l1[0]) <= s.hx && Math.abs(l1[1]) <= s.hy && Math.abs(l1[2]) <= s.hz) continue;
|
|
1600
|
+
for (let a = 0; a < 3; a++) q[a] = Math.min(h[a], Math.max(-h[a], l1[a]));
|
|
1601
|
+
if (this.through(s, q, dt)) continue;
|
|
1602
|
+
let worst = -Infinity;
|
|
1603
|
+
for (let a = 0; a < 3; a++) {
|
|
1604
|
+
const over = Math.abs(l1[a]) - h[a];
|
|
1605
|
+
if (over > worst) {
|
|
1606
|
+
worst = over;
|
|
1607
|
+
axis2 = a;
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
sign = l1[axis2] < 0 ? -1 : 1;
|
|
1611
|
+
for (let a = 0; a < 3; a++) l1[a] = Math.min(h[a] - SKIN, Math.max(-(h[a] - SKIN), l1[a]));
|
|
1612
|
+
sign = -sign;
|
|
1613
|
+
} else {
|
|
1614
|
+
const padded0 = Math.abs(l0[0]) <= s.hx + p && Math.abs(l0[1]) <= s.hy + p && Math.abs(l0[2]) <= s.hz + p;
|
|
1615
|
+
const bound = padded0 ? 0 : p;
|
|
1616
|
+
if (!(Math.abs(l1[0]) <= s.hx + bound && Math.abs(l1[1]) <= s.hy + bound && Math.abs(l1[2]) <= s.hz + bound)) continue;
|
|
1617
|
+
for (let a = 0; a < 3; a++) q[a] = Math.min(h[a], Math.max(-h[a], l1[a]));
|
|
1618
|
+
if (this.through(s, q, dt)) continue;
|
|
1619
|
+
let worst = -Infinity;
|
|
1620
|
+
for (let a = 0; a < 3; a++) {
|
|
1621
|
+
const over = Math.abs(l0[a]) - (h[a] + bound);
|
|
1622
|
+
if (over > worst) {
|
|
1623
|
+
worst = over;
|
|
1624
|
+
axis2 = a;
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
sign = l0[axis2] < 0 ? -1 : 1;
|
|
1628
|
+
l1[axis2] = sign * (h[axis2] + bound + SKIN);
|
|
1629
|
+
}
|
|
1630
|
+
const r = s.r;
|
|
1631
|
+
const out = this.out;
|
|
1632
|
+
out.x = s.cx + r[0] * l1[0] + r[1] * l1[1] + r[2] * l1[2];
|
|
1633
|
+
out.y = s.cy + r[3] * l1[0] + r[4] * l1[1] + r[5] * l1[2];
|
|
1634
|
+
out.z = s.cz + r[6] * l1[0] + r[7] * l1[1] + r[8] * l1[2];
|
|
1635
|
+
out.nx = r[axis2] * sign;
|
|
1636
|
+
out.ny = r[3 + axis2] * sign;
|
|
1637
|
+
out.nz = r[6 + axis2] * sign;
|
|
1638
|
+
return true;
|
|
1639
|
+
}
|
|
1640
|
+
return false;
|
|
1641
|
+
}
|
|
1642
|
+
};
|
|
1643
|
+
function slideAlong(out, vx2, vy2, vz2) {
|
|
1644
|
+
const into = vx2 * out.nx + vy2 * out.ny + vz2 * out.nz;
|
|
1645
|
+
if (into >= 0) return [vx2, vy2, vz2];
|
|
1646
|
+
return [vx2 - into * out.nx, vy2 - into * out.ny, vz2 - into * out.nz];
|
|
1647
|
+
}
|
|
1360
1648
|
var FLOOR_FRACTION = 0.4;
|
|
1361
1649
|
var FLOOR_BOUNCE = -0.2;
|
|
1362
1650
|
var ARRIVAL_FRAME = 30;
|
|
1363
1651
|
var ARRIVAL_BASE = 0.3;
|
|
1364
1652
|
var GROWTH_CAP_SECONDS = 3.5;
|
|
1653
|
+
var CARRIED_KINDS = [true, true, false, true, false];
|
|
1654
|
+
var PAD_OF_SIZE = 0.35;
|
|
1365
1655
|
function createPuffPool(capacity) {
|
|
1366
1656
|
const placeholder = { next: () => 0, between: (min2) => min2, direction: (out) => out, state: 0 };
|
|
1367
1657
|
return new OrderedPool(capacity, () => ({
|
|
@@ -1456,13 +1746,24 @@ var GameDestructionThree = (() => {
|
|
|
1456
1746
|
if (puff3.vy < 0) puff3.vy *= FLOOR_BOUNCE;
|
|
1457
1747
|
}
|
|
1458
1748
|
}
|
|
1459
|
-
function updatePuffs(pool, dt, wind) {
|
|
1749
|
+
function updatePuffs(pool, dt, wind, confiner) {
|
|
1460
1750
|
pool.compact(ageOrKeep2, dt);
|
|
1751
|
+
const confining = confiner !== void 0 && !confiner.empty;
|
|
1461
1752
|
for (const puff3 of pool.items) {
|
|
1462
1753
|
const age = puff3.t / puff3.life;
|
|
1463
1754
|
const heat = puff3.h0 > 0 ? puff3.h0 * Math.pow(Math.max(0, 1 - puff3.t / puff3.hl), 1.25) : 0;
|
|
1755
|
+
const x0 = puff3.x;
|
|
1756
|
+
const y0 = puff3.y;
|
|
1757
|
+
const z0 = puff3.z;
|
|
1464
1758
|
if (puff3.ring) moveOnRing(puff3, puff3.ring, wind);
|
|
1465
1759
|
else moveFree(puff3, dt, age, heat, wind);
|
|
1760
|
+
if (confining && CARRIED_KINDS[puff3.kind] && confiner.confine(x0, y0, z0, puff3.x, puff3.y, puff3.z, puff3.size * PAD_OF_SIZE, dt)) {
|
|
1761
|
+
const out = confiner.out;
|
|
1762
|
+
puff3.x = out.x;
|
|
1763
|
+
puff3.y = out.y;
|
|
1764
|
+
puff3.z = out.z;
|
|
1765
|
+
[puff3.vx, puff3.vy, puff3.vz] = slideAlong(out, puff3.vx, puff3.vy, puff3.vz);
|
|
1766
|
+
}
|
|
1466
1767
|
const size = puff3.s0 + (puff3.s1 - puff3.s0) * (1 - Math.exp(-puff3.t * puff3.gk)) + puff3.sg * Math.min(puff3.t, GROWTH_CAP_SECONDS);
|
|
1467
1768
|
puff3.size = size * Math.min(1, puff3.t * ARRIVAL_FRAME + ARRIVAL_BASE);
|
|
1468
1769
|
puff3.age = age;
|
|
@@ -1988,10 +2289,10 @@ var GameDestructionThree = (() => {
|
|
|
1988
2289
|
])
|
|
1989
2290
|
]
|
|
1990
2291
|
};
|
|
1991
|
-
function localToWorld(translation,
|
|
2292
|
+
function localToWorld(translation, rotation2, local2) {
|
|
1992
2293
|
const [x, y, z] = local2;
|
|
1993
|
-
const [a, c, e] = [Math.cos(
|
|
1994
|
-
const [b, d, f] = [Math.sin(
|
|
2294
|
+
const [a, c, e] = [Math.cos(rotation2[0]), Math.cos(rotation2[1]), Math.cos(rotation2[2])];
|
|
2295
|
+
const [b, d, f] = [Math.sin(rotation2[0]), Math.sin(rotation2[1]), Math.sin(rotation2[2])];
|
|
1995
2296
|
const [ae, af, be, bf] = [a * e, a * f, b * e, b * f];
|
|
1996
2297
|
return [
|
|
1997
2298
|
c * e * x + -c * f * y + d * z + translation[0],
|
|
@@ -2333,22 +2634,22 @@ var GameDestructionThree = (() => {
|
|
|
2333
2634
|
)
|
|
2334
2635
|
]
|
|
2335
2636
|
};
|
|
2336
|
-
function normalized(
|
|
2337
|
-
const length = Math.sqrt(
|
|
2637
|
+
function normalized(vector2) {
|
|
2638
|
+
const length = Math.sqrt(vector2[0] * vector2[0] + vector2[1] * vector2[1] + vector2[2] * vector2[2]) || 1;
|
|
2338
2639
|
const inverse = 1 / length;
|
|
2339
|
-
return [
|
|
2640
|
+
return [vector2[0] * inverse, vector2[1] * inverse, vector2[2] * inverse];
|
|
2340
2641
|
}
|
|
2341
|
-
function plus(
|
|
2342
|
-
return [
|
|
2642
|
+
function plus(vector2, x, y, z) {
|
|
2643
|
+
return [vector2[0] + x, vector2[1] + y, vector2[2] + z];
|
|
2343
2644
|
}
|
|
2344
|
-
function scaledBy(
|
|
2345
|
-
return [
|
|
2645
|
+
function scaledBy(vector2, factor) {
|
|
2646
|
+
return [vector2[0] * factor, vector2[1] * factor, vector2[2] * factor];
|
|
2346
2647
|
}
|
|
2347
|
-
function plusScaled(
|
|
2348
|
-
return [
|
|
2648
|
+
function plusScaled(vector2, direction, factor) {
|
|
2649
|
+
return [vector2[0] + direction[0] * factor, vector2[1] + direction[1] * factor, vector2[2] + direction[2] * factor];
|
|
2349
2650
|
}
|
|
2350
|
-
function negated(
|
|
2351
|
-
return [-
|
|
2651
|
+
function negated(vector2) {
|
|
2652
|
+
return [-vector2[0], -vector2[1], -vector2[2]];
|
|
2352
2653
|
}
|
|
2353
2654
|
var FRAME_DUST = normalized([0, -0.3, 1]);
|
|
2354
2655
|
var SPLINTER_DIRECTION = normalized([0, 0.3, 1]);
|
|
@@ -3651,49 +3952,32 @@ var GameDestructionThree = (() => {
|
|
|
3651
3952
|
/** The leak caught fire (an incendiary or tracer round, a spark, a fire near): the page's whole sequence, the fire running along the pool to the tank and the blast. */
|
|
3652
3953
|
aliasOf(FUEL_LEAK, "vehicle_leak_ignited", {})
|
|
3653
3954
|
];
|
|
3955
|
+
var vector = [variable("vx"), variable("vy"), variable("vz")];
|
|
3956
|
+
var range = (name) => [variable(name), variable(name)];
|
|
3957
|
+
var singleParticle = (id, system) => ({
|
|
3958
|
+
id,
|
|
3959
|
+
pageId: `particle:${id}`,
|
|
3960
|
+
team: "world",
|
|
3961
|
+
budget: { particles: 1, lights: 0 },
|
|
3962
|
+
loop: 1e-3,
|
|
3963
|
+
timeline: [
|
|
3964
|
+
spawn(system, {
|
|
3965
|
+
p: [0, 0, 0],
|
|
3966
|
+
v: vector,
|
|
3967
|
+
life: range("life"),
|
|
3968
|
+
size: range("size"),
|
|
3969
|
+
grow: variable("grow"),
|
|
3970
|
+
c0: variable("color"),
|
|
3971
|
+
a: variable("alpha"),
|
|
3972
|
+
g: variable("gravity"),
|
|
3973
|
+
drag: variable("drag")
|
|
3974
|
+
})
|
|
3975
|
+
]
|
|
3976
|
+
});
|
|
3977
|
+
var SINGLE_PARTICLE_EFFECTS = [singleParticle("particle_puff", "normal"), singleParticle("particle_glow", "add"), singleParticle("particle_streak", "streak")];
|
|
3654
3978
|
var ALL_EFFECTS = [BLOOD_HIT, HEADSHOT, DISMEMBER, BLOATER_CLOUD, SCREAMER_SHRIEK, CORPSE_DECAY, REANIMATION, EYES_IN_FOG, MUZZLE_FLASH, IMPACT_BY_MATERIAL, PENETRATION, CASINGS_AND_MAGAZINE, MOLOTOV, GRENADE, EXPLOSIVE_BARREL, SHOPFRONT_GLASS, DOOR_STAGES, BUILDING_COLLAPSE, BLOCK_WALL, METAL_DOOR_EFFECT, IRON_RAILING, WOODEN_FENCE, HIT_POINT_BREAKAGE, PRESSURE_CYLINDERS, BUILDING_FIRE, RAIN_AND_PUDDLES, FOG_AND_ASH, SCRAPING_SPARKS, ENGINE_SMOKE, FUEL_LEAK, CAR_EXPLOSION, WINDSHIELD, HEADLIGHTS_IN_RAIN, DAMAGE_AND_BITE, INFECTION_PHASES, PANIC, BLOATER_BLINDNESS, CAMPFIRE, COUGH_AND_BREATH];
|
|
3655
3979
|
var WORKSHOP_EFFECTS = Object.fromEntries(ALL_EFFECTS.map((effect) => [effect.id, effect]));
|
|
3656
|
-
var GAME_EFFECTS = { ...WORKSHOP_EFFECTS, ...Object.fromEntries([...EVENT_EFFECTS, ...VIEWMODEL_EFFECTS, ...VEHICLE_EFFECTS].map((effect) => [effect.id, effect])) };
|
|
3657
|
-
var LEHMER_MULTIPLIER = 16807;
|
|
3658
|
-
var LEHMER_MODULUS = 2147483647;
|
|
3659
|
-
var HASH_MIX = 2654435761;
|
|
3660
|
-
function normalizeLehmerSeed(seed) {
|
|
3661
|
-
const whole = Math.floor(Math.abs(seed)) % (LEHMER_MODULUS - 1);
|
|
3662
|
-
return whole === 0 ? 1 : whole;
|
|
3663
|
-
}
|
|
3664
|
-
function lehmer(seed) {
|
|
3665
|
-
let state = normalizeLehmerSeed(seed);
|
|
3666
|
-
const next = () => {
|
|
3667
|
-
state = state * LEHMER_MULTIPLIER % LEHMER_MODULUS;
|
|
3668
|
-
return (state - 1) / (LEHMER_MODULUS - 1);
|
|
3669
|
-
};
|
|
3670
|
-
return {
|
|
3671
|
-
next,
|
|
3672
|
-
between: (min2, max2) => min2 + (max2 - min2) * next(),
|
|
3673
|
-
direction(out) {
|
|
3674
|
-
const up = next() * 2 - 1;
|
|
3675
|
-
const angle = next() * Math.PI * 2;
|
|
3676
|
-
const ring2 = Math.sqrt(1 - up * up);
|
|
3677
|
-
out.x = ring2 * Math.cos(angle);
|
|
3678
|
-
out.y = up;
|
|
3679
|
-
out.z = ring2 * Math.sin(angle);
|
|
3680
|
-
return out;
|
|
3681
|
-
},
|
|
3682
|
-
get state() {
|
|
3683
|
-
return state;
|
|
3684
|
-
}
|
|
3685
|
-
};
|
|
3686
|
-
}
|
|
3687
|
-
function mixEventSeed(eventSeed) {
|
|
3688
|
-
let mixed = Math.imul((eventSeed | 0) ^ HASH_MIX, 2246822507);
|
|
3689
|
-
mixed ^= mixed >>> 13;
|
|
3690
|
-
mixed = Math.imul(mixed, 3266489909);
|
|
3691
|
-
mixed ^= mixed >>> 16;
|
|
3692
|
-
return (mixed >>> 0) % (LEHMER_MODULUS - 1) + 1;
|
|
3693
|
-
}
|
|
3694
|
-
function streamFor(eventSeed) {
|
|
3695
|
-
return lehmer(mixEventSeed(eventSeed));
|
|
3696
|
-
}
|
|
3980
|
+
var GAME_EFFECTS = { ...WORKSHOP_EFFECTS, ...Object.fromEntries([...EVENT_EFFECTS, ...VIEWMODEL_EFFECTS, ...VEHICLE_EFFECTS, ...SINGLE_PARTICLE_EFFECTS].map((effect) => [effect.id, effect])) };
|
|
3697
3981
|
var TABLE = {
|
|
3698
3982
|
concrete: { dust: 9078138, chip: 7236195, spark: 2 },
|
|
3699
3983
|
metal: { dust: 0, chip: 0, spark: 18 },
|
|
@@ -4363,8 +4647,8 @@ var GameDestructionThree = (() => {
|
|
|
4363
4647
|
var UP12 = [0, 1, 0];
|
|
4364
4648
|
var ZERO = [0, 0, 0];
|
|
4365
4649
|
var FULL_TURN_DRAWN = 6.283;
|
|
4366
|
-
function scaledSizes(
|
|
4367
|
-
return [
|
|
4650
|
+
function scaledSizes(range2, factor) {
|
|
4651
|
+
return [range2[0] * Math.sqrt(factor), range2[1] * Math.sqrt(factor)];
|
|
4368
4652
|
}
|
|
4369
4653
|
function fireEmit(engine, key, dt, centre, radius, factor, options = {}) {
|
|
4370
4654
|
const wind = options.wind ?? ZERO;
|
|
@@ -4997,8 +5281,8 @@ var GameDestructionThree = (() => {
|
|
|
4997
5281
|
function addScorch(store, random, x, z, radius) {
|
|
4998
5282
|
const variant = Math.floor(random.next() * SCORCH_VARIANTS);
|
|
4999
5283
|
const lift = 0.03 + nextLift(store) * 1e-3;
|
|
5000
|
-
const
|
|
5001
|
-
store.add({ kind: "scorch", x, z, radius, variant, lift, rotation });
|
|
5284
|
+
const rotation2 = random.next() * 6;
|
|
5285
|
+
store.add({ kind: "scorch", x, z, radius, variant, lift, rotation: rotation2 });
|
|
5002
5286
|
}
|
|
5003
5287
|
function addRimRocks(store, ground, random, x, z, radius) {
|
|
5004
5288
|
const count = Math.round(6 + radius * 7);
|
|
@@ -5027,8 +5311,8 @@ var GameDestructionThree = (() => {
|
|
|
5027
5311
|
function addCrater(store, ground, random, spec) {
|
|
5028
5312
|
ground?.dent(random, spec.x, spec.z, spec.radius, spec.depth);
|
|
5029
5313
|
if (!spec.marks) return;
|
|
5030
|
-
const
|
|
5031
|
-
store.add({ kind: "dirt", x: spec.x, z: spec.z, radius: spec.radius * 1.02, lift: 0.045, rotation });
|
|
5314
|
+
const rotation2 = random.next() * 6;
|
|
5315
|
+
store.add({ kind: "dirt", x: spec.x, z: spec.z, radius: spec.radius * 1.02, lift: 0.045, rotation: rotation2 });
|
|
5032
5316
|
addRimRocks(store, ground, random, spec.x, spec.z, spec.radius);
|
|
5033
5317
|
}
|
|
5034
5318
|
function addBloodSplat(store, ground, random, spec) {
|
|
@@ -5584,6 +5868,7 @@ var GameDestructionThree = (() => {
|
|
|
5584
5868
|
state.gas = Math.max(0, state.gas - dt / DECAY.gasSeconds);
|
|
5585
5869
|
state.beat *= Math.exp(-DECAY.beat * dt);
|
|
5586
5870
|
}
|
|
5871
|
+
var PAD_OF_SIZE2 = 0.35;
|
|
5587
5872
|
var clamp4 = (v, lo, hi) => v < lo ? lo : v > hi ? hi : v;
|
|
5588
5873
|
var lerp4 = (a, b, t) => a + (b - a) * t;
|
|
5589
5874
|
function rgb(hex) {
|
|
@@ -5743,9 +6028,20 @@ var GameDestructionThree = (() => {
|
|
|
5743
6028
|
vy2 *= k;
|
|
5744
6029
|
vz2 *= k;
|
|
5745
6030
|
}
|
|
5746
|
-
|
|
6031
|
+
let x = this.position[i3] + vx2 * dt;
|
|
5747
6032
|
let y = this.position[i3 + 1] + vy2 * dt;
|
|
5748
|
-
|
|
6033
|
+
let z = this.position[i3 + 2] + vz2 * dt;
|
|
6034
|
+
const confiner = host.confiner;
|
|
6035
|
+
if (def.carried && confiner && !confiner.empty) {
|
|
6036
|
+
const pad = this.size0[i] * lerp4(1, def.grow, t) * PAD_OF_SIZE2;
|
|
6037
|
+
if (confiner.confine(this.position[i3], this.position[i3 + 1], this.position[i3 + 2], x, y, z, pad, dt)) {
|
|
6038
|
+
const out = confiner.out;
|
|
6039
|
+
x = out.x;
|
|
6040
|
+
y = out.y;
|
|
6041
|
+
z = out.z;
|
|
6042
|
+
[vx2, vy2, vz2] = slideAlong(out, vx2, vy2, vz2);
|
|
6043
|
+
}
|
|
6044
|
+
}
|
|
5749
6045
|
if (def.ground !== "none") {
|
|
5750
6046
|
const own = this.floor[i];
|
|
5751
6047
|
const gy = Number.isNaN(own) ? host.groundAt(x, z) + 5e-3 : own;
|
|
@@ -5831,7 +6127,8 @@ var GameDestructionThree = (() => {
|
|
|
5831
6127
|
alpha: 0.35,
|
|
5832
6128
|
fadeIn: 0.15,
|
|
5833
6129
|
cone: 0.6,
|
|
5834
|
-
ground: "none"
|
|
6130
|
+
ground: "none",
|
|
6131
|
+
carried: true
|
|
5835
6132
|
},
|
|
5836
6133
|
sparks: {
|
|
5837
6134
|
id: "sparks",
|
|
@@ -5875,7 +6172,8 @@ var GameDestructionThree = (() => {
|
|
|
5875
6172
|
alpha: 0.4,
|
|
5876
6173
|
fadeIn: 0.1,
|
|
5877
6174
|
cone: 0.4,
|
|
5878
|
-
ground: "none"
|
|
6175
|
+
ground: "none",
|
|
6176
|
+
carried: true
|
|
5879
6177
|
},
|
|
5880
6178
|
shards: {
|
|
5881
6179
|
id: "shards",
|
|
@@ -6033,7 +6331,8 @@ var GameDestructionThree = (() => {
|
|
|
6033
6331
|
fadeIn: 0.1,
|
|
6034
6332
|
cone: 0.5,
|
|
6035
6333
|
ground: "stop",
|
|
6036
|
-
flutter: 0.6
|
|
6334
|
+
flutter: 0.6,
|
|
6335
|
+
carried: true
|
|
6037
6336
|
},
|
|
6038
6337
|
steam: {
|
|
6039
6338
|
id: "steam",
|
|
@@ -6055,7 +6354,8 @@ var GameDestructionThree = (() => {
|
|
|
6055
6354
|
alpha: 0.35,
|
|
6056
6355
|
fadeIn: 0.15,
|
|
6057
6356
|
cone: 0.6,
|
|
6058
|
-
ground: "none"
|
|
6357
|
+
ground: "none",
|
|
6358
|
+
carried: true
|
|
6059
6359
|
},
|
|
6060
6360
|
flash: {
|
|
6061
6361
|
id: "flash",
|
|
@@ -6188,7 +6488,8 @@ var GameDestructionThree = (() => {
|
|
|
6188
6488
|
const host = {
|
|
6189
6489
|
groundAt: this.options.groundAt,
|
|
6190
6490
|
gravity: this.options.gravity,
|
|
6191
|
-
land: (owner, x, y, z, color, tag) => this.listeners.get(owner)?.(x, y, z, color, tag)
|
|
6491
|
+
land: (owner, x, y, z, color, tag) => this.listeners.get(owner)?.(x, y, z, color, tag),
|
|
6492
|
+
...this.options.confiner ? { confiner: this.options.confiner } : {}
|
|
6192
6493
|
};
|
|
6193
6494
|
if (this.additive.live > 0 || this.additive.drawCount > 0) this.additive.update(dt, host);
|
|
6194
6495
|
if (this.normal.live > 0 || this.normal.drawCount > 0) this.normal.update(dt, host);
|
|
@@ -6201,9 +6502,9 @@ var GameDestructionThree = (() => {
|
|
|
6201
6502
|
var TWO_PI_ROUNDED = 6.2832;
|
|
6202
6503
|
var WIDE_CONE = 3.1;
|
|
6203
6504
|
var UP13 = [0, 1, 0];
|
|
6204
|
-
function drawRange(random,
|
|
6205
|
-
if (Array.isArray(
|
|
6206
|
-
return
|
|
6505
|
+
function drawRange(random, range2) {
|
|
6506
|
+
if (Array.isArray(range2)) return random.between(range2[0], range2[1]);
|
|
6507
|
+
return range2 || 0;
|
|
6207
6508
|
}
|
|
6208
6509
|
function randomUnit(random, out) {
|
|
6209
6510
|
const up = random.next() * 2 - 1;
|
|
@@ -6394,8 +6695,8 @@ var GameDestructionThree = (() => {
|
|
|
6394
6695
|
* Takes away the marks inside a box: world `center`, `half` extents along the axes of the world `rotation` (a quaternion, x y z w; none means the
|
|
6395
6696
|
* world axes). The surface they were on is gone (a brick came out of a wall with its bullet holes). Returns how many went.
|
|
6396
6697
|
*/
|
|
6397
|
-
clearInside(center, half,
|
|
6398
|
-
const qx = -
|
|
6698
|
+
clearInside(center, half, rotation2 = [0, 0, 0, 1]) {
|
|
6699
|
+
const qx = -rotation2[0], qy = -rotation2[1], qz = -rotation2[2], qw = rotation2[3];
|
|
6399
6700
|
let gone = 0;
|
|
6400
6701
|
for (const decal2 of this.decals) {
|
|
6401
6702
|
if (!decal2.on) continue;
|
|
@@ -6516,10 +6817,14 @@ var GameDestructionThree = (() => {
|
|
|
6516
6817
|
var DEFAULT_FADE_IN = 0.1;
|
|
6517
6818
|
var FLOATS_PER_VECTOR = 3;
|
|
6518
6819
|
var BYTE_MAX2 = 255;
|
|
6820
|
+
var CARRIED_GRAVITY = 3;
|
|
6821
|
+
var PAD_OF_SIZE3 = 0.35;
|
|
6519
6822
|
var SpritePool = class {
|
|
6520
|
-
|
|
6823
|
+
/** `carried`: the normal-blend pool (smoke, dust, steam), whose light sprites go round the closed spaces; the additive one (flames, sparks) does not. */
|
|
6824
|
+
constructor(capacity, context, carried = false) {
|
|
6521
6825
|
__publicField2(this, "capacity", capacity);
|
|
6522
6826
|
__publicField2(this, "context", context);
|
|
6827
|
+
__publicField2(this, "carried", carried);
|
|
6523
6828
|
__publicField2(this, "count", 0);
|
|
6524
6829
|
__publicField2(this, "position");
|
|
6525
6830
|
__publicField2(this, "velocity");
|
|
@@ -6619,6 +6924,7 @@ var GameDestructionThree = (() => {
|
|
|
6619
6924
|
}
|
|
6620
6925
|
update(dt, leaveDecal) {
|
|
6621
6926
|
const { position, velocity } = this;
|
|
6927
|
+
const confiner = this.context.confiner;
|
|
6622
6928
|
for (let index = this.count - 1; index >= 0; index--) {
|
|
6623
6929
|
this.life[index] -= dt;
|
|
6624
6930
|
if (this.life[index] <= 0) {
|
|
@@ -6632,9 +6938,25 @@ var GameDestructionThree = (() => {
|
|
|
6632
6938
|
velocity[offset] *= factor;
|
|
6633
6939
|
velocity[offset + 1] *= factor;
|
|
6634
6940
|
velocity[offset + 2] *= factor;
|
|
6941
|
+
const x0 = position[offset];
|
|
6942
|
+
const y0 = position[offset + 1];
|
|
6943
|
+
const z0 = position[offset + 2];
|
|
6635
6944
|
position[offset] += velocity[offset] * dt;
|
|
6636
6945
|
position[offset + 1] += velocity[offset + 1] * dt;
|
|
6637
6946
|
position[offset + 2] += velocity[offset + 2] * dt;
|
|
6947
|
+
if (this.carried && confiner && !confiner.empty && Math.abs(this.gravity[index]) < CARRIED_GRAVITY) {
|
|
6948
|
+
const size = this.startSize[index] * (1 + (this.growth[index] - 1) * age);
|
|
6949
|
+
if (confiner.confine(x0, y0, z0, position[offset], position[offset + 1], position[offset + 2], size * PAD_OF_SIZE3, dt)) {
|
|
6950
|
+
const out = confiner.out;
|
|
6951
|
+
position[offset] = out.x;
|
|
6952
|
+
position[offset + 1] = out.y;
|
|
6953
|
+
position[offset + 2] = out.z;
|
|
6954
|
+
const [vx2, vy2, vz2] = slideAlong(out, velocity[offset], velocity[offset + 1], velocity[offset + 2]);
|
|
6955
|
+
velocity[offset] = vx2;
|
|
6956
|
+
velocity[offset + 1] = vy2;
|
|
6957
|
+
velocity[offset + 2] = vz2;
|
|
6958
|
+
}
|
|
6959
|
+
}
|
|
6638
6960
|
const mode = this.groundMode[index];
|
|
6639
6961
|
if (mode) {
|
|
6640
6962
|
const groundHeight = this.context.groundAt(position[offset], position[offset + 2]);
|
|
@@ -6911,9 +7233,9 @@ var GameDestructionThree = (() => {
|
|
|
6911
7233
|
__publicField2(this, "placement");
|
|
6912
7234
|
__publicField2(this, "accumulators", /* @__PURE__ */ new Map());
|
|
6913
7235
|
const profile = options.profile ?? PROFILES.high;
|
|
6914
|
-
this.context = { random: options.random, groundAt: options.groundAt ?? workshopGround, quality: { level: 0, mult: 1 }, trace: options.trace };
|
|
7236
|
+
this.context = { random: options.random, groundAt: options.groundAt ?? workshopGround, quality: { level: 0, mult: 1 }, trace: options.trace, ...options.confiner ? { confiner: options.confiner } : {} };
|
|
6915
7237
|
this.add = new SpritePool(profile.sprites.add, this.context);
|
|
6916
|
-
this.normal = new SpritePool(profile.sprites.normal, this.context);
|
|
7238
|
+
this.normal = new SpritePool(profile.sprites.normal, this.context, true);
|
|
6917
7239
|
this.streaks = new StreakPool(profile.streaks, this.context);
|
|
6918
7240
|
this.debris = new DebrisPool(this.context);
|
|
6919
7241
|
this.decals = new DecalPool(this.context);
|
|
@@ -6949,20 +7271,20 @@ var GameDestructionThree = (() => {
|
|
|
6949
7271
|
return [origin[0] + cos2 * x + sin2 * z, origin[1] + point[1] - anchor[1], origin[2] - sin2 * x + cos2 * z];
|
|
6950
7272
|
}
|
|
6951
7273
|
/** A direction or velocity of the recipe's space in the world. */
|
|
6952
|
-
turn(
|
|
7274
|
+
turn(vector2) {
|
|
6953
7275
|
const placement = this.placement;
|
|
6954
|
-
if (!placement) return
|
|
6955
|
-
if (placement.orientation) return rotate(placement.orientation,
|
|
7276
|
+
if (!placement) return vector2;
|
|
7277
|
+
if (placement.orientation) return rotate(placement.orientation, vector2);
|
|
6956
7278
|
const cos2 = Math.cos(placement.yaw);
|
|
6957
7279
|
const sin2 = Math.sin(placement.yaw);
|
|
6958
|
-
return [cos2 *
|
|
7280
|
+
return [cos2 * vector2[0] + sin2 * vector2[2], vector2[1], -sin2 * vector2[0] + cos2 * vector2[2]];
|
|
6959
7281
|
}
|
|
6960
7282
|
placed(options) {
|
|
6961
7283
|
if (!this.placement) return options;
|
|
6962
7284
|
return { ...options, p: this.place(options.p), ...options.dir ? { dir: this.turn(options.dir) } : {}, ...options.v ? { v: this.turn(options.v) } : {} };
|
|
6963
7285
|
}
|
|
6964
|
-
spawn(system,
|
|
6965
|
-
const options = this.placed(
|
|
7286
|
+
spawn(system, recipe2) {
|
|
7287
|
+
const options = this.placed(recipe2);
|
|
6966
7288
|
this.context.trace?.(system, [options]);
|
|
6967
7289
|
if (system === "add") this.add.spawn(options);
|
|
6968
7290
|
else if (system === "normal") this.normal.spawn(options);
|
|
@@ -6982,43 +7304,43 @@ var GameDestructionThree = (() => {
|
|
|
6982
7304
|
this.accumulators.set(key, carried);
|
|
6983
7305
|
}
|
|
6984
7306
|
/** A solid particle (a cone, a sphere): the group sits at `p` turned by the placement, `v` is turned with it and `wv` is not. */
|
|
6985
|
-
mesh(
|
|
7307
|
+
mesh(recipe2) {
|
|
6986
7308
|
const placement = this.placement;
|
|
6987
|
-
const options = placement ? { ...
|
|
7309
|
+
const options = placement ? { ...recipe2, p: this.place(recipe2.p), ...recipe2.v ? { v: this.turn(recipe2.v) } : {} } : recipe2;
|
|
6988
7310
|
this.context.trace?.("mesh", [options]);
|
|
6989
|
-
const grouped =
|
|
7311
|
+
const grouped = recipe2.at !== void 0 || recipe2.roll !== void 0;
|
|
6990
7312
|
return this.meshes.spawn(options, placement && grouped ? placement.orientation ?? [0, Math.sin(placement.yaw / 2), 0, Math.cos(placement.yaw / 2)] : void 0);
|
|
6991
7313
|
}
|
|
6992
|
-
debrisPiece(
|
|
6993
|
-
const options = this.placed(
|
|
7314
|
+
debrisPiece(recipe2) {
|
|
7315
|
+
const options = this.placed(recipe2);
|
|
6994
7316
|
this.context.trace?.("debris", [options]);
|
|
6995
7317
|
this.debris.spawn(options);
|
|
6996
7318
|
}
|
|
6997
|
-
decal(
|
|
6998
|
-
let args =
|
|
7319
|
+
decal(recipe2) {
|
|
7320
|
+
let args = recipe2;
|
|
6999
7321
|
if (this.placement) {
|
|
7000
|
-
const [x, y, z] = this.place([
|
|
7001
|
-
const options =
|
|
7002
|
-
args = [x, y, z,
|
|
7322
|
+
const [x, y, z] = this.place([recipe2[0], recipe2[1], recipe2[2]]);
|
|
7323
|
+
const options = recipe2[5];
|
|
7324
|
+
args = [x, y, z, recipe2[3], recipe2[4], options?.n ? { ...options, n: this.turn(options.n) } : options];
|
|
7003
7325
|
}
|
|
7004
7326
|
this.context.trace?.("decal", args);
|
|
7005
7327
|
this.decals.add(args[0], args[1], args[2], args[3], args[4], args[5]);
|
|
7006
7328
|
}
|
|
7007
|
-
ring(
|
|
7008
|
-
const args = this.placement ? [this.place(
|
|
7329
|
+
ring(recipe2) {
|
|
7330
|
+
const args = this.placement ? [this.place(recipe2[0]), recipe2[1], recipe2[2], recipe2[3], recipe2[4], recipe2[5] && this.turn(recipe2[5]), recipe2[6]] : recipe2;
|
|
7009
7331
|
this.context.trace?.("ring", args);
|
|
7010
7332
|
this.rings.add(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
|
|
7011
7333
|
}
|
|
7012
7334
|
/** `steady` (a seventh number): the light holds its intensity for its duration and goes out, where the Workshop's fades with the square of its age. */
|
|
7013
|
-
flash(
|
|
7014
|
-
const args = this.placement ? [this.place(
|
|
7335
|
+
flash(recipe2) {
|
|
7336
|
+
const args = this.placement ? [this.place(recipe2[0]), recipe2[1], recipe2[2], recipe2[3], recipe2[4], recipe2[5], recipe2[6]] : recipe2;
|
|
7015
7337
|
this.context.trace?.("flash", args.slice(0, 6));
|
|
7016
7338
|
this.lights.flash(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
|
|
7017
7339
|
}
|
|
7018
7340
|
/** `fireLight` (W400): sways with the clock and flickers with one draw. */
|
|
7019
|
-
fireLight(slot,
|
|
7341
|
+
fireLight(slot, recipe2, intensity, time) {
|
|
7020
7342
|
const light = this.lights.fire[slot];
|
|
7021
|
-
const point = this.place(
|
|
7343
|
+
const point = this.place(recipe2);
|
|
7022
7344
|
light.x = point[0];
|
|
7023
7345
|
light.y = point[1];
|
|
7024
7346
|
light.z = point[2];
|
|
@@ -7101,12 +7423,14 @@ var GameDestructionThree = (() => {
|
|
|
7101
7423
|
const groundAt = options.groundAt ?? (ground ? (x, z) => ground.heightAt(x, z) : () => 0);
|
|
7102
7424
|
const handles = { next: 0, events: 0 };
|
|
7103
7425
|
const low = options.profile === "low";
|
|
7426
|
+
const enclosures = new Enclosures(20973 + (options.seed ?? 0));
|
|
7104
7427
|
const spriteSystem = new SpriteKindSystem({
|
|
7105
7428
|
capacity: options.sprites?.capacity ?? (low ? 1250 : 2500),
|
|
7106
7429
|
density: options.sprites?.density ?? (low ? 0.6 : 1),
|
|
7107
7430
|
seed: 2654435761 + (options.seed ?? 0),
|
|
7108
7431
|
groundAt,
|
|
7109
7432
|
gravity: options.gravity ?? DEFAULT_GRAVITY,
|
|
7433
|
+
confiner: enclosures,
|
|
7110
7434
|
...options.sprites?.kinds ? { kinds: options.sprites.kinds } : {}
|
|
7111
7435
|
});
|
|
7112
7436
|
const core = {
|
|
@@ -7156,7 +7480,7 @@ var GameDestructionThree = (() => {
|
|
|
7156
7480
|
return [camera2.x, camera2.y, camera2.z];
|
|
7157
7481
|
}, forward: (local2) => [local2[0] ?? 0, local2[1] ?? 0, local2[2] ?? 0] };
|
|
7158
7482
|
function workshop() {
|
|
7159
|
-
return engine ?? (engine = new WorkshopEngine({ random: sharedRandom, profile, groundAt }));
|
|
7483
|
+
return engine ?? (engine = new WorkshopEngine({ random: sharedRandom, profile, groundAt, confiner: enclosures }));
|
|
7160
7484
|
}
|
|
7161
7485
|
function effectPlayer() {
|
|
7162
7486
|
return player ?? (player = createEffectPlayer({ engine: workshop(), effects, view }));
|
|
@@ -7215,6 +7539,10 @@ var GameDestructionThree = (() => {
|
|
|
7215
7539
|
puff3.vz += dz * strength;
|
|
7216
7540
|
}
|
|
7217
7541
|
},
|
|
7542
|
+
enclose(id, enclosure) {
|
|
7543
|
+
enclosures.set(id, enclosure);
|
|
7544
|
+
},
|
|
7545
|
+
enclosures: () => enclosures,
|
|
7218
7546
|
stop(handle) {
|
|
7219
7547
|
player?.stop(handle);
|
|
7220
7548
|
const fires = core.fires;
|
|
@@ -7242,7 +7570,7 @@ var GameDestructionThree = (() => {
|
|
|
7242
7570
|
core.clock.time += dt;
|
|
7243
7571
|
core.schedule.update(core.clock.time);
|
|
7244
7572
|
updateRings(core.rings, dt);
|
|
7245
|
-
updatePuffs(core.puffs, dt, wind);
|
|
7573
|
+
updatePuffs(core.puffs, dt, wind, enclosures);
|
|
7246
7574
|
updateSparks(core.sparks, { dt, groundAt });
|
|
7247
7575
|
updateGlows(core.glows, dt);
|
|
7248
7576
|
updateShocks(core.shocks, core.puffs.items, dt);
|
|
@@ -7326,7 +7654,22 @@ var GameDestructionThree = (() => {
|
|
|
7326
7654
|
return key === void 0 ? void 0 : entry[key];
|
|
7327
7655
|
}
|
|
7328
7656
|
|
|
7329
|
-
// ../game-
|
|
7657
|
+
// ../game-render-three/dist/index.js
|
|
7658
|
+
var DEFAULT_ANGLE = Math.PI / 3;
|
|
7659
|
+
var LIGHT_PRIORITY = {
|
|
7660
|
+
blast: 900,
|
|
7661
|
+
rocket: 800,
|
|
7662
|
+
muzzle: 750,
|
|
7663
|
+
fire: 600,
|
|
7664
|
+
flare: 500,
|
|
7665
|
+
headlight: 400,
|
|
7666
|
+
weaponLight: 400,
|
|
7667
|
+
lamp: 200,
|
|
7668
|
+
street: 150
|
|
7669
|
+
};
|
|
7670
|
+
var EFFECT_STEP_SECONDS = 1 / 50;
|
|
7671
|
+
|
|
7672
|
+
// ../game-vfx-three/dist/chunk-ALDCQ5RH.js
|
|
7330
7673
|
var GLOW_VERTEX = `attribute vec4 aP;attribute vec4 aC;varying vec2 vU;varying vec4 vC;
|
|
7331
7674
|
void main(){vec3 R=vec3(viewMatrix[0][0],viewMatrix[1][0],viewMatrix[2][0]);vec3 Up=vec3(viewMatrix[0][1],viewMatrix[1][1],viewMatrix[2][1]);
|
|
7332
7675
|
vec3 wp=aP.xyz+(R*position.x+Up*position.y)*aP.w;vU=position.xy;vC=aC;gl_Position=projectionMatrix*viewMatrix*vec4(wp,1.);}`;
|
|
@@ -7605,8 +7948,26 @@ void main(){
|
|
|
7605
7948
|
}
|
|
7606
7949
|
};
|
|
7607
7950
|
}
|
|
7608
|
-
|
|
7951
|
+
var LIGHT_ON_THRESHOLD = 0.05;
|
|
7952
|
+
var FIRE_COLOR = 16742954;
|
|
7953
|
+
var FIRE_DECAY = 2;
|
|
7954
|
+
var BLAST_DECAY = 2;
|
|
7955
|
+
function followEntry(budget, handles, index, entry, request) {
|
|
7956
|
+
const handle = handles[index] ?? null;
|
|
7957
|
+
if (entry.intensity <= LIGHT_ON_THRESHOLD) {
|
|
7958
|
+
handle?.release({ fadeMs: 0 });
|
|
7959
|
+
handles[index] = null;
|
|
7960
|
+
return;
|
|
7961
|
+
}
|
|
7962
|
+
if (handle?.alive) {
|
|
7963
|
+
handle.update({ color: request.color, intensity: request.intensity, distance: request.distance, position: request.position });
|
|
7964
|
+
return;
|
|
7965
|
+
}
|
|
7966
|
+
handles[index] = budget.acquire(request);
|
|
7967
|
+
}
|
|
7968
|
+
function createLightLayer(THREE, pool, scale, budget) {
|
|
7609
7969
|
const group = new THREE.Group();
|
|
7970
|
+
if (budget) return createBudgetedLightLayer(group, pool, scale, budget);
|
|
7610
7971
|
const blast = pool.blast.map(() => {
|
|
7611
7972
|
const light = new THREE.PointLight(16752720, 0, 30, 2);
|
|
7612
7973
|
light.position.set(0, -50, 0);
|
|
@@ -7645,6 +8006,30 @@ void main(){
|
|
|
7645
8006
|
}
|
|
7646
8007
|
};
|
|
7647
8008
|
}
|
|
8009
|
+
function createBudgetedLightLayer(group, pool, scale, budget) {
|
|
8010
|
+
const blast = pool.blast.map(() => null);
|
|
8011
|
+
const fire = pool.fire.map(() => null);
|
|
8012
|
+
return {
|
|
8013
|
+
group,
|
|
8014
|
+
sync() {
|
|
8015
|
+
let lit = 0;
|
|
8016
|
+
pool.blast.forEach((entry, index) => {
|
|
8017
|
+
const request = { owner: "vfx.blast", priority: LIGHT_PRIORITY.blast, urgent: true, color: entry.color, intensity: entry.intensity * scale, distance: entry.distance, decay: BLAST_DECAY, position: [entry.x, entry.y, entry.z] };
|
|
8018
|
+
followEntry(budget, blast, index, entry, request);
|
|
8019
|
+
if (entry.intensity > LIGHT_ON_THRESHOLD) lit++;
|
|
8020
|
+
});
|
|
8021
|
+
pool.fire.forEach((entry, index) => {
|
|
8022
|
+
const request = { owner: "vfx.fire", priority: LIGHT_PRIORITY.fire, color: FIRE_COLOR, intensity: entry.intensity * scale, distance: entry.distance, decay: FIRE_DECAY, position: [entry.x, entry.y, entry.z] };
|
|
8023
|
+
followEntry(budget, fire, index, entry, request);
|
|
8024
|
+
if (entry.intensity > LIGHT_ON_THRESHOLD) lit++;
|
|
8025
|
+
});
|
|
8026
|
+
return lit;
|
|
8027
|
+
},
|
|
8028
|
+
dispose() {
|
|
8029
|
+
for (const handle of [...blast, ...fire]) handle?.release({ fadeMs: 0 });
|
|
8030
|
+
}
|
|
8031
|
+
};
|
|
8032
|
+
}
|
|
7648
8033
|
var SCORCH_SEED = 5;
|
|
7649
8034
|
var TEXTURE_SIZE = 256;
|
|
7650
8035
|
var FULL_TURN = Math.PI * 2;
|
|
@@ -7778,6 +8163,7 @@ void main(){
|
|
|
7778
8163
|
group.add(mesh2);
|
|
7779
8164
|
return mesh2;
|
|
7780
8165
|
}
|
|
8166
|
+
let probeGeometry;
|
|
7781
8167
|
const groundMarks = [];
|
|
7782
8168
|
const spareGeometries = [];
|
|
7783
8169
|
const blood = [];
|
|
@@ -7883,6 +8269,15 @@ void main(){
|
|
|
7883
8269
|
rockMesh();
|
|
7884
8270
|
plateMesh();
|
|
7885
8271
|
},
|
|
8272
|
+
probes() {
|
|
8273
|
+
probeGeometry ?? (probeGeometry = new THREE.PlaneGeometry(1e-3, 1e-3).rotateX(-Math.PI / 2));
|
|
8274
|
+
return [...scorchMaterials, dirtMaterial].map((material) => {
|
|
8275
|
+
const mesh2 = new THREE.Mesh(probeGeometry, material);
|
|
8276
|
+
mesh2.receiveShadow = true;
|
|
8277
|
+
mesh2.frustumCulled = false;
|
|
8278
|
+
return mesh2;
|
|
8279
|
+
});
|
|
8280
|
+
},
|
|
7886
8281
|
update(dt) {
|
|
7887
8282
|
for (let index = 0; index < blood.length; index++) {
|
|
7888
8283
|
const drawn = blood[index];
|
|
@@ -7895,6 +8290,7 @@ void main(){
|
|
|
7895
8290
|
dispose() {
|
|
7896
8291
|
clearMarks();
|
|
7897
8292
|
for (const mesh2 of [instanced.blood, instanced.rock, instanced.plate]) mesh2?.dispose();
|
|
8293
|
+
probeGeometry?.dispose();
|
|
7898
8294
|
for (const item of owned) item.dispose();
|
|
7899
8295
|
}
|
|
7900
8296
|
};
|
|
@@ -8470,7 +8866,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8470
8866
|
}
|
|
8471
8867
|
};
|
|
8472
8868
|
}
|
|
8473
|
-
function createWorkshopLayers(THREE, engine, pointScale, lightScale) {
|
|
8869
|
+
function createWorkshopLayers(THREE, engine, pointScale, lightScale, budget) {
|
|
8474
8870
|
const group = new THREE.Group();
|
|
8475
8871
|
group.name = "workshop";
|
|
8476
8872
|
const layers = [
|
|
@@ -8485,15 +8881,30 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8485
8881
|
for (const layer2 of layers) group.add(layer2.object);
|
|
8486
8882
|
const meshes = createMeshLayer(THREE, engine.meshes);
|
|
8487
8883
|
group.add(meshes.group);
|
|
8488
|
-
const
|
|
8489
|
-
const fireLights = engine.lights.fire.map(() => new THREE.PointLight(FIRE_LIGHT_COLOR, 0, FIRE_LIGHT_DISTANCE));
|
|
8490
|
-
for (const light of [...flashLights, ...fireLights]) group.add(light);
|
|
8884
|
+
const lights = budget ? budgetedLights(engine, lightScale, budget) : legacyLights(THREE, engine, lightScale, group);
|
|
8491
8885
|
return {
|
|
8492
8886
|
group,
|
|
8493
8887
|
sync() {
|
|
8494
8888
|
let drawCalls = 0;
|
|
8495
8889
|
for (const layer2 of layers) if (layer2.sync()) drawCalls++;
|
|
8496
8890
|
drawCalls += meshes.sync();
|
|
8891
|
+
lights.sync();
|
|
8892
|
+
return drawCalls;
|
|
8893
|
+
},
|
|
8894
|
+
dispose() {
|
|
8895
|
+
for (const layer2 of layers) layer2.dispose();
|
|
8896
|
+
meshes.dispose();
|
|
8897
|
+
lights.dispose();
|
|
8898
|
+
group.clear();
|
|
8899
|
+
}
|
|
8900
|
+
};
|
|
8901
|
+
}
|
|
8902
|
+
function legacyLights(THREE, engine, lightScale, group) {
|
|
8903
|
+
const flashLights = engine.lights.lights.map(() => new THREE.PointLight(16760944, 0, 14));
|
|
8904
|
+
const fireLights = engine.lights.fire.map(() => new THREE.PointLight(FIRE_LIGHT_COLOR, 0, FIRE_LIGHT_DISTANCE));
|
|
8905
|
+
for (const light of [...flashLights, ...fireLights]) group.add(light);
|
|
8906
|
+
return {
|
|
8907
|
+
sync() {
|
|
8497
8908
|
engine.lights.lights.forEach((source, index) => {
|
|
8498
8909
|
const light = flashLights[index];
|
|
8499
8910
|
light.position.set(source.x, source.y, source.z);
|
|
@@ -8506,12 +8917,27 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8506
8917
|
light.position.set(source.x, source.y, source.z);
|
|
8507
8918
|
light.intensity = source.intensity * lightScale;
|
|
8508
8919
|
});
|
|
8509
|
-
return drawCalls;
|
|
8510
8920
|
},
|
|
8511
8921
|
dispose() {
|
|
8512
|
-
|
|
8513
|
-
|
|
8514
|
-
|
|
8922
|
+
}
|
|
8923
|
+
};
|
|
8924
|
+
}
|
|
8925
|
+
function budgetedLights(engine, lightScale, budget) {
|
|
8926
|
+
const flash2 = engine.lights.lights.map(() => null);
|
|
8927
|
+
const fire = engine.lights.fire.map(() => null);
|
|
8928
|
+
return {
|
|
8929
|
+
sync() {
|
|
8930
|
+
engine.lights.lights.forEach((source, index) => {
|
|
8931
|
+
const request = { owner: "vfx.workshop", priority: LIGHT_PRIORITY.blast, urgent: true, color: source.color, intensity: source.intensity * lightScale, distance: source.distance, position: [source.x, source.y, source.z] };
|
|
8932
|
+
followEntry(budget, flash2, index, source, request);
|
|
8933
|
+
});
|
|
8934
|
+
engine.lights.fire.forEach((source, index) => {
|
|
8935
|
+
const request = { owner: "vfx.workshop", priority: LIGHT_PRIORITY.fire, color: FIRE_LIGHT_COLOR, intensity: source.intensity * lightScale, distance: FIRE_LIGHT_DISTANCE, position: [source.x, source.y, source.z] };
|
|
8936
|
+
followEntry(budget, fire, index, source, request);
|
|
8937
|
+
});
|
|
8938
|
+
},
|
|
8939
|
+
dispose() {
|
|
8940
|
+
for (const handle of [...flash2, ...fire]) handle?.release({ fadeMs: 0 });
|
|
8515
8941
|
}
|
|
8516
8942
|
};
|
|
8517
8943
|
}
|
|
@@ -8569,7 +8995,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8569
8995
|
const chunks = createChunkLayer(THREE, pools.chunks, { rock: rockGeometry, plate: plateGeometry }, colorOfChunk);
|
|
8570
8996
|
const shocks = createShockLayer(THREE, pools.shocks);
|
|
8571
8997
|
const sprites = createSpriteLayer(THREE, world.sprites(), options.pointScale ?? 700);
|
|
8572
|
-
const lights = createLightLayer(THREE, pools.lights, options.lightScale ?? Math.PI);
|
|
8998
|
+
const lights = createLightLayer(THREE, pools.lights, options.lightScale ?? Math.PI, options.lights);
|
|
8573
8999
|
const marks = createMarkLayer(THREE, { ground: pools.ground, createCanvas: options.createCanvas, rockGeometry, plateGeometry, ...options.markLimits });
|
|
8574
9000
|
root.add(puffs.mesh, sparks.mesh, glows.mesh, chunks.rocks, chunks.plates, shocks.group, lights.group, sprites.additive, sprites.normal, marks.group);
|
|
8575
9001
|
const stopMarks = world.onMarks((event) => marks.handle(event));
|
|
@@ -8602,7 +9028,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8602
9028
|
workshopLayers?.dispose();
|
|
8603
9029
|
if (workshopLayers) root.remove(workshopLayers.group);
|
|
8604
9030
|
workshopEngine = engine;
|
|
8605
|
-
workshopLayers = createWorkshopLayers(THREE, engine, options.pointScale ?? 700, 1);
|
|
9031
|
+
workshopLayers = createWorkshopLayers(THREE, engine, options.pointScale ?? 700, 1, options.lights);
|
|
8606
9032
|
root.add(workshopLayers.group);
|
|
8607
9033
|
applyLayers();
|
|
8608
9034
|
}
|
|
@@ -8642,6 +9068,8 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8642
9068
|
});
|
|
8643
9069
|
},
|
|
8644
9070
|
stop: (handle) => world.stop(handle),
|
|
9071
|
+
// a module's closed space (a shut car's cabin): the world's smoke, dust and steam go round it
|
|
9072
|
+
enclose: (id, enclosure) => world.enclose(id, enclosure),
|
|
8645
9073
|
configure(settings) {
|
|
8646
9074
|
const band = settings.lod_band;
|
|
8647
9075
|
if (typeof band === "string" && band in LOD_BANDS) world.forceLod(LOD_BANDS[band] ?? null);
|
|
@@ -8673,7 +9101,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8673
9101
|
const meshes = createMeshLayerProbes(THREE);
|
|
8674
9102
|
for (const mesh2 of meshes) mesh2.frustumCulled = false;
|
|
8675
9103
|
const group = new THREE.Group();
|
|
8676
|
-
group.add(...meshes);
|
|
9104
|
+
group.add(...meshes, ...marks.probes());
|
|
8677
9105
|
anchors = { meshes, group };
|
|
8678
9106
|
return { group, dispose: () => {
|
|
8679
9107
|
} };
|
|
@@ -8791,6 +9219,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8791
9219
|
var BIG_LENGTH = 0.2;
|
|
8792
9220
|
var BIG_WIDTH = 0.03;
|
|
8793
9221
|
var FRAGMENT_SEED = 1374496523;
|
|
9222
|
+
var SHARD_SHAPES = 6;
|
|
8794
9223
|
var isBig = (size) => {
|
|
8795
9224
|
const [, middle, longest] = [...size].sort((a, b) => a - b);
|
|
8796
9225
|
return longest >= BIG_LENGTH && middle >= BIG_WIDTH;
|
|
@@ -8840,7 +9269,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8840
9269
|
return m;
|
|
8841
9270
|
}
|
|
8842
9271
|
shardGeometry(seed) {
|
|
8843
|
-
const idx = seed %
|
|
9272
|
+
const idx = seed % SHARD_SHAPES;
|
|
8844
9273
|
let g = this.shardGeos[idx];
|
|
8845
9274
|
if (!g) {
|
|
8846
9275
|
const r = createRng(1e3 + idx);
|
|
@@ -8861,17 +9290,32 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8861
9290
|
}
|
|
8862
9291
|
return g;
|
|
8863
9292
|
}
|
|
9293
|
+
markParts() {
|
|
9294
|
+
this.markGeometry ?? (this.markGeometry = new this.THREE.CircleGeometry(1, 10));
|
|
9295
|
+
this.markMaterial ?? (this.markMaterial = new this.THREE.MeshBasicMaterial({ color: 723465, depthWrite: false, polygonOffset: true, polygonOffsetFactor: -4, polygonOffsetUnits: -4 }));
|
|
9296
|
+
return { geometry: this.markGeometry, material: this.markMaterial };
|
|
9297
|
+
}
|
|
9298
|
+
/**
|
|
9299
|
+
* Meshes, never put in a scene by this class, that draw every shared piece of a fragment once: the box, the six shards, the bullet-hole disc, and the opaque and
|
|
9300
|
+
* glass materials. A host draws them at load so the first blast does not upload these buffers in the middle of a frame.
|
|
9301
|
+
*/
|
|
9302
|
+
warmMeshes() {
|
|
9303
|
+
const opaque = this.materialFor("warm", 8421504, false);
|
|
9304
|
+
const glass = this.materialFor("warm", 8421504, true);
|
|
9305
|
+
const geometries = [this.box, ...Array.from({ length: SHARD_SHAPES }, (_, index) => this.shardGeometry(index))];
|
|
9306
|
+
const { geometry, material } = this.markParts();
|
|
9307
|
+
return [...geometries.flatMap((shared) => [new this.THREE.Mesh(shared, opaque), new this.THREE.Mesh(shared, glass)]), new this.THREE.Mesh(geometry, material)];
|
|
9308
|
+
}
|
|
8864
9309
|
/**
|
|
8865
9310
|
* Bullet holes that stay on a fragment (`Fragment.marks`): dark discs that are children of its mesh, so they fall, spin and settle with it. The mesh is
|
|
8866
9311
|
* a unit box scaled to the fragment, so each disc is scaled back; exact for a mark on a face, which is where a bullet hole is.
|
|
8867
9312
|
*/
|
|
8868
9313
|
addMarks(mesh2, f) {
|
|
8869
9314
|
if (!f.marks?.length) return;
|
|
8870
|
-
|
|
8871
|
-
this.markMaterial ?? (this.markMaterial = new this.THREE.MeshBasicMaterial({ color: 723465, depthWrite: false, polygonOffset: true, polygonOffsetFactor: -4, polygonOffsetUnits: -4 }));
|
|
9315
|
+
const { geometry, material } = this.markParts();
|
|
8872
9316
|
const sc = mesh2.scale;
|
|
8873
9317
|
for (const mark of f.marks) {
|
|
8874
|
-
const disc = new this.THREE.Mesh(
|
|
9318
|
+
const disc = new this.THREE.Mesh(geometry, material);
|
|
8875
9319
|
const radius = Math.max(4e-3, mark.diameter) * 0.6;
|
|
8876
9320
|
const n = this.v.set(mark.normal[0], mark.normal[1], mark.normal[2]).normalize();
|
|
8877
9321
|
disc.position.set(mark.point[0] / sc.x + n.x * 2e-3 / sc.x, mark.point[1] / sc.y + n.y * 2e-3 / sc.y, mark.point[2] / sc.z + n.z * 2e-3 / sc.z);
|
|
@@ -9454,7 +9898,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
9454
9898
|
const invM = 1 / b.mass;
|
|
9455
9899
|
const steps = clamp6(Math.ceil(dt / SUB_DT), 1, 8);
|
|
9456
9900
|
const h = dt / steps;
|
|
9457
|
-
let
|
|
9901
|
+
let landing2 = 0;
|
|
9458
9902
|
let landPoint = [pos[0], pos[1], pos[2]];
|
|
9459
9903
|
let contactedLast = false;
|
|
9460
9904
|
let touched = false;
|
|
@@ -9560,8 +10004,8 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
9560
10004
|
let impact2 = 0;
|
|
9561
10005
|
for (const r of rs) impact2 = Math.max(impact2, -(v[1] + w[2] * r[0] - w[0] * r[2]));
|
|
9562
10006
|
const restitution = impact2 > 2 ? 0.25 : 0;
|
|
9563
|
-
if (impact2 >
|
|
9564
|
-
|
|
10007
|
+
if (impact2 > landing2) {
|
|
10008
|
+
landing2 = impact2;
|
|
9565
10009
|
let sx = 0;
|
|
9566
10010
|
let sz = 0;
|
|
9567
10011
|
for (const r of rs) {
|
|
@@ -9697,9 +10141,9 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
9697
10141
|
b.root.position.set(pos[0] - off.x, pos[1] - off.y, pos[2] - off.z);
|
|
9698
10142
|
b.root.updateMatrixWorld(true);
|
|
9699
10143
|
b.onGround = contactedLast;
|
|
9700
|
-
if (
|
|
10144
|
+
if (landing2 > HARD_LANDING && this.time - b.lastHit > 0.15) {
|
|
9701
10145
|
b.lastHit = this.time;
|
|
9702
|
-
this.o.onHardLanding(b, landPoint,
|
|
10146
|
+
this.o.onHardLanding(b, landPoint, landing2);
|
|
9703
10147
|
}
|
|
9704
10148
|
const still = touched && !unstable && Math.hypot(v[0], v[1], v[2]) < 0.12 && Math.hypot(w[0], w[1], w[2]) < 0.45;
|
|
9705
10149
|
if (still) b.still += dt;
|
|
@@ -11179,6 +11623,69 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
11179
11623
|
return out;
|
|
11180
11624
|
};
|
|
11181
11625
|
var RESTING_HOLD_COS = Math.cos(Math.PI / 6);
|
|
11626
|
+
var assemblies_default = [
|
|
11627
|
+
{
|
|
11628
|
+
id: "brick_wall_plastered",
|
|
11629
|
+
name: "Plastered brick wall",
|
|
11630
|
+
core: { material: "brick", thickness: 0.09 },
|
|
11631
|
+
layers: [{ material: "plaster", thickness: 0.02, faces: "both" }],
|
|
11632
|
+
units: { size: [0.23, 0.075, 0.11], bond: "running", mortar: "plaster" },
|
|
11633
|
+
breach: { area: 0.25 }
|
|
11634
|
+
},
|
|
11635
|
+
{
|
|
11636
|
+
id: "concrete_block_wall",
|
|
11637
|
+
name: "Concrete block wall",
|
|
11638
|
+
core: { material: "concrete", thickness: 0.14 },
|
|
11639
|
+
fill: 0.55,
|
|
11640
|
+
units: { size: [0.39, 0.19, 0.14], bond: "running", mortar: "plaster" },
|
|
11641
|
+
breach: { area: 0.25 }
|
|
11642
|
+
},
|
|
11643
|
+
{
|
|
11644
|
+
id: "reinforced_concrete",
|
|
11645
|
+
name: "Reinforced concrete wall",
|
|
11646
|
+
core: { material: "concrete", thickness: 0.2 },
|
|
11647
|
+
reinforcement: { material: "steel", spacing: 0.18, diameter: 8e-3, residualCapacity: 0.15 },
|
|
11648
|
+
units: { size: [0.6, 0.42, 0.2], bond: "stack", mortar: "concrete" },
|
|
11649
|
+
breach: { area: 0.25 }
|
|
11650
|
+
},
|
|
11651
|
+
{
|
|
11652
|
+
id: "drywall",
|
|
11653
|
+
name: "Drywall partition on steel studs",
|
|
11654
|
+
core: { material: "plaster", thickness: 0.0125 },
|
|
11655
|
+
layers: [{ material: "plaster", thickness: 0.0125, faces: "+" }],
|
|
11656
|
+
depth: 0.095,
|
|
11657
|
+
breach: { area: 0.25 }
|
|
11658
|
+
},
|
|
11659
|
+
{
|
|
11660
|
+
id: "wood_frame_wall",
|
|
11661
|
+
name: "Wood frame wall",
|
|
11662
|
+
core: { material: "plywood", thickness: 0.012 },
|
|
11663
|
+
layers: [{ material: "plaster", thickness: 0.0125, faces: "-" }],
|
|
11664
|
+
depth: 0.1135,
|
|
11665
|
+
breach: { area: 0.25 }
|
|
11666
|
+
},
|
|
11667
|
+
{
|
|
11668
|
+
id: "log_wall",
|
|
11669
|
+
name: "Log wall",
|
|
11670
|
+
core: { material: "wood_soft", thickness: 0.2 },
|
|
11671
|
+
fill: 0.785,
|
|
11672
|
+
breach: { area: 0.25 }
|
|
11673
|
+
},
|
|
11674
|
+
{
|
|
11675
|
+
id: "sheet_metal_shack",
|
|
11676
|
+
name: "Corrugated sheet metal wall",
|
|
11677
|
+
core: { material: "steel", thickness: 6e-4 },
|
|
11678
|
+
depth: 0.02,
|
|
11679
|
+
breach: { area: 0.25 }
|
|
11680
|
+
},
|
|
11681
|
+
{
|
|
11682
|
+
id: "glass_pane",
|
|
11683
|
+
name: "Glass pane",
|
|
11684
|
+
core: { material: "glass", thickness: 6e-3 },
|
|
11685
|
+
breach: { area: 0.1 }
|
|
11686
|
+
}
|
|
11687
|
+
];
|
|
11688
|
+
var SHIPPED = structuredClone(assemblies_default);
|
|
11182
11689
|
|
|
11183
11690
|
// src/spec.ts
|
|
11184
11691
|
function containsOf(value) {
|
|
@@ -11544,6 +12051,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
11544
12051
|
this.b = tmpV(THREE);
|
|
11545
12052
|
this.m4 = new THREE.Matrix4();
|
|
11546
12053
|
this.ray = new THREE.Raycaster();
|
|
12054
|
+
this.ray.layers.enableAll();
|
|
11547
12055
|
this.box = new THREE.Box3();
|
|
11548
12056
|
this.t = tmpV(THREE);
|
|
11549
12057
|
this.lbox = new THREE.Box3();
|
|
@@ -11551,9 +12059,9 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
11551
12059
|
/**
|
|
11552
12060
|
* @param range vertex range `[v0, v1)` of a merged mesh this part is drawn by (see `MeshRange`); `hosts` caches the shared state per mesh for one `bind`.
|
|
11553
12061
|
*/
|
|
11554
|
-
makeMeshVis(mesh2, home,
|
|
12062
|
+
makeMeshVis(mesh2, home, range2, hosts) {
|
|
11555
12063
|
let host = null;
|
|
11556
|
-
if (
|
|
12064
|
+
if (range2) {
|
|
11557
12065
|
host = hosts?.get(mesh2) ?? null;
|
|
11558
12066
|
if (!host) {
|
|
11559
12067
|
host = { mesh: mesh2, origGeometry: mesh2.geometry, origMaterial: mesh2.material, ownGeo: false, work: null, ownMat: false, sharers: [] };
|
|
@@ -11579,8 +12087,8 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
11579
12087
|
bottomY: 0,
|
|
11580
12088
|
moved: false,
|
|
11581
12089
|
host,
|
|
11582
|
-
range:
|
|
11583
|
-
merged: host &&
|
|
12090
|
+
range: range2 ? [range2[0], range2[1]] : null,
|
|
12091
|
+
merged: host && range2 ? { host, range: [range2[0], range2[1]] } : null,
|
|
11584
12092
|
loose: false,
|
|
11585
12093
|
collapsed: false,
|
|
11586
12094
|
hidden: false,
|
|
@@ -11922,8 +12430,8 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
11922
12430
|
* Takes away the decals of a mesh that sit inside a box (world `center`, `half` extents along the axes of the world `rotation`): the surface they
|
|
11923
12431
|
* marked is gone (a unit came out of the wall with its bullet holes and spalls).
|
|
11924
12432
|
*/
|
|
11925
|
-
clearDecals(mv, center, half,
|
|
11926
|
-
const inv =
|
|
12433
|
+
clearDecals(mv, center, half, rotation2) {
|
|
12434
|
+
const inv = rotation2.clone().invert();
|
|
11927
12435
|
const p = new this.THREE.Vector3();
|
|
11928
12436
|
for (let i = mv.decals.length - 1; i >= 0; i--) {
|
|
11929
12437
|
const d = mv.decals[i];
|
|
@@ -12149,24 +12657,24 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
12149
12657
|
geo.boundingBox = null;
|
|
12150
12658
|
geo.boundingSphere = null;
|
|
12151
12659
|
}
|
|
12152
|
-
collapseRange(arr,
|
|
12153
|
-
const x = arr[
|
|
12154
|
-
const y = arr[
|
|
12155
|
-
const z = arr[
|
|
12156
|
-
for (let i =
|
|
12660
|
+
collapseRange(arr, range2) {
|
|
12661
|
+
const x = arr[range2[0] * 3];
|
|
12662
|
+
const y = arr[range2[0] * 3 + 1];
|
|
12663
|
+
const z = arr[range2[0] * 3 + 2];
|
|
12664
|
+
for (let i = range2[0] * 3; i < range2[1] * 3; i += 3) {
|
|
12157
12665
|
arr[i] = x;
|
|
12158
12666
|
arr[i + 1] = y;
|
|
12159
12667
|
arr[i + 2] = z;
|
|
12160
12668
|
}
|
|
12161
12669
|
}
|
|
12162
12670
|
/** Melt of one range: shorter in Y (down to 25 %) with the bottom fixed, a bit wider around its centre, with the same noise as a whole mesh. */
|
|
12163
|
-
meltRange(arr, work,
|
|
12671
|
+
meltRange(arr, work, range2, melt) {
|
|
12164
12672
|
let minY = Infinity;
|
|
12165
12673
|
let maxY = -Infinity;
|
|
12166
12674
|
let cx = 0;
|
|
12167
12675
|
let cz = 0;
|
|
12168
|
-
const n = Math.max(1,
|
|
12169
|
-
for (let i =
|
|
12676
|
+
const n = Math.max(1, range2[1] - range2[0]);
|
|
12677
|
+
for (let i = range2[0] * 3; i < range2[1] * 3; i += 3) {
|
|
12170
12678
|
minY = Math.min(minY, work[i + 1]);
|
|
12171
12679
|
maxY = Math.max(maxY, work[i + 1]);
|
|
12172
12680
|
cx += work[i];
|
|
@@ -12177,7 +12685,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
12177
12685
|
const h = Math.max(1e-4, maxY - minY);
|
|
12178
12686
|
const sy = lerp5(1, 0.25, melt);
|
|
12179
12687
|
const sxz = 1 + 0.18 * melt;
|
|
12180
|
-
for (let i =
|
|
12688
|
+
for (let i = range2[0] * 3, v = 0; i < range2[1] * 3; i += 3, v++) {
|
|
12181
12689
|
const noise = (Math.imul(v + 1, 2654435761) >>> 0) % 1e3 / 1e3;
|
|
12182
12690
|
arr[i] = cx + (work[i] - cx) * sxz;
|
|
12183
12691
|
arr[i + 2] = cz + (work[i + 2] - cz) * sxz;
|
|
@@ -12534,8 +13042,26 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
12534
13042
|
__publicField(this, "queue", []);
|
|
12535
13043
|
/** Presentation work an event left for later frames (fragments still to spawn, loose groups still to split), run in order within the frame budget. */
|
|
12536
13044
|
__publicField(this, "slices", []);
|
|
12537
|
-
/** When the work of this frame must stop; `Infinity` outside
|
|
13045
|
+
/** When the work of this frame must stop; `Infinity` outside a drain, where a call finishes what it started. */
|
|
12538
13046
|
__publicField(this, "sliceDeadline", Infinity);
|
|
13047
|
+
/** The clock the drain reads; a budget lends its own while it runs the queue. */
|
|
13048
|
+
__publicField(this, "drainClock", () => performance.now());
|
|
13049
|
+
/** true once a frame budget owns the draining: `update` no longer drains by itself. */
|
|
13050
|
+
__publicField(this, "attached", false);
|
|
13051
|
+
__publicField(this, "eventQueue", {
|
|
13052
|
+
id: DEFERRED_QUEUE_ID.DESTRUCTION_EVENTS,
|
|
13053
|
+
pending: () => this.queue.length + this.slices.length,
|
|
13054
|
+
run: (deadline, clock) => this.runBudgeted(deadline, clock),
|
|
13055
|
+
flush: () => {
|
|
13056
|
+
for (let guard = 0; guard < 16 && this.queue.length + this.slices.length > 0; guard++) this.runBudgeted(Infinity, () => 0);
|
|
13057
|
+
},
|
|
13058
|
+
attach: () => {
|
|
13059
|
+
this.attached = true;
|
|
13060
|
+
},
|
|
13061
|
+
detach: () => {
|
|
13062
|
+
this.attached = false;
|
|
13063
|
+
}
|
|
13064
|
+
});
|
|
12539
13065
|
__publicField(this, "unsubscribe");
|
|
12540
13066
|
__publicField(this, "visuals");
|
|
12541
13067
|
__publicField(this, "fragments");
|
|
@@ -12581,6 +13107,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
12581
13107
|
const maxParticles = Math.max(8, Math.floor((o.maxParticles ?? 2500) * (this.low ? 0.5 : 1)));
|
|
12582
13108
|
this.visuals = new Visuals(THREE, this.low, 600);
|
|
12583
13109
|
this.ground = new GroundSpots(THREE, o.scene, this.groundAt, 48);
|
|
13110
|
+
if (!o.vfx) warnOnce("game-destruction-three.own-effects-world", "game-destruction-three made an effects world of its own because the host lent none (options.vfx); pass the host effects so the effects share one budget");
|
|
12584
13111
|
this.vfx = o.vfx ?? createVfx({ profile: this.quality, gravity: this.gravity, groundAt: this.groundAt, sprites: { capacity: maxParticles, density: this.low ? 0.6 : 1 } });
|
|
12585
13112
|
this.ownVfx = o.vfx ? void 0 : createVfxRenderer(THREE, { scene: o.scene, camera: o.camera ?? new THREE.PerspectiveCamera(), vfx: this.vfx, pointScale: o.pointScale ?? 700 });
|
|
12586
13113
|
this.stopLanding = this.vfx.onLand(this.owner, (x, _y, z, color, tag) => {
|
|
@@ -12818,7 +13345,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
12818
13345
|
if (this.disposed) return;
|
|
12819
13346
|
dt = clamp6(dt, 0, 0.1);
|
|
12820
13347
|
this.time += dt;
|
|
12821
|
-
this.drainQueue();
|
|
13348
|
+
if (!this.attached) this.drainQueue();
|
|
12822
13349
|
for (const b of this.bounds.values()) b.onFrame?.(dt);
|
|
12823
13350
|
for (const b of this.bounds.values()) if (b.soilNode && this.world.state(b.id)?.soil?.status === "yielding") this.onSettle(b.id);
|
|
12824
13351
|
this.updateActive(dt);
|
|
@@ -12829,36 +13356,50 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
12829
13356
|
this.ownVfx?.update(dt);
|
|
12830
13357
|
this.syncTransforms();
|
|
12831
13358
|
}
|
|
13359
|
+
deferredQueue() {
|
|
13360
|
+
return this.eventQueue;
|
|
13361
|
+
}
|
|
12832
13362
|
drainQueue() {
|
|
13363
|
+
this.runBudgeted(performance.now() + this.eventBudgetMs, () => performance.now());
|
|
13364
|
+
}
|
|
13365
|
+
/** Applies the waiting events in order until the deadline, after the slices earlier events left; always at least one unit when something waits. Returns the units run. */
|
|
13366
|
+
runBudgeted(deadline, clock) {
|
|
12833
13367
|
const batch = this.queue.splice(0, this.queue.length);
|
|
12834
|
-
const
|
|
13368
|
+
const outerClock = this.drainClock;
|
|
13369
|
+
this.drainClock = clock;
|
|
12835
13370
|
this.sliceDeadline = deadline;
|
|
13371
|
+
let ran = 0;
|
|
12836
13372
|
try {
|
|
12837
|
-
this.runSlices(deadline);
|
|
13373
|
+
ran = this.runSlices(deadline);
|
|
12838
13374
|
for (let i = 0; i < batch.length; i++) {
|
|
12839
|
-
if (i > 0 &&
|
|
13375
|
+
if ((i > 0 || ran > 0 && this.attached) && clock() >= deadline) {
|
|
12840
13376
|
this.queue.unshift(...batch.slice(i));
|
|
12841
|
-
return;
|
|
13377
|
+
return ran;
|
|
12842
13378
|
}
|
|
12843
13379
|
try {
|
|
12844
13380
|
this.apply(batch[i]);
|
|
12845
13381
|
} catch (err) {
|
|
12846
13382
|
if (typeof console !== "undefined") console.error("game-destruction-three: failed to apply", batch[i].type, err);
|
|
12847
13383
|
}
|
|
13384
|
+
ran++;
|
|
12848
13385
|
}
|
|
12849
13386
|
} finally {
|
|
12850
13387
|
this.sliceDeadline = Infinity;
|
|
13388
|
+
this.drainClock = outerClock;
|
|
12851
13389
|
}
|
|
13390
|
+
return ran;
|
|
12852
13391
|
}
|
|
12853
13392
|
/** Runs the work left by earlier frames until the deadline; at least one piece per frame, so it always finishes. */
|
|
12854
13393
|
runSlices(deadline) {
|
|
12855
|
-
|
|
13394
|
+
let ran = 0;
|
|
13395
|
+
for (; this.slices.length > 0 && (ran === 0 || this.drainClock() < deadline); ran++) {
|
|
12856
13396
|
try {
|
|
12857
13397
|
this.slices.shift()();
|
|
12858
13398
|
} catch (err) {
|
|
12859
13399
|
if (typeof console !== "undefined") console.error("game-destruction-three: failed to run deferred work", err);
|
|
12860
13400
|
}
|
|
12861
13401
|
}
|
|
13402
|
+
return ran;
|
|
12862
13403
|
}
|
|
12863
13404
|
/**
|
|
12864
13405
|
* The ground under an object settled or tilted: its parts are drawn under a node with the soil's offset (`ObjectState.soil.offset`), so the host's
|
|
@@ -13364,8 +13905,8 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13364
13905
|
const T = this.THREE;
|
|
13365
13906
|
const center = new T.Vector3(ev.center[0], ev.center[1], ev.center[2]);
|
|
13366
13907
|
const half = new T.Vector3(ev.size[0] / 2 + CHIP_DECAL_EDGE, ev.size[1] / 2 + CHIP_DECAL_EDGE, ev.size[2] / 2 + CHIP_DECAL_EDGE);
|
|
13367
|
-
const
|
|
13368
|
-
for (const part of this.bounds.get(ev.object)?.parts.values() ?? []) for (const mv of part.meshes) this.visuals.clearDecals(mv, center, half,
|
|
13908
|
+
const rotation2 = new T.Quaternion(ev.rotation[0], ev.rotation[1], ev.rotation[2], ev.rotation[3]);
|
|
13909
|
+
for (const part of this.bounds.get(ev.object)?.parts.values() ?? []) for (const mv of part.meshes) this.visuals.clearDecals(mv, center, half, rotation2);
|
|
13369
13910
|
this.vfx.peekWorkshop()?.decals.clearInside(ev.center, [half.x, half.y, half.z], ev.rotation);
|
|
13370
13911
|
this.vfx.burst("dust", ev.center, [0, 1, 0], 8, 0.8, { color });
|
|
13371
13912
|
this.sound(impactKey(def), ev.center, 0.7);
|
|
@@ -13416,7 +13957,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13416
13957
|
const maxAlive = this.low ? Math.floor(this.maxFragments / 2) : this.maxFragments;
|
|
13417
13958
|
const step = this.low ? 2 : 1;
|
|
13418
13959
|
for (let i = from; i < ev.fragments.length; i += step) {
|
|
13419
|
-
if (i - from >= MIN_FRAGMENTS_PER_SLICE * step &&
|
|
13960
|
+
if (i - from >= MIN_FRAGMENTS_PER_SLICE * step && this.drainClock() >= this.sliceDeadline) {
|
|
13420
13961
|
this.slices.push(() => this.spawnFragments(ev, i, look));
|
|
13421
13962
|
return;
|
|
13422
13963
|
}
|
|
@@ -13440,7 +13981,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13440
13981
|
if (!st || st.groups.length < 2) return;
|
|
13441
13982
|
const loose = st.groups.length - 1;
|
|
13442
13983
|
for (let i = 0; i < loose; i++) {
|
|
13443
|
-
if (i > 0 &&
|
|
13984
|
+
if (i > 0 && this.drainClock() >= this.sliceDeadline) {
|
|
13444
13985
|
this.slices.push(() => {
|
|
13445
13986
|
this.staticDirty.add(objectId);
|
|
13446
13987
|
this.splitLoose(objectId);
|
|
@@ -13819,6 +14360,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13819
14360
|
const materials = [kit.discMaterial().clone(), kit.patchMaterial(8421504).clone(), kit.lineMaterial(0).clone()];
|
|
13820
14361
|
const group = new T.Group();
|
|
13821
14362
|
group.add(new T.Mesh(kit.discGeometry(), materials[0]), new T.Mesh(kit.discGeometry(), materials[1]), new T.LineSegments(geometry, materials[2]));
|
|
14363
|
+
group.add(...this.fragments.warmMeshes());
|
|
13822
14364
|
for (const probe of group.children) probe.frustumCulled = false;
|
|
13823
14365
|
this.warmProbes = { group, geometry, materials };
|
|
13824
14366
|
return { group, dispose: () => {
|
|
@@ -13849,7 +14391,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13849
14391
|
}
|
|
13850
14392
|
};
|
|
13851
14393
|
|
|
13852
|
-
// ../game-audio/dist/
|
|
14394
|
+
// ../game-audio/dist/chunk-DZITVFMJ.js
|
|
13853
14395
|
var DISTANCE_CURVES = {
|
|
13854
14396
|
/** The game's `sfx`: `vol / (1 + d² × 0.004)`, cutoff `/ (1 + d × 0.01)`, silent below 0.01 (jogo L62091–62092, L62101). */
|
|
13855
14397
|
game_sfx: { model: "inverse_square", k: 4e-3, cutoffK: 0.01, minGain: 0.01 },
|
|
@@ -13864,31 +14406,6 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13864
14406
|
/** The game's animal calls: `max(0, 1 − d / 70) × 0.25`, silent at or below 0.005 (jogo L66627–66628). */
|
|
13865
14407
|
animals: { model: "linear", range: 70, scale: 0.25, minGain: 5e-3 }
|
|
13866
14408
|
};
|
|
13867
|
-
var mix_profiles_default = [
|
|
13868
|
-
{
|
|
13869
|
-
id: "game",
|
|
13870
|
-
master: 0.5,
|
|
13871
|
-
noise: { seconds: 1.5, create: "lazy" },
|
|
13872
|
-
sources: ["jogo:L62077-62081 master 0.5 to the output", "jogo:L62082-62088 noise 1.5 s made by the first sound that needs it"]
|
|
13873
|
-
},
|
|
13874
|
-
{
|
|
13875
|
-
id: "art_scene",
|
|
13876
|
-
master: 0.85,
|
|
13877
|
-
compressor: { threshold: -12, ratio: 5 },
|
|
13878
|
-
reverb: { seconds: 2.2, decay: 3.4, wet: 0.4 },
|
|
13879
|
-
noise: { seconds: 2, create: "eager" },
|
|
13880
|
-
sources: [
|
|
13881
|
-
"cena:L1308 compressor -12 dB, ratio 5",
|
|
13882
|
-
"cena:L1309 master 0.85",
|
|
13883
|
-
"cena:L1310 convolver, impulse 2.2 s of (1 - i/len)^3.4",
|
|
13884
|
-
"cena:L1311 wet 0.4",
|
|
13885
|
-
"cena:L1312 noise 2 s made with the chain"
|
|
13886
|
-
]
|
|
13887
|
-
}
|
|
13888
|
-
];
|
|
13889
|
-
var MIX_PROFILES = Object.fromEntries(
|
|
13890
|
-
mix_profiles_default.map((profile) => [profile.id, profile])
|
|
13891
|
-
);
|
|
13892
14409
|
var game_sfx_default = {
|
|
13893
14410
|
sources: ["jogo:L62089-62107"],
|
|
13894
14411
|
note: "The game's sfx table P: [lowpass cutoff Hz, peak gain, seconds]. Played as a noise burst with the game's distance curve (falloff game_sfx) and a 0.05 s tail. Team names in `team`.",
|
|
@@ -13933,6 +14450,78 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13933
14450
|
};
|
|
13934
14451
|
}
|
|
13935
14452
|
var GAME_SFX_BANK = { id: "game_sfx", sounds: [...GAME_SFX_CLASSES, GAME_SFX_FALLBACK].map((row) => noiseClassRecipe(row)) };
|
|
14453
|
+
var mix_profiles_default = [
|
|
14454
|
+
{
|
|
14455
|
+
id: "game",
|
|
14456
|
+
master: 0.5,
|
|
14457
|
+
noise: { seconds: 1.5, create: "lazy" },
|
|
14458
|
+
sources: ["jogo:L62077-62081 master 0.5 to the output", "jogo:L62082-62088 noise 1.5 s made by the first sound that needs it"]
|
|
14459
|
+
},
|
|
14460
|
+
{
|
|
14461
|
+
id: "art_scene",
|
|
14462
|
+
master: 0.85,
|
|
14463
|
+
compressor: { threshold: -12, ratio: 5 },
|
|
14464
|
+
reverb: { seconds: 2.2, decay: 3.4, wet: 0.4 },
|
|
14465
|
+
noise: { seconds: 2, create: "eager" },
|
|
14466
|
+
sources: [
|
|
14467
|
+
"cena:L1308 compressor -12 dB, ratio 5",
|
|
14468
|
+
"cena:L1309 master 0.85",
|
|
14469
|
+
"cena:L1310 convolver, impulse 2.2 s of (1 - i/len)^3.4",
|
|
14470
|
+
"cena:L1311 wet 0.4",
|
|
14471
|
+
"cena:L1312 noise 2 s made with the chain"
|
|
14472
|
+
]
|
|
14473
|
+
}
|
|
14474
|
+
];
|
|
14475
|
+
var MIX_PROFILES = Object.fromEntries(
|
|
14476
|
+
mix_profiles_default.map((profile) => [profile.id, profile])
|
|
14477
|
+
);
|
|
14478
|
+
var BENCH_BANK = {
|
|
14479
|
+
id: "audio_bench",
|
|
14480
|
+
sounds: [
|
|
14481
|
+
{
|
|
14482
|
+
id: "bench_ping",
|
|
14483
|
+
bus: "ui",
|
|
14484
|
+
pan: true,
|
|
14485
|
+
duration: 0.25,
|
|
14486
|
+
layers: [
|
|
14487
|
+
{
|
|
14488
|
+
gain: 0.5,
|
|
14489
|
+
wet: 0.3,
|
|
14490
|
+
source: { kind: "osc", wave: "sine", frequency: { from: 880 } },
|
|
14491
|
+
envelope: [
|
|
14492
|
+
[0, 1e-4, "set", "fixed"],
|
|
14493
|
+
[2e-3, 1, "exp"],
|
|
14494
|
+
["1d", 1e-4, "exp", "fixed"]
|
|
14495
|
+
]
|
|
14496
|
+
}
|
|
14497
|
+
],
|
|
14498
|
+
falloff: DISTANCE_CURVES.art_scene,
|
|
14499
|
+
sources: ["sdk: bench probe, a 880 Hz ping through the art scene output stage"]
|
|
14500
|
+
},
|
|
14501
|
+
{
|
|
14502
|
+
id: "bench_hiss",
|
|
14503
|
+
bus: "ui",
|
|
14504
|
+
pan: true,
|
|
14505
|
+
duration: [0.3, 0.9],
|
|
14506
|
+
layers: [
|
|
14507
|
+
{
|
|
14508
|
+
gain: 0.4,
|
|
14509
|
+
source: { kind: "noise", offset: "random", offsetScale: 1.5, loop: true },
|
|
14510
|
+
filters: { mode: "serial", bank: [{ type: "highpass", frequency: { set: 3e3 }, q: 0.7 }] },
|
|
14511
|
+
envelope: [
|
|
14512
|
+
[0, 1e-4, "set", "fixed"],
|
|
14513
|
+
[2e-3, 1, "exp"],
|
|
14514
|
+
["1d", 1e-4, "exp", "fixed"]
|
|
14515
|
+
]
|
|
14516
|
+
}
|
|
14517
|
+
],
|
|
14518
|
+
falloff: DISTANCE_CURVES.art_scene,
|
|
14519
|
+
sources: ["sdk: bench probe, a highpass hiss of random length"]
|
|
14520
|
+
}
|
|
14521
|
+
]
|
|
14522
|
+
};
|
|
14523
|
+
|
|
14524
|
+
// ../game-audio/dist/index.js
|
|
13936
14525
|
var ATTACK = 2e-3;
|
|
13937
14526
|
function lengthOf(d, attack) {
|
|
13938
14527
|
if (typeof d === "number") return attack + d;
|
|
@@ -13970,6 +14559,31 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13970
14559
|
envelope: envelope(ATTACK)
|
|
13971
14560
|
};
|
|
13972
14561
|
}
|
|
14562
|
+
function sceneVoice(o) {
|
|
14563
|
+
return {
|
|
14564
|
+
duration: lengthOf(o.d, 0),
|
|
14565
|
+
gain: o.vol,
|
|
14566
|
+
wet: 0.45,
|
|
14567
|
+
source: {
|
|
14568
|
+
kind: "formant_voice",
|
|
14569
|
+
wave: o.wave ?? "sawtooth",
|
|
14570
|
+
frequency: { from: o.f0, to: o.f1, curve: "linear", over: "duration" },
|
|
14571
|
+
vibrato: { rate: [4, 10], depth: 0.08 },
|
|
14572
|
+
formants: [
|
|
14573
|
+
{ frequency: o.fA, q: 4 },
|
|
14574
|
+
{ frequency: o.fB, q: 6 }
|
|
14575
|
+
],
|
|
14576
|
+
breath: { frequency: o.fB, q: 1.1, gain: o.noise },
|
|
14577
|
+
mix: 3.2
|
|
14578
|
+
},
|
|
14579
|
+
envelope: [
|
|
14580
|
+
[0, 1e-4, "set", "fixed"],
|
|
14581
|
+
[0.1, 1, "exp"],
|
|
14582
|
+
["0.6d", 1, "set"],
|
|
14583
|
+
["1d", 1e-4, "exp", "fixed"]
|
|
14584
|
+
]
|
|
14585
|
+
};
|
|
14586
|
+
}
|
|
13973
14587
|
var sceneMany = (count, make) => Array.from({ length: count }, make);
|
|
13974
14588
|
function sceneRecipe(id, layers, line, options = {}) {
|
|
13975
14589
|
return {
|
|
@@ -13983,51 +14597,172 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13983
14597
|
sources: [`cena:${line}`]
|
|
13984
14598
|
};
|
|
13985
14599
|
}
|
|
13986
|
-
var
|
|
13987
|
-
|
|
13988
|
-
|
|
13989
|
-
|
|
13990
|
-
|
|
13991
|
-
|
|
13992
|
-
|
|
13993
|
-
|
|
13994
|
-
|
|
13995
|
-
|
|
13996
|
-
|
|
13997
|
-
|
|
13998
|
-
|
|
13999
|
-
|
|
14000
|
-
|
|
14001
|
-
|
|
14002
|
-
|
|
14003
|
-
|
|
14004
|
-
|
|
14005
|
-
|
|
14006
|
-
|
|
14007
|
-
|
|
14008
|
-
|
|
14009
|
-
|
|
14010
|
-
|
|
14011
|
-
|
|
14012
|
-
|
|
14013
|
-
|
|
14014
|
-
|
|
14015
|
-
|
|
14016
|
-
|
|
14017
|
-
|
|
14018
|
-
|
|
14019
|
-
|
|
14020
|
-
|
|
14021
|
-
|
|
14022
|
-
|
|
14023
|
-
|
|
14024
|
-
|
|
14025
|
-
|
|
14026
|
-
|
|
14027
|
-
|
|
14028
|
-
|
|
14029
|
-
|
|
14600
|
+
var TAKES = [
|
|
14601
|
+
{ f: 1, t: 1, v: 1 },
|
|
14602
|
+
{ f: 1.08, t: 0.9, v: 0.92 },
|
|
14603
|
+
{ f: 0.93, t: 1.12, v: 1.05 },
|
|
14604
|
+
{ f: 1.03, t: 1.05, v: 0.88 }
|
|
14605
|
+
];
|
|
14606
|
+
var FOOTSTEP_FALLOFF = { model: "inverse_square", k: 0.03, cutoffK: 0.03, minGain: 4e-3 };
|
|
14607
|
+
var BODY_FALLOFF = { model: "inverse_square", k: 0.012, cutoffK: 0.015, minGain: 4e-3 };
|
|
14608
|
+
var SURFACES = {
|
|
14609
|
+
concrete: { heel: { f: 95, d: 0.05, vol: 0.55 }, roll: { type: "bandpass", f: 2300, q: 1.1, d: 0.05, vol: 0.38 }, grains: { count: 2, f: 4200, q: 2, spread: 0.04, vol: 0.08 } },
|
|
14610
|
+
asphalt: { heel: { f: 90, d: 0.05, vol: 0.5 }, roll: { type: "bandpass", f: 1700, q: 0.9, d: 0.06, vol: 0.36 }, grains: { count: 4, f: 3600, q: 2.5, spread: 0.06, vol: 0.1 } },
|
|
14611
|
+
wood: { heel: { f: 130, d: 0.08, vol: 0.55 }, roll: { type: "lowpass", f: 1300, q: 0.8, d: 0.06, vol: 0.3 }, ring: [{ f: 210, d: 0.1, vol: 0.18 }, { f: 470, d: 0.06, vol: 0.06 }] },
|
|
14612
|
+
tile: { heel: { f: 110, d: 0.04, vol: 0.45 }, roll: { type: "bandpass", f: 3600, q: 2, d: 0.03, vol: 0.42 }, ring: [{ f: 1900, d: 0.03, vol: 0.05 }] },
|
|
14613
|
+
dirt: { heel: { f: 75, d: 0.06, vol: 0.45 }, roll: { type: "lowpass", f: 750, q: 0.7, d: 0.09, vol: 0.4 }, grains: { count: 3, f: 1800, q: 1.5, spread: 0.07, vol: 0.06 } },
|
|
14614
|
+
grass: { heel: { f: 70, d: 0.05, vol: 0.32 }, roll: { type: "highpass", f: 2600, q: 0.7, d: 0.13, vol: 0.28 }, grains: { count: 4, f: 5200, q: 1.2, spread: 0.1, vol: 0.07 } },
|
|
14615
|
+
gravel: { heel: { f: 80, d: 0.05, vol: 0.4 }, roll: { type: "lowpass", f: 950, q: 0.8, d: 0.1, vol: 0.3 }, grains: { count: 8, f: 2600, q: 3, spread: 0.13, vol: 0.2 } },
|
|
14616
|
+
sand: { heel: { f: 65, d: 0.06, vol: 0.3 }, roll: { type: "bandpass", f: 1500, q: 0.6, d: 0.16, vol: 0.3 }, grains: { count: 5, f: 4800, q: 1.5, spread: 0.12, vol: 0.05 } },
|
|
14617
|
+
metal: { heel: { f: 120, d: 0.05, vol: 0.5 }, roll: { type: "bandpass", f: 2800, q: 1.5, d: 0.03, vol: 0.25 }, ring: [{ f: 420, d: 0.25, vol: 0.16 }, { f: 1130, d: 0.18, vol: 0.09 }, { f: 2470, d: 0.1, vol: 0.04 }] },
|
|
14618
|
+
water: { heel: { f: 70, d: 0.04, vol: 0.25 }, roll: { type: "bandpass", f: 3e3, q: 1.2, d: 0.1, vol: 0.18 }, splash: { f: 1100, f2: 380, d: 0.22, vol: 0.55 }, grains: { count: 4, f: 2400, q: 6, spread: 0.18, vol: 0.12 } },
|
|
14619
|
+
glass: { heel: { f: 90, d: 0.04, vol: 0.4 }, roll: { type: "highpass", f: 4500, q: 0.8, d: 0.06, vol: 0.2 }, grains: { count: 9, f: 6200, q: 5, spread: 0.12, vol: 0.22 }, ring: [{ f: 3900, d: 0.04, vol: 0.04 }, { f: 5300, d: 0.03, vol: 0.03 }] },
|
|
14620
|
+
carpet: { heel: { f: 70, d: 0.05, vol: 0.32 }, roll: { type: "lowpass", f: 420, q: 0.7, d: 0.07, vol: 0.3 } }
|
|
14621
|
+
};
|
|
14622
|
+
var GAITS = {
|
|
14623
|
+
walk: { vol: 1, bright: 1, toe: 0.075, short: 1 },
|
|
14624
|
+
run: { vol: 1.35, bright: 1.25, toe: 0.035, short: 0.75 }
|
|
14625
|
+
};
|
|
14626
|
+
var grainLayers = (g, take, start, scale) => Array.from(
|
|
14627
|
+
{ length: g.count },
|
|
14628
|
+
(_, i) => sceneNoise({ type: "bandpass", f: [g.f * take.f * 0.85, g.f * take.f * 1.15], q: g.q, d: [8e-3, 0.02], vol: g.vol * scale * take.v, delay: start + (i + 0.5) / g.count * g.spread * take.t })
|
|
14629
|
+
);
|
|
14630
|
+
var ringLayers = (rings, take, scale, at3 = 0) => rings.map((r) => sceneTone({ f: r.f * take.f, d: r.d * take.t, vol: r.vol * scale * take.v, delay: at3 }));
|
|
14631
|
+
function footLayers(surface, take, gait, weight = 1) {
|
|
14632
|
+
const s = SURFACES[surface];
|
|
14633
|
+
const toe = gait.toe * take.t;
|
|
14634
|
+
return [
|
|
14635
|
+
sceneTone({ f: s.heel.f * take.f * weight ** -0.3, f2: s.heel.f * take.f * 0.6, d: s.heel.d * gait.short * take.t * weight ** 0.5, vol: s.heel.vol * gait.vol * take.v * weight ** 0.5 }),
|
|
14636
|
+
sceneNoise({ type: "lowpass", f: 500 * gait.bright, d: 0.02 * take.t, vol: 0.18 * gait.vol * take.v * weight ** 0.5 }),
|
|
14637
|
+
sceneNoise({ type: s.roll.type, f: [s.roll.f * take.f * gait.bright * 0.92, s.roll.f * take.f * gait.bright * 1.08], q: s.roll.q, d: s.roll.d * gait.short * take.t * weight ** 0.3, vol: s.roll.vol * gait.vol * take.v, delay: toe }),
|
|
14638
|
+
...s.grains ? grainLayers(s.grains, take, toe * 0.5, gait.vol * weight ** 0.5) : [],
|
|
14639
|
+
...s.ring ? ringLayers(s.ring, take, gait.vol * weight ** 0.5) : [],
|
|
14640
|
+
...s.splash ? [sceneNoise({ type: "bandpass", f: s.splash.f * take.f, f2: s.splash.f2 * take.f, q: 1.4, d: s.splash.d * take.t * weight ** 0.4, vol: s.splash.vol * gait.vol * take.v * weight ** 0.5 })] : []
|
|
14641
|
+
];
|
|
14642
|
+
}
|
|
14643
|
+
var quieter = (level, layers) => layers.map((layer2) => {
|
|
14644
|
+
const gain = layer2.gain ?? 1;
|
|
14645
|
+
if (typeof gain === "number") return { ...layer2, gain: gain * level };
|
|
14646
|
+
if (Array.isArray(gain)) return { ...layer2, gain: [gain[0] * level, gain[1] * level] };
|
|
14647
|
+
return layer2;
|
|
14648
|
+
});
|
|
14649
|
+
var recipe = (id, layers, falloff, bus = "world") => ({ id, bus, pan: true, layers, falloff, sources: ["sdk"] });
|
|
14650
|
+
var takeId = (id, index) => `${id}_${String(index + 1).padStart(2, "0")}`;
|
|
14651
|
+
function takes(id, layersOf, falloff, rate = [0.96, 1.04], bus) {
|
|
14652
|
+
const sounds = TAKES.map((take, index) => recipe(takeId(id, index), layersOf(take, index), falloff, bus));
|
|
14653
|
+
return { sounds, set: { id, variants: sounds.map((sound) => sound.id), rate } };
|
|
14654
|
+
}
|
|
14655
|
+
var footstep = (surface, gait) => takes(footstepSoundId(surface, gait), (take) => footLayers(surface, take, GAITS[gait]), FOOTSTEP_FALLOFF);
|
|
14656
|
+
var LANDINGS = { light: { weight: 1.4, cloth: 0.12 }, heavy: { weight: 2.4, cloth: 0.22 } };
|
|
14657
|
+
var LANDING_LEVEL = 0.65;
|
|
14658
|
+
var landing = (surface, landing2) => takes(
|
|
14659
|
+
`land_${surface}_${landing2}`,
|
|
14660
|
+
(take) => quieter(LANDING_LEVEL, [
|
|
14661
|
+
// both feet, a hair apart, then the knees taking the weight (a low body thump) and the clothes settling
|
|
14662
|
+
...footLayers(surface, take, GAITS.run, LANDINGS[landing2].weight),
|
|
14663
|
+
...footLayers(surface, { ...take, v: take.v * 0.6 }, GAITS.run, LANDINGS[landing2].weight * 0.6).map((layer2) => ({ ...layer2, at: (typeof layer2.at === "number" ? layer2.at : 0) + 0.018 * take.t })),
|
|
14664
|
+
sceneTone({ f: 60 * take.f, f2: 38, d: 0.14 * LANDINGS[landing2].weight * take.t, vol: 0.22 * LANDINGS[landing2].weight ** 0.7 * take.v, delay: 0.02 }),
|
|
14665
|
+
sceneNoise({ type: "bandpass", f: [1800, 2600], q: 0.8, d: 0.18, vol: LANDINGS[landing2].cloth * take.v, delay: 0.04 })
|
|
14666
|
+
]),
|
|
14667
|
+
FOOTSTEP_FALLOFF
|
|
14668
|
+
);
|
|
14669
|
+
var whoosh = (blow3, from, to, d, vol, q = 1.6) => (take) => [
|
|
14670
|
+
// the air: a band sweeping up as the limb speeds up; it peaks `SWING_LEAD_SECONDS` in, the moment before the contact, then dies away
|
|
14671
|
+
sceneNoise({ type: "bandpass", f: from * take.f, f2: to * take.f, q, a: SWING_LEAD_SECONDS[blow3], d: d * take.t, vol: vol * take.v }),
|
|
14672
|
+
sceneNoise({ type: "lowpass", f: 600 * take.f, a: SWING_LEAD_SECONDS[blow3], d: d * take.t * 0.8, vol: vol * 0.35 * take.v })
|
|
14673
|
+
];
|
|
14674
|
+
var fleshHit = (o) => (take) => [
|
|
14675
|
+
sceneNoise({ type: "bandpass", f: o.slapF * take.f, q: 1.2, d: 0.03 * take.t, vol: o.slap * take.v }),
|
|
14676
|
+
sceneNoise({ type: "highpass", f: 3500 * take.f, d: 0.012, vol: o.slap * 0.4 * take.v }),
|
|
14677
|
+
sceneTone({ f: o.thudF * take.f, f2: o.thudF * 0.5, d: o.thudD * take.t, vol: o.thud * take.v }),
|
|
14678
|
+
sceneNoise({ type: "lowpass", f: 600 * take.f, d: o.thudD * 1.2 * take.t, vol: o.thud * 0.5 * take.v }),
|
|
14679
|
+
...o.crack ? [sceneNoise({ type: "highpass", f: 2500, d: 0.015, vol: o.crack * take.v, delay: 6e-3 }), sceneTone({ wave: "square", f: 900 * take.f, f2: 300, d: 0.02, vol: o.crack * 0.15 * take.v, delay: 6e-3 })] : [],
|
|
14680
|
+
...o.wet ? [sceneNoise({ type: "bandpass", f: 1400 * take.f, f2: 500, q: 2.5, d: 0.12 * take.t, vol: o.wet * take.v, delay: 0.01 })] : []
|
|
14681
|
+
];
|
|
14682
|
+
var knock = (o) => (take) => [
|
|
14683
|
+
sceneNoise({ type: "bandpass", f: o.clickF * take.f, q: 1.5, d: 0.018, vol: o.click * take.v }),
|
|
14684
|
+
...o.tones.map(([f, d, vol]) => sceneTone({ f: f * take.f, d: d * take.t, vol: vol * take.v }))
|
|
14685
|
+
];
|
|
14686
|
+
var voice = (o) => (take) => [
|
|
14687
|
+
sceneVoice({ f0: o.f0 * take.f, f1: o.f1 * take.f, d: o.d * take.t, fA: o.fA * take.f, fB: o.fB * take.f, noise: o.noise, vol: o.vol * take.v })
|
|
14688
|
+
];
|
|
14689
|
+
var BODY = {
|
|
14690
|
+
jump: (take) => [
|
|
14691
|
+
sceneNoise({ type: "bandpass", f: 900 * take.f, f2: 1700 * take.f, q: 1, a: 0.03, d: 0.12, vol: 0.18 * take.v }),
|
|
14692
|
+
sceneNoise({ type: "bandpass", f: 2200 * take.f, q: 0.8, d: 0.04, vol: 0.12 * take.v }),
|
|
14693
|
+
sceneTone({ f: 85 * take.f, f2: 60, d: 0.04, vol: 0.2 * take.v })
|
|
14694
|
+
],
|
|
14695
|
+
cloth_rustle: (take) => [
|
|
14696
|
+
{ ...sceneNoise({ type: "bandpass", f: 2400 * take.f, q: 0.8, a: 0.06, d: 0.22 * take.t, vol: 0.12 * take.v }), modulators: [{ target: "gain", wave: "triangle", rate: [9, 14], depth: 0.5 }] }
|
|
14697
|
+
],
|
|
14698
|
+
body_fall: (take) => [
|
|
14699
|
+
sceneTone({ f: 58 * take.f, f2: 35, d: 0.28 * take.t, vol: 0.9 * take.v }),
|
|
14700
|
+
sceneNoise({ type: "lowpass", f: 480 * take.f, d: 0.3 * take.t, vol: 0.55 * take.v }),
|
|
14701
|
+
sceneNoise({ type: "bandpass", f: 1300 * take.f, q: 1, d: 0.05, vol: 0.3 * take.v }),
|
|
14702
|
+
// the limbs a moment later, and the clothes
|
|
14703
|
+
sceneTone({ f: 75 * take.f, f2: 45, d: 0.12, vol: 0.4 * take.v, delay: 0.13 * take.t }),
|
|
14704
|
+
sceneNoise({ type: "bandpass", f: 2200, q: 0.8, d: 0.2, vol: 0.12 * take.v, delay: 0.05 })
|
|
14705
|
+
],
|
|
14706
|
+
fall_damage: (take) => [
|
|
14707
|
+
...BODY.body_fall(take),
|
|
14708
|
+
sceneNoise({ type: "highpass", f: 2800, d: 0.02, vol: 0.35 * take.v, delay: 0.01 }),
|
|
14709
|
+
...voice({ f0: 170, f1: 110, d: 0.32, fA: 650, fB: 1150, noise: 0.25, vol: 0.32 })(take).map((layer2) => ({ ...layer2, at: 0.08 }))
|
|
14710
|
+
],
|
|
14711
|
+
player_hurt: voice({ f0: 150, f1: 105, d: 0.26, fA: 620, fB: 1100, noise: 0.3, vol: 0.35 }),
|
|
14712
|
+
player_breath_run: (take) => [
|
|
14713
|
+
sceneNoise({ type: "bandpass", f: 1200 * take.f, q: 1, a: 0.08, d: 0.22 * take.t, vol: 0.25 * take.v }),
|
|
14714
|
+
sceneNoise({ type: "bandpass", f: 900 * take.f, q: 1, a: 0.06, d: 0.26 * take.t, vol: 0.3 * take.v, delay: 0.3 * take.t })
|
|
14715
|
+
],
|
|
14716
|
+
player_death: voice({ f0: 135, f1: 68, d: 1, fA: 560, fB: 980, noise: 0.35, vol: 0.4 }),
|
|
14717
|
+
bite: (take) => [
|
|
14718
|
+
sceneNoise({ type: "highpass", f: 2600, d: 0.015, vol: 0.4 * take.v }),
|
|
14719
|
+
sceneNoise({ type: "bandpass", f: 1600 * take.f, f2: 450, q: 2.2, d: 0.16 * take.t, vol: 0.55 * take.v, delay: 0.01 }),
|
|
14720
|
+
sceneNoise({ type: "bandpass", f: 3200 * take.f, f2: 1800, q: 1.2, d: 0.22 * take.t, vol: 0.25 * take.v, delay: 0.09 }),
|
|
14721
|
+
sceneTone({ f: 120 * take.f, f2: 70, d: 0.06, vol: 0.3 * take.v })
|
|
14722
|
+
],
|
|
14723
|
+
grab: (take) => [
|
|
14724
|
+
sceneNoise({ type: "bandpass", f: 1900 * take.f, q: 0.9, a: 4e-3, d: 0.13 * take.t, vol: 0.32 * take.v }),
|
|
14725
|
+
sceneTone({ f: 95 * take.f, f2: 60, d: 0.07, vol: 0.3 * take.v }),
|
|
14726
|
+
sceneNoise({ type: "lowpass", f: 700, d: 0.08, vol: 0.2 * take.v })
|
|
14727
|
+
],
|
|
14728
|
+
punch_swing: whoosh("punch", 450, 1500, 0.16, 0.9),
|
|
14729
|
+
punch_hit_body: fleshHit({ slap: 0.55, slapF: 1500, thud: 0.6, thudF: 115, thudD: 0.09 }),
|
|
14730
|
+
punch_hit_face: fleshHit({ slap: 0.75, slapF: 2300, thud: 0.45, thudF: 150, thudD: 0.07, crack: 0.25 }),
|
|
14731
|
+
punch_hit_object: knock({ clickF: 1800, click: 0.3, tones: [[210, 0.04, 0.25]] }),
|
|
14732
|
+
kick_swing: whoosh("kick", 280, 950, 0.22, 1, 1.3),
|
|
14733
|
+
kick_hit: fleshHit({ slap: 0.45, slapF: 1100, thud: 0.85, thudF: 82, thudD: 0.14 }),
|
|
14734
|
+
kick_hit_object: knock({ clickF: 1e3, click: 0.3, tones: [[92, 0.08, 0.5]] }),
|
|
14735
|
+
shove_two_hands: (take) => [
|
|
14736
|
+
sceneNoise({ type: "bandpass", f: 950 * take.f, q: 0.9, a: 0.01, d: 0.13 * take.t, vol: 0.38 * take.v }),
|
|
14737
|
+
sceneTone({ f: 100 * take.f, f2: 60, d: 0.1 * take.t, vol: 0.45 * take.v }),
|
|
14738
|
+
sceneNoise({ type: "bandpass", f: 2300, q: 0.8, d: 0.16, vol: 0.12 * take.v, delay: 0.03 })
|
|
14739
|
+
],
|
|
14740
|
+
knife_swing: whoosh("blade", 1900, 4600, 0.12, 1.1, 2.2),
|
|
14741
|
+
knife_stab: fleshHit({ slap: 0.2, slapF: 1200, thud: 0.4, thudF: 160, thudD: 0.06, wet: 0.5 }),
|
|
14742
|
+
knife_slash: (take) => [
|
|
14743
|
+
sceneNoise({ type: "highpass", f: 3200 * take.f, f2: 1800, d: 0.13 * take.t, vol: 0.35 * take.v }),
|
|
14744
|
+
sceneNoise({ type: "bandpass", f: 1300 * take.f, f2: 600, q: 2.5, d: 0.12 * take.t, vol: 0.35 * take.v, delay: 0.02 })
|
|
14745
|
+
],
|
|
14746
|
+
knife_hit_object: knock({ clickF: 3200, click: 0.25, tones: [[2800, 0.08, 0.07], [4150, 0.06, 0.05]] }),
|
|
14747
|
+
blunt_swing: whoosh("blunt", 220, 760, 0.28, 1.1, 1.5),
|
|
14748
|
+
blunt_hit: fleshHit({ slap: 0.35, slapF: 900, thud: 1, thudF: 70, thudD: 0.18, crack: 0.3 }),
|
|
14749
|
+
blunt_hit_object: knock({ clickF: 1400, click: 0.35, tones: [[300, 0.12, 0.25], [760, 0.08, 0.12]] }),
|
|
14750
|
+
axe_swing: whoosh("chop", 190, 620, 0.3, 1.2, 1.4),
|
|
14751
|
+
axe_chop: fleshHit({ slap: 0.3, slapF: 1400, thud: 0.75, thudF: 140, thudD: 0.1, crack: 0.35, wet: 0.45 }),
|
|
14752
|
+
axe_hit_object: knock({ clickF: 2200, click: 0.4, tones: [[1500, 0.15, 0.1], [2300, 0.1, 0.06], [140, 0.1, 0.35]] })
|
|
14753
|
+
};
|
|
14754
|
+
var BODY_BUS = { player_hurt: "voices", player_death: "voices", player_breath_run: "voices", fall_damage: "voices" };
|
|
14755
|
+
var built = [
|
|
14756
|
+
...SURFACE_IDS.flatMap((surface) => GAIT_IDS.map((gait) => footstep(surface, gait))),
|
|
14757
|
+
...SURFACE_IDS.flatMap((surface) => LANDING_IDS.map((l) => landing(surface, l))),
|
|
14758
|
+
...BODY_SOUND_IDS.map((id) => takes(id, BODY[id], BODY_FALLOFF, id.endsWith("_swing") ? [0.94, 1.06] : [0.96, 1.04], BODY_BUS[id]))
|
|
14759
|
+
];
|
|
14760
|
+
var BODY_FOLEY_BANK = {
|
|
14761
|
+
id: "body_foley",
|
|
14762
|
+
sounds: built.flatMap((entry) => entry.sounds),
|
|
14763
|
+
sets: built.map((entry) => entry.set)
|
|
14030
14764
|
};
|
|
14765
|
+
var BODY_FOLEY_SET_IDS = [...FOOTSTEP_SOUND_IDS, ...LAND_SOUND_IDS, ...BODY_SOUND_IDS];
|
|
14031
14766
|
|
|
14032
14767
|
// src/audio/recipes.ts
|
|
14033
14768
|
var scene = (id, layers, line, vars) => sceneRecipe(id, layers, line, vars ? { vars } : {});
|