@adatechnology/game-vfx-three 0.1.3 → 0.2.1
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/README.md +2 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.global.js +916 -215
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +101 -1
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.global.js
CHANGED
|
@@ -1374,77 +1374,77 @@ var GameVfxThree = (() => {
|
|
|
1374
1374
|
}));
|
|
1375
1375
|
}
|
|
1376
1376
|
function spawnPuff(pool, random, init) {
|
|
1377
|
-
const
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
return
|
|
1407
|
-
}
|
|
1408
|
-
function ageOrKeep2(
|
|
1409
|
-
|
|
1410
|
-
return
|
|
1411
|
-
}
|
|
1412
|
-
function moveOnRing(
|
|
1377
|
+
const puff3 = pool.acquire();
|
|
1378
|
+
puff3.x = init.x ?? 0;
|
|
1379
|
+
puff3.y = init.y ?? 0;
|
|
1380
|
+
puff3.z = init.z ?? 0;
|
|
1381
|
+
puff3.vx = init.vx ?? 0;
|
|
1382
|
+
puff3.vy = init.vy ?? 0;
|
|
1383
|
+
puff3.vz = init.vz ?? 0;
|
|
1384
|
+
puff3.s0 = init.s0 ?? 0.2;
|
|
1385
|
+
puff3.s1 = init.s1 ?? 1;
|
|
1386
|
+
puff3.sg = init.sg ?? 0.1;
|
|
1387
|
+
puff3.gk = init.gk ?? 6;
|
|
1388
|
+
puff3.life = init.life ?? 3;
|
|
1389
|
+
puff3.t = 0;
|
|
1390
|
+
puff3.h0 = init.h0 ?? 0;
|
|
1391
|
+
puff3.hl = init.hl ?? 0.4;
|
|
1392
|
+
puff3.drag = init.drag ?? 3;
|
|
1393
|
+
puff3.buoy = init.buoy ?? 0.5;
|
|
1394
|
+
puff3.grav = init.grav ?? 0;
|
|
1395
|
+
puff3.kind = init.kind ?? 0;
|
|
1396
|
+
puff3.seed = random.next();
|
|
1397
|
+
puff3.wind = init.wind ?? 1;
|
|
1398
|
+
puff3.color = init.color ?? SMOKE_COLORS.grey;
|
|
1399
|
+
puff3.ring = init.ring ?? null;
|
|
1400
|
+
puff3.ph = init.ph ?? 0;
|
|
1401
|
+
puff3.th = init.th ?? 0;
|
|
1402
|
+
puff3.rng = random;
|
|
1403
|
+
puff3.age = 0;
|
|
1404
|
+
puff3.heat = 0;
|
|
1405
|
+
puff3.size = 0;
|
|
1406
|
+
return puff3;
|
|
1407
|
+
}
|
|
1408
|
+
function ageOrKeep2(puff3, dt) {
|
|
1409
|
+
puff3.t += dt;
|
|
1410
|
+
return puff3.t < puff3.life;
|
|
1411
|
+
}
|
|
1412
|
+
function moveOnRing(puff3, ring2, wind) {
|
|
1413
1413
|
const ringTime = ring2.t;
|
|
1414
1414
|
const centerY = ring2.y0 + ring2.rise * (1 - Math.exp(-ringTime * ring2.rk));
|
|
1415
1415
|
const majorRadius = ring2.R0 + (ring2.R1 - ring2.R0) * (1 - Math.exp(-ringTime * 1.6));
|
|
1416
|
-
const theta =
|
|
1416
|
+
const theta = puff3.th + ringTime * ring2.roll;
|
|
1417
1417
|
const minorRadius = ring2.r * (0.8 + 0.4 * Math.min(1, ringTime));
|
|
1418
1418
|
const radius = majorRadius + minorRadius * Math.cos(theta);
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
}
|
|
1423
|
-
function moveFree(
|
|
1424
|
-
const damping = Math.exp(-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
if (
|
|
1433
|
-
|
|
1434
|
-
if (
|
|
1419
|
+
puff3.x = ring2.x + Math.cos(puff3.ph) * radius + wind.x * ringTime * 0.6;
|
|
1420
|
+
puff3.z = ring2.z + Math.sin(puff3.ph) * radius + wind.z * ringTime * 0.6;
|
|
1421
|
+
puff3.y = centerY + minorRadius * Math.sin(theta);
|
|
1422
|
+
}
|
|
1423
|
+
function moveFree(puff3, dt, age, heat, wind) {
|
|
1424
|
+
const damping = Math.exp(-puff3.drag * dt);
|
|
1425
|
+
puff3.vx *= damping;
|
|
1426
|
+
puff3.vy *= damping;
|
|
1427
|
+
puff3.vz *= damping;
|
|
1428
|
+
puff3.vy += (puff3.buoy * (heat > 0 ? 1.6 : 1) - puff3.grav) * dt;
|
|
1429
|
+
puff3.x += (puff3.vx + wind.x * puff3.wind * age) * dt;
|
|
1430
|
+
puff3.y += puff3.vy * dt;
|
|
1431
|
+
puff3.z += (puff3.vz + wind.z * puff3.wind * age) * dt;
|
|
1432
|
+
if (puff3.y < puff3.s0 * FLOOR_FRACTION) {
|
|
1433
|
+
puff3.y = puff3.s0 * FLOOR_FRACTION;
|
|
1434
|
+
if (puff3.vy < 0) puff3.vy *= FLOOR_BOUNCE;
|
|
1435
1435
|
}
|
|
1436
1436
|
}
|
|
1437
1437
|
function updatePuffs(pool, dt, wind) {
|
|
1438
1438
|
pool.compact(ageOrKeep2, dt);
|
|
1439
|
-
for (const
|
|
1440
|
-
const age =
|
|
1441
|
-
const heat =
|
|
1442
|
-
if (
|
|
1443
|
-
else moveFree(
|
|
1444
|
-
const size =
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1439
|
+
for (const puff3 of pool.items) {
|
|
1440
|
+
const age = puff3.t / puff3.life;
|
|
1441
|
+
const heat = puff3.h0 > 0 ? puff3.h0 * Math.pow(Math.max(0, 1 - puff3.t / puff3.hl), 1.25) : 0;
|
|
1442
|
+
if (puff3.ring) moveOnRing(puff3, puff3.ring, wind);
|
|
1443
|
+
else moveFree(puff3, dt, age, heat, wind);
|
|
1444
|
+
const size = puff3.s0 + (puff3.s1 - puff3.s0) * (1 - Math.exp(-puff3.t * puff3.gk)) + puff3.sg * Math.min(puff3.t, GROWTH_CAP_SECONDS);
|
|
1445
|
+
puff3.size = size * Math.min(1, puff3.t * ARRIVAL_FRAME + ARRIVAL_BASE);
|
|
1446
|
+
puff3.age = age;
|
|
1447
|
+
puff3.heat = heat;
|
|
1448
1448
|
}
|
|
1449
1449
|
}
|
|
1450
1450
|
var GROUND_LIFT = 0.02;
|
|
@@ -1501,9 +1501,9 @@ var GameVfxThree = (() => {
|
|
|
1501
1501
|
var HOT_GLOW_COLOR = [1, 0.45, 0.12];
|
|
1502
1502
|
function addPuff(core, random, init) {
|
|
1503
1503
|
core.spawned.puffs++;
|
|
1504
|
-
const
|
|
1505
|
-
core.trace?.puff?.(
|
|
1506
|
-
return
|
|
1504
|
+
const puff3 = spawnPuff(core.puffs, random, init);
|
|
1505
|
+
core.trace?.puff?.(puff3);
|
|
1506
|
+
return puff3;
|
|
1507
1507
|
}
|
|
1508
1508
|
function addSpark(core, init) {
|
|
1509
1509
|
core.spawned.sparks++;
|
|
@@ -1685,6 +1685,7 @@ var GameVfxThree = (() => {
|
|
|
1685
1685
|
var neg = call("neg");
|
|
1686
1686
|
var abs = call("abs");
|
|
1687
1687
|
var sqrt = call("sqrt");
|
|
1688
|
+
var exp = call("exp");
|
|
1688
1689
|
var sin = call("sin");
|
|
1689
1690
|
var cos = call("cos");
|
|
1690
1691
|
var atan2 = call("atan2");
|
|
@@ -1730,10 +1731,12 @@ var GameVfxThree = (() => {
|
|
|
1730
1731
|
var INDEX = { $: "index" };
|
|
1731
1732
|
var QUALITY = { $: "quality" };
|
|
1732
1733
|
var FRESH = { $: "fresh" };
|
|
1734
|
+
var DIRECTION = { $: "direction" };
|
|
1733
1735
|
var CAMERA_POSITION = { $: "cameraPosition" };
|
|
1734
1736
|
var burst = (system, count, spawn2) => ({ op: "burst", system, count, spawn: spawn2 });
|
|
1735
1737
|
var spawn = (system, options) => ({ op: "spawn", system, spawn: options });
|
|
1736
1738
|
var emit = (key, system, rate, options) => ({ op: "emit", key, system, rate, spawn: options });
|
|
1739
|
+
var mesh = (options) => ({ op: "mesh", spawn: options });
|
|
1737
1740
|
var debris = (options) => ({ op: "debris", spawn: options });
|
|
1738
1741
|
var decal = (...args) => ({ op: "decal", args });
|
|
1739
1742
|
var ring = (...args) => ({ op: "ring", args });
|
|
@@ -2745,6 +2748,241 @@ var GameVfxThree = (() => {
|
|
|
2745
2748
|
)
|
|
2746
2749
|
]
|
|
2747
2750
|
};
|
|
2751
|
+
var SPOTS_X = [-3, 1, 5];
|
|
2752
|
+
var SPOTS_Z = [-1, -2.4, 0.4];
|
|
2753
|
+
var FOG_AND_ASH = {
|
|
2754
|
+
id: "fog_and_ash",
|
|
2755
|
+
pageId: "neblina",
|
|
2756
|
+
team: "world",
|
|
2757
|
+
budget: { particles: 120, lights: 1 },
|
|
2758
|
+
loop: 0,
|
|
2759
|
+
view: { eye: [3, 1.8, 7.5], target: [-3, 1.2, -1] },
|
|
2760
|
+
setup: [
|
|
2761
|
+
cue("fog", { density: 0.075 }),
|
|
2762
|
+
cue("lamp_cone", { visible: true }),
|
|
2763
|
+
cue("zombie_visible", { index: -1, visible: false }),
|
|
2764
|
+
repeat(
|
|
2765
|
+
SPOTS_X.length,
|
|
2766
|
+
set("turn", rnd(-0.6, 0.6)),
|
|
2767
|
+
behavior("walkers", "place", { index: INDEX, x: pick(SPOTS_X, INDEX), z: pick(SPOTS_Z, INDEX), facing: variable("turn") })
|
|
2768
|
+
)
|
|
2769
|
+
],
|
|
2770
|
+
timeline: [],
|
|
2771
|
+
tick: [
|
|
2772
|
+
emit("fog", "normal", 5, { p: [rnd(-14, 10), rnd(0.2, 1.1), rnd(-3, 8)], v: [rnd(0.15, 0.35), 0, rnd(-0.05, 0.05)], sp: 0, life: [9, 13], size: [3, 5], grow: 1.4, c0: 8227488, a: 0.13, fi: 0.35 }),
|
|
2773
|
+
emit("ash", "normal", 14, { p: [rnd(-10, 8), rnd(4, 6), rnd(-3, 7)], v: [rnd(0.1, 0.4), -0.35, rnd(-0.1, 0.1)], sp: [0.05, 0.15], life: [8, 12], size: [0.025, 0.04], c0: 10525328, a: 0.75, fi: 0.1, gnd: 1 })
|
|
2774
|
+
]
|
|
2775
|
+
};
|
|
2776
|
+
var RAIN_CAPACITY = 4e3;
|
|
2777
|
+
var FALL_SPEED = 15;
|
|
2778
|
+
var WIND_PER_FALL = 0.07;
|
|
2779
|
+
var STREAK_SLANT = 0.04;
|
|
2780
|
+
var STREAK_LENGTH = 0.6;
|
|
2781
|
+
var BOX_X = [-15, 15];
|
|
2782
|
+
var BOX_Z = [-6, 16];
|
|
2783
|
+
var START_HEIGHT = [0, 16];
|
|
2784
|
+
var REENTRY_HEIGHT = [14, 17];
|
|
2785
|
+
var SPLASH_CHANCE = 0.35;
|
|
2786
|
+
var SPLASH_RANGE = 12;
|
|
2787
|
+
var SPRITE_CHANCE = 0.5;
|
|
2788
|
+
var UP9 = [0, 1, 0];
|
|
2789
|
+
var WORKSHOP_PUDDLES = [
|
|
2790
|
+
[-1.5, 2.2, 1.6, 0.9],
|
|
2791
|
+
[3, 3.6, 1.1, 0.7],
|
|
2792
|
+
[-6, 3.2, 1.3, 0.8],
|
|
2793
|
+
[1.4, -2.2, 0.9, 0.5]
|
|
2794
|
+
];
|
|
2795
|
+
var inPuddle = (puddles, x, z) => puddles.some((p) => ((x - p[0]) / p[2]) ** 2 + ((z - p[1]) / p[3]) ** 2 < 1);
|
|
2796
|
+
var RainField = class {
|
|
2797
|
+
constructor(engine) {
|
|
2798
|
+
__publicField(this, "engine", engine);
|
|
2799
|
+
__publicField(this, "positions", new Float32Array(RAIN_CAPACITY * 6));
|
|
2800
|
+
__publicField(this, "count", 0);
|
|
2801
|
+
__publicField(this, "wind", 1);
|
|
2802
|
+
__publicField(this, "on", false);
|
|
2803
|
+
__publicField(this, "centerX", 0);
|
|
2804
|
+
__publicField(this, "centerZ", 0);
|
|
2805
|
+
__publicField(this, "puddles", WORKSHOP_PUDDLES);
|
|
2806
|
+
__publicField(this, "puddleAt");
|
|
2807
|
+
}
|
|
2808
|
+
/** `initRain` (W321): `count` streaks (thinned by the quality), each drawn at a random place in the box. */
|
|
2809
|
+
init(count, wind) {
|
|
2810
|
+
const { random } = this.engine;
|
|
2811
|
+
this.count = Math.min(RAIN_CAPACITY, Math.round(count * this.engine.context.quality.mult));
|
|
2812
|
+
this.wind = wind;
|
|
2813
|
+
this.on = true;
|
|
2814
|
+
for (let index = 0; index < this.count; index++) {
|
|
2815
|
+
const offset = index * 6;
|
|
2816
|
+
const x = random.between(BOX_X[0], BOX_X[1]);
|
|
2817
|
+
const y = random.between(START_HEIGHT[0], START_HEIGHT[1]);
|
|
2818
|
+
const z = random.between(BOX_Z[0], BOX_Z[1]);
|
|
2819
|
+
this.set(offset, x, y, z);
|
|
2820
|
+
}
|
|
2821
|
+
}
|
|
2822
|
+
/**
|
|
2823
|
+
* What a game does with the field every frame: the box follows the camera (`centerX`, `centerZ`), the streaks thin or thicken to `count` (a new streak
|
|
2824
|
+
* starts at a random place of the box, as `init` draws it) and the wind slants them. The golden never calls it.
|
|
2825
|
+
*/
|
|
2826
|
+
drive(count, wind, centerX, centerZ) {
|
|
2827
|
+
const { random } = this.engine;
|
|
2828
|
+
const target = Math.max(0, Math.min(RAIN_CAPACITY, Math.round(count * this.engine.context.quality.mult)));
|
|
2829
|
+
this.wind = wind;
|
|
2830
|
+
this.centerX = centerX;
|
|
2831
|
+
this.centerZ = centerZ;
|
|
2832
|
+
this.on = target > 0;
|
|
2833
|
+
for (let index = this.count; index < target; index++) {
|
|
2834
|
+
this.set(index * 6, random.between(BOX_X[0], BOX_X[1]) + centerX, random.between(START_HEIGHT[0], START_HEIGHT[1]), random.between(BOX_Z[0], BOX_Z[1]) + centerZ);
|
|
2835
|
+
}
|
|
2836
|
+
this.count = target;
|
|
2837
|
+
}
|
|
2838
|
+
/** `updateRain` (W322-329). `camera` is where the eye is; `splash` lets the drops that land leave a splash. */
|
|
2839
|
+
update(dt, splash, camera2) {
|
|
2840
|
+
if (!this.on) return;
|
|
2841
|
+
const { random, context } = this.engine;
|
|
2842
|
+
const positions = this.positions;
|
|
2843
|
+
const fall = FALL_SPEED * dt;
|
|
2844
|
+
const slant = this.wind * fall * WIND_PER_FALL;
|
|
2845
|
+
const reach = SPLASH_RANGE / (1 + context.quality.level);
|
|
2846
|
+
for (let index = 0; index < this.count; index++) {
|
|
2847
|
+
const o = index * 6;
|
|
2848
|
+
positions[o] += slant;
|
|
2849
|
+
positions[o + 3] += slant;
|
|
2850
|
+
positions[o + 1] -= fall;
|
|
2851
|
+
positions[o + 4] -= fall;
|
|
2852
|
+
const ground = context.groundAt(positions[o], positions[o + 2]);
|
|
2853
|
+
if (positions[o + 4] < ground) {
|
|
2854
|
+
const x = positions[o];
|
|
2855
|
+
const z = positions[o + 2];
|
|
2856
|
+
if (splash && random.next() < SPLASH_CHANCE) {
|
|
2857
|
+
const distance = Math.hypot(x - camera2[0], z - camera2[2]);
|
|
2858
|
+
if (distance < reach) {
|
|
2859
|
+
if (random.next() < SPRITE_CHANCE) {
|
|
2860
|
+
this.engine.spawn("normal", { p: [x, ground + 0.01, z], dir: UP9, cone: 0.6, sp: [0.6, 1.3], life: [0.18, 0.3], size: 0.035, c0: 12110044, a: 0.6, g: 9.8, fi: 0 });
|
|
2861
|
+
}
|
|
2862
|
+
if (this.puddleAt ? this.puddleAt(x, z) : inPuddle(this.puddles, x, z)) {
|
|
2863
|
+
this.engine.ring([[x, ground + 0.012, z], 0.01, random.between(0.12, 0.25), random.between(0.4, 0.6), 6978192]);
|
|
2864
|
+
}
|
|
2865
|
+
}
|
|
2866
|
+
}
|
|
2867
|
+
const nx = random.between(BOX_X[0], BOX_X[1]) + this.centerX;
|
|
2868
|
+
const ny = random.between(REENTRY_HEIGHT[0], REENTRY_HEIGHT[1]);
|
|
2869
|
+
const nz = random.between(BOX_Z[0], BOX_Z[1]) + this.centerZ;
|
|
2870
|
+
this.set(o, nx, ny, nz);
|
|
2871
|
+
}
|
|
2872
|
+
}
|
|
2873
|
+
}
|
|
2874
|
+
/** `rain.visible = false; RN.on = false` (W440): the field stops; the streaks stay where they were. */
|
|
2875
|
+
clear() {
|
|
2876
|
+
this.on = false;
|
|
2877
|
+
}
|
|
2878
|
+
set(offset, x, y, z) {
|
|
2879
|
+
const positions = this.positions;
|
|
2880
|
+
positions[offset] = x;
|
|
2881
|
+
positions[offset + 1] = y;
|
|
2882
|
+
positions[offset + 2] = z;
|
|
2883
|
+
positions[offset + 3] = x + this.wind * STREAK_SLANT;
|
|
2884
|
+
positions[offset + 4] = y - STREAK_LENGTH;
|
|
2885
|
+
positions[offset + 5] = z;
|
|
2886
|
+
}
|
|
2887
|
+
};
|
|
2888
|
+
var DROPS = [900, 2200, 4e3];
|
|
2889
|
+
var SLANT = [0.3, 1.2, 4.5];
|
|
2890
|
+
var STORM = 2;
|
|
2891
|
+
var FLASH_STEPS = ite(lt(variable("flash"), 0.08), 1, ite(lt(variable("flash"), 0.16), 0.2, ite(lt(variable("flash"), 0.26), 0.8, 0)));
|
|
2892
|
+
var RAIN_AND_PUDDLES = {
|
|
2893
|
+
id: "rain_and_puddles",
|
|
2894
|
+
pageId: "chuva",
|
|
2895
|
+
team: "world",
|
|
2896
|
+
params: { id: "intensity", options: ["drizzle", "rain", "storm"], default: 1 },
|
|
2897
|
+
budget: { particles: 4e3, decals: 4 },
|
|
2898
|
+
loop: 0,
|
|
2899
|
+
view: { eye: [2, 2, 7], target: [-1, 0.6, 1] },
|
|
2900
|
+
setup: [
|
|
2901
|
+
cue("lamp_cone", { visible: true }),
|
|
2902
|
+
...WORKSHOP_PUDDLES.map(([x, z, radiusX, radiusZ]) => decal(x, 0, z, radiusX * 2, 790550, { grow: 0, life: 1e6, ar: radiusZ / radiusX }))
|
|
2903
|
+
],
|
|
2904
|
+
timeline: [
|
|
2905
|
+
behavior("rain", "init", { count: ite(eq(PARAM, 0), DROPS[0], ite(eq(PARAM, 1), DROPS[1], DROPS[2])), wind: ite(eq(PARAM, 0), SLANT[0], ite(eq(PARAM, 1), SLANT[1], SLANT[2])) }),
|
|
2906
|
+
set("nextStrike", rnd(2, 4)),
|
|
2907
|
+
set("flash", -1)
|
|
2908
|
+
],
|
|
2909
|
+
tick: [
|
|
2910
|
+
behavior("rain", "update", { dt: DELTA, splash: gt(PARAM, 0) }),
|
|
2911
|
+
when(eq(PARAM, STORM), [
|
|
2912
|
+
when(gt(TIME, variable("nextStrike")), [set("nextStrike", add(TIME, rnd(3.5, 6))), set("flash", 0)]),
|
|
2913
|
+
when(ge(variable("flash"), 0), [
|
|
2914
|
+
set("flash", add(variable("flash"), DELTA)),
|
|
2915
|
+
set("light", FLASH_STEPS),
|
|
2916
|
+
cue("lightning", { intensity: variable("light") }),
|
|
2917
|
+
screen({ max: { white: mul(variable("light"), 0.12) } }),
|
|
2918
|
+
when(gt(variable("flash"), 0.4), [set("flash", -1), cue("lightning", { intensity: 0 })])
|
|
2919
|
+
]),
|
|
2920
|
+
emit("sheet", "normal", 2.5, { p: [-12, 2.5, rnd(-1, 8)], box: [0, 2, 0], v: [7, -0.5, 0], sp: 0, life: [3, 4], size: [3, 5], grow: 1.3, c0: 9083568, a: 0.06, fi: 0.3 })
|
|
2921
|
+
])
|
|
2922
|
+
]
|
|
2923
|
+
};
|
|
2924
|
+
var CAR_ORIGIN2 = [5.6, 0, 0.8];
|
|
2925
|
+
var CAR_ROTATION2 = [0, -0.4, 0];
|
|
2926
|
+
var carPoint = (x, y, z) => localToWorld(CAR_ORIGIN2, CAR_ROTATION2, [x, y, z]);
|
|
2927
|
+
var carDirection = (from, to) => normalized([to[0] - from[0], to[1] - from[1], to[2] - from[2]]);
|
|
2928
|
+
var BEAM_FROM = carPoint(0, 0.74, 2.15);
|
|
2929
|
+
var BEAM_DIRECTION = carDirection(BEAM_FROM, carPoint(0, 0.74, 3.15));
|
|
2930
|
+
var BEAM_SIDE = [BEAM_DIRECTION[2], 0, -BEAM_DIRECTION[0]];
|
|
2931
|
+
var WALKERS = 6;
|
|
2932
|
+
var WALK_SPEED2 = 0.7;
|
|
2933
|
+
var DROPS2 = 1800;
|
|
2934
|
+
var SLANT2 = 0.8;
|
|
2935
|
+
var startWalking = [
|
|
2936
|
+
set("spot", query("car", "point", rnd(-2, 2), 0, rnd(8, 18))),
|
|
2937
|
+
set("goal", query("car", "point", rnd(-0.6, 0.6), 0, 2.6)),
|
|
2938
|
+
behavior("walkers", "place", { index: INDEX, x: pick(variable("spot"), 0), z: pick(variable("spot"), 2), facing: 0 }),
|
|
2939
|
+
behavior("walkers", "walk", { index: INDEX, to: variable("goal"), speed: WALK_SPEED2 })
|
|
2940
|
+
];
|
|
2941
|
+
var HEADLIGHTS_IN_RAIN = {
|
|
2942
|
+
id: "headlights_in_rain",
|
|
2943
|
+
pageId: "farol",
|
|
2944
|
+
team: "vehicles",
|
|
2945
|
+
budget: { particles: 600, lights: 2 },
|
|
2946
|
+
loop: 0,
|
|
2947
|
+
view: { eye: [-2.5, 2, 5.5], target: [4, 1, 6] },
|
|
2948
|
+
setup: [
|
|
2949
|
+
cue("fog", { density: 0.05 }),
|
|
2950
|
+
cue("headlights", { on: true, intensity: 2.4, color: 16773584 }),
|
|
2951
|
+
behavior("rain", "init", { count: DROPS2, wind: SLANT2 }),
|
|
2952
|
+
repeat(WALKERS, ...startWalking)
|
|
2953
|
+
],
|
|
2954
|
+
timeline: [],
|
|
2955
|
+
tick: [
|
|
2956
|
+
behavior("rain", "update", { dt: DELTA, splash: true }),
|
|
2957
|
+
emit(
|
|
2958
|
+
"lit",
|
|
2959
|
+
"streak",
|
|
2960
|
+
600,
|
|
2961
|
+
local(
|
|
2962
|
+
"depth",
|
|
2963
|
+
rnd(1, 13),
|
|
2964
|
+
local(
|
|
2965
|
+
"spread",
|
|
2966
|
+
mul(variable("depth"), 0.33, sqrt(rand())),
|
|
2967
|
+
local(
|
|
2968
|
+
"turn",
|
|
2969
|
+
rnd(0, 6.283),
|
|
2970
|
+
local("base", vadd(BEAM_FROM, vscale(BEAM_DIRECTION, variable("depth")), vscale(BEAM_SIDE, mul(cos(variable("turn")), variable("spread")))), {
|
|
2971
|
+
p: vwith(variable("base"), 1, add(vy(variable("base")), mul(sin(variable("turn")), variable("spread"), 0.6))),
|
|
2972
|
+
v: [0.8, -14, 0],
|
|
2973
|
+
sp: 0,
|
|
2974
|
+
life: 0.06,
|
|
2975
|
+
len: 0.035,
|
|
2976
|
+
c0: 13622512,
|
|
2977
|
+
a: 0.9
|
|
2978
|
+
})
|
|
2979
|
+
)
|
|
2980
|
+
)
|
|
2981
|
+
)
|
|
2982
|
+
),
|
|
2983
|
+
repeat(WALKERS, when(not(query("walkers", "is_walking", INDEX)), startWalking))
|
|
2984
|
+
]
|
|
2985
|
+
};
|
|
2748
2986
|
var YAW = -Math.PI / 2;
|
|
2749
2987
|
var COS = Math.cos(YAW);
|
|
2750
2988
|
var SIN = Math.sin(YAW);
|
|
@@ -2772,10 +3010,6 @@ var GameVfxThree = (() => {
|
|
|
2772
3010
|
fireLight(0, [vx(variable("contact")), 0.34, vz(variable("contact"))], 1.6, mul(TIME, 3))
|
|
2773
3011
|
]
|
|
2774
3012
|
};
|
|
2775
|
-
var CAR_ORIGIN2 = [5.6, 0, 0.8];
|
|
2776
|
-
var CAR_ROTATION2 = [0, -0.4, 0];
|
|
2777
|
-
var carPoint = (x, y, z) => localToWorld(CAR_ORIGIN2, CAR_ROTATION2, [x, y, z]);
|
|
2778
|
-
var carDirection = (from, to) => normalized([to[0] - from[0], to[1] - from[1], to[2] - from[2]]);
|
|
2779
3013
|
var HOOD = carPoint(0, 1.02, 1.4);
|
|
2780
3014
|
var EXHAUST = carPoint(0.5, 0.3, -2.2);
|
|
2781
3015
|
var EXHAUST_DIRECTION = carDirection(EXHAUST, carPoint(0.5, 0.3, -3));
|
|
@@ -2809,7 +3043,7 @@ var GameVfxThree = (() => {
|
|
|
2809
3043
|
], [fireLightOff(0)])
|
|
2810
3044
|
]
|
|
2811
3045
|
};
|
|
2812
|
-
var
|
|
3046
|
+
var UP10 = [0, 1, 0];
|
|
2813
3047
|
var doorVelocity = (side) => {
|
|
2814
3048
|
const out = carPoint(side * 4, 3, 0.3);
|
|
2815
3049
|
const centre = carPoint(0, 0, 0.3);
|
|
@@ -2819,7 +3053,7 @@ var GameVfxThree = (() => {
|
|
|
2819
3053
|
call2("explode", vadd(query("car", "position"), [0, 0.6, 0]), 1.8, 2759188),
|
|
2820
3054
|
cue("car_burnt"),
|
|
2821
3055
|
behavior("car", "launch", { rise: 4.5, spin: 0.9 }),
|
|
2822
|
-
repeat(scaled(30), debris({ p: vadd(query("car", "position"), [0, 1.3, 0]), dir:
|
|
3056
|
+
repeat(scaled(30), debris({ p: vadd(query("car", "position"), [0, 1.3, 0]), dir: UP10, cone: 1.3, sp: [2, 6], size: [0.06, 6e-3, 0.06], c: 11061464, life: 20 })),
|
|
2823
3057
|
debris({ p: carPoint(0, 1, 1.4), v: [rnd(-1, 1), 9, rnd(-1, 1)], sp: 0, size: [1.6, 0.06, 1.2], c: 3808536, spin: 6, life: 20, bounce: 0.2 }),
|
|
2824
3058
|
...[-1, 1].map((side) => debris({ p: carPoint(side * 0.95, 0.7, 0.3), v: doorVelocity(side), sp: 0, size: [0.06, 0.7, 1.1], c: 3808536, spin: 5, life: 20, bounce: 0.2 })),
|
|
2825
3059
|
debris({ p: carPoint(0.95, 0.38, 1.35), v: [3, 4, 2], sp: 0, size: [0.3, 0.76, 0.76], c: 1118481, spin: 8, life: 20, bounce: 0.4 })
|
|
@@ -2989,7 +3223,7 @@ var GameVfxThree = (() => {
|
|
|
2989
3223
|
])
|
|
2990
3224
|
]
|
|
2991
3225
|
};
|
|
2992
|
-
var
|
|
3226
|
+
var WALKERS2 = 6;
|
|
2993
3227
|
var NEAR = 9;
|
|
2994
3228
|
var RANGE = 7;
|
|
2995
3229
|
var RESTING_BPM = 70;
|
|
@@ -3005,7 +3239,7 @@ var GameVfxThree = (() => {
|
|
|
3005
3239
|
setup: [
|
|
3006
3240
|
cue("zombie_visible", { index: -1, visible: false }),
|
|
3007
3241
|
repeat(
|
|
3008
|
-
|
|
3242
|
+
WALKERS2,
|
|
3009
3243
|
set("startX", rnd(-4, 4)),
|
|
3010
3244
|
set("startZ", sub(rnd(-4, -2), mul(INDEX, 0.6))),
|
|
3011
3245
|
behavior("walkers", "place", { index: INDEX, x: variable("startX"), z: variable("startZ"), facing: 0 }),
|
|
@@ -3015,7 +3249,7 @@ var GameVfxThree = (() => {
|
|
|
3015
3249
|
timeline: [],
|
|
3016
3250
|
tick: [
|
|
3017
3251
|
set("nearest", 99),
|
|
3018
|
-
repeat(
|
|
3252
|
+
repeat(WALKERS2, set("nearest", min(variable("nearest"), vdist(walkerPoint, CAMERA_POSITION)))),
|
|
3019
3253
|
set("fear", clamp(div(sub(NEAR, variable("nearest")), RANGE), 0, 1)),
|
|
3020
3254
|
set("bpm", add(RESTING_BPM, mul(BPM_RISE, variable("fear")))),
|
|
3021
3255
|
when(lt(mod(div(mul(TIME, variable("bpm")), 60), 1), div(mul(DELTA, variable("bpm")), 60)), [screen({ set: { beat: add(0.4, mul(0.6, variable("fear"))) } })]),
|
|
@@ -3082,7 +3316,7 @@ var GameVfxThree = (() => {
|
|
|
3082
3316
|
]
|
|
3083
3317
|
};
|
|
3084
3318
|
var FACING4 = [0, 0, 1];
|
|
3085
|
-
var
|
|
3319
|
+
var UP11 = [0, 1, 0];
|
|
3086
3320
|
var ORIGIN = [0, 0, 0];
|
|
3087
3321
|
var FORWARD4 = [0, 0, -1];
|
|
3088
3322
|
var IMPACT_MATERIALS = ["concrete", "metal", "wood", "glass", "flesh", "water"];
|
|
@@ -3212,12 +3446,157 @@ var GameVfxThree = (() => {
|
|
|
3212
3446
|
team: "destruction",
|
|
3213
3447
|
budget: { particles: 20, debris: 8 },
|
|
3214
3448
|
loop: 2,
|
|
3215
|
-
timeline: [call2("chips", ORIGIN,
|
|
3449
|
+
timeline: [call2("chips", ORIGIN, UP11, 8, 0.9), call2("rust_at", ORIGIN, 6)]
|
|
3216
3450
|
}
|
|
3217
3451
|
];
|
|
3218
|
-
var
|
|
3452
|
+
var PI = Math.PI;
|
|
3453
|
+
var SMOKE = { color: 9079430, width: 10, height: 8, gravity: -0.08, drag: 2.2, growth: 2.1 };
|
|
3454
|
+
var FLASH_SECONDS = 0.055;
|
|
3455
|
+
var FLASH_RAMP = [0.6, 0.9];
|
|
3456
|
+
var FLASH_OPACITY = 0.95;
|
|
3457
|
+
var FLAME_COLORS = [16742946, 16760896, 13121050, 16773296];
|
|
3458
|
+
var FLAME_ADDITIVE = 3;
|
|
3459
|
+
var ORIGIN2 = [0, 0, 0];
|
|
3460
|
+
var SIZE = variable("size");
|
|
3461
|
+
var wide = (width) => mul(sub(rand(), 0.5), width);
|
|
3462
|
+
var puff2 = (point, velocity, world, radius, life, opacity) => mesh({
|
|
3463
|
+
shape: "sphere",
|
|
3464
|
+
p: point,
|
|
3465
|
+
v: velocity,
|
|
3466
|
+
wv: world,
|
|
3467
|
+
r: radius,
|
|
3468
|
+
seg: SMOKE.width,
|
|
3469
|
+
seg2: SMOKE.height,
|
|
3470
|
+
life,
|
|
3471
|
+
c0: SMOKE.color,
|
|
3472
|
+
a: opacity,
|
|
3473
|
+
fade: true,
|
|
3474
|
+
lit: true,
|
|
3475
|
+
g: SMOKE.gravity,
|
|
3476
|
+
drag: SMOKE.drag,
|
|
3477
|
+
grow: SMOKE.growth
|
|
3478
|
+
});
|
|
3479
|
+
var flameBit = (point, velocity, world, radius, life) => [
|
|
3480
|
+
set("bitPoint", point),
|
|
3481
|
+
set("bitVelocity", velocity),
|
|
3482
|
+
set("bitWorld", world),
|
|
3483
|
+
set("bitRadius", radius),
|
|
3484
|
+
set("bitLife", life),
|
|
3485
|
+
set("bitColour", floor(mul(rand(), FLAME_COLORS.length))),
|
|
3486
|
+
mesh({
|
|
3487
|
+
shape: "icosahedron",
|
|
3488
|
+
p: variable("bitPoint"),
|
|
3489
|
+
v: variable("bitVelocity"),
|
|
3490
|
+
wv: variable("bitWorld"),
|
|
3491
|
+
r: variable("bitRadius"),
|
|
3492
|
+
seg: 1,
|
|
3493
|
+
rot: [mul(rand(), 3), mul(rand(), 3), 0],
|
|
3494
|
+
spin: [3, 4, 2],
|
|
3495
|
+
life: variable("bitLife"),
|
|
3496
|
+
c0: pick(FLAME_COLORS, variable("bitColour")),
|
|
3497
|
+
add: eq(variable("bitColour"), FLAME_ADDITIVE),
|
|
3498
|
+
a: 0.9,
|
|
3499
|
+
fade: true,
|
|
3500
|
+
g: -1.4,
|
|
3501
|
+
drag: 1.4,
|
|
3502
|
+
grow: 2.2
|
|
3503
|
+
})
|
|
3504
|
+
];
|
|
3505
|
+
var flashPiece = (shape, radius, height, width, at3, rot, color) => mesh({ shape, r: radius, ...height === void 0 ? {} : { h: height }, seg: width, seg2: shape === "sphere" ? 8 : 1, p: ORIGIN2, at: at3, rot, roll: variable("roll"), ramp: FLASH_RAMP, life: FLASH_SECONDS, c0: color, a: FLASH_OPACITY, add: true });
|
|
3506
|
+
var MUZZLE_FLASH2 = {
|
|
3507
|
+
id: "viewmodel_muzzle_flash",
|
|
3508
|
+
pageId: "event:viewmodel_muzzle_flash",
|
|
3509
|
+
team: "weapons",
|
|
3510
|
+
budget: { particles: 12, lights: 1 },
|
|
3511
|
+
loop: 0.1,
|
|
3512
|
+
timeline: [
|
|
3513
|
+
set("angles", []),
|
|
3514
|
+
repeat(4, append("angles", add(div(mul(INDEX, PI), 2), mul(rand(), 0.6)))),
|
|
3515
|
+
set("roll", mul(rand(), PI)),
|
|
3516
|
+
flash(ORIGIN2, 16756832, mul(4, SIZE), FLASH_SECONDS, mul(2, SIZE), true, true),
|
|
3517
|
+
flashPiece("cone_open", mul(0.013, SIZE), mul(0.085, SIZE), 10, [mul(0.042, SIZE), 0, 0], [0, 0, -PI / 2], 16757575),
|
|
3518
|
+
repeat(
|
|
3519
|
+
4,
|
|
3520
|
+
set("angle", pick(variable("angles"), INDEX)),
|
|
3521
|
+
flashPiece(
|
|
3522
|
+
"cone",
|
|
3523
|
+
mul(5e-3, SIZE),
|
|
3524
|
+
mul(0.04, SIZE),
|
|
3525
|
+
6,
|
|
3526
|
+
[mul(0.012, SIZE), mul(cos(variable("angle")), 0.016, SIZE), mul(sin(variable("angle")), 0.016, SIZE)],
|
|
3527
|
+
[variable("angle"), 0, -PI / 2],
|
|
3528
|
+
16757575
|
|
3529
|
+
)
|
|
3530
|
+
),
|
|
3531
|
+
flashPiece("sphere", mul(0.016, SIZE), void 0, 12, [mul(8e-3, SIZE), 0, 0], [0, 0, 0], 16773568),
|
|
3532
|
+
repeat(
|
|
3533
|
+
6,
|
|
3534
|
+
puff2(
|
|
3535
|
+
ORIGIN2,
|
|
3536
|
+
[add(0.15, mul(rand(), 0.35)), add(0.03, mul(rand(), 0.12)), mul(sub(rand(), 0.5), 0.14)],
|
|
3537
|
+
[0, 0, 0],
|
|
3538
|
+
mul(0.013, SIZE),
|
|
3539
|
+
add(1.3, mul(rand(), 0.6)),
|
|
3540
|
+
0.45
|
|
3541
|
+
)
|
|
3542
|
+
)
|
|
3543
|
+
]
|
|
3544
|
+
};
|
|
3545
|
+
var SMOKE_PUFF = {
|
|
3546
|
+
id: "weapon_smoke_puff",
|
|
3547
|
+
pageId: "event:weapon_smoke_puff",
|
|
3548
|
+
team: "weapons",
|
|
3549
|
+
budget: { particles: 1 },
|
|
3550
|
+
loop: 0.1,
|
|
3551
|
+
timeline: [puff2(ORIGIN2, void 0, [variable("vx"), variable("vy"), variable("vz")], variable("radius"), variable("life"), variable("opacity"))]
|
|
3552
|
+
};
|
|
3553
|
+
var BACKBLAST = {
|
|
3554
|
+
id: "launcher_backblast",
|
|
3555
|
+
pageId: "event:launcher_backblast",
|
|
3556
|
+
team: "weapons",
|
|
3557
|
+
budget: { particles: 40 },
|
|
3558
|
+
loop: 0.1,
|
|
3559
|
+
timeline: [
|
|
3560
|
+
repeat(26, puff2(ORIGIN2, [neg(add(1.5, mul(rand(), 3))), 0, 0], [wide(1.4), wide(0.8), wide(1.4)], add(0.03, mul(rand(), 0.03)), add(1.8, mul(rand(), 1.4)), 0.5)),
|
|
3561
|
+
repeat(14, ...flameBit(ORIGIN2, [neg(add(2, mul(rand(), 2))), 0, 0], [wide(1), wide(0.6), wide(1)], 0.02, 0.25))
|
|
3562
|
+
]
|
|
3563
|
+
};
|
|
3564
|
+
var FLAME_JET = {
|
|
3565
|
+
id: "flame_jet",
|
|
3566
|
+
pageId: "event:flame_jet",
|
|
3567
|
+
team: "weapons",
|
|
3568
|
+
budget: { particles: 30 },
|
|
3569
|
+
loop: 0.1,
|
|
3570
|
+
timeline: [
|
|
3571
|
+
repeat(
|
|
3572
|
+
floor(mul(420, variable("dt"), variable("scale"))),
|
|
3573
|
+
set("speed", mul(add(2.2, mul(rand(), 1.1)), variable("scale"))),
|
|
3574
|
+
...flameBit(
|
|
3575
|
+
[mul(rand(), variable("speed"), min(variable("dt"), 0.3)), 0, 0],
|
|
3576
|
+
[variable("speed"), 0, 0],
|
|
3577
|
+
[wide(0.35), mul(sub(rand(), 0.3), 0.3), wide(0.35)],
|
|
3578
|
+
add(0.02, mul(rand(), 0.022)),
|
|
3579
|
+
add(0.4, mul(rand(), 0.35))
|
|
3580
|
+
)
|
|
3581
|
+
),
|
|
3582
|
+
when(lt(rand(), 0.5), [
|
|
3583
|
+
puff2([add(mul(1.1, variable("scale")), mul(rand(), 0.4)), 0, 0], void 0, [mul(vx(DIRECTION), 0.6), 0.35, mul(vz(DIRECTION), 0.6)], 0.03, 1.6, 0.4)
|
|
3584
|
+
])
|
|
3585
|
+
]
|
|
3586
|
+
};
|
|
3587
|
+
var VIEWMODEL_EFFECTS = [MUZZLE_FLASH2, SMOKE_PUFF, BACKBLAST, FLAME_JET];
|
|
3588
|
+
var aliasOf = (base, id, changes) => ({ ...base, id, pageId: `vehicle:${id}`, anchor: CAR_ORIGIN2, ...changes });
|
|
3589
|
+
var VEHICLE_EFFECTS = [
|
|
3590
|
+
/** The engine on fire: `engine_smoke` at its worst condition (black smoke, flames in the hood, a light). */
|
|
3591
|
+
aliasOf(ENGINE_SMOKE, "vehicle_fire", { params: { id: "condition", options: ["100", "60", "30", "10"], default: 3 }, loop: 12 }),
|
|
3592
|
+
/** The exhaust of a car under way: `engine_smoke` in the best condition, for half a second so a moving car asks again. */
|
|
3593
|
+
aliasOf(ENGINE_SMOKE, "vehicle_exhaust", { params: { id: "condition", options: ["100", "60", "30", "10"], default: 0 }, loop: 0.5 }),
|
|
3594
|
+
/** A hole in the tank: the page's own petrol leak (drips, pool, sparks, fire running to the tank). */
|
|
3595
|
+
aliasOf(FUEL_LEAK, "vehicle_leak", {})
|
|
3596
|
+
];
|
|
3597
|
+
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];
|
|
3219
3598
|
var WORKSHOP_EFFECTS = Object.fromEntries(ALL_EFFECTS.map((effect) => [effect.id, effect]));
|
|
3220
|
-
var GAME_EFFECTS = { ...WORKSHOP_EFFECTS, ...Object.fromEntries(EVENT_EFFECTS.map((effect) => [effect.id, effect])) };
|
|
3599
|
+
var GAME_EFFECTS = { ...WORKSHOP_EFFECTS, ...Object.fromEntries([...EVENT_EFFECTS, ...VIEWMODEL_EFFECTS, ...VEHICLE_EFFECTS].map((effect) => [effect.id, effect])) };
|
|
3221
3600
|
var LEHMER_MULTIPLIER = 16807;
|
|
3222
3601
|
var LEHMER_MODULUS = 2147483647;
|
|
3223
3602
|
var HASH_MIX = 2654435761;
|
|
@@ -3313,7 +3692,7 @@ var GameVfxThree = (() => {
|
|
|
3313
3692
|
}
|
|
3314
3693
|
var COLUMNS = 6;
|
|
3315
3694
|
var ROWS = 5;
|
|
3316
|
-
var
|
|
3695
|
+
var ORIGIN3 = [-2.2, 0, 2.6];
|
|
3317
3696
|
var BLOCK_SIZE = [0.5, 0.44, 0.25];
|
|
3318
3697
|
var OBJECT_ID_DRAWS2 = 4;
|
|
3319
3698
|
var FLOOR2 = 0.13;
|
|
@@ -3356,7 +3735,7 @@ var GameVfxThree = (() => {
|
|
|
3356
3735
|
const chipScale = random.between(0.8, 1.3) * scale;
|
|
3357
3736
|
for (let draw = 0; draw < OBJECT_ID_DRAWS2; draw++) random.next();
|
|
3358
3737
|
best.holes.push({ x: offsetX, y: offsetY, scale, chipTurn, chipScale });
|
|
3359
|
-
impact(host.engine, "concrete", [
|
|
3738
|
+
impact(host.engine, "concrete", [ORIGIN3[0] + x, y, ORIGIN3[2] + 0.13], [0, 0, 1], 0.8);
|
|
3360
3739
|
} else if (action === "collapse") {
|
|
3361
3740
|
const { x, y } = args;
|
|
3362
3741
|
for (const block of blocks) {
|
|
@@ -3406,7 +3785,7 @@ var GameVfxThree = (() => {
|
|
|
3406
3785
|
}
|
|
3407
3786
|
};
|
|
3408
3787
|
}
|
|
3409
|
-
var
|
|
3788
|
+
var ORIGIN4 = [5.6, 0, 0.8];
|
|
3410
3789
|
var MAX_TILT = 0.25;
|
|
3411
3790
|
function createCarBehavior() {
|
|
3412
3791
|
let y = 0;
|
|
@@ -3438,8 +3817,13 @@ var GameVfxThree = (() => {
|
|
|
3438
3817
|
}
|
|
3439
3818
|
}
|
|
3440
3819
|
},
|
|
3441
|
-
query(_host, name) {
|
|
3442
|
-
if (name === "position") return [
|
|
3820
|
+
query(_host, name, args) {
|
|
3821
|
+
if (name === "position") return [ORIGIN4[0], y, ORIGIN4[2]];
|
|
3822
|
+
if (name === "point") {
|
|
3823
|
+
const [x, py, z] = args;
|
|
3824
|
+
const point = carPoint(x, py, z);
|
|
3825
|
+
return [point[0], point[1] + y, point[2]];
|
|
3826
|
+
}
|
|
3443
3827
|
if (name === "roll") return roll;
|
|
3444
3828
|
throw new Error(`car: unknown query ${name}`);
|
|
3445
3829
|
},
|
|
@@ -3639,6 +4023,29 @@ var GameVfxThree = (() => {
|
|
|
3639
4023
|
}
|
|
3640
4024
|
};
|
|
3641
4025
|
}
|
|
4026
|
+
function createRainBehavior() {
|
|
4027
|
+
return {
|
|
4028
|
+
reset() {
|
|
4029
|
+
},
|
|
4030
|
+
act(host, action, args) {
|
|
4031
|
+
const { engine, camera: camera2 } = host;
|
|
4032
|
+
if (action === "init") {
|
|
4033
|
+
const { count, wind } = args;
|
|
4034
|
+
engine.rain.init(count, wind);
|
|
4035
|
+
} else if (action === "update") {
|
|
4036
|
+
const { dt, splash } = args;
|
|
4037
|
+
engine.rain.update(dt, splash, camera2.position);
|
|
4038
|
+
}
|
|
4039
|
+
},
|
|
4040
|
+
query(host, name) {
|
|
4041
|
+
if (name === "count") return host.engine.rain.count;
|
|
4042
|
+
if (name === "on") return host.engine.rain.on;
|
|
4043
|
+
throw new Error(`rain: unknown query ${name}`);
|
|
4044
|
+
},
|
|
4045
|
+
update() {
|
|
4046
|
+
}
|
|
4047
|
+
};
|
|
4048
|
+
}
|
|
3642
4049
|
var WALKER_COUNT = 10;
|
|
3643
4050
|
var ARRIVAL_DISTANCE = 0.05;
|
|
3644
4051
|
var SWAY_AMPLITUDE = 0.04;
|
|
@@ -3704,7 +4111,8 @@ var GameVfxThree = (() => {
|
|
|
3704
4111
|
blocks: () => createBlocksBehavior(),
|
|
3705
4112
|
plate: () => createPlateBehavior(),
|
|
3706
4113
|
cylinder: () => createCylinderBehavior(),
|
|
3707
|
-
car: () => createCarBehavior()
|
|
4114
|
+
car: () => createCarBehavior(),
|
|
4115
|
+
rain: () => createRainBehavior()
|
|
3708
4116
|
};
|
|
3709
4117
|
var NOOP = () => {
|
|
3710
4118
|
};
|
|
@@ -3775,6 +4183,8 @@ var GameVfxThree = (() => {
|
|
|
3775
4183
|
return Math.abs(asNumber(first));
|
|
3776
4184
|
case "sqrt":
|
|
3777
4185
|
return Math.sqrt(asNumber(first));
|
|
4186
|
+
case "exp":
|
|
4187
|
+
return Math.exp(asNumber(first));
|
|
3778
4188
|
case "sin":
|
|
3779
4189
|
return Math.sin(asNumber(first));
|
|
3780
4190
|
case "cos":
|
|
@@ -3893,7 +4303,7 @@ var GameVfxThree = (() => {
|
|
|
3893
4303
|
return evaluateCall(value.$, args.map((entry) => resolve(entry, context)));
|
|
3894
4304
|
}
|
|
3895
4305
|
}
|
|
3896
|
-
var
|
|
4306
|
+
var UP12 = [0, 1, 0];
|
|
3897
4307
|
var ZERO = [0, 0, 0];
|
|
3898
4308
|
var FULL_TURN_DRAWN = 6.283;
|
|
3899
4309
|
function scaledSizes(range, factor) {
|
|
@@ -3906,7 +4316,7 @@ var GameVfxThree = (() => {
|
|
|
3906
4316
|
p: centre,
|
|
3907
4317
|
r: radius,
|
|
3908
4318
|
flat: true,
|
|
3909
|
-
dir: options.dir ??
|
|
4319
|
+
dir: options.dir ?? UP12,
|
|
3910
4320
|
cone: 0.35,
|
|
3911
4321
|
sp: [0.4, 1.4],
|
|
3912
4322
|
v: wind,
|
|
@@ -3923,7 +4333,7 @@ var GameVfxThree = (() => {
|
|
|
3923
4333
|
p: centre,
|
|
3924
4334
|
r: radius * 0.6,
|
|
3925
4335
|
flat: true,
|
|
3926
|
-
dir:
|
|
4336
|
+
dir: UP12,
|
|
3927
4337
|
cone: 0.3,
|
|
3928
4338
|
sp: [0.3, 0.8],
|
|
3929
4339
|
life: [0.2, 0.4],
|
|
@@ -3938,14 +4348,14 @@ var GameVfxThree = (() => {
|
|
|
3938
4348
|
if (engine.quality < 2) {
|
|
3939
4349
|
engine.emit(`${key}e`, "streak", 10 * factor, dt, () => {
|
|
3940
4350
|
const jitter = plus(wind, engine.random.between(-0.4, 0.4), 0, engine.random.between(-0.4, 0.4));
|
|
3941
|
-
return { p: centre, box: [radius, 0, radius], dir:
|
|
4351
|
+
return { p: centre, box: [radius, 0, radius], dir: UP12, cone: 0.5, sp: [1.5, 3.5], v: jitter, life: [0.8, 1.8], len: 0.03, c0: 16756816, c1: 6295552, g: -0.6, drag: 0.4 };
|
|
3942
4352
|
});
|
|
3943
4353
|
}
|
|
3944
4354
|
if (options.noSmoke) return;
|
|
3945
4355
|
engine.emit(`${key}s`, "normal", (options.smoke || 14) * factor, dt, () => ({
|
|
3946
4356
|
p: plus(centre, 0, 0.8 * sqrtFactor, 0),
|
|
3947
4357
|
r: radius * 0.7,
|
|
3948
|
-
dir:
|
|
4358
|
+
dir: UP12,
|
|
3949
4359
|
cone: 0.35,
|
|
3950
4360
|
sp: [0.6, 1.4],
|
|
3951
4361
|
v: wind,
|
|
@@ -3985,15 +4395,15 @@ var GameVfxThree = (() => {
|
|
|
3985
4395
|
engine.screen.shake += 0.7 * scale;
|
|
3986
4396
|
engine.screen.white += 0.18 * scale;
|
|
3987
4397
|
engine.burst("add", 55 * scale, { p: point, r: 0.3 * scale, sp: [2, 7 * scale], drag: 4, life: [0.25, 0.6], size: [0.7 * scale, 1.4 * scale], grow: 1.7, c0: 16773296, c1: 10103304, fi: 0.04 });
|
|
3988
|
-
engine.burst("add", 28 * scale, { p: plus(point, 0, 0.3, 0), r: 0.3, dir:
|
|
4398
|
+
engine.burst("add", 28 * scale, { p: plus(point, 0, 0.3, 0), r: 0.3, dir: UP12, cone: 0.7, sp: [2, 5 * scale], drag: 1.5, life: [0.6, 1.1], size: [0.6 * scale, 1 * scale], grow: 1.3, c0: 16760928, c1: 5902853, g: -2, fi: 0.05 });
|
|
3989
4399
|
engine.ring([plus(point, 0, 0.05, 0), 0.3, 7 * scale, 0.55, 16767136]);
|
|
3990
4400
|
const toCamera = normalized([cameraPosition[0] - point[0], cameraPosition[1] - point[1], cameraPosition[2] - point[2]]);
|
|
3991
4401
|
engine.ring([plus(point, 0, 1, 0), 0.3, 5 * scale, 0.35, 16773328, toCamera]);
|
|
3992
|
-
engine.burst("normal", 32 * scale, { p: plus(point, 0, 0.6, 0), r: 0.8 * scale, dir:
|
|
4402
|
+
engine.burst("normal", 32 * scale, { p: plus(point, 0, 0.6, 0), r: 0.8 * scale, dir: UP12, cone: 1.1, sp: [1, 3], drag: 1.2, life: [3, 6], size: [1 * scale, 1.8 * scale], grow: 2.6, c0: 2828068, c1: 987155, a: 0.6, fi: 0.18, g: -0.35 });
|
|
3993
4403
|
ringOfDust(engine, point, scale);
|
|
3994
|
-
if (engine.quality < 2) engine.burst("streak", 44 * scale, { p: point, dir:
|
|
4404
|
+
if (engine.quality < 2) engine.burst("streak", 44 * scale, { p: point, dir: UP12, cone: 1.45, sp: [10, 26], life: [0.3, 0.7], len: 0.03, c0: 16760944, c1: 8396800, g: 9.8, gnd: 2 });
|
|
3995
4405
|
for (let index = 0; index < engine.scaled(16 * scale); index++) {
|
|
3996
|
-
engine.debrisPiece({ p: point, dir:
|
|
4406
|
+
engine.debrisPiece({ p: point, dir: UP12, cone: 1.2, sp: [3, 9], size: [0.12, 0.06, 0.1], k: [0.6, 1.6], c: chipColor || 2762274, life: 9 });
|
|
3997
4407
|
}
|
|
3998
4408
|
engine.decal([point[0], engine.context.groundAt(point[0], point[2]), point[2], 3 * scale, 657930, { grow: 0.15, life: 60 }]);
|
|
3999
4409
|
}
|
|
@@ -4136,6 +4546,7 @@ var GameVfxThree = (() => {
|
|
|
4136
4546
|
if (!def) return;
|
|
4137
4547
|
this.schedule.clear();
|
|
4138
4548
|
this.variables.clear();
|
|
4549
|
+
for (const [name, value] of Object.entries(this.setup.values ?? {})) this.variables.set(name, value);
|
|
4139
4550
|
for (const behavior2 of this.deps.behaviors()) behavior2.reset(this.host);
|
|
4140
4551
|
this.time = 0;
|
|
4141
4552
|
this.within(() => {
|
|
@@ -4194,6 +4605,10 @@ var GameVfxThree = (() => {
|
|
|
4194
4605
|
return engine.spawn(step.system, this.value(step.spawn));
|
|
4195
4606
|
case "emit":
|
|
4196
4607
|
return engine.emit(step.key, step.system, this.value(step.rate), this.dt, () => this.value(step.spawn));
|
|
4608
|
+
case "mesh": {
|
|
4609
|
+
engine.mesh(this.value(step.spawn));
|
|
4610
|
+
return;
|
|
4611
|
+
}
|
|
4197
4612
|
case "debris":
|
|
4198
4613
|
return engine.debrisPiece(this.value(step.spawn));
|
|
4199
4614
|
case "decal":
|
|
@@ -4275,7 +4690,7 @@ var GameVfxThree = (() => {
|
|
|
4275
4690
|
this.index = previous;
|
|
4276
4691
|
}
|
|
4277
4692
|
};
|
|
4278
|
-
var
|
|
4693
|
+
var ORIGIN5 = [0, 0, 0];
|
|
4279
4694
|
var DEFAULT_HEADING = [0, 0, -1];
|
|
4280
4695
|
var DEFAULT_MAX_INSTANCES = 48;
|
|
4281
4696
|
var ENDLESS_SECONDS = 60;
|
|
@@ -4320,7 +4735,7 @@ var GameVfxThree = (() => {
|
|
|
4320
4735
|
}
|
|
4321
4736
|
function placementOf(entry) {
|
|
4322
4737
|
const origin = entry.follow ? [entry.origin[0] + positionOf2(entry.follow)[0], entry.origin[1] + positionOf2(entry.follow)[1], entry.origin[2] + positionOf2(entry.follow)[2]] : entry.origin;
|
|
4323
|
-
return { origin, anchor: entry.anchor, yaw: entry.yaw };
|
|
4738
|
+
return { origin, anchor: entry.anchor, yaw: entry.yaw, ...entry.orientation ? { orientation: entry.orientation } : {} };
|
|
4324
4739
|
}
|
|
4325
4740
|
function drawing(entry, action) {
|
|
4326
4741
|
const context = engine.context;
|
|
@@ -4344,8 +4759,9 @@ var GameVfxThree = (() => {
|
|
|
4344
4759
|
random: playOptions.seed !== void 0 ? streamOf(playOptions.seed) : void 0,
|
|
4345
4760
|
follow: playOptions.follow,
|
|
4346
4761
|
origin: point,
|
|
4347
|
-
anchor: def.anchor ??
|
|
4762
|
+
anchor: def.anchor ?? ORIGIN5,
|
|
4348
4763
|
yaw: yawOf(heading, playOptions.direction),
|
|
4764
|
+
orientation: playOptions.orientation,
|
|
4349
4765
|
seconds: playOptions.seconds ?? (def.loop && def.loop > 0 ? def.loop : ENDLESS_SECONDS)
|
|
4350
4766
|
};
|
|
4351
4767
|
playing.push(entry);
|
|
@@ -4354,7 +4770,8 @@ var GameVfxThree = (() => {
|
|
|
4354
4770
|
() => instance.begin(def, paramIndex(def, playOptions.param), {
|
|
4355
4771
|
placement: placementOf(entry),
|
|
4356
4772
|
...playOptions.direction ? { direction: playOptions.direction } : {},
|
|
4357
|
-
...playOptions.normal ? { normal: playOptions.normal } : {}
|
|
4773
|
+
...playOptions.normal ? { normal: playOptions.normal } : {},
|
|
4774
|
+
...playOptions.values ? { values: playOptions.values } : {}
|
|
4358
4775
|
})
|
|
4359
4776
|
);
|
|
4360
4777
|
return entry.handle;
|
|
@@ -4614,15 +5031,15 @@ var GameVfxThree = (() => {
|
|
|
4614
5031
|
return shock;
|
|
4615
5032
|
}
|
|
4616
5033
|
function pushPuffs(puffs, shock, reach, dt, age) {
|
|
4617
|
-
for (const
|
|
4618
|
-
if (
|
|
4619
|
-
const dx =
|
|
4620
|
-
const dz =
|
|
5034
|
+
for (const puff3 of puffs) {
|
|
5035
|
+
if (puff3.ring || puff3.t > PUSH_AGE_LIMIT) continue;
|
|
5036
|
+
const dx = puff3.x - shock.x;
|
|
5037
|
+
const dz = puff3.z - shock.z;
|
|
4621
5038
|
const distance = Math.hypot(dx, dz) + 1e-3;
|
|
4622
|
-
if (Math.abs(distance - reach) < PUSH_BAND &&
|
|
5039
|
+
if (Math.abs(distance - reach) < PUSH_BAND && puff3.y < PUSH_CEILING) {
|
|
4623
5040
|
const strength = 4 * dt * (1 - age);
|
|
4624
|
-
|
|
4625
|
-
|
|
5041
|
+
puff3.vx += dx / distance * strength * 6;
|
|
5042
|
+
puff3.vz += dz / distance * strength * 6;
|
|
4626
5043
|
}
|
|
4627
5044
|
}
|
|
4628
5045
|
}
|
|
@@ -4922,10 +5339,10 @@ var GameVfxThree = (() => {
|
|
|
4922
5339
|
const life = random.between(ring2.life * 0.75, ring2.life);
|
|
4923
5340
|
const h0 = random.between(1, 1.25);
|
|
4924
5341
|
const hl = random.between(0.9, 1.6);
|
|
4925
|
-
const
|
|
4926
|
-
|
|
4927
|
-
|
|
4928
|
-
|
|
5342
|
+
const puff3 = addPuff(core, random, { x, y, z, s0: spec.radius * 0.2, s1, sg: spec.radius * 0.06, gk: 3, life, h0, hl, color, kind: 0 });
|
|
5343
|
+
puff3.ring = ring2;
|
|
5344
|
+
puff3.ph = random.next() * Math.PI * 2;
|
|
5345
|
+
puff3.th = random.next() * Math.PI * 2;
|
|
4929
5346
|
}
|
|
4930
5347
|
const stemCount = Math.round((spec.stem || 18) * Math.max(lod, 0.4));
|
|
4931
5348
|
for (let index = 0; index < stemCount; index++) {
|
|
@@ -5726,7 +6143,7 @@ var GameVfxThree = (() => {
|
|
|
5726
6143
|
};
|
|
5727
6144
|
var TWO_PI_ROUNDED = 6.2832;
|
|
5728
6145
|
var WIDE_CONE = 3.1;
|
|
5729
|
-
var
|
|
6146
|
+
var UP13 = [0, 1, 0];
|
|
5730
6147
|
function drawRange(random, range) {
|
|
5731
6148
|
if (Array.isArray(range)) return random.between(range[0], range[1]);
|
|
5732
6149
|
return range || 0;
|
|
@@ -5754,7 +6171,7 @@ var GameVfxThree = (() => {
|
|
|
5754
6171
|
}
|
|
5755
6172
|
function coneDirection(random, direction, cone, out) {
|
|
5756
6173
|
if (cone >= WIDE_CONE) return randomUnit(random, out);
|
|
5757
|
-
const [dx, dy, dz] = direction ??
|
|
6174
|
+
const [dx, dy, dz] = direction ?? UP13;
|
|
5758
6175
|
const cosTilt = 1 - random.next() * (1 - Math.cos(cone));
|
|
5759
6176
|
const sinTilt = Math.sqrt(1 - cosTilt * cosTilt);
|
|
5760
6177
|
const phase = random.next() * TWO_PI_ROUNDED;
|
|
@@ -5874,12 +6291,12 @@ var GameVfxThree = (() => {
|
|
|
5874
6291
|
}
|
|
5875
6292
|
};
|
|
5876
6293
|
var CAPACITY2 = 400;
|
|
5877
|
-
var
|
|
6294
|
+
var UP14 = [0, 1, 0];
|
|
5878
6295
|
var DEFAULT_LIFE2 = 60;
|
|
5879
6296
|
var DEFAULT_GROW = 1.2;
|
|
5880
6297
|
var EVAPORATION = { fuel: [6, 5], water: [40, 20] };
|
|
5881
6298
|
function createDecal() {
|
|
5882
|
-
return { on: false, x: 0, y: 0, z: 0, sx: 0, sy: 0, t: 0, life: 0, grow: 0, color: 0, normal:
|
|
6299
|
+
return { on: false, x: 0, y: 0, z: 0, sx: 0, sy: 0, t: 0, life: 0, grow: 0, color: 0, normal: UP14, fluid: void 0, dryColor: -1, dryAt: 0, dryTime: 0 };
|
|
5883
6300
|
}
|
|
5884
6301
|
var DecalPool = class {
|
|
5885
6302
|
constructor(context) {
|
|
@@ -5892,7 +6309,7 @@ var GameVfxThree = (() => {
|
|
|
5892
6309
|
const random = this.context.random;
|
|
5893
6310
|
const index = this.next++ % CAPACITY2;
|
|
5894
6311
|
const decal2 = this.decals[index];
|
|
5895
|
-
const normal = options.n ??
|
|
6312
|
+
const normal = options.n ?? UP14;
|
|
5896
6313
|
random.between(0, 6.28);
|
|
5897
6314
|
const offset = 4e-3 + index % 40 * 4e-4;
|
|
5898
6315
|
decal2.on = true;
|
|
@@ -5933,6 +6350,94 @@ var GameVfxThree = (() => {
|
|
|
5933
6350
|
}
|
|
5934
6351
|
}
|
|
5935
6352
|
};
|
|
6353
|
+
var CAPACITY3 = 400;
|
|
6354
|
+
var IDENTITY = [0, 0, 0, 1];
|
|
6355
|
+
function multiply(a, b) {
|
|
6356
|
+
const [ax, ay, az, aw] = a;
|
|
6357
|
+
const [bx, by, bz, bw] = b;
|
|
6358
|
+
return [aw * bx + ax * bw + ay * bz - az * by, aw * by - ax * bz + ay * bw + az * bx, aw * bz + ax * by - ay * bx + az * bw, aw * bw - ax * bx - ay * by - az * bz];
|
|
6359
|
+
}
|
|
6360
|
+
var aboutX = (angle) => [Math.sin(angle / 2), 0, 0, Math.cos(angle / 2)];
|
|
6361
|
+
var MeshPool = class {
|
|
6362
|
+
constructor(capacity = CAPACITY3) {
|
|
6363
|
+
__publicField(this, "capacity", capacity);
|
|
6364
|
+
__publicField(this, "particles", []);
|
|
6365
|
+
__publicField(this, "serial", 0);
|
|
6366
|
+
}
|
|
6367
|
+
get count() {
|
|
6368
|
+
return this.particles.length;
|
|
6369
|
+
}
|
|
6370
|
+
spawn(options, frame = IDENTITY) {
|
|
6371
|
+
const velocity = options.v ?? [0, 0, 0];
|
|
6372
|
+
const world = options.wv ?? [0, 0, 0];
|
|
6373
|
+
const particle = {
|
|
6374
|
+
id: ++this.serial,
|
|
6375
|
+
shape: options.shape,
|
|
6376
|
+
radius: options.r,
|
|
6377
|
+
height: options.h ?? 0,
|
|
6378
|
+
segments: options.seg ?? 0,
|
|
6379
|
+
segments2: options.seg2 ?? 0,
|
|
6380
|
+
color: options.c0,
|
|
6381
|
+
additive: options.add === true,
|
|
6382
|
+
lit: options.lit === true,
|
|
6383
|
+
x: options.p[0],
|
|
6384
|
+
y: options.p[1],
|
|
6385
|
+
z: options.p[2],
|
|
6386
|
+
frame: options.roll ? multiply(frame, aboutX(options.roll)) : frame,
|
|
6387
|
+
at: options.at ?? [0, 0, 0],
|
|
6388
|
+
rx: options.rot?.[0] ?? 0,
|
|
6389
|
+
ry: options.rot?.[1] ?? 0,
|
|
6390
|
+
rz: options.rot?.[2] ?? 0,
|
|
6391
|
+
scale: 1,
|
|
6392
|
+
opacity: options.a,
|
|
6393
|
+
age: 0,
|
|
6394
|
+
life: options.life,
|
|
6395
|
+
vx: velocity[0] + world[0],
|
|
6396
|
+
vy: velocity[1] + world[1],
|
|
6397
|
+
vz: velocity[2] + world[2],
|
|
6398
|
+
spin: options.spin ?? [0, 0, 0],
|
|
6399
|
+
gravity: options.g ?? 0,
|
|
6400
|
+
drag: options.drag ?? 0,
|
|
6401
|
+
grow: options.grow ?? 0,
|
|
6402
|
+
ramp: options.ramp,
|
|
6403
|
+
fade: options.fade === true,
|
|
6404
|
+
startOpacity: options.a
|
|
6405
|
+
};
|
|
6406
|
+
this.particles.push(particle);
|
|
6407
|
+
if (this.particles.length > this.capacity) this.particles.shift();
|
|
6408
|
+
return particle;
|
|
6409
|
+
}
|
|
6410
|
+
update(dt) {
|
|
6411
|
+
const live = this.particles;
|
|
6412
|
+
for (let index = 0; index < live.length; index++) {
|
|
6413
|
+
const particle = live[index];
|
|
6414
|
+
particle.age += dt;
|
|
6415
|
+
if (particle.ramp ? particle.age >= particle.life : particle.age > particle.life) {
|
|
6416
|
+
live.splice(index--, 1);
|
|
6417
|
+
continue;
|
|
6418
|
+
}
|
|
6419
|
+
if (particle.fade) particle.opacity = Math.max(0, particle.startOpacity * (1 - particle.age / particle.life));
|
|
6420
|
+
particle.vy -= particle.gravity * dt;
|
|
6421
|
+
if (particle.drag) {
|
|
6422
|
+
const keep = Math.max(0, 1 - particle.drag * dt);
|
|
6423
|
+
particle.vx *= keep;
|
|
6424
|
+
particle.vy *= keep;
|
|
6425
|
+
particle.vz *= keep;
|
|
6426
|
+
}
|
|
6427
|
+
particle.x += particle.vx * dt;
|
|
6428
|
+
particle.y += particle.vy * dt;
|
|
6429
|
+
particle.z += particle.vz * dt;
|
|
6430
|
+
particle.rx += particle.spin[0] * dt;
|
|
6431
|
+
particle.ry += particle.spin[1] * dt;
|
|
6432
|
+
particle.rz += particle.spin[2] * dt;
|
|
6433
|
+
if (particle.grow) particle.scale *= 1 + particle.grow * dt;
|
|
6434
|
+
if (particle.ramp) particle.scale = particle.ramp[0] + Math.min(1, particle.age / particle.life) * particle.ramp[1];
|
|
6435
|
+
}
|
|
6436
|
+
}
|
|
6437
|
+
clear() {
|
|
6438
|
+
this.particles.length = 0;
|
|
6439
|
+
}
|
|
6440
|
+
};
|
|
5936
6441
|
var DEFAULT_FADE_IN = 0.1;
|
|
5937
6442
|
var FLOATS_PER_VECTOR = 3;
|
|
5938
6443
|
var BYTE_MAX2 = 255;
|
|
@@ -6222,11 +6727,11 @@ var GameVfxThree = (() => {
|
|
|
6222
6727
|
};
|
|
6223
6728
|
var RING_CAPACITY = 120;
|
|
6224
6729
|
var LIGHT_CAPACITY = 4;
|
|
6225
|
-
var
|
|
6730
|
+
var UP15 = [0, 1, 0];
|
|
6226
6731
|
var DEFAULT_LIGHT_DISTANCE = 14;
|
|
6227
6732
|
var WaveRingPool = class {
|
|
6228
6733
|
constructor() {
|
|
6229
|
-
__publicField(this, "rings", Array.from({ length: RING_CAPACITY }, () => ({ on: false, point:
|
|
6734
|
+
__publicField(this, "rings", Array.from({ length: RING_CAPACITY }, () => ({ on: false, point: UP15, from: 0, to: 0, t: 0, duration: 1, color: 0, normal: UP15, hold: 0 })));
|
|
6230
6735
|
__publicField(this, "count", 0);
|
|
6231
6736
|
__publicField(this, "next", 0);
|
|
6232
6737
|
}
|
|
@@ -6239,7 +6744,7 @@ var GameVfxThree = (() => {
|
|
|
6239
6744
|
ring2.t = 0;
|
|
6240
6745
|
ring2.duration = duration;
|
|
6241
6746
|
ring2.color = color;
|
|
6242
|
-
ring2.normal = normal ??
|
|
6747
|
+
ring2.normal = normal ?? UP15;
|
|
6243
6748
|
ring2.hold = hold || 0;
|
|
6244
6749
|
}
|
|
6245
6750
|
clear() {
|
|
@@ -6259,7 +6764,7 @@ var GameVfxThree = (() => {
|
|
|
6259
6764
|
var FlashLightPool = class {
|
|
6260
6765
|
constructor(context) {
|
|
6261
6766
|
__publicField(this, "context", context);
|
|
6262
|
-
__publicField(this, "lights", Array.from({ length: LIGHT_CAPACITY }, () => ({ x: 0, y: 0, z: 0, color: 16760944, distance: DEFAULT_LIGHT_DISTANCE, peak: 0, duration: 1, t: 0, intensity: 0 })));
|
|
6767
|
+
__publicField(this, "lights", Array.from({ length: LIGHT_CAPACITY }, () => ({ x: 0, y: 0, z: 0, color: 16760944, distance: DEFAULT_LIGHT_DISTANCE, peak: 0, duration: 1, t: 0, intensity: 0, steady: false })));
|
|
6263
6768
|
__publicField(this, "fire", [
|
|
6264
6769
|
{ x: 0, y: 0, z: 0, intensity: 0 },
|
|
6265
6770
|
{ x: 0, y: 0, z: 0, intensity: 0 }
|
|
@@ -6269,7 +6774,7 @@ var GameVfxThree = (() => {
|
|
|
6269
6774
|
get lit() {
|
|
6270
6775
|
return this.lights.filter((light) => light.intensity > 0).length;
|
|
6271
6776
|
}
|
|
6272
|
-
flash(point, color, intensity, duration, distance, force) {
|
|
6777
|
+
flash(point, color, intensity, duration, distance, force, steady) {
|
|
6273
6778
|
const { level } = this.context.quality;
|
|
6274
6779
|
if (level >= 1 && !force) return;
|
|
6275
6780
|
if (level >= 2 && force !== "boom") return;
|
|
@@ -6282,6 +6787,7 @@ var GameVfxThree = (() => {
|
|
|
6282
6787
|
light.peak = intensity;
|
|
6283
6788
|
light.duration = duration;
|
|
6284
6789
|
light.t = 0;
|
|
6790
|
+
light.steady = steady === true;
|
|
6285
6791
|
light.intensity = intensity;
|
|
6286
6792
|
}
|
|
6287
6793
|
clear() {
|
|
@@ -6293,7 +6799,7 @@ var GameVfxThree = (() => {
|
|
|
6293
6799
|
if (light.intensity <= 0) continue;
|
|
6294
6800
|
light.t += dt;
|
|
6295
6801
|
const age = light.t / light.duration;
|
|
6296
|
-
light.intensity = age >= 1 ? 0 : light.peak * (1 - age) * (1 - age);
|
|
6802
|
+
light.intensity = age >= 1 ? 0 : light.steady ? light.peak : light.peak * (1 - age) * (1 - age);
|
|
6297
6803
|
}
|
|
6298
6804
|
}
|
|
6299
6805
|
};
|
|
@@ -6301,6 +6807,14 @@ var GameVfxThree = (() => {
|
|
|
6301
6807
|
var FIRE_FLICKER_SWAY = 0.25;
|
|
6302
6808
|
var FIRE_FLICKER_JITTER = 0.08;
|
|
6303
6809
|
var LENS_FADE = 0.16;
|
|
6810
|
+
function rotate(q, v) {
|
|
6811
|
+
const [qx, qy, qz, qw] = q;
|
|
6812
|
+
const ix = qw * v[0] + qy * v[2] - qz * v[1];
|
|
6813
|
+
const iy = qw * v[1] + qz * v[0] - qx * v[2];
|
|
6814
|
+
const iz = qw * v[2] + qx * v[1] - qy * v[0];
|
|
6815
|
+
const iw = -qx * v[0] - qy * v[1] - qz * v[2];
|
|
6816
|
+
return [ix * qw + iw * -qx + iy * -qz - iz * -qy, iy * qw + iw * -qy + iz * -qx - ix * -qz, iz * qw + iw * -qz + ix * -qy - iy * -qx];
|
|
6817
|
+
}
|
|
6304
6818
|
function workshopGround(x, z) {
|
|
6305
6819
|
return z < -2.9 && z > -4.5 && Math.abs(x) < 13 ? 0.12 : 0;
|
|
6306
6820
|
}
|
|
@@ -6314,6 +6828,8 @@ var GameVfxThree = (() => {
|
|
|
6314
6828
|
__publicField(this, "decals");
|
|
6315
6829
|
__publicField(this, "rings", new WaveRingPool());
|
|
6316
6830
|
__publicField(this, "lights");
|
|
6831
|
+
__publicField(this, "rain", new RainField(this));
|
|
6832
|
+
__publicField(this, "meshes", new MeshPool());
|
|
6317
6833
|
__publicField(this, "screen", createScreenState());
|
|
6318
6834
|
__publicField(this, "lens", []);
|
|
6319
6835
|
__publicField(this, "post", {});
|
|
@@ -6346,7 +6862,11 @@ var GameVfxThree = (() => {
|
|
|
6346
6862
|
place(point) {
|
|
6347
6863
|
const placement = this.placement;
|
|
6348
6864
|
if (!placement) return point;
|
|
6349
|
-
const { anchor, origin, yaw } = placement;
|
|
6865
|
+
const { anchor, origin, yaw, orientation } = placement;
|
|
6866
|
+
if (orientation) {
|
|
6867
|
+
const turned = rotate(orientation, [point[0] - anchor[0], point[1] - anchor[1], point[2] - anchor[2]]);
|
|
6868
|
+
return [origin[0] + turned[0], origin[1] + turned[1], origin[2] + turned[2]];
|
|
6869
|
+
}
|
|
6350
6870
|
const x = point[0] - anchor[0];
|
|
6351
6871
|
const z = point[2] - anchor[2];
|
|
6352
6872
|
const cos2 = Math.cos(yaw);
|
|
@@ -6357,6 +6877,7 @@ var GameVfxThree = (() => {
|
|
|
6357
6877
|
turn(vector) {
|
|
6358
6878
|
const placement = this.placement;
|
|
6359
6879
|
if (!placement) return vector;
|
|
6880
|
+
if (placement.orientation) return rotate(placement.orientation, vector);
|
|
6360
6881
|
const cos2 = Math.cos(placement.yaw);
|
|
6361
6882
|
const sin2 = Math.sin(placement.yaw);
|
|
6362
6883
|
return [cos2 * vector[0] + sin2 * vector[2], vector[1], -sin2 * vector[0] + cos2 * vector[2]];
|
|
@@ -6385,6 +6906,14 @@ var GameVfxThree = (() => {
|
|
|
6385
6906
|
}
|
|
6386
6907
|
this.accumulators.set(key, carried);
|
|
6387
6908
|
}
|
|
6909
|
+
/** 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. */
|
|
6910
|
+
mesh(recipe) {
|
|
6911
|
+
const placement = this.placement;
|
|
6912
|
+
const options = placement ? { ...recipe, p: this.place(recipe.p), ...recipe.v ? { v: this.turn(recipe.v) } : {} } : recipe;
|
|
6913
|
+
this.context.trace?.("mesh", [options]);
|
|
6914
|
+
const grouped = recipe.at !== void 0 || recipe.roll !== void 0;
|
|
6915
|
+
return this.meshes.spawn(options, placement && grouped ? placement.orientation ?? [0, Math.sin(placement.yaw / 2), 0, Math.cos(placement.yaw / 2)] : void 0);
|
|
6916
|
+
}
|
|
6388
6917
|
debrisPiece(recipe) {
|
|
6389
6918
|
const options = this.placed(recipe);
|
|
6390
6919
|
this.context.trace?.("debris", [options]);
|
|
@@ -6405,10 +6934,11 @@ var GameVfxThree = (() => {
|
|
|
6405
6934
|
this.context.trace?.("ring", args);
|
|
6406
6935
|
this.rings.add(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
|
|
6407
6936
|
}
|
|
6937
|
+
/** `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. */
|
|
6408
6938
|
flash(recipe) {
|
|
6409
|
-
const args = this.placement ? [this.place(recipe[0]), recipe[1], recipe[2], recipe[3], recipe[4], recipe[5]] : recipe;
|
|
6410
|
-
this.context.trace?.("flash", args);
|
|
6411
|
-
this.lights.flash(args[0], args[1], args[2], args[3], args[4], args[5]);
|
|
6939
|
+
const args = this.placement ? [this.place(recipe[0]), recipe[1], recipe[2], recipe[3], recipe[4], recipe[5], recipe[6]] : recipe;
|
|
6940
|
+
this.context.trace?.("flash", args.slice(0, 6));
|
|
6941
|
+
this.lights.flash(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
|
|
6412
6942
|
}
|
|
6413
6943
|
/** `fireLight` (W400): sways with the clock and flickers with one draw. */
|
|
6414
6944
|
fireLight(slot, recipe, intensity, time) {
|
|
@@ -6433,6 +6963,7 @@ var GameVfxThree = (() => {
|
|
|
6433
6963
|
this.debris.update(dt);
|
|
6434
6964
|
this.decals.update(dt);
|
|
6435
6965
|
this.rings.update(dt);
|
|
6966
|
+
this.meshes.update(dt);
|
|
6436
6967
|
this.lights.update(dt);
|
|
6437
6968
|
updateScreen(this.screen, dt);
|
|
6438
6969
|
for (let index = this.lens.length - 1; index >= 0; index--) {
|
|
@@ -6449,7 +6980,9 @@ var GameVfxThree = (() => {
|
|
|
6449
6980
|
this.debris.clear();
|
|
6450
6981
|
this.decals.clear();
|
|
6451
6982
|
this.rings.clear();
|
|
6983
|
+
this.meshes.clear();
|
|
6452
6984
|
this.lights.clear();
|
|
6985
|
+
this.rain.clear();
|
|
6453
6986
|
this.accumulators.clear();
|
|
6454
6987
|
resetScreenState(this.screen);
|
|
6455
6988
|
this.lens.length = 0;
|
|
@@ -6595,16 +7128,16 @@ var GameVfxThree = (() => {
|
|
|
6595
7128
|
},
|
|
6596
7129
|
push(point, radius, speed) {
|
|
6597
7130
|
spriteSystem.push(point, radius, speed);
|
|
6598
|
-
for (const
|
|
6599
|
-
const dx =
|
|
6600
|
-
const dy =
|
|
6601
|
-
const dz =
|
|
7131
|
+
for (const puff3 of core.puffs.items) {
|
|
7132
|
+
const dx = puff3.x - point[0];
|
|
7133
|
+
const dy = puff3.y - point[1];
|
|
7134
|
+
const dz = puff3.z - point[2];
|
|
6602
7135
|
const distance = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
|
6603
7136
|
if (distance >= radius) continue;
|
|
6604
7137
|
const strength = speed * (1 - distance / radius) / (distance + 1e-3);
|
|
6605
|
-
|
|
6606
|
-
|
|
6607
|
-
|
|
7138
|
+
puff3.vx += dx * strength;
|
|
7139
|
+
puff3.vy += dy * strength;
|
|
7140
|
+
puff3.vz += dz * strength;
|
|
6608
7141
|
}
|
|
6609
7142
|
},
|
|
6610
7143
|
stop(handle) {
|
|
@@ -6621,6 +7154,12 @@ var GameVfxThree = (() => {
|
|
|
6621
7154
|
camera2.y = position[1];
|
|
6622
7155
|
camera2.z = position[2];
|
|
6623
7156
|
},
|
|
7157
|
+
setWind(next) {
|
|
7158
|
+
wind.x = next[0];
|
|
7159
|
+
wind.y = next[1];
|
|
7160
|
+
wind.z = next[2];
|
|
7161
|
+
},
|
|
7162
|
+
wind: () => [wind.x, wind.y, wind.z],
|
|
6624
7163
|
forceLod(scale) {
|
|
6625
7164
|
core.clock.forcedLod = scale;
|
|
6626
7165
|
},
|
|
@@ -6950,6 +7489,27 @@ var GameVfxThree = (() => {
|
|
|
6950
7489
|
budget: "Up to 600 particles per building and 2 fire lights. Beyond 80 m only the smoke column and the glow of the windows remain, which become a landmark.",
|
|
6951
7490
|
network: "A fire entity on the server per building, with a spread state."
|
|
6952
7491
|
},
|
|
7492
|
+
rain_and_puddles: {
|
|
7493
|
+
name: "Rain, splashes and puddles",
|
|
7494
|
+
short: "Drops with wind, splashes and rings only near the camera, lightning in the storm.",
|
|
7495
|
+
cost: "\u2264 4,000 drops",
|
|
7496
|
+
costNote: "splash up to 12 m",
|
|
7497
|
+
paramLabel: "Intensity",
|
|
7498
|
+
when: "The weather of the world. Rain raises the background noise and masks footsteps (it can be used for stealth).",
|
|
7499
|
+
look: "A fine drizzle, almost vertical. Rain with splashes on the asphalt and rings in the puddles, which are dark and mirror-like. A storm with drops slanted by the wind, sheets of water passing and a double flash of lightning that lights the scene for 0.2 s and reveals the horde.",
|
|
7500
|
+
budget: "Up to 4,000 drops tied to the camera in a 30 m box. Splashes and rings only within 12 m and only on what the camera sees.",
|
|
7501
|
+
network: "The server sends the weather and the lightning seed, so everyone sees the same flash."
|
|
7502
|
+
},
|
|
7503
|
+
fog_and_ash: {
|
|
7504
|
+
name: "Fog and ash",
|
|
7505
|
+
short: "Low layered mist, ash falling and the lamp post with its cone of light.",
|
|
7506
|
+
cost: "\u2264 120 sprites",
|
|
7507
|
+
costNote: "1 cone of light",
|
|
7508
|
+
when: "Before dawn, near the river and in burnt zones (ash). It cuts the sight of the zombies and of the player.",
|
|
7509
|
+
look: "The engine fog plus a layer of low mist that moves slowly, fine ash falling in a spiral and the beam of the lamp posts in view. Zombie silhouettes show before their details.",
|
|
7510
|
+
budget: "Up to 60 large mist sprites (half resolution) and 60 of ash. The lamp cone is an additive mesh, not real volumetric light.",
|
|
7511
|
+
network: "The weather comes from the server. The density is local, by zone."
|
|
7512
|
+
},
|
|
6953
7513
|
scraping_sparks: {
|
|
6954
7514
|
name: "Scraping sparks",
|
|
6955
7515
|
short: "A bumper dragging on the asphalt: a river of bouncing sparks and a mark on the ground.",
|
|
@@ -7001,6 +7561,16 @@ var GameVfxThree = (() => {
|
|
|
7001
7561
|
budget: "Texture only: a crack mask with 4 stages and a blood decal on the glass. Glass dust: 6 particles per blow.",
|
|
7002
7562
|
network: "The server sends the glass health. Blood on the glass is local."
|
|
7003
7563
|
},
|
|
7564
|
+
headlights_in_rain: {
|
|
7565
|
+
name: "Headlights in the rain",
|
|
7566
|
+
short: "A visible beam, drops lit inside the cone and the horde walking into the light.",
|
|
7567
|
+
cost: "\u2264 600 lit drops",
|
|
7568
|
+
costNote: "2 spots, no shadow",
|
|
7569
|
+
when: "Headlights on at night, with rain or fog.",
|
|
7570
|
+
look: "Two cones of light in the air, rain drops that shine only inside the beam and zombie silhouettes that light up when they enter the light. Outside the cone the rain almost disappears.",
|
|
7571
|
+
budget: "2 spotlights without shadow, 2 additive cones and up to 600 extra drops only inside the cone. Headlights of cars beyond 40 m stay as a cone only, with no real light.",
|
|
7572
|
+
network: "The state of the headlights is already replicated with the car."
|
|
7573
|
+
},
|
|
7004
7574
|
damage_and_bite: {
|
|
7005
7575
|
name: "Damage and bite",
|
|
7006
7576
|
short: "A red edge on the side of the blow, blood on the lens and the pulse of the bite.",
|
|
@@ -7318,6 +7888,27 @@ var GameVfxThree = (() => {
|
|
|
7318
7888
|
budget: "At\xE9 600 part\xEDculas por pr\xE9dio e 2 luzes de fogo. Al\xE9m de 80 m fica s\xF3 a coluna de fuma\xE7a e o brilho das janelas, que viram ponto de refer\xEAncia.",
|
|
7319
7889
|
network: "Entidade de fogo no servidor por pr\xE9dio, com estado de espalhar."
|
|
7320
7890
|
},
|
|
7891
|
+
rain_and_puddles: {
|
|
7892
|
+
name: "Chuva, respingos e po\xE7as",
|
|
7893
|
+
short: "Gotas com vento, respingos e an\xE9is s\xF3 perto da c\xE2mera, rel\xE2mpago no temporal.",
|
|
7894
|
+
cost: "\u2264 4.000 gotas",
|
|
7895
|
+
costNote: "respingo at\xE9 12 m",
|
|
7896
|
+
paramLabel: "Intensidade",
|
|
7897
|
+
when: "Clima do mundo. Chuva aumenta o ru\xEDdo de fundo e mascara passos (d\xE1 para usar na furtividade).",
|
|
7898
|
+
look: "Garoa fina quase vertical. Chuva com respingos no asfalto e an\xE9is nas po\xE7as, que ficam escuras e espelhadas. Temporal com gotas inclinadas pelo vento, cortinas de \xE1gua passando e rel\xE2mpago duplo que clareia a cena por 0,2 s e revela a horda.",
|
|
7899
|
+
budget: "At\xE9 4.000 gotas presas \xE0 c\xE2mera numa caixa de 30 m. Respingos e an\xE9is s\xF3 a menos de 12 m e s\xF3 em cima do que a c\xE2mera v\xEA.",
|
|
7900
|
+
network: "O servidor manda o clima e a semente do rel\xE2mpago, para todos verem o mesmo clar\xE3o."
|
|
7901
|
+
},
|
|
7902
|
+
fog_and_ash: {
|
|
7903
|
+
name: "Neblina e cinzas",
|
|
7904
|
+
short: "N\xE9voa rasteira em camadas, cinza caindo e o poste com cone de luz.",
|
|
7905
|
+
cost: "\u2264 120 sprites",
|
|
7906
|
+
costNote: "1 cone de luz",
|
|
7907
|
+
when: "Madrugada, perto de rio e em zonas queimadas (cinza). Reduz a vis\xE3o dos zumbis e do jogador.",
|
|
7908
|
+
look: "Neblina do motor mais uma camada de n\xE9voa baixa que se move devagar, cinza fina caindo em espiral e o feixe dos postes vis\xEDvel. Silhuetas de zumbis aparecem antes dos detalhes.",
|
|
7909
|
+
budget: "At\xE9 60 sprites grandes de n\xE9voa (meia resolu\xE7\xE3o) e 60 de cinza. O cone do poste \xE9 uma malha aditiva, n\xE3o luz volum\xE9trica real.",
|
|
7910
|
+
network: "Clima vem do servidor. Densidade \xE9 local por zona."
|
|
7911
|
+
},
|
|
7321
7912
|
scraping_sparks: {
|
|
7322
7913
|
name: "Fa\xEDscas de raspagem",
|
|
7323
7914
|
short: "Para-choque arrastando no asfalto: rio de fa\xEDscas que quicam e marca no ch\xE3o.",
|
|
@@ -7369,6 +7960,16 @@ var GameVfxThree = (() => {
|
|
|
7369
7960
|
budget: "S\xF3 textura: uma m\xE1scara de rachadura com 4 est\xE1gios e um decal de sangue no vidro. P\xF3 de vidro: 6 part\xEDculas por golpe.",
|
|
7370
7961
|
network: "O servidor manda a vida do vidro. Sangue no vidro \xE9 local."
|
|
7371
7962
|
},
|
|
7963
|
+
headlights_in_rain: {
|
|
7964
|
+
name: "Far\xF3is na chuva",
|
|
7965
|
+
short: "Feixe vis\xEDvel, gotas acesas dentro do cone e a horda entrando na luz.",
|
|
7966
|
+
cost: "\u2264 600 gotas acesas",
|
|
7967
|
+
costNote: "2 spots sem sombra",
|
|
7968
|
+
when: "Far\xF3is ligados \xE0 noite, com chuva ou neblina.",
|
|
7969
|
+
look: "Dois cones de luz vis\xEDveis no ar, gotas de chuva que brilham s\xF3 dentro do feixe e silhuetas de zumbi que acendem quando entram na luz. Fora do cone, a chuva quase some.",
|
|
7970
|
+
budget: "2 spotlights sem sombra, 2 cones aditivos e at\xE9 600 gotas extras s\xF3 dentro do cone. Far\xF3is de carros a mais de 40 m ficam s\xF3 como cone, sem luz real.",
|
|
7971
|
+
network: "Estado do farol j\xE1 \xE9 replicado com o carro."
|
|
7972
|
+
},
|
|
7372
7973
|
damage_and_bite: {
|
|
7373
7974
|
name: "Dano e mordida",
|
|
7374
7975
|
short: "Borda vermelha do lado do golpe, sangue na lente e o pulso da mordida.",
|
|
@@ -7559,11 +8160,11 @@ void main(){
|
|
|
7559
8160
|
geometry.setAttribute("aC", attributes[2]);
|
|
7560
8161
|
geometry.instanceCount = 0;
|
|
7561
8162
|
const material = new THREE.ShaderMaterial({ uniforms, vertexShader: PUFF_VERTEX, fragmentShader: PUFF_FRAGMENT });
|
|
7562
|
-
const
|
|
7563
|
-
|
|
7564
|
-
|
|
8163
|
+
const mesh2 = new THREE.Mesh(geometry, material);
|
|
8164
|
+
mesh2.name = "vfx-puffs";
|
|
8165
|
+
mesh2.frustumCulled = false;
|
|
7565
8166
|
return {
|
|
7566
|
-
mesh,
|
|
8167
|
+
mesh: mesh2,
|
|
7567
8168
|
sync() {
|
|
7568
8169
|
let n = 0;
|
|
7569
8170
|
for (const p of pool.items) {
|
|
@@ -7604,12 +8205,12 @@ void main(){
|
|
|
7604
8205
|
geometry.setAttribute("aE", attributes[2]);
|
|
7605
8206
|
geometry.instanceCount = 0;
|
|
7606
8207
|
const material = new THREE.ShaderMaterial({ transparent: true, depthWrite: false, blending: THREE.AdditiveBlending, vertexShader: SPARK_VERTEX, fragmentShader: SPARK_FRAGMENT });
|
|
7607
|
-
const
|
|
7608
|
-
|
|
7609
|
-
|
|
7610
|
-
|
|
8208
|
+
const mesh2 = new THREE.Mesh(geometry, material);
|
|
8209
|
+
mesh2.name = "vfx-sparks";
|
|
8210
|
+
mesh2.frustumCulled = false;
|
|
8211
|
+
mesh2.renderOrder = 5;
|
|
7611
8212
|
return {
|
|
7612
|
-
mesh,
|
|
8213
|
+
mesh: mesh2,
|
|
7613
8214
|
sync() {
|
|
7614
8215
|
let n = 0;
|
|
7615
8216
|
for (const s of pool.items) {
|
|
@@ -7647,12 +8248,12 @@ void main(){
|
|
|
7647
8248
|
geometry.setAttribute("aC", attributes[1]);
|
|
7648
8249
|
geometry.instanceCount = 0;
|
|
7649
8250
|
const material = new THREE.ShaderMaterial({ transparent: true, depthWrite: false, blending: THREE.AdditiveBlending, vertexShader: GLOW_VERTEX, fragmentShader: GLOW_FRAGMENT });
|
|
7650
|
-
const
|
|
7651
|
-
|
|
7652
|
-
|
|
7653
|
-
|
|
8251
|
+
const mesh2 = new THREE.Mesh(geometry, material);
|
|
8252
|
+
mesh2.name = "vfx-glows";
|
|
8253
|
+
mesh2.frustumCulled = false;
|
|
8254
|
+
mesh2.renderOrder = 6;
|
|
7654
8255
|
return {
|
|
7655
|
-
mesh,
|
|
8256
|
+
mesh: mesh2,
|
|
7656
8257
|
sync() {
|
|
7657
8258
|
let n = 0;
|
|
7658
8259
|
for (const g of pool.items) {
|
|
@@ -7681,14 +8282,14 @@ void main(){
|
|
|
7681
8282
|
const rockMaterial = new THREE.MeshStandardMaterial({ color: 16777215, roughness: 0.85, flatShading: true });
|
|
7682
8283
|
const plateMaterial = rockMaterial.clone();
|
|
7683
8284
|
const make = (geometry, material) => {
|
|
7684
|
-
const
|
|
7685
|
-
|
|
7686
|
-
|
|
7687
|
-
|
|
7688
|
-
|
|
7689
|
-
|
|
7690
|
-
|
|
7691
|
-
return
|
|
8285
|
+
const mesh2 = new THREE.InstancedMesh(geometry, material, capacity);
|
|
8286
|
+
mesh2.instanceMatrix.setUsage(THREE.DynamicDrawUsage);
|
|
8287
|
+
mesh2.castShadow = true;
|
|
8288
|
+
mesh2.receiveShadow = true;
|
|
8289
|
+
mesh2.frustumCulled = false;
|
|
8290
|
+
mesh2.count = 0;
|
|
8291
|
+
mesh2.setColorAt(0, new THREE.Color(1, 1, 1));
|
|
8292
|
+
return mesh2;
|
|
7692
8293
|
};
|
|
7693
8294
|
const rocks = make(shapes.rock, rockMaterial);
|
|
7694
8295
|
const plates = make(shapes.plate, plateMaterial);
|
|
@@ -7707,20 +8308,20 @@ void main(){
|
|
|
7707
8308
|
euler.set(chunk.rx, chunk.ry, chunk.rz);
|
|
7708
8309
|
quaternion.setFromEuler(euler);
|
|
7709
8310
|
matrix.compose(position.set(chunk.x, chunk.y, chunk.z), quaternion, scale.set(chunk.sx, chunk.sy, chunk.sz));
|
|
7710
|
-
const
|
|
8311
|
+
const mesh2 = chunk.plate ? plates : rocks;
|
|
7711
8312
|
const index = chunk.plate ? plateCount++ : rockCount++;
|
|
7712
|
-
|
|
8313
|
+
mesh2.setMatrixAt(index, matrix);
|
|
7713
8314
|
const color = colorOf(chunk);
|
|
7714
|
-
const colors =
|
|
8315
|
+
const colors = mesh2.instanceColor.array;
|
|
7715
8316
|
colors[index * 3] = color[0];
|
|
7716
8317
|
colors[index * 3 + 1] = color[1];
|
|
7717
8318
|
colors[index * 3 + 2] = color[2];
|
|
7718
8319
|
}
|
|
7719
8320
|
rocks.count = rockCount;
|
|
7720
8321
|
plates.count = plateCount;
|
|
7721
|
-
for (const
|
|
7722
|
-
|
|
7723
|
-
|
|
8322
|
+
for (const mesh2 of [rocks, plates]) {
|
|
8323
|
+
mesh2.instanceMatrix.needsUpdate = true;
|
|
8324
|
+
mesh2.instanceColor.needsUpdate = true;
|
|
7724
8325
|
}
|
|
7725
8326
|
return rockCount + plateCount;
|
|
7726
8327
|
},
|
|
@@ -7910,28 +8511,28 @@ void main(){
|
|
|
7910
8511
|
position.setXYZ(index, worldX, (options.ground?.heightAt(worldX, worldZ) ?? 0) + mark.lift, worldZ);
|
|
7911
8512
|
}
|
|
7912
8513
|
geometry.computeVertexNormals();
|
|
7913
|
-
const
|
|
7914
|
-
|
|
7915
|
-
return
|
|
8514
|
+
const mesh2 = new THREE.Mesh(geometry, material);
|
|
8515
|
+
mesh2.receiveShadow = true;
|
|
8516
|
+
return mesh2;
|
|
7916
8517
|
}
|
|
7917
8518
|
function addRock(mark) {
|
|
7918
|
-
const
|
|
7919
|
-
|
|
7920
|
-
|
|
7921
|
-
|
|
7922
|
-
|
|
7923
|
-
|
|
7924
|
-
return
|
|
8519
|
+
const mesh2 = new THREE.Mesh(mark.plate ? options.plateGeometry : options.rockGeometry, rockMaterial(mark.color));
|
|
8520
|
+
mesh2.position.set(mark.x, mark.y, mark.z);
|
|
8521
|
+
mesh2.scale.set(mark.scale[0], mark.scale[1], mark.scale[2]);
|
|
8522
|
+
mesh2.rotation.set(mark.rotation[0], mark.rotation[1], mark.rotation[2]);
|
|
8523
|
+
mesh2.castShadow = true;
|
|
8524
|
+
mesh2.receiveShadow = true;
|
|
8525
|
+
return mesh2;
|
|
7925
8526
|
}
|
|
7926
8527
|
function addBlood(mark) {
|
|
7927
|
-
const
|
|
7928
|
-
|
|
7929
|
-
|
|
7930
|
-
|
|
7931
|
-
|
|
7932
|
-
|
|
7933
|
-
blood.push({ mesh, scaleX: mark.scaleX, scaleZ: mark.scaleZ, age: 0 });
|
|
7934
|
-
return
|
|
8528
|
+
const mesh2 = new THREE.Mesh(bloodGeometry, bloodMaterial);
|
|
8529
|
+
mesh2.position.set(mark.x, mark.y, mark.z);
|
|
8530
|
+
mesh2.scale.set(mark.scaleX, 1, mark.scaleZ);
|
|
8531
|
+
mesh2.rotation.y = mark.rotation;
|
|
8532
|
+
mesh2.receiveShadow = true;
|
|
8533
|
+
mesh2.scale.multiplyScalar(0.05);
|
|
8534
|
+
blood.push({ mesh: mesh2, scaleX: mark.scaleX, scaleZ: mark.scaleZ, age: 0 });
|
|
8535
|
+
return mesh2;
|
|
7935
8536
|
}
|
|
7936
8537
|
function build(mark) {
|
|
7937
8538
|
if (mark.kind === "scorch") return conform(mark, scorchMaterials[mark.variant]);
|
|
@@ -8153,6 +8754,75 @@ void main() {
|
|
|
8153
8754
|
};
|
|
8154
8755
|
}
|
|
8155
8756
|
|
|
8757
|
+
// src/mesh-layer.ts
|
|
8758
|
+
var SPHERE_DEFAULT_WIDTH = 8;
|
|
8759
|
+
var SPHERE_DEFAULT_HEIGHT = 6;
|
|
8760
|
+
function geometryOf(THREE, particle) {
|
|
8761
|
+
switch (particle.shape) {
|
|
8762
|
+
case "cone":
|
|
8763
|
+
return new THREE.ConeGeometry(particle.radius, particle.height, particle.segments || void 0, particle.segments2 || 1, false);
|
|
8764
|
+
case "cone_open":
|
|
8765
|
+
return new THREE.ConeGeometry(particle.radius, particle.height, particle.segments || void 0, particle.segments2 || 1, true);
|
|
8766
|
+
case "sphere":
|
|
8767
|
+
return new THREE.SphereGeometry(particle.radius, particle.segments || SPHERE_DEFAULT_WIDTH, particle.segments2 || SPHERE_DEFAULT_HEIGHT);
|
|
8768
|
+
case "icosahedron":
|
|
8769
|
+
return new THREE.IcosahedronGeometry(particle.radius, particle.segments);
|
|
8770
|
+
}
|
|
8771
|
+
}
|
|
8772
|
+
function materialOf(THREE, particle) {
|
|
8773
|
+
if (particle.lit) return new THREE.MeshStandardMaterial({ color: particle.color, roughness: 1, metalness: 0, transparent: true, opacity: particle.opacity, depthWrite: false });
|
|
8774
|
+
return new THREE.MeshBasicMaterial({ color: particle.color, transparent: true, opacity: particle.opacity, depthWrite: false, ...particle.additive ? { blending: THREE.AdditiveBlending } : {} });
|
|
8775
|
+
}
|
|
8776
|
+
function createMeshLayer(THREE, pool) {
|
|
8777
|
+
const group = new THREE.Group();
|
|
8778
|
+
group.name = "workshop-meshes";
|
|
8779
|
+
const drawn = /* @__PURE__ */ new Map();
|
|
8780
|
+
const frame = new THREE.Quaternion();
|
|
8781
|
+
const euler = new THREE.Euler();
|
|
8782
|
+
const turn = new THREE.Quaternion();
|
|
8783
|
+
const offset = new THREE.Vector3();
|
|
8784
|
+
function release(mesh2) {
|
|
8785
|
+
mesh2.removeFromParent();
|
|
8786
|
+
mesh2.geometry.dispose();
|
|
8787
|
+
mesh2.material.dispose();
|
|
8788
|
+
}
|
|
8789
|
+
return {
|
|
8790
|
+
group,
|
|
8791
|
+
sync() {
|
|
8792
|
+
const live = /* @__PURE__ */ new Set();
|
|
8793
|
+
for (const particle of pool.particles) {
|
|
8794
|
+
live.add(particle.id);
|
|
8795
|
+
let mesh2 = drawn.get(particle.id);
|
|
8796
|
+
if (!mesh2) {
|
|
8797
|
+
mesh2 = new THREE.Mesh(geometryOf(THREE, particle), materialOf(THREE, particle));
|
|
8798
|
+
mesh2.frustumCulled = false;
|
|
8799
|
+
mesh2.renderOrder = particle.additive ? 5 : 3;
|
|
8800
|
+
drawn.set(particle.id, mesh2);
|
|
8801
|
+
group.add(mesh2);
|
|
8802
|
+
}
|
|
8803
|
+
frame.set(particle.frame[0], particle.frame[1], particle.frame[2], particle.frame[3]);
|
|
8804
|
+
offset.set(particle.at[0], particle.at[1], particle.at[2]).multiplyScalar(particle.scale).applyQuaternion(frame);
|
|
8805
|
+
mesh2.position.set(particle.x + offset.x, particle.y + offset.y, particle.z + offset.z);
|
|
8806
|
+
turn.setFromEuler(euler.set(particle.rx, particle.ry, particle.rz));
|
|
8807
|
+
mesh2.quaternion.copy(frame).multiply(turn);
|
|
8808
|
+
mesh2.scale.setScalar(particle.scale);
|
|
8809
|
+
mesh2.material.opacity = particle.opacity;
|
|
8810
|
+
}
|
|
8811
|
+
for (const [id, mesh2] of drawn) {
|
|
8812
|
+
if (live.has(id)) continue;
|
|
8813
|
+
release(mesh2);
|
|
8814
|
+
drawn.delete(id);
|
|
8815
|
+
}
|
|
8816
|
+
return pool.count;
|
|
8817
|
+
},
|
|
8818
|
+
dispose() {
|
|
8819
|
+
for (const mesh2 of drawn.values()) release(mesh2);
|
|
8820
|
+
drawn.clear();
|
|
8821
|
+
group.removeFromParent();
|
|
8822
|
+
}
|
|
8823
|
+
};
|
|
8824
|
+
}
|
|
8825
|
+
|
|
8156
8826
|
// src/shaders/workshop-sprite.ts
|
|
8157
8827
|
var WORKSHOP_SPRITE_VERTEX = `attribute float size;attribute float alpha;attribute vec3 pcol;varying vec3 vC;varying float vA;uniform float uScale;
|
|
8158
8828
|
void main(){vC=pcol;vA=alpha;vec4 mv=modelViewMatrix*vec4(position,1.);gl_PointSize=clamp(size*uScale/-mv.z,1.,512.);gl_Position=projectionMatrix*mv;}`;
|
|
@@ -8231,13 +8901,37 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8231
8901
|
}
|
|
8232
8902
|
};
|
|
8233
8903
|
}
|
|
8904
|
+
function rainLayer(THREE, rain) {
|
|
8905
|
+
const geometry = new THREE.BufferGeometry();
|
|
8906
|
+
const position = new THREE.BufferAttribute(rain.positions, 3).setUsage(THREE.DynamicDrawUsage);
|
|
8907
|
+
geometry.setAttribute("position", position);
|
|
8908
|
+
geometry.setDrawRange(0, 0);
|
|
8909
|
+
const material = new THREE.LineBasicMaterial({ color: 10466255, transparent: true, opacity: 0.35, depthWrite: false });
|
|
8910
|
+
const lines = new THREE.LineSegments(geometry, material);
|
|
8911
|
+
lines.frustumCulled = false;
|
|
8912
|
+
lines.name = "workshop-rain";
|
|
8913
|
+
return {
|
|
8914
|
+
object: lines,
|
|
8915
|
+
sync() {
|
|
8916
|
+
const drawn = rain.on && rain.count > 0;
|
|
8917
|
+
lines.visible = drawn;
|
|
8918
|
+
geometry.setDrawRange(0, drawn ? rain.count * 2 : 0);
|
|
8919
|
+
position.needsUpdate = true;
|
|
8920
|
+
return drawn;
|
|
8921
|
+
},
|
|
8922
|
+
dispose() {
|
|
8923
|
+
geometry.dispose();
|
|
8924
|
+
material.dispose();
|
|
8925
|
+
}
|
|
8926
|
+
};
|
|
8927
|
+
}
|
|
8234
8928
|
function debrisLayer(THREE, pool) {
|
|
8235
8929
|
const geometry = new THREE.BoxGeometry(1, 1, 1);
|
|
8236
8930
|
const material = new THREE.MeshStandardMaterial({ color: 16777215, roughness: 0.45, metalness: 0.25, flatShading: true });
|
|
8237
|
-
const
|
|
8238
|
-
|
|
8239
|
-
|
|
8240
|
-
|
|
8931
|
+
const mesh2 = new THREE.InstancedMesh(geometry, material, DEBRIS_CAPACITY);
|
|
8932
|
+
mesh2.instanceMatrix.setUsage(THREE.DynamicDrawUsage);
|
|
8933
|
+
mesh2.frustumCulled = false;
|
|
8934
|
+
mesh2.name = "workshop-debris";
|
|
8241
8935
|
const euler = new THREE.Euler();
|
|
8242
8936
|
const quaternion = new THREE.Quaternion();
|
|
8243
8937
|
const position = new THREE.Vector3();
|
|
@@ -8245,16 +8939,16 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8245
8939
|
const matrix = new THREE.Matrix4();
|
|
8246
8940
|
const colour = new THREE.Color();
|
|
8247
8941
|
const hidden = new THREE.Matrix4().makeScale(0, 0, 0);
|
|
8248
|
-
for (let index = 0; index < DEBRIS_CAPACITY; index++)
|
|
8249
|
-
|
|
8942
|
+
for (let index = 0; index < DEBRIS_CAPACITY; index++) mesh2.setMatrixAt(index, hidden);
|
|
8943
|
+
mesh2.setColorAt(0, colour.setHex(16777215));
|
|
8250
8944
|
return {
|
|
8251
|
-
object:
|
|
8945
|
+
object: mesh2,
|
|
8252
8946
|
sync() {
|
|
8253
8947
|
let drawn = false;
|
|
8254
8948
|
for (let index = 0; index < DEBRIS_CAPACITY; index++) {
|
|
8255
8949
|
const piece = pool.pieces[index];
|
|
8256
8950
|
if (!piece.on) {
|
|
8257
|
-
|
|
8951
|
+
mesh2.setMatrixAt(index, hidden);
|
|
8258
8952
|
continue;
|
|
8259
8953
|
}
|
|
8260
8954
|
drawn = true;
|
|
@@ -8262,11 +8956,11 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8262
8956
|
euler.set(piece.rx, piece.ry, piece.rz);
|
|
8263
8957
|
quaternion.setFromEuler(euler);
|
|
8264
8958
|
matrix.compose(position.set(piece.x, piece.y, piece.z), quaternion, scale.set(piece.sx * shrink, piece.sy * shrink, piece.sz * shrink));
|
|
8265
|
-
|
|
8266
|
-
|
|
8959
|
+
mesh2.setMatrixAt(index, matrix);
|
|
8960
|
+
mesh2.setColorAt(index, colour.setHex(piece.color));
|
|
8267
8961
|
}
|
|
8268
|
-
|
|
8269
|
-
if (
|
|
8962
|
+
mesh2.instanceMatrix.needsUpdate = true;
|
|
8963
|
+
if (mesh2.instanceColor) mesh2.instanceColor.needsUpdate = true;
|
|
8270
8964
|
return drawn;
|
|
8271
8965
|
},
|
|
8272
8966
|
dispose() {
|
|
@@ -8323,11 +9017,11 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8323
9017
|
const dryMesh = new THREE.InstancedMesh(geometry, dry, DECAL_CAPACITY);
|
|
8324
9018
|
const group = new THREE.Group();
|
|
8325
9019
|
group.name = "workshop-decals";
|
|
8326
|
-
for (const
|
|
8327
|
-
|
|
8328
|
-
|
|
8329
|
-
|
|
8330
|
-
group.add(
|
|
9020
|
+
for (const mesh2 of [wetMesh, dryMesh]) {
|
|
9021
|
+
mesh2.frustumCulled = false;
|
|
9022
|
+
mesh2.renderOrder = 1;
|
|
9023
|
+
mesh2.instanceMatrix.setUsage(THREE.DynamicDrawUsage);
|
|
9024
|
+
group.add(mesh2);
|
|
8331
9025
|
}
|
|
8332
9026
|
const hidden = new THREE.Matrix4().makeScale(0, 0, 0);
|
|
8333
9027
|
const colour = new THREE.Color();
|
|
@@ -8364,13 +9058,13 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8364
9058
|
quaternion.multiply(turn.setFromAxisAngle(forward, index * 2.399963));
|
|
8365
9059
|
const offset = 4e-3 + index % 40 * 4e-4;
|
|
8366
9060
|
matrix.compose(position.set(decal2.x + normal.x * offset, decal2.y + normal.y * offset, decal2.z + normal.z * offset), quaternion, scale.set(look.sx, look.sy, 1));
|
|
8367
|
-
const
|
|
8368
|
-
|
|
8369
|
-
|
|
9061
|
+
const mesh2 = look.dried ? dryMesh : wetMesh;
|
|
9062
|
+
mesh2.setMatrixAt(index, matrix);
|
|
9063
|
+
mesh2.setColorAt(index, colour);
|
|
8370
9064
|
}
|
|
8371
|
-
for (const
|
|
8372
|
-
|
|
8373
|
-
if (
|
|
9065
|
+
for (const mesh2 of [wetMesh, dryMesh]) {
|
|
9066
|
+
mesh2.instanceMatrix.needsUpdate = true;
|
|
9067
|
+
if (mesh2.instanceColor) mesh2.instanceColor.needsUpdate = true;
|
|
8374
9068
|
}
|
|
8375
9069
|
return drawn;
|
|
8376
9070
|
},
|
|
@@ -8384,10 +9078,10 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8384
9078
|
function ringLayer(THREE, pool) {
|
|
8385
9079
|
const geometry = new THREE.RingGeometry(0.86, 1, 40);
|
|
8386
9080
|
const material = new THREE.MeshBasicMaterial({ color: 16777215, transparent: true, blending: THREE.AdditiveBlending, depthWrite: false, side: THREE.DoubleSide });
|
|
8387
|
-
const
|
|
8388
|
-
|
|
8389
|
-
|
|
8390
|
-
|
|
9081
|
+
const mesh2 = new THREE.InstancedMesh(geometry, material, RING_CAPACITY3);
|
|
9082
|
+
mesh2.frustumCulled = false;
|
|
9083
|
+
mesh2.instanceMatrix.setUsage(THREE.DynamicDrawUsage);
|
|
9084
|
+
mesh2.name = "workshop-rings";
|
|
8391
9085
|
const hidden = new THREE.Matrix4().makeScale(0, 0, 0);
|
|
8392
9086
|
const colour = new THREE.Color();
|
|
8393
9087
|
const normal = new THREE.Vector3();
|
|
@@ -8396,16 +9090,16 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8396
9090
|
const position = new THREE.Vector3();
|
|
8397
9091
|
const scale = new THREE.Vector3();
|
|
8398
9092
|
const matrix = new THREE.Matrix4();
|
|
8399
|
-
|
|
8400
|
-
for (let index = 0; index < RING_CAPACITY3; index++)
|
|
9093
|
+
mesh2.setColorAt(0, colour.setHex(0));
|
|
9094
|
+
for (let index = 0; index < RING_CAPACITY3; index++) mesh2.setMatrixAt(index, hidden);
|
|
8401
9095
|
return {
|
|
8402
|
-
object:
|
|
9096
|
+
object: mesh2,
|
|
8403
9097
|
sync() {
|
|
8404
9098
|
let drawn = false;
|
|
8405
9099
|
for (let index = 0; index < RING_CAPACITY3; index++) {
|
|
8406
9100
|
const ring2 = pool.rings[index];
|
|
8407
9101
|
if (!ring2.on) {
|
|
8408
|
-
|
|
9102
|
+
mesh2.setMatrixAt(index, hidden);
|
|
8409
9103
|
continue;
|
|
8410
9104
|
}
|
|
8411
9105
|
drawn = true;
|
|
@@ -8413,11 +9107,11 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8413
9107
|
const radius = ring2.from + (ring2.to - ring2.from) * (1 - Math.pow(1 - k, 2));
|
|
8414
9108
|
quaternion.setFromUnitVectors(forward, normal.set(ring2.normal[0], ring2.normal[1], ring2.normal[2]));
|
|
8415
9109
|
matrix.compose(position.set(ring2.point[0], ring2.point[1], ring2.point[2]), quaternion, scale.set(radius, radius, 1));
|
|
8416
|
-
|
|
8417
|
-
|
|
9110
|
+
mesh2.setMatrixAt(index, matrix);
|
|
9111
|
+
mesh2.setColorAt(index, colour.setHex(ring2.color).multiplyScalar(ring2.hold ? ring2.hold : 1 - k));
|
|
8418
9112
|
}
|
|
8419
|
-
|
|
8420
|
-
if (
|
|
9113
|
+
mesh2.instanceMatrix.needsUpdate = true;
|
|
9114
|
+
if (mesh2.instanceColor) mesh2.instanceColor.needsUpdate = true;
|
|
8421
9115
|
return drawn;
|
|
8422
9116
|
},
|
|
8423
9117
|
dispose() {
|
|
@@ -8433,11 +9127,14 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8433
9127
|
spriteLayer(THREE, engine.add, true, 1, pointScale),
|
|
8434
9128
|
spriteLayer(THREE, engine.normal, false, 0.55, pointScale),
|
|
8435
9129
|
streakLayer(THREE, engine.streaks),
|
|
9130
|
+
rainLayer(THREE, engine.rain),
|
|
8436
9131
|
debrisLayer(THREE, engine.debris),
|
|
8437
9132
|
decalLayer(THREE, engine.decals),
|
|
8438
9133
|
ringLayer(THREE, engine.rings)
|
|
8439
9134
|
];
|
|
8440
9135
|
for (const layer2 of layers) group.add(layer2.object);
|
|
9136
|
+
const meshes = createMeshLayer(THREE, engine.meshes);
|
|
9137
|
+
group.add(meshes.group);
|
|
8441
9138
|
const flashLights = engine.lights.lights.map(() => new THREE.PointLight(16760944, 0, 14));
|
|
8442
9139
|
const fireLights = engine.lights.fire.map(() => new THREE.PointLight(FIRE_LIGHT_COLOR, 0, FIRE_LIGHT_DISTANCE));
|
|
8443
9140
|
for (const light of [...flashLights, ...fireLights]) group.add(light);
|
|
@@ -8446,6 +9143,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8446
9143
|
sync() {
|
|
8447
9144
|
let drawCalls = 0;
|
|
8448
9145
|
for (const layer2 of layers) if (layer2.sync()) drawCalls++;
|
|
9146
|
+
drawCalls += meshes.sync();
|
|
8449
9147
|
engine.lights.lights.forEach((source, index) => {
|
|
8450
9148
|
const light = flashLights[index];
|
|
8451
9149
|
light.position.set(source.x, source.y, source.z);
|
|
@@ -8462,6 +9160,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8462
9160
|
},
|
|
8463
9161
|
dispose() {
|
|
8464
9162
|
for (const layer2 of layers) layer2.dispose();
|
|
9163
|
+
meshes.dispose();
|
|
8465
9164
|
group.clear();
|
|
8466
9165
|
}
|
|
8467
9166
|
};
|
|
@@ -8580,8 +9279,10 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8580
9279
|
return world.play(request.effect, request.point, {
|
|
8581
9280
|
...request.direction ? { direction: request.direction } : {},
|
|
8582
9281
|
...request.normal ? { normal: request.normal } : {},
|
|
9282
|
+
...request.orientation ? { orientation: request.orientation } : {},
|
|
8583
9283
|
...request.seed !== void 0 ? { seed: request.seed } : {},
|
|
8584
|
-
...request.param !== void 0 ? { param: request.param } : {}
|
|
9284
|
+
...request.param !== void 0 ? { param: request.param } : {},
|
|
9285
|
+
...request.values ? { values: request.values } : {}
|
|
8585
9286
|
});
|
|
8586
9287
|
},
|
|
8587
9288
|
stop: (handle) => world.stop(handle),
|
|
@@ -9002,8 +9703,8 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
9002
9703
|
const uv = geometry.attributes.uv;
|
|
9003
9704
|
for (let index = 0; index < position.count; index++) uv.setXY(index, position.getX(index) / metres, position.getZ(index) / metres);
|
|
9004
9705
|
const material = options.material ?? new THREE.MeshStandardMaterial({ color: 2829359, roughness: 0.93, flatShading: true });
|
|
9005
|
-
const
|
|
9006
|
-
|
|
9706
|
+
const mesh2 = new THREE.Mesh(geometry, material);
|
|
9707
|
+
mesh2.receiveShadow = true;
|
|
9007
9708
|
let version = -1;
|
|
9008
9709
|
function sync() {
|
|
9009
9710
|
if (field.version === version) return false;
|
|
@@ -9014,7 +9715,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
9014
9715
|
return true;
|
|
9015
9716
|
}
|
|
9016
9717
|
return {
|
|
9017
|
-
mesh,
|
|
9718
|
+
mesh: mesh2,
|
|
9018
9719
|
sync,
|
|
9019
9720
|
dispose() {
|
|
9020
9721
|
geometry.dispose();
|