@adatechnology/game-fluids-three 0.2.3 → 0.3.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/dist/index.d.ts +14 -0
- package/dist/index.global.js +918 -233
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +29 -2
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.global.js
CHANGED
|
@@ -1364,77 +1364,77 @@ var GameFluidsThree = (() => {
|
|
|
1364
1364
|
}));
|
|
1365
1365
|
}
|
|
1366
1366
|
function spawnPuff(pool, random, init) {
|
|
1367
|
-
const
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
return
|
|
1397
|
-
}
|
|
1398
|
-
function ageOrKeep2(
|
|
1399
|
-
|
|
1400
|
-
return
|
|
1401
|
-
}
|
|
1402
|
-
function moveOnRing(
|
|
1367
|
+
const puff3 = pool.acquire();
|
|
1368
|
+
puff3.x = init.x ?? 0;
|
|
1369
|
+
puff3.y = init.y ?? 0;
|
|
1370
|
+
puff3.z = init.z ?? 0;
|
|
1371
|
+
puff3.vx = init.vx ?? 0;
|
|
1372
|
+
puff3.vy = init.vy ?? 0;
|
|
1373
|
+
puff3.vz = init.vz ?? 0;
|
|
1374
|
+
puff3.s0 = init.s0 ?? 0.2;
|
|
1375
|
+
puff3.s1 = init.s1 ?? 1;
|
|
1376
|
+
puff3.sg = init.sg ?? 0.1;
|
|
1377
|
+
puff3.gk = init.gk ?? 6;
|
|
1378
|
+
puff3.life = init.life ?? 3;
|
|
1379
|
+
puff3.t = 0;
|
|
1380
|
+
puff3.h0 = init.h0 ?? 0;
|
|
1381
|
+
puff3.hl = init.hl ?? 0.4;
|
|
1382
|
+
puff3.drag = init.drag ?? 3;
|
|
1383
|
+
puff3.buoy = init.buoy ?? 0.5;
|
|
1384
|
+
puff3.grav = init.grav ?? 0;
|
|
1385
|
+
puff3.kind = init.kind ?? 0;
|
|
1386
|
+
puff3.seed = random.next();
|
|
1387
|
+
puff3.wind = init.wind ?? 1;
|
|
1388
|
+
puff3.color = init.color ?? SMOKE_COLORS.grey;
|
|
1389
|
+
puff3.ring = init.ring ?? null;
|
|
1390
|
+
puff3.ph = init.ph ?? 0;
|
|
1391
|
+
puff3.th = init.th ?? 0;
|
|
1392
|
+
puff3.rng = random;
|
|
1393
|
+
puff3.age = 0;
|
|
1394
|
+
puff3.heat = 0;
|
|
1395
|
+
puff3.size = 0;
|
|
1396
|
+
return puff3;
|
|
1397
|
+
}
|
|
1398
|
+
function ageOrKeep2(puff3, dt) {
|
|
1399
|
+
puff3.t += dt;
|
|
1400
|
+
return puff3.t < puff3.life;
|
|
1401
|
+
}
|
|
1402
|
+
function moveOnRing(puff3, ring2, wind) {
|
|
1403
1403
|
const ringTime = ring2.t;
|
|
1404
1404
|
const centerY = ring2.y0 + ring2.rise * (1 - Math.exp(-ringTime * ring2.rk));
|
|
1405
1405
|
const majorRadius = ring2.R0 + (ring2.R1 - ring2.R0) * (1 - Math.exp(-ringTime * 1.6));
|
|
1406
|
-
const theta =
|
|
1406
|
+
const theta = puff3.th + ringTime * ring2.roll;
|
|
1407
1407
|
const minorRadius = ring2.r * (0.8 + 0.4 * Math.min(1, ringTime));
|
|
1408
1408
|
const radius = majorRadius + minorRadius * Math.cos(theta);
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
}
|
|
1413
|
-
function moveFree(
|
|
1414
|
-
const damping = Math.exp(-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
if (
|
|
1423
|
-
|
|
1424
|
-
if (
|
|
1409
|
+
puff3.x = ring2.x + Math.cos(puff3.ph) * radius + wind.x * ringTime * 0.6;
|
|
1410
|
+
puff3.z = ring2.z + Math.sin(puff3.ph) * radius + wind.z * ringTime * 0.6;
|
|
1411
|
+
puff3.y = centerY + minorRadius * Math.sin(theta);
|
|
1412
|
+
}
|
|
1413
|
+
function moveFree(puff3, dt, age, heat, wind) {
|
|
1414
|
+
const damping = Math.exp(-puff3.drag * dt);
|
|
1415
|
+
puff3.vx *= damping;
|
|
1416
|
+
puff3.vy *= damping;
|
|
1417
|
+
puff3.vz *= damping;
|
|
1418
|
+
puff3.vy += (puff3.buoy * (heat > 0 ? 1.6 : 1) - puff3.grav) * dt;
|
|
1419
|
+
puff3.x += (puff3.vx + wind.x * puff3.wind * age) * dt;
|
|
1420
|
+
puff3.y += puff3.vy * dt;
|
|
1421
|
+
puff3.z += (puff3.vz + wind.z * puff3.wind * age) * dt;
|
|
1422
|
+
if (puff3.y < puff3.s0 * FLOOR_FRACTION) {
|
|
1423
|
+
puff3.y = puff3.s0 * FLOOR_FRACTION;
|
|
1424
|
+
if (puff3.vy < 0) puff3.vy *= FLOOR_BOUNCE;
|
|
1425
1425
|
}
|
|
1426
1426
|
}
|
|
1427
1427
|
function updatePuffs(pool, dt, wind) {
|
|
1428
1428
|
pool.compact(ageOrKeep2, dt);
|
|
1429
|
-
for (const
|
|
1430
|
-
const age =
|
|
1431
|
-
const heat =
|
|
1432
|
-
if (
|
|
1433
|
-
else moveFree(
|
|
1434
|
-
const size =
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1429
|
+
for (const puff3 of pool.items) {
|
|
1430
|
+
const age = puff3.t / puff3.life;
|
|
1431
|
+
const heat = puff3.h0 > 0 ? puff3.h0 * Math.pow(Math.max(0, 1 - puff3.t / puff3.hl), 1.25) : 0;
|
|
1432
|
+
if (puff3.ring) moveOnRing(puff3, puff3.ring, wind);
|
|
1433
|
+
else moveFree(puff3, dt, age, heat, wind);
|
|
1434
|
+
const size = puff3.s0 + (puff3.s1 - puff3.s0) * (1 - Math.exp(-puff3.t * puff3.gk)) + puff3.sg * Math.min(puff3.t, GROWTH_CAP_SECONDS);
|
|
1435
|
+
puff3.size = size * Math.min(1, puff3.t * ARRIVAL_FRAME + ARRIVAL_BASE);
|
|
1436
|
+
puff3.age = age;
|
|
1437
|
+
puff3.heat = heat;
|
|
1438
1438
|
}
|
|
1439
1439
|
}
|
|
1440
1440
|
var GROUND_LIFT = 0.02;
|
|
@@ -1491,9 +1491,9 @@ var GameFluidsThree = (() => {
|
|
|
1491
1491
|
var HOT_GLOW_COLOR = [1, 0.45, 0.12];
|
|
1492
1492
|
function addPuff(core, random, init) {
|
|
1493
1493
|
core.spawned.puffs++;
|
|
1494
|
-
const
|
|
1495
|
-
core.trace?.puff?.(
|
|
1496
|
-
return
|
|
1494
|
+
const puff3 = spawnPuff(core.puffs, random, init);
|
|
1495
|
+
core.trace?.puff?.(puff3);
|
|
1496
|
+
return puff3;
|
|
1497
1497
|
}
|
|
1498
1498
|
function addSpark(core, init) {
|
|
1499
1499
|
core.spawned.sparks++;
|
|
@@ -1675,6 +1675,7 @@ var GameFluidsThree = (() => {
|
|
|
1675
1675
|
var neg = call("neg");
|
|
1676
1676
|
var abs = call("abs");
|
|
1677
1677
|
var sqrt = call("sqrt");
|
|
1678
|
+
var exp = call("exp");
|
|
1678
1679
|
var sin = call("sin");
|
|
1679
1680
|
var cos = call("cos");
|
|
1680
1681
|
var atan2 = call("atan2");
|
|
@@ -1720,10 +1721,12 @@ var GameFluidsThree = (() => {
|
|
|
1720
1721
|
var INDEX = { $: "index" };
|
|
1721
1722
|
var QUALITY = { $: "quality" };
|
|
1722
1723
|
var FRESH = { $: "fresh" };
|
|
1724
|
+
var DIRECTION = { $: "direction" };
|
|
1723
1725
|
var CAMERA_POSITION = { $: "cameraPosition" };
|
|
1724
1726
|
var burst = (system, count, spawn2) => ({ op: "burst", system, count, spawn: spawn2 });
|
|
1725
1727
|
var spawn = (system, options) => ({ op: "spawn", system, spawn: options });
|
|
1726
1728
|
var emit = (key, system, rate, options) => ({ op: "emit", key, system, rate, spawn: options });
|
|
1729
|
+
var mesh = (options) => ({ op: "mesh", spawn: options });
|
|
1727
1730
|
var debris = (options) => ({ op: "debris", spawn: options });
|
|
1728
1731
|
var decal = (...args) => ({ op: "decal", args });
|
|
1729
1732
|
var ring = (...args) => ({ op: "ring", args });
|
|
@@ -2735,6 +2738,241 @@ var GameFluidsThree = (() => {
|
|
|
2735
2738
|
)
|
|
2736
2739
|
]
|
|
2737
2740
|
};
|
|
2741
|
+
var SPOTS_X = [-3, 1, 5];
|
|
2742
|
+
var SPOTS_Z = [-1, -2.4, 0.4];
|
|
2743
|
+
var FOG_AND_ASH = {
|
|
2744
|
+
id: "fog_and_ash",
|
|
2745
|
+
pageId: "neblina",
|
|
2746
|
+
team: "world",
|
|
2747
|
+
budget: { particles: 120, lights: 1 },
|
|
2748
|
+
loop: 0,
|
|
2749
|
+
view: { eye: [3, 1.8, 7.5], target: [-3, 1.2, -1] },
|
|
2750
|
+
setup: [
|
|
2751
|
+
cue("fog", { density: 0.075 }),
|
|
2752
|
+
cue("lamp_cone", { visible: true }),
|
|
2753
|
+
cue("zombie_visible", { index: -1, visible: false }),
|
|
2754
|
+
repeat(
|
|
2755
|
+
SPOTS_X.length,
|
|
2756
|
+
set("turn", rnd(-0.6, 0.6)),
|
|
2757
|
+
behavior("walkers", "place", { index: INDEX, x: pick(SPOTS_X, INDEX), z: pick(SPOTS_Z, INDEX), facing: variable("turn") })
|
|
2758
|
+
)
|
|
2759
|
+
],
|
|
2760
|
+
timeline: [],
|
|
2761
|
+
tick: [
|
|
2762
|
+
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 }),
|
|
2763
|
+
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 })
|
|
2764
|
+
]
|
|
2765
|
+
};
|
|
2766
|
+
var RAIN_CAPACITY = 4e3;
|
|
2767
|
+
var FALL_SPEED = 15;
|
|
2768
|
+
var WIND_PER_FALL = 0.07;
|
|
2769
|
+
var STREAK_SLANT = 0.04;
|
|
2770
|
+
var STREAK_LENGTH = 0.6;
|
|
2771
|
+
var BOX_X = [-15, 15];
|
|
2772
|
+
var BOX_Z = [-6, 16];
|
|
2773
|
+
var START_HEIGHT = [0, 16];
|
|
2774
|
+
var REENTRY_HEIGHT = [14, 17];
|
|
2775
|
+
var SPLASH_CHANCE = 0.35;
|
|
2776
|
+
var SPLASH_RANGE = 12;
|
|
2777
|
+
var SPRITE_CHANCE = 0.5;
|
|
2778
|
+
var UP9 = [0, 1, 0];
|
|
2779
|
+
var WORKSHOP_PUDDLES = [
|
|
2780
|
+
[-1.5, 2.2, 1.6, 0.9],
|
|
2781
|
+
[3, 3.6, 1.1, 0.7],
|
|
2782
|
+
[-6, 3.2, 1.3, 0.8],
|
|
2783
|
+
[1.4, -2.2, 0.9, 0.5]
|
|
2784
|
+
];
|
|
2785
|
+
var inPuddle = (puddles, x, z) => puddles.some((p) => ((x - p[0]) / p[2]) ** 2 + ((z - p[1]) / p[3]) ** 2 < 1);
|
|
2786
|
+
var RainField = class {
|
|
2787
|
+
constructor(engine) {
|
|
2788
|
+
__publicField2(this, "engine", engine);
|
|
2789
|
+
__publicField2(this, "positions", new Float32Array(RAIN_CAPACITY * 6));
|
|
2790
|
+
__publicField2(this, "count", 0);
|
|
2791
|
+
__publicField2(this, "wind", 1);
|
|
2792
|
+
__publicField2(this, "on", false);
|
|
2793
|
+
__publicField2(this, "centerX", 0);
|
|
2794
|
+
__publicField2(this, "centerZ", 0);
|
|
2795
|
+
__publicField2(this, "puddles", WORKSHOP_PUDDLES);
|
|
2796
|
+
__publicField2(this, "puddleAt");
|
|
2797
|
+
}
|
|
2798
|
+
/** `initRain` (W321): `count` streaks (thinned by the quality), each drawn at a random place in the box. */
|
|
2799
|
+
init(count, wind) {
|
|
2800
|
+
const { random } = this.engine;
|
|
2801
|
+
this.count = Math.min(RAIN_CAPACITY, Math.round(count * this.engine.context.quality.mult));
|
|
2802
|
+
this.wind = wind;
|
|
2803
|
+
this.on = true;
|
|
2804
|
+
for (let index = 0; index < this.count; index++) {
|
|
2805
|
+
const offset = index * 6;
|
|
2806
|
+
const x = random.between(BOX_X[0], BOX_X[1]);
|
|
2807
|
+
const y = random.between(START_HEIGHT[0], START_HEIGHT[1]);
|
|
2808
|
+
const z = random.between(BOX_Z[0], BOX_Z[1]);
|
|
2809
|
+
this.set(offset, x, y, z);
|
|
2810
|
+
}
|
|
2811
|
+
}
|
|
2812
|
+
/**
|
|
2813
|
+
* 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
|
|
2814
|
+
* starts at a random place of the box, as `init` draws it) and the wind slants them. The golden never calls it.
|
|
2815
|
+
*/
|
|
2816
|
+
drive(count, wind, centerX, centerZ) {
|
|
2817
|
+
const { random } = this.engine;
|
|
2818
|
+
const target = Math.max(0, Math.min(RAIN_CAPACITY, Math.round(count * this.engine.context.quality.mult)));
|
|
2819
|
+
this.wind = wind;
|
|
2820
|
+
this.centerX = centerX;
|
|
2821
|
+
this.centerZ = centerZ;
|
|
2822
|
+
this.on = target > 0;
|
|
2823
|
+
for (let index = this.count; index < target; index++) {
|
|
2824
|
+
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);
|
|
2825
|
+
}
|
|
2826
|
+
this.count = target;
|
|
2827
|
+
}
|
|
2828
|
+
/** `updateRain` (W322-329). `camera` is where the eye is; `splash` lets the drops that land leave a splash. */
|
|
2829
|
+
update(dt, splash, camera2) {
|
|
2830
|
+
if (!this.on) return;
|
|
2831
|
+
const { random, context } = this.engine;
|
|
2832
|
+
const positions = this.positions;
|
|
2833
|
+
const fall = FALL_SPEED * dt;
|
|
2834
|
+
const slant = this.wind * fall * WIND_PER_FALL;
|
|
2835
|
+
const reach = SPLASH_RANGE / (1 + context.quality.level);
|
|
2836
|
+
for (let index = 0; index < this.count; index++) {
|
|
2837
|
+
const o = index * 6;
|
|
2838
|
+
positions[o] += slant;
|
|
2839
|
+
positions[o + 3] += slant;
|
|
2840
|
+
positions[o + 1] -= fall;
|
|
2841
|
+
positions[o + 4] -= fall;
|
|
2842
|
+
const ground = context.groundAt(positions[o], positions[o + 2]);
|
|
2843
|
+
if (positions[o + 4] < ground) {
|
|
2844
|
+
const x = positions[o];
|
|
2845
|
+
const z = positions[o + 2];
|
|
2846
|
+
if (splash && random.next() < SPLASH_CHANCE) {
|
|
2847
|
+
const distance2 = Math.hypot(x - camera2[0], z - camera2[2]);
|
|
2848
|
+
if (distance2 < reach) {
|
|
2849
|
+
if (random.next() < SPRITE_CHANCE) {
|
|
2850
|
+
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 });
|
|
2851
|
+
}
|
|
2852
|
+
if (this.puddleAt ? this.puddleAt(x, z) : inPuddle(this.puddles, x, z)) {
|
|
2853
|
+
this.engine.ring([[x, ground + 0.012, z], 0.01, random.between(0.12, 0.25), random.between(0.4, 0.6), 6978192]);
|
|
2854
|
+
}
|
|
2855
|
+
}
|
|
2856
|
+
}
|
|
2857
|
+
const nx = random.between(BOX_X[0], BOX_X[1]) + this.centerX;
|
|
2858
|
+
const ny = random.between(REENTRY_HEIGHT[0], REENTRY_HEIGHT[1]);
|
|
2859
|
+
const nz = random.between(BOX_Z[0], BOX_Z[1]) + this.centerZ;
|
|
2860
|
+
this.set(o, nx, ny, nz);
|
|
2861
|
+
}
|
|
2862
|
+
}
|
|
2863
|
+
}
|
|
2864
|
+
/** `rain.visible = false; RN.on = false` (W440): the field stops; the streaks stay where they were. */
|
|
2865
|
+
clear() {
|
|
2866
|
+
this.on = false;
|
|
2867
|
+
}
|
|
2868
|
+
set(offset, x, y, z) {
|
|
2869
|
+
const positions = this.positions;
|
|
2870
|
+
positions[offset] = x;
|
|
2871
|
+
positions[offset + 1] = y;
|
|
2872
|
+
positions[offset + 2] = z;
|
|
2873
|
+
positions[offset + 3] = x + this.wind * STREAK_SLANT;
|
|
2874
|
+
positions[offset + 4] = y - STREAK_LENGTH;
|
|
2875
|
+
positions[offset + 5] = z;
|
|
2876
|
+
}
|
|
2877
|
+
};
|
|
2878
|
+
var DROPS = [900, 2200, 4e3];
|
|
2879
|
+
var SLANT = [0.3, 1.2, 4.5];
|
|
2880
|
+
var STORM = 2;
|
|
2881
|
+
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)));
|
|
2882
|
+
var RAIN_AND_PUDDLES = {
|
|
2883
|
+
id: "rain_and_puddles",
|
|
2884
|
+
pageId: "chuva",
|
|
2885
|
+
team: "world",
|
|
2886
|
+
params: { id: "intensity", options: ["drizzle", "rain", "storm"], default: 1 },
|
|
2887
|
+
budget: { particles: 4e3, decals: 4 },
|
|
2888
|
+
loop: 0,
|
|
2889
|
+
view: { eye: [2, 2, 7], target: [-1, 0.6, 1] },
|
|
2890
|
+
setup: [
|
|
2891
|
+
cue("lamp_cone", { visible: true }),
|
|
2892
|
+
...WORKSHOP_PUDDLES.map(([x, z, radiusX, radiusZ]) => decal(x, 0, z, radiusX * 2, 790550, { grow: 0, life: 1e6, ar: radiusZ / radiusX }))
|
|
2893
|
+
],
|
|
2894
|
+
timeline: [
|
|
2895
|
+
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])) }),
|
|
2896
|
+
set("nextStrike", rnd(2, 4)),
|
|
2897
|
+
set("flash", -1)
|
|
2898
|
+
],
|
|
2899
|
+
tick: [
|
|
2900
|
+
behavior("rain", "update", { dt: DELTA, splash: gt(PARAM, 0) }),
|
|
2901
|
+
when(eq(PARAM, STORM), [
|
|
2902
|
+
when(gt(TIME, variable("nextStrike")), [set("nextStrike", add(TIME, rnd(3.5, 6))), set("flash", 0)]),
|
|
2903
|
+
when(ge(variable("flash"), 0), [
|
|
2904
|
+
set("flash", add(variable("flash"), DELTA)),
|
|
2905
|
+
set("light", FLASH_STEPS),
|
|
2906
|
+
cue("lightning", { intensity: variable("light") }),
|
|
2907
|
+
screen({ max: { white: mul(variable("light"), 0.12) } }),
|
|
2908
|
+
when(gt(variable("flash"), 0.4), [set("flash", -1), cue("lightning", { intensity: 0 })])
|
|
2909
|
+
]),
|
|
2910
|
+
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 })
|
|
2911
|
+
])
|
|
2912
|
+
]
|
|
2913
|
+
};
|
|
2914
|
+
var CAR_ORIGIN2 = [5.6, 0, 0.8];
|
|
2915
|
+
var CAR_ROTATION2 = [0, -0.4, 0];
|
|
2916
|
+
var carPoint = (x, y, z) => localToWorld(CAR_ORIGIN2, CAR_ROTATION2, [x, y, z]);
|
|
2917
|
+
var carDirection = (from, to) => normalized([to[0] - from[0], to[1] - from[1], to[2] - from[2]]);
|
|
2918
|
+
var BEAM_FROM = carPoint(0, 0.74, 2.15);
|
|
2919
|
+
var BEAM_DIRECTION = carDirection(BEAM_FROM, carPoint(0, 0.74, 3.15));
|
|
2920
|
+
var BEAM_SIDE = [BEAM_DIRECTION[2], 0, -BEAM_DIRECTION[0]];
|
|
2921
|
+
var WALKERS = 6;
|
|
2922
|
+
var WALK_SPEED2 = 0.7;
|
|
2923
|
+
var DROPS2 = 1800;
|
|
2924
|
+
var SLANT2 = 0.8;
|
|
2925
|
+
var startWalking = [
|
|
2926
|
+
set("spot", query("car", "point", rnd(-2, 2), 0, rnd(8, 18))),
|
|
2927
|
+
set("goal", query("car", "point", rnd(-0.6, 0.6), 0, 2.6)),
|
|
2928
|
+
behavior("walkers", "place", { index: INDEX, x: pick(variable("spot"), 0), z: pick(variable("spot"), 2), facing: 0 }),
|
|
2929
|
+
behavior("walkers", "walk", { index: INDEX, to: variable("goal"), speed: WALK_SPEED2 })
|
|
2930
|
+
];
|
|
2931
|
+
var HEADLIGHTS_IN_RAIN = {
|
|
2932
|
+
id: "headlights_in_rain",
|
|
2933
|
+
pageId: "farol",
|
|
2934
|
+
team: "vehicles",
|
|
2935
|
+
budget: { particles: 600, lights: 2 },
|
|
2936
|
+
loop: 0,
|
|
2937
|
+
view: { eye: [-2.5, 2, 5.5], target: [4, 1, 6] },
|
|
2938
|
+
setup: [
|
|
2939
|
+
cue("fog", { density: 0.05 }),
|
|
2940
|
+
cue("headlights", { on: true, intensity: 2.4, color: 16773584 }),
|
|
2941
|
+
behavior("rain", "init", { count: DROPS2, wind: SLANT2 }),
|
|
2942
|
+
repeat(WALKERS, ...startWalking)
|
|
2943
|
+
],
|
|
2944
|
+
timeline: [],
|
|
2945
|
+
tick: [
|
|
2946
|
+
behavior("rain", "update", { dt: DELTA, splash: true }),
|
|
2947
|
+
emit(
|
|
2948
|
+
"lit",
|
|
2949
|
+
"streak",
|
|
2950
|
+
600,
|
|
2951
|
+
local(
|
|
2952
|
+
"depth",
|
|
2953
|
+
rnd(1, 13),
|
|
2954
|
+
local(
|
|
2955
|
+
"spread",
|
|
2956
|
+
mul(variable("depth"), 0.33, sqrt(rand())),
|
|
2957
|
+
local(
|
|
2958
|
+
"turn",
|
|
2959
|
+
rnd(0, 6.283),
|
|
2960
|
+
local("base", vadd(BEAM_FROM, vscale(BEAM_DIRECTION, variable("depth")), vscale(BEAM_SIDE, mul(cos(variable("turn")), variable("spread")))), {
|
|
2961
|
+
p: vwith(variable("base"), 1, add(vy(variable("base")), mul(sin(variable("turn")), variable("spread"), 0.6))),
|
|
2962
|
+
v: [0.8, -14, 0],
|
|
2963
|
+
sp: 0,
|
|
2964
|
+
life: 0.06,
|
|
2965
|
+
len: 0.035,
|
|
2966
|
+
c0: 13622512,
|
|
2967
|
+
a: 0.9
|
|
2968
|
+
})
|
|
2969
|
+
)
|
|
2970
|
+
)
|
|
2971
|
+
)
|
|
2972
|
+
),
|
|
2973
|
+
repeat(WALKERS, when(not(query("walkers", "is_walking", INDEX)), startWalking))
|
|
2974
|
+
]
|
|
2975
|
+
};
|
|
2738
2976
|
var YAW = -Math.PI / 2;
|
|
2739
2977
|
var COS = Math.cos(YAW);
|
|
2740
2978
|
var SIN = Math.sin(YAW);
|
|
@@ -2762,10 +3000,6 @@ var GameFluidsThree = (() => {
|
|
|
2762
3000
|
fireLight(0, [vx(variable("contact")), 0.34, vz(variable("contact"))], 1.6, mul(TIME, 3))
|
|
2763
3001
|
]
|
|
2764
3002
|
};
|
|
2765
|
-
var CAR_ORIGIN2 = [5.6, 0, 0.8];
|
|
2766
|
-
var CAR_ROTATION2 = [0, -0.4, 0];
|
|
2767
|
-
var carPoint = (x, y, z) => localToWorld(CAR_ORIGIN2, CAR_ROTATION2, [x, y, z]);
|
|
2768
|
-
var carDirection = (from, to) => normalized([to[0] - from[0], to[1] - from[1], to[2] - from[2]]);
|
|
2769
3003
|
var HOOD = carPoint(0, 1.02, 1.4);
|
|
2770
3004
|
var EXHAUST = carPoint(0.5, 0.3, -2.2);
|
|
2771
3005
|
var EXHAUST_DIRECTION = carDirection(EXHAUST, carPoint(0.5, 0.3, -3));
|
|
@@ -2799,7 +3033,7 @@ var GameFluidsThree = (() => {
|
|
|
2799
3033
|
], [fireLightOff(0)])
|
|
2800
3034
|
]
|
|
2801
3035
|
};
|
|
2802
|
-
var
|
|
3036
|
+
var UP10 = [0, 1, 0];
|
|
2803
3037
|
var doorVelocity = (side) => {
|
|
2804
3038
|
const out = carPoint(side * 4, 3, 0.3);
|
|
2805
3039
|
const centre = carPoint(0, 0, 0.3);
|
|
@@ -2809,7 +3043,7 @@ var GameFluidsThree = (() => {
|
|
|
2809
3043
|
call2("explode", vadd(query("car", "position"), [0, 0.6, 0]), 1.8, 2759188),
|
|
2810
3044
|
cue("car_burnt"),
|
|
2811
3045
|
behavior("car", "launch", { rise: 4.5, spin: 0.9 }),
|
|
2812
|
-
repeat(scaled(30), debris({ p: vadd(query("car", "position"), [0, 1.3, 0]), dir:
|
|
3046
|
+
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 })),
|
|
2813
3047
|
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 }),
|
|
2814
3048
|
...[-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 })),
|
|
2815
3049
|
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 })
|
|
@@ -2979,7 +3213,7 @@ var GameFluidsThree = (() => {
|
|
|
2979
3213
|
])
|
|
2980
3214
|
]
|
|
2981
3215
|
};
|
|
2982
|
-
var
|
|
3216
|
+
var WALKERS2 = 6;
|
|
2983
3217
|
var NEAR = 9;
|
|
2984
3218
|
var RANGE = 7;
|
|
2985
3219
|
var RESTING_BPM = 70;
|
|
@@ -2995,7 +3229,7 @@ var GameFluidsThree = (() => {
|
|
|
2995
3229
|
setup: [
|
|
2996
3230
|
cue("zombie_visible", { index: -1, visible: false }),
|
|
2997
3231
|
repeat(
|
|
2998
|
-
|
|
3232
|
+
WALKERS2,
|
|
2999
3233
|
set("startX", rnd(-4, 4)),
|
|
3000
3234
|
set("startZ", sub(rnd(-4, -2), mul(INDEX, 0.6))),
|
|
3001
3235
|
behavior("walkers", "place", { index: INDEX, x: variable("startX"), z: variable("startZ"), facing: 0 }),
|
|
@@ -3005,7 +3239,7 @@ var GameFluidsThree = (() => {
|
|
|
3005
3239
|
timeline: [],
|
|
3006
3240
|
tick: [
|
|
3007
3241
|
set("nearest", 99),
|
|
3008
|
-
repeat(
|
|
3242
|
+
repeat(WALKERS2, set("nearest", min(variable("nearest"), vdist(walkerPoint, CAMERA_POSITION)))),
|
|
3009
3243
|
set("fear", clamp(div(sub(NEAR, variable("nearest")), RANGE), 0, 1)),
|
|
3010
3244
|
set("bpm", add(RESTING_BPM, mul(BPM_RISE, variable("fear")))),
|
|
3011
3245
|
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"))) } })]),
|
|
@@ -3072,7 +3306,7 @@ var GameFluidsThree = (() => {
|
|
|
3072
3306
|
]
|
|
3073
3307
|
};
|
|
3074
3308
|
var FACING4 = [0, 0, 1];
|
|
3075
|
-
var
|
|
3309
|
+
var UP11 = [0, 1, 0];
|
|
3076
3310
|
var ORIGIN = [0, 0, 0];
|
|
3077
3311
|
var FORWARD4 = [0, 0, -1];
|
|
3078
3312
|
var IMPACT_MATERIALS = ["concrete", "metal", "wood", "glass", "flesh", "water"];
|
|
@@ -3202,12 +3436,157 @@ var GameFluidsThree = (() => {
|
|
|
3202
3436
|
team: "destruction",
|
|
3203
3437
|
budget: { particles: 20, debris: 8 },
|
|
3204
3438
|
loop: 2,
|
|
3205
|
-
timeline: [call2("chips", ORIGIN,
|
|
3439
|
+
timeline: [call2("chips", ORIGIN, UP11, 8, 0.9), call2("rust_at", ORIGIN, 6)]
|
|
3206
3440
|
}
|
|
3207
3441
|
];
|
|
3208
|
-
var
|
|
3442
|
+
var PI = Math.PI;
|
|
3443
|
+
var SMOKE = { color: 9079430, width: 10, height: 8, gravity: -0.08, drag: 2.2, growth: 2.1 };
|
|
3444
|
+
var FLASH_SECONDS = 0.055;
|
|
3445
|
+
var FLASH_RAMP = [0.6, 0.9];
|
|
3446
|
+
var FLASH_OPACITY = 0.95;
|
|
3447
|
+
var FLAME_COLORS = [16742946, 16760896, 13121050, 16773296];
|
|
3448
|
+
var FLAME_ADDITIVE = 3;
|
|
3449
|
+
var ORIGIN2 = [0, 0, 0];
|
|
3450
|
+
var SIZE = variable("size");
|
|
3451
|
+
var wide = (width) => mul(sub(rand(), 0.5), width);
|
|
3452
|
+
var puff2 = (point, velocity, world, radius, life, opacity) => mesh({
|
|
3453
|
+
shape: "sphere",
|
|
3454
|
+
p: point,
|
|
3455
|
+
v: velocity,
|
|
3456
|
+
wv: world,
|
|
3457
|
+
r: radius,
|
|
3458
|
+
seg: SMOKE.width,
|
|
3459
|
+
seg2: SMOKE.height,
|
|
3460
|
+
life,
|
|
3461
|
+
c0: SMOKE.color,
|
|
3462
|
+
a: opacity,
|
|
3463
|
+
fade: true,
|
|
3464
|
+
lit: true,
|
|
3465
|
+
g: SMOKE.gravity,
|
|
3466
|
+
drag: SMOKE.drag,
|
|
3467
|
+
grow: SMOKE.growth
|
|
3468
|
+
});
|
|
3469
|
+
var flameBit = (point, velocity, world, radius, life) => [
|
|
3470
|
+
set("bitPoint", point),
|
|
3471
|
+
set("bitVelocity", velocity),
|
|
3472
|
+
set("bitWorld", world),
|
|
3473
|
+
set("bitRadius", radius),
|
|
3474
|
+
set("bitLife", life),
|
|
3475
|
+
set("bitColour", floor(mul(rand(), FLAME_COLORS.length))),
|
|
3476
|
+
mesh({
|
|
3477
|
+
shape: "icosahedron",
|
|
3478
|
+
p: variable("bitPoint"),
|
|
3479
|
+
v: variable("bitVelocity"),
|
|
3480
|
+
wv: variable("bitWorld"),
|
|
3481
|
+
r: variable("bitRadius"),
|
|
3482
|
+
seg: 1,
|
|
3483
|
+
rot: [mul(rand(), 3), mul(rand(), 3), 0],
|
|
3484
|
+
spin: [3, 4, 2],
|
|
3485
|
+
life: variable("bitLife"),
|
|
3486
|
+
c0: pick(FLAME_COLORS, variable("bitColour")),
|
|
3487
|
+
add: eq(variable("bitColour"), FLAME_ADDITIVE),
|
|
3488
|
+
a: 0.9,
|
|
3489
|
+
fade: true,
|
|
3490
|
+
g: -1.4,
|
|
3491
|
+
drag: 1.4,
|
|
3492
|
+
grow: 2.2
|
|
3493
|
+
})
|
|
3494
|
+
];
|
|
3495
|
+
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 });
|
|
3496
|
+
var MUZZLE_FLASH2 = {
|
|
3497
|
+
id: "viewmodel_muzzle_flash",
|
|
3498
|
+
pageId: "event:viewmodel_muzzle_flash",
|
|
3499
|
+
team: "weapons",
|
|
3500
|
+
budget: { particles: 12, lights: 1 },
|
|
3501
|
+
loop: 0.1,
|
|
3502
|
+
timeline: [
|
|
3503
|
+
set("angles", []),
|
|
3504
|
+
repeat(4, append("angles", add(div(mul(INDEX, PI), 2), mul(rand(), 0.6)))),
|
|
3505
|
+
set("roll", mul(rand(), PI)),
|
|
3506
|
+
flash(ORIGIN2, 16756832, mul(4, SIZE), FLASH_SECONDS, mul(2, SIZE), true, true),
|
|
3507
|
+
flashPiece("cone_open", mul(0.013, SIZE), mul(0.085, SIZE), 10, [mul(0.042, SIZE), 0, 0], [0, 0, -PI / 2], 16757575),
|
|
3508
|
+
repeat(
|
|
3509
|
+
4,
|
|
3510
|
+
set("angle", pick(variable("angles"), INDEX)),
|
|
3511
|
+
flashPiece(
|
|
3512
|
+
"cone",
|
|
3513
|
+
mul(5e-3, SIZE),
|
|
3514
|
+
mul(0.04, SIZE),
|
|
3515
|
+
6,
|
|
3516
|
+
[mul(0.012, SIZE), mul(cos(variable("angle")), 0.016, SIZE), mul(sin(variable("angle")), 0.016, SIZE)],
|
|
3517
|
+
[variable("angle"), 0, -PI / 2],
|
|
3518
|
+
16757575
|
|
3519
|
+
)
|
|
3520
|
+
),
|
|
3521
|
+
flashPiece("sphere", mul(0.016, SIZE), void 0, 12, [mul(8e-3, SIZE), 0, 0], [0, 0, 0], 16773568),
|
|
3522
|
+
repeat(
|
|
3523
|
+
6,
|
|
3524
|
+
puff2(
|
|
3525
|
+
ORIGIN2,
|
|
3526
|
+
[add(0.15, mul(rand(), 0.35)), add(0.03, mul(rand(), 0.12)), mul(sub(rand(), 0.5), 0.14)],
|
|
3527
|
+
[0, 0, 0],
|
|
3528
|
+
mul(0.013, SIZE),
|
|
3529
|
+
add(1.3, mul(rand(), 0.6)),
|
|
3530
|
+
0.45
|
|
3531
|
+
)
|
|
3532
|
+
)
|
|
3533
|
+
]
|
|
3534
|
+
};
|
|
3535
|
+
var SMOKE_PUFF = {
|
|
3536
|
+
id: "weapon_smoke_puff",
|
|
3537
|
+
pageId: "event:weapon_smoke_puff",
|
|
3538
|
+
team: "weapons",
|
|
3539
|
+
budget: { particles: 1 },
|
|
3540
|
+
loop: 0.1,
|
|
3541
|
+
timeline: [puff2(ORIGIN2, void 0, [variable("vx"), variable("vy"), variable("vz")], variable("radius"), variable("life"), variable("opacity"))]
|
|
3542
|
+
};
|
|
3543
|
+
var BACKBLAST = {
|
|
3544
|
+
id: "launcher_backblast",
|
|
3545
|
+
pageId: "event:launcher_backblast",
|
|
3546
|
+
team: "weapons",
|
|
3547
|
+
budget: { particles: 40 },
|
|
3548
|
+
loop: 0.1,
|
|
3549
|
+
timeline: [
|
|
3550
|
+
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)),
|
|
3551
|
+
repeat(14, ...flameBit(ORIGIN2, [neg(add(2, mul(rand(), 2))), 0, 0], [wide(1), wide(0.6), wide(1)], 0.02, 0.25))
|
|
3552
|
+
]
|
|
3553
|
+
};
|
|
3554
|
+
var FLAME_JET = {
|
|
3555
|
+
id: "flame_jet",
|
|
3556
|
+
pageId: "event:flame_jet",
|
|
3557
|
+
team: "weapons",
|
|
3558
|
+
budget: { particles: 30 },
|
|
3559
|
+
loop: 0.1,
|
|
3560
|
+
timeline: [
|
|
3561
|
+
repeat(
|
|
3562
|
+
floor(mul(420, variable("dt"), variable("scale"))),
|
|
3563
|
+
set("speed", mul(add(2.2, mul(rand(), 1.1)), variable("scale"))),
|
|
3564
|
+
...flameBit(
|
|
3565
|
+
[mul(rand(), variable("speed"), min(variable("dt"), 0.3)), 0, 0],
|
|
3566
|
+
[variable("speed"), 0, 0],
|
|
3567
|
+
[wide(0.35), mul(sub(rand(), 0.3), 0.3), wide(0.35)],
|
|
3568
|
+
add(0.02, mul(rand(), 0.022)),
|
|
3569
|
+
add(0.4, mul(rand(), 0.35))
|
|
3570
|
+
)
|
|
3571
|
+
),
|
|
3572
|
+
when(lt(rand(), 0.5), [
|
|
3573
|
+
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)
|
|
3574
|
+
])
|
|
3575
|
+
]
|
|
3576
|
+
};
|
|
3577
|
+
var VIEWMODEL_EFFECTS = [MUZZLE_FLASH2, SMOKE_PUFF, BACKBLAST, FLAME_JET];
|
|
3578
|
+
var aliasOf = (base, id, changes) => ({ ...base, id, pageId: `vehicle:${id}`, anchor: CAR_ORIGIN2, ...changes });
|
|
3579
|
+
var VEHICLE_EFFECTS = [
|
|
3580
|
+
/** The engine on fire: `engine_smoke` at its worst condition (black smoke, flames in the hood, a light). */
|
|
3581
|
+
aliasOf(ENGINE_SMOKE, "vehicle_fire", { params: { id: "condition", options: ["100", "60", "30", "10"], default: 3 }, loop: 12 }),
|
|
3582
|
+
/** The exhaust of a car under way: `engine_smoke` in the best condition, for half a second so a moving car asks again. */
|
|
3583
|
+
aliasOf(ENGINE_SMOKE, "vehicle_exhaust", { params: { id: "condition", options: ["100", "60", "30", "10"], default: 0 }, loop: 0.5 }),
|
|
3584
|
+
/** A hole in the tank: the page's own petrol leak (drips, pool, sparks, fire running to the tank). */
|
|
3585
|
+
aliasOf(FUEL_LEAK, "vehicle_leak", {})
|
|
3586
|
+
];
|
|
3587
|
+
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];
|
|
3209
3588
|
var WORKSHOP_EFFECTS = Object.fromEntries(ALL_EFFECTS.map((effect) => [effect.id, effect]));
|
|
3210
|
-
var GAME_EFFECTS = { ...WORKSHOP_EFFECTS, ...Object.fromEntries(EVENT_EFFECTS.map((effect) => [effect.id, effect])) };
|
|
3589
|
+
var GAME_EFFECTS = { ...WORKSHOP_EFFECTS, ...Object.fromEntries([...EVENT_EFFECTS, ...VIEWMODEL_EFFECTS, ...VEHICLE_EFFECTS].map((effect) => [effect.id, effect])) };
|
|
3211
3590
|
var LEHMER_MULTIPLIER = 16807;
|
|
3212
3591
|
var LEHMER_MODULUS = 2147483647;
|
|
3213
3592
|
var HASH_MIX = 2654435761;
|
|
@@ -3303,7 +3682,7 @@ var GameFluidsThree = (() => {
|
|
|
3303
3682
|
}
|
|
3304
3683
|
var COLUMNS = 6;
|
|
3305
3684
|
var ROWS = 5;
|
|
3306
|
-
var
|
|
3685
|
+
var ORIGIN3 = [-2.2, 0, 2.6];
|
|
3307
3686
|
var BLOCK_SIZE = [0.5, 0.44, 0.25];
|
|
3308
3687
|
var OBJECT_ID_DRAWS2 = 4;
|
|
3309
3688
|
var FLOOR2 = 0.13;
|
|
@@ -3346,7 +3725,7 @@ var GameFluidsThree = (() => {
|
|
|
3346
3725
|
const chipScale = random.between(0.8, 1.3) * scale2;
|
|
3347
3726
|
for (let draw = 0; draw < OBJECT_ID_DRAWS2; draw++) random.next();
|
|
3348
3727
|
best.holes.push({ x: offsetX, y: offsetY, scale: scale2, chipTurn, chipScale });
|
|
3349
|
-
impact(host.engine, "concrete", [
|
|
3728
|
+
impact(host.engine, "concrete", [ORIGIN3[0] + x, y, ORIGIN3[2] + 0.13], [0, 0, 1], 0.8);
|
|
3350
3729
|
} else if (action === "collapse") {
|
|
3351
3730
|
const { x, y } = args;
|
|
3352
3731
|
for (const block of blocks) {
|
|
@@ -3396,7 +3775,7 @@ var GameFluidsThree = (() => {
|
|
|
3396
3775
|
}
|
|
3397
3776
|
};
|
|
3398
3777
|
}
|
|
3399
|
-
var
|
|
3778
|
+
var ORIGIN4 = [5.6, 0, 0.8];
|
|
3400
3779
|
var MAX_TILT = 0.25;
|
|
3401
3780
|
function createCarBehavior() {
|
|
3402
3781
|
let y = 0;
|
|
@@ -3428,8 +3807,13 @@ var GameFluidsThree = (() => {
|
|
|
3428
3807
|
}
|
|
3429
3808
|
}
|
|
3430
3809
|
},
|
|
3431
|
-
query(_host, name) {
|
|
3432
|
-
if (name === "position") return [
|
|
3810
|
+
query(_host, name, args) {
|
|
3811
|
+
if (name === "position") return [ORIGIN4[0], y, ORIGIN4[2]];
|
|
3812
|
+
if (name === "point") {
|
|
3813
|
+
const [x, py, z] = args;
|
|
3814
|
+
const point = carPoint(x, py, z);
|
|
3815
|
+
return [point[0], point[1] + y, point[2]];
|
|
3816
|
+
}
|
|
3433
3817
|
if (name === "roll") return roll;
|
|
3434
3818
|
throw new Error(`car: unknown query ${name}`);
|
|
3435
3819
|
},
|
|
@@ -3629,6 +4013,29 @@ var GameFluidsThree = (() => {
|
|
|
3629
4013
|
}
|
|
3630
4014
|
};
|
|
3631
4015
|
}
|
|
4016
|
+
function createRainBehavior() {
|
|
4017
|
+
return {
|
|
4018
|
+
reset() {
|
|
4019
|
+
},
|
|
4020
|
+
act(host, action, args) {
|
|
4021
|
+
const { engine, camera: camera2 } = host;
|
|
4022
|
+
if (action === "init") {
|
|
4023
|
+
const { count, wind } = args;
|
|
4024
|
+
engine.rain.init(count, wind);
|
|
4025
|
+
} else if (action === "update") {
|
|
4026
|
+
const { dt, splash } = args;
|
|
4027
|
+
engine.rain.update(dt, splash, camera2.position);
|
|
4028
|
+
}
|
|
4029
|
+
},
|
|
4030
|
+
query(host, name) {
|
|
4031
|
+
if (name === "count") return host.engine.rain.count;
|
|
4032
|
+
if (name === "on") return host.engine.rain.on;
|
|
4033
|
+
throw new Error(`rain: unknown query ${name}`);
|
|
4034
|
+
},
|
|
4035
|
+
update() {
|
|
4036
|
+
}
|
|
4037
|
+
};
|
|
4038
|
+
}
|
|
3632
4039
|
var WALKER_COUNT = 10;
|
|
3633
4040
|
var ARRIVAL_DISTANCE = 0.05;
|
|
3634
4041
|
var SWAY_AMPLITUDE = 0.04;
|
|
@@ -3694,7 +4101,8 @@ var GameFluidsThree = (() => {
|
|
|
3694
4101
|
blocks: () => createBlocksBehavior(),
|
|
3695
4102
|
plate: () => createPlateBehavior(),
|
|
3696
4103
|
cylinder: () => createCylinderBehavior(),
|
|
3697
|
-
car: () => createCarBehavior()
|
|
4104
|
+
car: () => createCarBehavior(),
|
|
4105
|
+
rain: () => createRainBehavior()
|
|
3698
4106
|
};
|
|
3699
4107
|
var NOOP = () => {
|
|
3700
4108
|
};
|
|
@@ -3765,6 +4173,8 @@ var GameFluidsThree = (() => {
|
|
|
3765
4173
|
return Math.abs(asNumber(first));
|
|
3766
4174
|
case "sqrt":
|
|
3767
4175
|
return Math.sqrt(asNumber(first));
|
|
4176
|
+
case "exp":
|
|
4177
|
+
return Math.exp(asNumber(first));
|
|
3768
4178
|
case "sin":
|
|
3769
4179
|
return Math.sin(asNumber(first));
|
|
3770
4180
|
case "cos":
|
|
@@ -3883,7 +4293,7 @@ var GameFluidsThree = (() => {
|
|
|
3883
4293
|
return evaluateCall(value.$, args.map((entry) => resolve(entry, context)));
|
|
3884
4294
|
}
|
|
3885
4295
|
}
|
|
3886
|
-
var
|
|
4296
|
+
var UP12 = [0, 1, 0];
|
|
3887
4297
|
var ZERO = [0, 0, 0];
|
|
3888
4298
|
var FULL_TURN_DRAWN = 6.283;
|
|
3889
4299
|
function scaledSizes(range2, factor) {
|
|
@@ -3896,7 +4306,7 @@ var GameFluidsThree = (() => {
|
|
|
3896
4306
|
p: centre,
|
|
3897
4307
|
r: radius,
|
|
3898
4308
|
flat: true,
|
|
3899
|
-
dir: options.dir ??
|
|
4309
|
+
dir: options.dir ?? UP12,
|
|
3900
4310
|
cone: 0.35,
|
|
3901
4311
|
sp: [0.4, 1.4],
|
|
3902
4312
|
v: wind,
|
|
@@ -3913,7 +4323,7 @@ var GameFluidsThree = (() => {
|
|
|
3913
4323
|
p: centre,
|
|
3914
4324
|
r: radius * 0.6,
|
|
3915
4325
|
flat: true,
|
|
3916
|
-
dir:
|
|
4326
|
+
dir: UP12,
|
|
3917
4327
|
cone: 0.3,
|
|
3918
4328
|
sp: [0.3, 0.8],
|
|
3919
4329
|
life: [0.2, 0.4],
|
|
@@ -3928,14 +4338,14 @@ var GameFluidsThree = (() => {
|
|
|
3928
4338
|
if (engine.quality < 2) {
|
|
3929
4339
|
engine.emit(`${key}e`, "streak", 10 * factor, dt, () => {
|
|
3930
4340
|
const jitter = plus(wind, engine.random.between(-0.4, 0.4), 0, engine.random.between(-0.4, 0.4));
|
|
3931
|
-
return { p: centre, box: [radius, 0, radius], dir:
|
|
4341
|
+
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 };
|
|
3932
4342
|
});
|
|
3933
4343
|
}
|
|
3934
4344
|
if (options.noSmoke) return;
|
|
3935
4345
|
engine.emit(`${key}s`, "normal", (options.smoke || 14) * factor, dt, () => ({
|
|
3936
4346
|
p: plus(centre, 0, 0.8 * sqrtFactor, 0),
|
|
3937
4347
|
r: radius * 0.7,
|
|
3938
|
-
dir:
|
|
4348
|
+
dir: UP12,
|
|
3939
4349
|
cone: 0.35,
|
|
3940
4350
|
sp: [0.6, 1.4],
|
|
3941
4351
|
v: wind,
|
|
@@ -3975,15 +4385,15 @@ var GameFluidsThree = (() => {
|
|
|
3975
4385
|
engine.screen.shake += 0.7 * scale2;
|
|
3976
4386
|
engine.screen.white += 0.18 * scale2;
|
|
3977
4387
|
engine.burst("add", 55 * scale2, { p: point, r: 0.3 * scale2, sp: [2, 7 * scale2], drag: 4, life: [0.25, 0.6], size: [0.7 * scale2, 1.4 * scale2], grow: 1.7, c0: 16773296, c1: 10103304, fi: 0.04 });
|
|
3978
|
-
engine.burst("add", 28 * scale2, { p: plus(point, 0, 0.3, 0), r: 0.3, dir:
|
|
4388
|
+
engine.burst("add", 28 * scale2, { p: plus(point, 0, 0.3, 0), r: 0.3, dir: UP12, cone: 0.7, sp: [2, 5 * scale2], drag: 1.5, life: [0.6, 1.1], size: [0.6 * scale2, 1 * scale2], grow: 1.3, c0: 16760928, c1: 5902853, g: -2, fi: 0.05 });
|
|
3979
4389
|
engine.ring([plus(point, 0, 0.05, 0), 0.3, 7 * scale2, 0.55, 16767136]);
|
|
3980
4390
|
const toCamera = normalized([cameraPosition[0] - point[0], cameraPosition[1] - point[1], cameraPosition[2] - point[2]]);
|
|
3981
4391
|
engine.ring([plus(point, 0, 1, 0), 0.3, 5 * scale2, 0.35, 16773328, toCamera]);
|
|
3982
|
-
engine.burst("normal", 32 * scale2, { p: plus(point, 0, 0.6, 0), r: 0.8 * scale2, dir:
|
|
4392
|
+
engine.burst("normal", 32 * scale2, { p: plus(point, 0, 0.6, 0), r: 0.8 * scale2, dir: UP12, cone: 1.1, sp: [1, 3], drag: 1.2, life: [3, 6], size: [1 * scale2, 1.8 * scale2], grow: 2.6, c0: 2828068, c1: 987155, a: 0.6, fi: 0.18, g: -0.35 });
|
|
3983
4393
|
ringOfDust(engine, point, scale2);
|
|
3984
|
-
if (engine.quality < 2) engine.burst("streak", 44 * scale2, { p: point, dir:
|
|
4394
|
+
if (engine.quality < 2) engine.burst("streak", 44 * scale2, { 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 });
|
|
3985
4395
|
for (let index = 0; index < engine.scaled(16 * scale2); index++) {
|
|
3986
|
-
engine.debrisPiece({ p: point, dir:
|
|
4396
|
+
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 });
|
|
3987
4397
|
}
|
|
3988
4398
|
engine.decal([point[0], engine.context.groundAt(point[0], point[2]), point[2], 3 * scale2, 657930, { grow: 0.15, life: 60 }]);
|
|
3989
4399
|
}
|
|
@@ -4126,6 +4536,7 @@ var GameFluidsThree = (() => {
|
|
|
4126
4536
|
if (!def) return;
|
|
4127
4537
|
this.schedule.clear();
|
|
4128
4538
|
this.variables.clear();
|
|
4539
|
+
for (const [name, value] of Object.entries(this.setup.values ?? {})) this.variables.set(name, value);
|
|
4129
4540
|
for (const behavior2 of this.deps.behaviors()) behavior2.reset(this.host);
|
|
4130
4541
|
this.time = 0;
|
|
4131
4542
|
this.within(() => {
|
|
@@ -4184,6 +4595,10 @@ var GameFluidsThree = (() => {
|
|
|
4184
4595
|
return engine.spawn(step.system, this.value(step.spawn));
|
|
4185
4596
|
case "emit":
|
|
4186
4597
|
return engine.emit(step.key, step.system, this.value(step.rate), this.dt, () => this.value(step.spawn));
|
|
4598
|
+
case "mesh": {
|
|
4599
|
+
engine.mesh(this.value(step.spawn));
|
|
4600
|
+
return;
|
|
4601
|
+
}
|
|
4187
4602
|
case "debris":
|
|
4188
4603
|
return engine.debrisPiece(this.value(step.spawn));
|
|
4189
4604
|
case "decal":
|
|
@@ -4265,7 +4680,7 @@ var GameFluidsThree = (() => {
|
|
|
4265
4680
|
this.index = previous;
|
|
4266
4681
|
}
|
|
4267
4682
|
};
|
|
4268
|
-
var
|
|
4683
|
+
var ORIGIN5 = [0, 0, 0];
|
|
4269
4684
|
var DEFAULT_HEADING = [0, 0, -1];
|
|
4270
4685
|
var DEFAULT_MAX_INSTANCES = 48;
|
|
4271
4686
|
var ENDLESS_SECONDS = 60;
|
|
@@ -4310,7 +4725,7 @@ var GameFluidsThree = (() => {
|
|
|
4310
4725
|
}
|
|
4311
4726
|
function placementOf(entry) {
|
|
4312
4727
|
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;
|
|
4313
|
-
return { origin, anchor: entry.anchor, yaw: entry.yaw };
|
|
4728
|
+
return { origin, anchor: entry.anchor, yaw: entry.yaw, ...entry.orientation ? { orientation: entry.orientation } : {} };
|
|
4314
4729
|
}
|
|
4315
4730
|
function drawing(entry, action) {
|
|
4316
4731
|
const context = engine.context;
|
|
@@ -4334,8 +4749,9 @@ var GameFluidsThree = (() => {
|
|
|
4334
4749
|
random: playOptions.seed !== void 0 ? streamOf(playOptions.seed) : void 0,
|
|
4335
4750
|
follow: playOptions.follow,
|
|
4336
4751
|
origin: point,
|
|
4337
|
-
anchor: def.anchor ??
|
|
4752
|
+
anchor: def.anchor ?? ORIGIN5,
|
|
4338
4753
|
yaw: yawOf(heading, playOptions.direction),
|
|
4754
|
+
orientation: playOptions.orientation,
|
|
4339
4755
|
seconds: playOptions.seconds ?? (def.loop && def.loop > 0 ? def.loop : ENDLESS_SECONDS)
|
|
4340
4756
|
};
|
|
4341
4757
|
playing.push(entry);
|
|
@@ -4344,7 +4760,8 @@ var GameFluidsThree = (() => {
|
|
|
4344
4760
|
() => instance.begin(def, paramIndex(def, playOptions.param), {
|
|
4345
4761
|
placement: placementOf(entry),
|
|
4346
4762
|
...playOptions.direction ? { direction: playOptions.direction } : {},
|
|
4347
|
-
...playOptions.normal ? { normal: playOptions.normal } : {}
|
|
4763
|
+
...playOptions.normal ? { normal: playOptions.normal } : {},
|
|
4764
|
+
...playOptions.values ? { values: playOptions.values } : {}
|
|
4348
4765
|
})
|
|
4349
4766
|
);
|
|
4350
4767
|
return entry.handle;
|
|
@@ -4604,15 +5021,15 @@ var GameFluidsThree = (() => {
|
|
|
4604
5021
|
return shock;
|
|
4605
5022
|
}
|
|
4606
5023
|
function pushPuffs(puffs, shock, reach, dt, age) {
|
|
4607
|
-
for (const
|
|
4608
|
-
if (
|
|
4609
|
-
const dx =
|
|
4610
|
-
const dz =
|
|
5024
|
+
for (const puff3 of puffs) {
|
|
5025
|
+
if (puff3.ring || puff3.t > PUSH_AGE_LIMIT) continue;
|
|
5026
|
+
const dx = puff3.x - shock.x;
|
|
5027
|
+
const dz = puff3.z - shock.z;
|
|
4611
5028
|
const distance2 = Math.hypot(dx, dz) + 1e-3;
|
|
4612
|
-
if (Math.abs(distance2 - reach) < PUSH_BAND &&
|
|
5029
|
+
if (Math.abs(distance2 - reach) < PUSH_BAND && puff3.y < PUSH_CEILING) {
|
|
4613
5030
|
const strength = 4 * dt * (1 - age);
|
|
4614
|
-
|
|
4615
|
-
|
|
5031
|
+
puff3.vx += dx / distance2 * strength * 6;
|
|
5032
|
+
puff3.vz += dz / distance2 * strength * 6;
|
|
4616
5033
|
}
|
|
4617
5034
|
}
|
|
4618
5035
|
}
|
|
@@ -4912,10 +5329,10 @@ var GameFluidsThree = (() => {
|
|
|
4912
5329
|
const life = random.between(ring2.life * 0.75, ring2.life);
|
|
4913
5330
|
const h0 = random.between(1, 1.25);
|
|
4914
5331
|
const hl = random.between(0.9, 1.6);
|
|
4915
|
-
const
|
|
4916
|
-
|
|
4917
|
-
|
|
4918
|
-
|
|
5332
|
+
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 });
|
|
5333
|
+
puff3.ring = ring2;
|
|
5334
|
+
puff3.ph = random.next() * Math.PI * 2;
|
|
5335
|
+
puff3.th = random.next() * Math.PI * 2;
|
|
4919
5336
|
}
|
|
4920
5337
|
const stemCount = Math.round((spec.stem || 18) * Math.max(lod, 0.4));
|
|
4921
5338
|
for (let index = 0; index < stemCount; index++) {
|
|
@@ -5716,7 +6133,7 @@ var GameFluidsThree = (() => {
|
|
|
5716
6133
|
};
|
|
5717
6134
|
var TWO_PI_ROUNDED = 6.2832;
|
|
5718
6135
|
var WIDE_CONE = 3.1;
|
|
5719
|
-
var
|
|
6136
|
+
var UP13 = [0, 1, 0];
|
|
5720
6137
|
function drawRange(random, range2) {
|
|
5721
6138
|
if (Array.isArray(range2)) return random.between(range2[0], range2[1]);
|
|
5722
6139
|
return range2 || 0;
|
|
@@ -5744,7 +6161,7 @@ var GameFluidsThree = (() => {
|
|
|
5744
6161
|
}
|
|
5745
6162
|
function coneDirection(random, direction, cone, out) {
|
|
5746
6163
|
if (cone >= WIDE_CONE) return randomUnit(random, out);
|
|
5747
|
-
const [dx, dy, dz] = direction ??
|
|
6164
|
+
const [dx, dy, dz] = direction ?? UP13;
|
|
5748
6165
|
const cosTilt = 1 - random.next() * (1 - Math.cos(cone));
|
|
5749
6166
|
const sinTilt = Math.sqrt(1 - cosTilt * cosTilt);
|
|
5750
6167
|
const phase = random.next() * TWO_PI_ROUNDED;
|
|
@@ -5864,12 +6281,12 @@ var GameFluidsThree = (() => {
|
|
|
5864
6281
|
}
|
|
5865
6282
|
};
|
|
5866
6283
|
var CAPACITY2 = 400;
|
|
5867
|
-
var
|
|
6284
|
+
var UP14 = [0, 1, 0];
|
|
5868
6285
|
var DEFAULT_LIFE2 = 60;
|
|
5869
6286
|
var DEFAULT_GROW = 1.2;
|
|
5870
6287
|
var EVAPORATION = { fuel: [6, 5], water: [40, 20] };
|
|
5871
6288
|
function createDecal() {
|
|
5872
|
-
return { on: false, x: 0, y: 0, z: 0, sx: 0, sy: 0, t: 0, life: 0, grow: 0, color: 0, normal:
|
|
6289
|
+
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 };
|
|
5873
6290
|
}
|
|
5874
6291
|
var DecalPool = class {
|
|
5875
6292
|
constructor(context) {
|
|
@@ -5882,7 +6299,7 @@ var GameFluidsThree = (() => {
|
|
|
5882
6299
|
const random = this.context.random;
|
|
5883
6300
|
const index = this.next++ % CAPACITY2;
|
|
5884
6301
|
const decal2 = this.decals[index];
|
|
5885
|
-
const normal = options.n ??
|
|
6302
|
+
const normal = options.n ?? UP14;
|
|
5886
6303
|
random.between(0, 6.28);
|
|
5887
6304
|
const offset = 4e-3 + index % 40 * 4e-4;
|
|
5888
6305
|
decal2.on = true;
|
|
@@ -5923,6 +6340,94 @@ var GameFluidsThree = (() => {
|
|
|
5923
6340
|
}
|
|
5924
6341
|
}
|
|
5925
6342
|
};
|
|
6343
|
+
var CAPACITY3 = 400;
|
|
6344
|
+
var IDENTITY = [0, 0, 0, 1];
|
|
6345
|
+
function multiply(a, b) {
|
|
6346
|
+
const [ax, ay, az, aw] = a;
|
|
6347
|
+
const [bx, by, bz, bw] = b;
|
|
6348
|
+
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];
|
|
6349
|
+
}
|
|
6350
|
+
var aboutX = (angle) => [Math.sin(angle / 2), 0, 0, Math.cos(angle / 2)];
|
|
6351
|
+
var MeshPool = class {
|
|
6352
|
+
constructor(capacity = CAPACITY3) {
|
|
6353
|
+
__publicField2(this, "capacity", capacity);
|
|
6354
|
+
__publicField2(this, "particles", []);
|
|
6355
|
+
__publicField2(this, "serial", 0);
|
|
6356
|
+
}
|
|
6357
|
+
get count() {
|
|
6358
|
+
return this.particles.length;
|
|
6359
|
+
}
|
|
6360
|
+
spawn(options, frame = IDENTITY) {
|
|
6361
|
+
const velocity = options.v ?? [0, 0, 0];
|
|
6362
|
+
const world = options.wv ?? [0, 0, 0];
|
|
6363
|
+
const particle = {
|
|
6364
|
+
id: ++this.serial,
|
|
6365
|
+
shape: options.shape,
|
|
6366
|
+
radius: options.r,
|
|
6367
|
+
height: options.h ?? 0,
|
|
6368
|
+
segments: options.seg ?? 0,
|
|
6369
|
+
segments2: options.seg2 ?? 0,
|
|
6370
|
+
color: options.c0,
|
|
6371
|
+
additive: options.add === true,
|
|
6372
|
+
lit: options.lit === true,
|
|
6373
|
+
x: options.p[0],
|
|
6374
|
+
y: options.p[1],
|
|
6375
|
+
z: options.p[2],
|
|
6376
|
+
frame: options.roll ? multiply(frame, aboutX(options.roll)) : frame,
|
|
6377
|
+
at: options.at ?? [0, 0, 0],
|
|
6378
|
+
rx: options.rot?.[0] ?? 0,
|
|
6379
|
+
ry: options.rot?.[1] ?? 0,
|
|
6380
|
+
rz: options.rot?.[2] ?? 0,
|
|
6381
|
+
scale: 1,
|
|
6382
|
+
opacity: options.a,
|
|
6383
|
+
age: 0,
|
|
6384
|
+
life: options.life,
|
|
6385
|
+
vx: velocity[0] + world[0],
|
|
6386
|
+
vy: velocity[1] + world[1],
|
|
6387
|
+
vz: velocity[2] + world[2],
|
|
6388
|
+
spin: options.spin ?? [0, 0, 0],
|
|
6389
|
+
gravity: options.g ?? 0,
|
|
6390
|
+
drag: options.drag ?? 0,
|
|
6391
|
+
grow: options.grow ?? 0,
|
|
6392
|
+
ramp: options.ramp,
|
|
6393
|
+
fade: options.fade === true,
|
|
6394
|
+
startOpacity: options.a
|
|
6395
|
+
};
|
|
6396
|
+
this.particles.push(particle);
|
|
6397
|
+
if (this.particles.length > this.capacity) this.particles.shift();
|
|
6398
|
+
return particle;
|
|
6399
|
+
}
|
|
6400
|
+
update(dt) {
|
|
6401
|
+
const live = this.particles;
|
|
6402
|
+
for (let index = 0; index < live.length; index++) {
|
|
6403
|
+
const particle = live[index];
|
|
6404
|
+
particle.age += dt;
|
|
6405
|
+
if (particle.ramp ? particle.age >= particle.life : particle.age > particle.life) {
|
|
6406
|
+
live.splice(index--, 1);
|
|
6407
|
+
continue;
|
|
6408
|
+
}
|
|
6409
|
+
if (particle.fade) particle.opacity = Math.max(0, particle.startOpacity * (1 - particle.age / particle.life));
|
|
6410
|
+
particle.vy -= particle.gravity * dt;
|
|
6411
|
+
if (particle.drag) {
|
|
6412
|
+
const keep = Math.max(0, 1 - particle.drag * dt);
|
|
6413
|
+
particle.vx *= keep;
|
|
6414
|
+
particle.vy *= keep;
|
|
6415
|
+
particle.vz *= keep;
|
|
6416
|
+
}
|
|
6417
|
+
particle.x += particle.vx * dt;
|
|
6418
|
+
particle.y += particle.vy * dt;
|
|
6419
|
+
particle.z += particle.vz * dt;
|
|
6420
|
+
particle.rx += particle.spin[0] * dt;
|
|
6421
|
+
particle.ry += particle.spin[1] * dt;
|
|
6422
|
+
particle.rz += particle.spin[2] * dt;
|
|
6423
|
+
if (particle.grow) particle.scale *= 1 + particle.grow * dt;
|
|
6424
|
+
if (particle.ramp) particle.scale = particle.ramp[0] + Math.min(1, particle.age / particle.life) * particle.ramp[1];
|
|
6425
|
+
}
|
|
6426
|
+
}
|
|
6427
|
+
clear() {
|
|
6428
|
+
this.particles.length = 0;
|
|
6429
|
+
}
|
|
6430
|
+
};
|
|
5926
6431
|
var DEFAULT_FADE_IN = 0.1;
|
|
5927
6432
|
var FLOATS_PER_VECTOR = 3;
|
|
5928
6433
|
var BYTE_MAX2 = 255;
|
|
@@ -6212,11 +6717,11 @@ var GameFluidsThree = (() => {
|
|
|
6212
6717
|
};
|
|
6213
6718
|
var RING_CAPACITY = 120;
|
|
6214
6719
|
var LIGHT_CAPACITY = 4;
|
|
6215
|
-
var
|
|
6720
|
+
var UP15 = [0, 1, 0];
|
|
6216
6721
|
var DEFAULT_LIGHT_DISTANCE = 14;
|
|
6217
6722
|
var WaveRingPool = class {
|
|
6218
6723
|
constructor() {
|
|
6219
|
-
__publicField2(this, "rings", Array.from({ length: RING_CAPACITY }, () => ({ on: false, point:
|
|
6724
|
+
__publicField2(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 })));
|
|
6220
6725
|
__publicField2(this, "count", 0);
|
|
6221
6726
|
__publicField2(this, "next", 0);
|
|
6222
6727
|
}
|
|
@@ -6229,7 +6734,7 @@ var GameFluidsThree = (() => {
|
|
|
6229
6734
|
ring2.t = 0;
|
|
6230
6735
|
ring2.duration = duration;
|
|
6231
6736
|
ring2.color = color;
|
|
6232
|
-
ring2.normal = normal ??
|
|
6737
|
+
ring2.normal = normal ?? UP15;
|
|
6233
6738
|
ring2.hold = hold || 0;
|
|
6234
6739
|
}
|
|
6235
6740
|
clear() {
|
|
@@ -6249,7 +6754,7 @@ var GameFluidsThree = (() => {
|
|
|
6249
6754
|
var FlashLightPool = class {
|
|
6250
6755
|
constructor(context) {
|
|
6251
6756
|
__publicField2(this, "context", context);
|
|
6252
|
-
__publicField2(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 })));
|
|
6757
|
+
__publicField2(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 })));
|
|
6253
6758
|
__publicField2(this, "fire", [
|
|
6254
6759
|
{ x: 0, y: 0, z: 0, intensity: 0 },
|
|
6255
6760
|
{ x: 0, y: 0, z: 0, intensity: 0 }
|
|
@@ -6259,7 +6764,7 @@ var GameFluidsThree = (() => {
|
|
|
6259
6764
|
get lit() {
|
|
6260
6765
|
return this.lights.filter((light) => light.intensity > 0).length;
|
|
6261
6766
|
}
|
|
6262
|
-
flash(point, color, intensity, duration, distance2, force) {
|
|
6767
|
+
flash(point, color, intensity, duration, distance2, force, steady) {
|
|
6263
6768
|
const { level } = this.context.quality;
|
|
6264
6769
|
if (level >= 1 && !force) return;
|
|
6265
6770
|
if (level >= 2 && force !== "boom") return;
|
|
@@ -6272,6 +6777,7 @@ var GameFluidsThree = (() => {
|
|
|
6272
6777
|
light.peak = intensity;
|
|
6273
6778
|
light.duration = duration;
|
|
6274
6779
|
light.t = 0;
|
|
6780
|
+
light.steady = steady === true;
|
|
6275
6781
|
light.intensity = intensity;
|
|
6276
6782
|
}
|
|
6277
6783
|
clear() {
|
|
@@ -6283,7 +6789,7 @@ var GameFluidsThree = (() => {
|
|
|
6283
6789
|
if (light.intensity <= 0) continue;
|
|
6284
6790
|
light.t += dt;
|
|
6285
6791
|
const age = light.t / light.duration;
|
|
6286
|
-
light.intensity = age >= 1 ? 0 : light.peak * (1 - age) * (1 - age);
|
|
6792
|
+
light.intensity = age >= 1 ? 0 : light.steady ? light.peak : light.peak * (1 - age) * (1 - age);
|
|
6287
6793
|
}
|
|
6288
6794
|
}
|
|
6289
6795
|
};
|
|
@@ -6291,6 +6797,14 @@ var GameFluidsThree = (() => {
|
|
|
6291
6797
|
var FIRE_FLICKER_SWAY = 0.25;
|
|
6292
6798
|
var FIRE_FLICKER_JITTER = 0.08;
|
|
6293
6799
|
var LENS_FADE = 0.16;
|
|
6800
|
+
function rotate(q, v) {
|
|
6801
|
+
const [qx, qy, qz, qw] = q;
|
|
6802
|
+
const ix = qw * v[0] + qy * v[2] - qz * v[1];
|
|
6803
|
+
const iy = qw * v[1] + qz * v[0] - qx * v[2];
|
|
6804
|
+
const iz = qw * v[2] + qx * v[1] - qy * v[0];
|
|
6805
|
+
const iw = -qx * v[0] - qy * v[1] - qz * v[2];
|
|
6806
|
+
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];
|
|
6807
|
+
}
|
|
6294
6808
|
function workshopGround(x, z) {
|
|
6295
6809
|
return z < -2.9 && z > -4.5 && Math.abs(x) < 13 ? 0.12 : 0;
|
|
6296
6810
|
}
|
|
@@ -6304,6 +6818,8 @@ var GameFluidsThree = (() => {
|
|
|
6304
6818
|
__publicField2(this, "decals");
|
|
6305
6819
|
__publicField2(this, "rings", new WaveRingPool());
|
|
6306
6820
|
__publicField2(this, "lights");
|
|
6821
|
+
__publicField2(this, "rain", new RainField(this));
|
|
6822
|
+
__publicField2(this, "meshes", new MeshPool());
|
|
6307
6823
|
__publicField2(this, "screen", createScreenState());
|
|
6308
6824
|
__publicField2(this, "lens", []);
|
|
6309
6825
|
__publicField2(this, "post", {});
|
|
@@ -6336,7 +6852,11 @@ var GameFluidsThree = (() => {
|
|
|
6336
6852
|
place(point) {
|
|
6337
6853
|
const placement = this.placement;
|
|
6338
6854
|
if (!placement) return point;
|
|
6339
|
-
const { anchor, origin, yaw } = placement;
|
|
6855
|
+
const { anchor, origin, yaw, orientation } = placement;
|
|
6856
|
+
if (orientation) {
|
|
6857
|
+
const turned = rotate(orientation, [point[0] - anchor[0], point[1] - anchor[1], point[2] - anchor[2]]);
|
|
6858
|
+
return [origin[0] + turned[0], origin[1] + turned[1], origin[2] + turned[2]];
|
|
6859
|
+
}
|
|
6340
6860
|
const x = point[0] - anchor[0];
|
|
6341
6861
|
const z = point[2] - anchor[2];
|
|
6342
6862
|
const cos2 = Math.cos(yaw);
|
|
@@ -6347,6 +6867,7 @@ var GameFluidsThree = (() => {
|
|
|
6347
6867
|
turn(vector) {
|
|
6348
6868
|
const placement = this.placement;
|
|
6349
6869
|
if (!placement) return vector;
|
|
6870
|
+
if (placement.orientation) return rotate(placement.orientation, vector);
|
|
6350
6871
|
const cos2 = Math.cos(placement.yaw);
|
|
6351
6872
|
const sin2 = Math.sin(placement.yaw);
|
|
6352
6873
|
return [cos2 * vector[0] + sin2 * vector[2], vector[1], -sin2 * vector[0] + cos2 * vector[2]];
|
|
@@ -6375,6 +6896,14 @@ var GameFluidsThree = (() => {
|
|
|
6375
6896
|
}
|
|
6376
6897
|
this.accumulators.set(key, carried);
|
|
6377
6898
|
}
|
|
6899
|
+
/** 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. */
|
|
6900
|
+
mesh(recipe) {
|
|
6901
|
+
const placement = this.placement;
|
|
6902
|
+
const options = placement ? { ...recipe, p: this.place(recipe.p), ...recipe.v ? { v: this.turn(recipe.v) } : {} } : recipe;
|
|
6903
|
+
this.context.trace?.("mesh", [options]);
|
|
6904
|
+
const grouped = recipe.at !== void 0 || recipe.roll !== void 0;
|
|
6905
|
+
return this.meshes.spawn(options, placement && grouped ? placement.orientation ?? [0, Math.sin(placement.yaw / 2), 0, Math.cos(placement.yaw / 2)] : void 0);
|
|
6906
|
+
}
|
|
6378
6907
|
debrisPiece(recipe) {
|
|
6379
6908
|
const options = this.placed(recipe);
|
|
6380
6909
|
this.context.trace?.("debris", [options]);
|
|
@@ -6395,10 +6924,11 @@ var GameFluidsThree = (() => {
|
|
|
6395
6924
|
this.context.trace?.("ring", args);
|
|
6396
6925
|
this.rings.add(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
|
|
6397
6926
|
}
|
|
6927
|
+
/** `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. */
|
|
6398
6928
|
flash(recipe) {
|
|
6399
|
-
const args = this.placement ? [this.place(recipe[0]), recipe[1], recipe[2], recipe[3], recipe[4], recipe[5]] : recipe;
|
|
6400
|
-
this.context.trace?.("flash", args);
|
|
6401
|
-
this.lights.flash(args[0], args[1], args[2], args[3], args[4], args[5]);
|
|
6929
|
+
const args = this.placement ? [this.place(recipe[0]), recipe[1], recipe[2], recipe[3], recipe[4], recipe[5], recipe[6]] : recipe;
|
|
6930
|
+
this.context.trace?.("flash", args.slice(0, 6));
|
|
6931
|
+
this.lights.flash(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
|
|
6402
6932
|
}
|
|
6403
6933
|
/** `fireLight` (W400): sways with the clock and flickers with one draw. */
|
|
6404
6934
|
fireLight(slot, recipe, intensity, time) {
|
|
@@ -6423,6 +6953,7 @@ var GameFluidsThree = (() => {
|
|
|
6423
6953
|
this.debris.update(dt);
|
|
6424
6954
|
this.decals.update(dt);
|
|
6425
6955
|
this.rings.update(dt);
|
|
6956
|
+
this.meshes.update(dt);
|
|
6426
6957
|
this.lights.update(dt);
|
|
6427
6958
|
updateScreen(this.screen, dt);
|
|
6428
6959
|
for (let index = this.lens.length - 1; index >= 0; index--) {
|
|
@@ -6439,7 +6970,9 @@ var GameFluidsThree = (() => {
|
|
|
6439
6970
|
this.debris.clear();
|
|
6440
6971
|
this.decals.clear();
|
|
6441
6972
|
this.rings.clear();
|
|
6973
|
+
this.meshes.clear();
|
|
6442
6974
|
this.lights.clear();
|
|
6975
|
+
this.rain.clear();
|
|
6443
6976
|
this.accumulators.clear();
|
|
6444
6977
|
resetScreenState(this.screen);
|
|
6445
6978
|
this.lens.length = 0;
|
|
@@ -6585,16 +7118,16 @@ var GameFluidsThree = (() => {
|
|
|
6585
7118
|
},
|
|
6586
7119
|
push(point, radius, speed) {
|
|
6587
7120
|
spriteSystem.push(point, radius, speed);
|
|
6588
|
-
for (const
|
|
6589
|
-
const dx =
|
|
6590
|
-
const dy =
|
|
6591
|
-
const dz =
|
|
7121
|
+
for (const puff3 of core.puffs.items) {
|
|
7122
|
+
const dx = puff3.x - point[0];
|
|
7123
|
+
const dy = puff3.y - point[1];
|
|
7124
|
+
const dz = puff3.z - point[2];
|
|
6592
7125
|
const distance2 = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
|
6593
7126
|
if (distance2 >= radius) continue;
|
|
6594
7127
|
const strength = speed * (1 - distance2 / radius) / (distance2 + 1e-3);
|
|
6595
|
-
|
|
6596
|
-
|
|
6597
|
-
|
|
7128
|
+
puff3.vx += dx * strength;
|
|
7129
|
+
puff3.vy += dy * strength;
|
|
7130
|
+
puff3.vz += dz * strength;
|
|
6598
7131
|
}
|
|
6599
7132
|
},
|
|
6600
7133
|
stop(handle) {
|
|
@@ -6611,6 +7144,12 @@ var GameFluidsThree = (() => {
|
|
|
6611
7144
|
camera2.y = position[1];
|
|
6612
7145
|
camera2.z = position[2];
|
|
6613
7146
|
},
|
|
7147
|
+
setWind(next) {
|
|
7148
|
+
wind.x = next[0];
|
|
7149
|
+
wind.y = next[1];
|
|
7150
|
+
wind.z = next[2];
|
|
7151
|
+
},
|
|
7152
|
+
wind: () => [wind.x, wind.y, wind.z],
|
|
6614
7153
|
forceLod(scale2) {
|
|
6615
7154
|
core.clock.forcedLod = scale2;
|
|
6616
7155
|
},
|
|
@@ -6792,11 +7331,11 @@ void main(){
|
|
|
6792
7331
|
geometry.setAttribute("aC", attributes[2]);
|
|
6793
7332
|
geometry.instanceCount = 0;
|
|
6794
7333
|
const material = new THREE.ShaderMaterial({ uniforms, vertexShader: PUFF_VERTEX, fragmentShader: PUFF_FRAGMENT });
|
|
6795
|
-
const
|
|
6796
|
-
|
|
6797
|
-
|
|
7334
|
+
const mesh2 = new THREE.Mesh(geometry, material);
|
|
7335
|
+
mesh2.name = "vfx-puffs";
|
|
7336
|
+
mesh2.frustumCulled = false;
|
|
6798
7337
|
return {
|
|
6799
|
-
mesh,
|
|
7338
|
+
mesh: mesh2,
|
|
6800
7339
|
sync() {
|
|
6801
7340
|
let n = 0;
|
|
6802
7341
|
for (const p of pool.items) {
|
|
@@ -6837,12 +7376,12 @@ void main(){
|
|
|
6837
7376
|
geometry.setAttribute("aE", attributes[2]);
|
|
6838
7377
|
geometry.instanceCount = 0;
|
|
6839
7378
|
const material = new THREE.ShaderMaterial({ transparent: true, depthWrite: false, blending: THREE.AdditiveBlending, vertexShader: SPARK_VERTEX, fragmentShader: SPARK_FRAGMENT });
|
|
6840
|
-
const
|
|
6841
|
-
|
|
6842
|
-
|
|
6843
|
-
|
|
7379
|
+
const mesh2 = new THREE.Mesh(geometry, material);
|
|
7380
|
+
mesh2.name = "vfx-sparks";
|
|
7381
|
+
mesh2.frustumCulled = false;
|
|
7382
|
+
mesh2.renderOrder = 5;
|
|
6844
7383
|
return {
|
|
6845
|
-
mesh,
|
|
7384
|
+
mesh: mesh2,
|
|
6846
7385
|
sync() {
|
|
6847
7386
|
let n = 0;
|
|
6848
7387
|
for (const s of pool.items) {
|
|
@@ -6880,12 +7419,12 @@ void main(){
|
|
|
6880
7419
|
geometry.setAttribute("aC", attributes[1]);
|
|
6881
7420
|
geometry.instanceCount = 0;
|
|
6882
7421
|
const material = new THREE.ShaderMaterial({ transparent: true, depthWrite: false, blending: THREE.AdditiveBlending, vertexShader: GLOW_VERTEX, fragmentShader: GLOW_FRAGMENT });
|
|
6883
|
-
const
|
|
6884
|
-
|
|
6885
|
-
|
|
6886
|
-
|
|
7422
|
+
const mesh2 = new THREE.Mesh(geometry, material);
|
|
7423
|
+
mesh2.name = "vfx-glows";
|
|
7424
|
+
mesh2.frustumCulled = false;
|
|
7425
|
+
mesh2.renderOrder = 6;
|
|
6887
7426
|
return {
|
|
6888
|
-
mesh,
|
|
7427
|
+
mesh: mesh2,
|
|
6889
7428
|
sync() {
|
|
6890
7429
|
let n = 0;
|
|
6891
7430
|
for (const g of pool.items) {
|
|
@@ -6914,14 +7453,14 @@ void main(){
|
|
|
6914
7453
|
const rockMaterial = new THREE.MeshStandardMaterial({ color: 16777215, roughness: 0.85, flatShading: true });
|
|
6915
7454
|
const plateMaterial = rockMaterial.clone();
|
|
6916
7455
|
const make = (geometry, material) => {
|
|
6917
|
-
const
|
|
6918
|
-
|
|
6919
|
-
|
|
6920
|
-
|
|
6921
|
-
|
|
6922
|
-
|
|
6923
|
-
|
|
6924
|
-
return
|
|
7456
|
+
const mesh2 = new THREE.InstancedMesh(geometry, material, capacity);
|
|
7457
|
+
mesh2.instanceMatrix.setUsage(THREE.DynamicDrawUsage);
|
|
7458
|
+
mesh2.castShadow = true;
|
|
7459
|
+
mesh2.receiveShadow = true;
|
|
7460
|
+
mesh2.frustumCulled = false;
|
|
7461
|
+
mesh2.count = 0;
|
|
7462
|
+
mesh2.setColorAt(0, new THREE.Color(1, 1, 1));
|
|
7463
|
+
return mesh2;
|
|
6925
7464
|
};
|
|
6926
7465
|
const rocks = make(shapes.rock, rockMaterial);
|
|
6927
7466
|
const plates = make(shapes.plate, plateMaterial);
|
|
@@ -6940,20 +7479,20 @@ void main(){
|
|
|
6940
7479
|
euler.set(chunk.rx, chunk.ry, chunk.rz);
|
|
6941
7480
|
quaternion.setFromEuler(euler);
|
|
6942
7481
|
matrix.compose(position.set(chunk.x, chunk.y, chunk.z), quaternion, scale2.set(chunk.sx, chunk.sy, chunk.sz));
|
|
6943
|
-
const
|
|
7482
|
+
const mesh2 = chunk.plate ? plates : rocks;
|
|
6944
7483
|
const index = chunk.plate ? plateCount++ : rockCount++;
|
|
6945
|
-
|
|
7484
|
+
mesh2.setMatrixAt(index, matrix);
|
|
6946
7485
|
const color = colorOf(chunk);
|
|
6947
|
-
const colors =
|
|
7486
|
+
const colors = mesh2.instanceColor.array;
|
|
6948
7487
|
colors[index * 3] = color[0];
|
|
6949
7488
|
colors[index * 3 + 1] = color[1];
|
|
6950
7489
|
colors[index * 3 + 2] = color[2];
|
|
6951
7490
|
}
|
|
6952
7491
|
rocks.count = rockCount;
|
|
6953
7492
|
plates.count = plateCount;
|
|
6954
|
-
for (const
|
|
6955
|
-
|
|
6956
|
-
|
|
7493
|
+
for (const mesh2 of [rocks, plates]) {
|
|
7494
|
+
mesh2.instanceMatrix.needsUpdate = true;
|
|
7495
|
+
mesh2.instanceColor.needsUpdate = true;
|
|
6957
7496
|
}
|
|
6958
7497
|
return rockCount + plateCount;
|
|
6959
7498
|
},
|
|
@@ -7137,28 +7676,28 @@ void main(){
|
|
|
7137
7676
|
position.setXYZ(index, worldX, (options.ground?.heightAt(worldX, worldZ) ?? 0) + mark.lift, worldZ);
|
|
7138
7677
|
}
|
|
7139
7678
|
geometry.computeVertexNormals();
|
|
7140
|
-
const
|
|
7141
|
-
|
|
7142
|
-
return
|
|
7679
|
+
const mesh2 = new THREE.Mesh(geometry, material);
|
|
7680
|
+
mesh2.receiveShadow = true;
|
|
7681
|
+
return mesh2;
|
|
7143
7682
|
}
|
|
7144
7683
|
function addRock(mark) {
|
|
7145
|
-
const
|
|
7146
|
-
|
|
7147
|
-
|
|
7148
|
-
|
|
7149
|
-
|
|
7150
|
-
|
|
7151
|
-
return
|
|
7684
|
+
const mesh2 = new THREE.Mesh(mark.plate ? options.plateGeometry : options.rockGeometry, rockMaterial(mark.color));
|
|
7685
|
+
mesh2.position.set(mark.x, mark.y, mark.z);
|
|
7686
|
+
mesh2.scale.set(mark.scale[0], mark.scale[1], mark.scale[2]);
|
|
7687
|
+
mesh2.rotation.set(mark.rotation[0], mark.rotation[1], mark.rotation[2]);
|
|
7688
|
+
mesh2.castShadow = true;
|
|
7689
|
+
mesh2.receiveShadow = true;
|
|
7690
|
+
return mesh2;
|
|
7152
7691
|
}
|
|
7153
7692
|
function addBlood(mark) {
|
|
7154
|
-
const
|
|
7155
|
-
|
|
7156
|
-
|
|
7157
|
-
|
|
7158
|
-
|
|
7159
|
-
|
|
7160
|
-
blood.push({ mesh, scaleX: mark.scaleX, scaleZ: mark.scaleZ, age: 0 });
|
|
7161
|
-
return
|
|
7693
|
+
const mesh2 = new THREE.Mesh(bloodGeometry, bloodMaterial);
|
|
7694
|
+
mesh2.position.set(mark.x, mark.y, mark.z);
|
|
7695
|
+
mesh2.scale.set(mark.scaleX, 1, mark.scaleZ);
|
|
7696
|
+
mesh2.rotation.y = mark.rotation;
|
|
7697
|
+
mesh2.receiveShadow = true;
|
|
7698
|
+
mesh2.scale.multiplyScalar(0.05);
|
|
7699
|
+
blood.push({ mesh: mesh2, scaleX: mark.scaleX, scaleZ: mark.scaleZ, age: 0 });
|
|
7700
|
+
return mesh2;
|
|
7162
7701
|
}
|
|
7163
7702
|
function build(mark) {
|
|
7164
7703
|
if (mark.kind === "scorch") return conform(mark, scorchMaterials[mark.variant]);
|
|
@@ -7369,6 +7908,73 @@ void main() {
|
|
|
7369
7908
|
}
|
|
7370
7909
|
};
|
|
7371
7910
|
}
|
|
7911
|
+
var SPHERE_DEFAULT_WIDTH = 8;
|
|
7912
|
+
var SPHERE_DEFAULT_HEIGHT = 6;
|
|
7913
|
+
function geometryOf(THREE, particle) {
|
|
7914
|
+
switch (particle.shape) {
|
|
7915
|
+
case "cone":
|
|
7916
|
+
return new THREE.ConeGeometry(particle.radius, particle.height, particle.segments || void 0, particle.segments2 || 1, false);
|
|
7917
|
+
case "cone_open":
|
|
7918
|
+
return new THREE.ConeGeometry(particle.radius, particle.height, particle.segments || void 0, particle.segments2 || 1, true);
|
|
7919
|
+
case "sphere":
|
|
7920
|
+
return new THREE.SphereGeometry(particle.radius, particle.segments || SPHERE_DEFAULT_WIDTH, particle.segments2 || SPHERE_DEFAULT_HEIGHT);
|
|
7921
|
+
case "icosahedron":
|
|
7922
|
+
return new THREE.IcosahedronGeometry(particle.radius, particle.segments);
|
|
7923
|
+
}
|
|
7924
|
+
}
|
|
7925
|
+
function materialOf(THREE, particle) {
|
|
7926
|
+
if (particle.lit) return new THREE.MeshStandardMaterial({ color: particle.color, roughness: 1, metalness: 0, transparent: true, opacity: particle.opacity, depthWrite: false });
|
|
7927
|
+
return new THREE.MeshBasicMaterial({ color: particle.color, transparent: true, opacity: particle.opacity, depthWrite: false, ...particle.additive ? { blending: THREE.AdditiveBlending } : {} });
|
|
7928
|
+
}
|
|
7929
|
+
function createMeshLayer(THREE, pool) {
|
|
7930
|
+
const group = new THREE.Group();
|
|
7931
|
+
group.name = "workshop-meshes";
|
|
7932
|
+
const drawn = /* @__PURE__ */ new Map();
|
|
7933
|
+
const frame = new THREE.Quaternion();
|
|
7934
|
+
const euler = new THREE.Euler();
|
|
7935
|
+
const turn = new THREE.Quaternion();
|
|
7936
|
+
const offset = new THREE.Vector3();
|
|
7937
|
+
function release(mesh2) {
|
|
7938
|
+
mesh2.removeFromParent();
|
|
7939
|
+
mesh2.geometry.dispose();
|
|
7940
|
+
mesh2.material.dispose();
|
|
7941
|
+
}
|
|
7942
|
+
return {
|
|
7943
|
+
group,
|
|
7944
|
+
sync() {
|
|
7945
|
+
const live = /* @__PURE__ */ new Set();
|
|
7946
|
+
for (const particle of pool.particles) {
|
|
7947
|
+
live.add(particle.id);
|
|
7948
|
+
let mesh2 = drawn.get(particle.id);
|
|
7949
|
+
if (!mesh2) {
|
|
7950
|
+
mesh2 = new THREE.Mesh(geometryOf(THREE, particle), materialOf(THREE, particle));
|
|
7951
|
+
mesh2.frustumCulled = false;
|
|
7952
|
+
mesh2.renderOrder = particle.additive ? 5 : 3;
|
|
7953
|
+
drawn.set(particle.id, mesh2);
|
|
7954
|
+
group.add(mesh2);
|
|
7955
|
+
}
|
|
7956
|
+
frame.set(particle.frame[0], particle.frame[1], particle.frame[2], particle.frame[3]);
|
|
7957
|
+
offset.set(particle.at[0], particle.at[1], particle.at[2]).multiplyScalar(particle.scale).applyQuaternion(frame);
|
|
7958
|
+
mesh2.position.set(particle.x + offset.x, particle.y + offset.y, particle.z + offset.z);
|
|
7959
|
+
turn.setFromEuler(euler.set(particle.rx, particle.ry, particle.rz));
|
|
7960
|
+
mesh2.quaternion.copy(frame).multiply(turn);
|
|
7961
|
+
mesh2.scale.setScalar(particle.scale);
|
|
7962
|
+
mesh2.material.opacity = particle.opacity;
|
|
7963
|
+
}
|
|
7964
|
+
for (const [id, mesh2] of drawn) {
|
|
7965
|
+
if (live.has(id)) continue;
|
|
7966
|
+
release(mesh2);
|
|
7967
|
+
drawn.delete(id);
|
|
7968
|
+
}
|
|
7969
|
+
return pool.count;
|
|
7970
|
+
},
|
|
7971
|
+
dispose() {
|
|
7972
|
+
for (const mesh2 of drawn.values()) release(mesh2);
|
|
7973
|
+
drawn.clear();
|
|
7974
|
+
group.removeFromParent();
|
|
7975
|
+
}
|
|
7976
|
+
};
|
|
7977
|
+
}
|
|
7372
7978
|
var WORKSHOP_SPRITE_VERTEX = `attribute float size;attribute float alpha;attribute vec3 pcol;varying vec3 vC;varying float vA;uniform float uScale;
|
|
7373
7979
|
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;}`;
|
|
7374
7980
|
var WORKSHOP_SPRITE_FRAGMENT = `uniform float uSoft;varying vec3 vC;varying float vA;
|
|
@@ -7444,13 +8050,37 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
7444
8050
|
}
|
|
7445
8051
|
};
|
|
7446
8052
|
}
|
|
8053
|
+
function rainLayer(THREE, rain) {
|
|
8054
|
+
const geometry = new THREE.BufferGeometry();
|
|
8055
|
+
const position = new THREE.BufferAttribute(rain.positions, 3).setUsage(THREE.DynamicDrawUsage);
|
|
8056
|
+
geometry.setAttribute("position", position);
|
|
8057
|
+
geometry.setDrawRange(0, 0);
|
|
8058
|
+
const material = new THREE.LineBasicMaterial({ color: 10466255, transparent: true, opacity: 0.35, depthWrite: false });
|
|
8059
|
+
const lines = new THREE.LineSegments(geometry, material);
|
|
8060
|
+
lines.frustumCulled = false;
|
|
8061
|
+
lines.name = "workshop-rain";
|
|
8062
|
+
return {
|
|
8063
|
+
object: lines,
|
|
8064
|
+
sync() {
|
|
8065
|
+
const drawn = rain.on && rain.count > 0;
|
|
8066
|
+
lines.visible = drawn;
|
|
8067
|
+
geometry.setDrawRange(0, drawn ? rain.count * 2 : 0);
|
|
8068
|
+
position.needsUpdate = true;
|
|
8069
|
+
return drawn;
|
|
8070
|
+
},
|
|
8071
|
+
dispose() {
|
|
8072
|
+
geometry.dispose();
|
|
8073
|
+
material.dispose();
|
|
8074
|
+
}
|
|
8075
|
+
};
|
|
8076
|
+
}
|
|
7447
8077
|
function debrisLayer(THREE, pool) {
|
|
7448
8078
|
const geometry = new THREE.BoxGeometry(1, 1, 1);
|
|
7449
8079
|
const material = new THREE.MeshStandardMaterial({ color: 16777215, roughness: 0.45, metalness: 0.25, flatShading: true });
|
|
7450
|
-
const
|
|
7451
|
-
|
|
7452
|
-
|
|
7453
|
-
|
|
8080
|
+
const mesh2 = new THREE.InstancedMesh(geometry, material, DEBRIS_CAPACITY);
|
|
8081
|
+
mesh2.instanceMatrix.setUsage(THREE.DynamicDrawUsage);
|
|
8082
|
+
mesh2.frustumCulled = false;
|
|
8083
|
+
mesh2.name = "workshop-debris";
|
|
7454
8084
|
const euler = new THREE.Euler();
|
|
7455
8085
|
const quaternion = new THREE.Quaternion();
|
|
7456
8086
|
const position = new THREE.Vector3();
|
|
@@ -7458,16 +8088,16 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
7458
8088
|
const matrix = new THREE.Matrix4();
|
|
7459
8089
|
const colour = new THREE.Color();
|
|
7460
8090
|
const hidden = new THREE.Matrix4().makeScale(0, 0, 0);
|
|
7461
|
-
for (let index = 0; index < DEBRIS_CAPACITY; index++)
|
|
7462
|
-
|
|
8091
|
+
for (let index = 0; index < DEBRIS_CAPACITY; index++) mesh2.setMatrixAt(index, hidden);
|
|
8092
|
+
mesh2.setColorAt(0, colour.setHex(16777215));
|
|
7463
8093
|
return {
|
|
7464
|
-
object:
|
|
8094
|
+
object: mesh2,
|
|
7465
8095
|
sync() {
|
|
7466
8096
|
let drawn = false;
|
|
7467
8097
|
for (let index = 0; index < DEBRIS_CAPACITY; index++) {
|
|
7468
8098
|
const piece = pool.pieces[index];
|
|
7469
8099
|
if (!piece.on) {
|
|
7470
|
-
|
|
8100
|
+
mesh2.setMatrixAt(index, hidden);
|
|
7471
8101
|
continue;
|
|
7472
8102
|
}
|
|
7473
8103
|
drawn = true;
|
|
@@ -7475,11 +8105,11 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
7475
8105
|
euler.set(piece.rx, piece.ry, piece.rz);
|
|
7476
8106
|
quaternion.setFromEuler(euler);
|
|
7477
8107
|
matrix.compose(position.set(piece.x, piece.y, piece.z), quaternion, scale2.set(piece.sx * shrink, piece.sy * shrink, piece.sz * shrink));
|
|
7478
|
-
|
|
7479
|
-
|
|
8108
|
+
mesh2.setMatrixAt(index, matrix);
|
|
8109
|
+
mesh2.setColorAt(index, colour.setHex(piece.color));
|
|
7480
8110
|
}
|
|
7481
|
-
|
|
7482
|
-
if (
|
|
8111
|
+
mesh2.instanceMatrix.needsUpdate = true;
|
|
8112
|
+
if (mesh2.instanceColor) mesh2.instanceColor.needsUpdate = true;
|
|
7483
8113
|
return drawn;
|
|
7484
8114
|
},
|
|
7485
8115
|
dispose() {
|
|
@@ -7536,11 +8166,11 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
7536
8166
|
const dryMesh = new THREE.InstancedMesh(geometry, dry, DECAL_CAPACITY);
|
|
7537
8167
|
const group = new THREE.Group();
|
|
7538
8168
|
group.name = "workshop-decals";
|
|
7539
|
-
for (const
|
|
7540
|
-
|
|
7541
|
-
|
|
7542
|
-
|
|
7543
|
-
group.add(
|
|
8169
|
+
for (const mesh2 of [wetMesh, dryMesh]) {
|
|
8170
|
+
mesh2.frustumCulled = false;
|
|
8171
|
+
mesh2.renderOrder = 1;
|
|
8172
|
+
mesh2.instanceMatrix.setUsage(THREE.DynamicDrawUsage);
|
|
8173
|
+
group.add(mesh2);
|
|
7544
8174
|
}
|
|
7545
8175
|
const hidden = new THREE.Matrix4().makeScale(0, 0, 0);
|
|
7546
8176
|
const colour = new THREE.Color();
|
|
@@ -7577,13 +8207,13 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
7577
8207
|
quaternion.multiply(turn.setFromAxisAngle(forward, index * 2.399963));
|
|
7578
8208
|
const offset = 4e-3 + index % 40 * 4e-4;
|
|
7579
8209
|
matrix.compose(position.set(decal2.x + normal.x * offset, decal2.y + normal.y * offset, decal2.z + normal.z * offset), quaternion, scale2.set(look.sx, look.sy, 1));
|
|
7580
|
-
const
|
|
7581
|
-
|
|
7582
|
-
|
|
8210
|
+
const mesh2 = look.dried ? dryMesh : wetMesh;
|
|
8211
|
+
mesh2.setMatrixAt(index, matrix);
|
|
8212
|
+
mesh2.setColorAt(index, colour);
|
|
7583
8213
|
}
|
|
7584
|
-
for (const
|
|
7585
|
-
|
|
7586
|
-
if (
|
|
8214
|
+
for (const mesh2 of [wetMesh, dryMesh]) {
|
|
8215
|
+
mesh2.instanceMatrix.needsUpdate = true;
|
|
8216
|
+
if (mesh2.instanceColor) mesh2.instanceColor.needsUpdate = true;
|
|
7587
8217
|
}
|
|
7588
8218
|
return drawn;
|
|
7589
8219
|
},
|
|
@@ -7597,10 +8227,10 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
7597
8227
|
function ringLayer(THREE, pool) {
|
|
7598
8228
|
const geometry = new THREE.RingGeometry(0.86, 1, 40);
|
|
7599
8229
|
const material = new THREE.MeshBasicMaterial({ color: 16777215, transparent: true, blending: THREE.AdditiveBlending, depthWrite: false, side: THREE.DoubleSide });
|
|
7600
|
-
const
|
|
7601
|
-
|
|
7602
|
-
|
|
7603
|
-
|
|
8230
|
+
const mesh2 = new THREE.InstancedMesh(geometry, material, RING_CAPACITY3);
|
|
8231
|
+
mesh2.frustumCulled = false;
|
|
8232
|
+
mesh2.instanceMatrix.setUsage(THREE.DynamicDrawUsage);
|
|
8233
|
+
mesh2.name = "workshop-rings";
|
|
7604
8234
|
const hidden = new THREE.Matrix4().makeScale(0, 0, 0);
|
|
7605
8235
|
const colour = new THREE.Color();
|
|
7606
8236
|
const normal = new THREE.Vector3();
|
|
@@ -7609,16 +8239,16 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
7609
8239
|
const position = new THREE.Vector3();
|
|
7610
8240
|
const scale2 = new THREE.Vector3();
|
|
7611
8241
|
const matrix = new THREE.Matrix4();
|
|
7612
|
-
|
|
7613
|
-
for (let index = 0; index < RING_CAPACITY3; index++)
|
|
8242
|
+
mesh2.setColorAt(0, colour.setHex(0));
|
|
8243
|
+
for (let index = 0; index < RING_CAPACITY3; index++) mesh2.setMatrixAt(index, hidden);
|
|
7614
8244
|
return {
|
|
7615
|
-
object:
|
|
8245
|
+
object: mesh2,
|
|
7616
8246
|
sync() {
|
|
7617
8247
|
let drawn = false;
|
|
7618
8248
|
for (let index = 0; index < RING_CAPACITY3; index++) {
|
|
7619
8249
|
const ring2 = pool.rings[index];
|
|
7620
8250
|
if (!ring2.on) {
|
|
7621
|
-
|
|
8251
|
+
mesh2.setMatrixAt(index, hidden);
|
|
7622
8252
|
continue;
|
|
7623
8253
|
}
|
|
7624
8254
|
drawn = true;
|
|
@@ -7626,11 +8256,11 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
7626
8256
|
const radius = ring2.from + (ring2.to - ring2.from) * (1 - Math.pow(1 - k, 2));
|
|
7627
8257
|
quaternion.setFromUnitVectors(forward, normal.set(ring2.normal[0], ring2.normal[1], ring2.normal[2]));
|
|
7628
8258
|
matrix.compose(position.set(ring2.point[0], ring2.point[1], ring2.point[2]), quaternion, scale2.set(radius, radius, 1));
|
|
7629
|
-
|
|
7630
|
-
|
|
8259
|
+
mesh2.setMatrixAt(index, matrix);
|
|
8260
|
+
mesh2.setColorAt(index, colour.setHex(ring2.color).multiplyScalar(ring2.hold ? ring2.hold : 1 - k));
|
|
7631
8261
|
}
|
|
7632
|
-
|
|
7633
|
-
if (
|
|
8262
|
+
mesh2.instanceMatrix.needsUpdate = true;
|
|
8263
|
+
if (mesh2.instanceColor) mesh2.instanceColor.needsUpdate = true;
|
|
7634
8264
|
return drawn;
|
|
7635
8265
|
},
|
|
7636
8266
|
dispose() {
|
|
@@ -7646,11 +8276,14 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
7646
8276
|
spriteLayer(THREE, engine.add, true, 1, pointScale),
|
|
7647
8277
|
spriteLayer(THREE, engine.normal, false, 0.55, pointScale),
|
|
7648
8278
|
streakLayer(THREE, engine.streaks),
|
|
8279
|
+
rainLayer(THREE, engine.rain),
|
|
7649
8280
|
debrisLayer(THREE, engine.debris),
|
|
7650
8281
|
decalLayer(THREE, engine.decals),
|
|
7651
8282
|
ringLayer(THREE, engine.rings)
|
|
7652
8283
|
];
|
|
7653
8284
|
for (const layer2 of layers) group.add(layer2.object);
|
|
8285
|
+
const meshes = createMeshLayer(THREE, engine.meshes);
|
|
8286
|
+
group.add(meshes.group);
|
|
7654
8287
|
const flashLights = engine.lights.lights.map(() => new THREE.PointLight(16760944, 0, 14));
|
|
7655
8288
|
const fireLights = engine.lights.fire.map(() => new THREE.PointLight(FIRE_LIGHT_COLOR, 0, FIRE_LIGHT_DISTANCE));
|
|
7656
8289
|
for (const light of [...flashLights, ...fireLights]) group.add(light);
|
|
@@ -7659,6 +8292,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
7659
8292
|
sync() {
|
|
7660
8293
|
let drawCalls = 0;
|
|
7661
8294
|
for (const layer2 of layers) if (layer2.sync()) drawCalls++;
|
|
8295
|
+
drawCalls += meshes.sync();
|
|
7662
8296
|
engine.lights.lights.forEach((source, index) => {
|
|
7663
8297
|
const light = flashLights[index];
|
|
7664
8298
|
light.position.set(source.x, source.y, source.z);
|
|
@@ -7675,6 +8309,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
7675
8309
|
},
|
|
7676
8310
|
dispose() {
|
|
7677
8311
|
for (const layer2 of layers) layer2.dispose();
|
|
8312
|
+
meshes.dispose();
|
|
7678
8313
|
group.clear();
|
|
7679
8314
|
}
|
|
7680
8315
|
};
|
|
@@ -7790,8 +8425,10 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
7790
8425
|
return world.play(request.effect, request.point, {
|
|
7791
8426
|
...request.direction ? { direction: request.direction } : {},
|
|
7792
8427
|
...request.normal ? { normal: request.normal } : {},
|
|
8428
|
+
...request.orientation ? { orientation: request.orientation } : {},
|
|
7793
8429
|
...request.seed !== void 0 ? { seed: request.seed } : {},
|
|
7794
|
-
...request.param !== void 0 ? { param: request.param } : {}
|
|
8430
|
+
...request.param !== void 0 ? { param: request.param } : {},
|
|
8431
|
+
...request.values ? { values: request.values } : {}
|
|
7795
8432
|
});
|
|
7796
8433
|
},
|
|
7797
8434
|
stop: (handle) => world.stop(handle),
|
|
@@ -8605,7 +9242,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8605
9242
|
if (lastRow < 0) return;
|
|
8606
9243
|
const profile = profileOf2();
|
|
8607
9244
|
const rainScale = 1 - options.weather().rain;
|
|
8608
|
-
const seconds = dryingSeconds * rainScale;
|
|
9245
|
+
const seconds = dryingSeconds * rainScale * (options.weather().drying ?? 1);
|
|
8609
9246
|
for (let row = firstRow; row <= lastRow; row++) {
|
|
8610
9247
|
const offset = row * width;
|
|
8611
9248
|
for (let column = firstColumn; column <= lastColumn; column++) {
|
|
@@ -8729,6 +9366,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8729
9366
|
}
|
|
8730
9367
|
var DEFAULT_STEP_RATE = 180;
|
|
8731
9368
|
var DEFAULT_MAX_STEPS = 6;
|
|
9369
|
+
var WASH_BELOW_DRYNESS = 0.5;
|
|
8732
9370
|
function createFilm(options) {
|
|
8733
9371
|
const { layout, random } = options;
|
|
8734
9372
|
const cellCount = layout.width * layout.height;
|
|
@@ -8739,7 +9377,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8739
9377
|
dryness: new Float32Array(cellCount),
|
|
8740
9378
|
dampness: new Float32Array(cellCount)
|
|
8741
9379
|
};
|
|
8742
|
-
let weatherState = { rain: 0 };
|
|
9380
|
+
let weatherState = { rain: 0, drying: 1 };
|
|
8743
9381
|
let currentProfile = options.profile;
|
|
8744
9382
|
const context = { field, random, profile: () => currentProfile };
|
|
8745
9383
|
const drops = createDropPool(layout, context);
|
|
@@ -8777,9 +9415,29 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8777
9415
|
simulator.advance({ dt, dryingSeconds });
|
|
8778
9416
|
},
|
|
8779
9417
|
setWeather(weather) {
|
|
8780
|
-
weatherState = {
|
|
9418
|
+
weatherState = {
|
|
9419
|
+
rain: Math.min(1, Math.max(0, weather.rain ?? weatherState.rain)),
|
|
9420
|
+
drying: Math.max(0, weather.drying ?? weatherState.drying ?? 1)
|
|
9421
|
+
};
|
|
8781
9422
|
},
|
|
8782
9423
|
weather: () => ({ ...weatherState }),
|
|
9424
|
+
wash(maxDryness = WASH_BELOW_DRYNESS) {
|
|
9425
|
+
simulator.refreshBounds();
|
|
9426
|
+
const { firstRow, lastRow, firstColumn, lastColumn } = simulator.bounds;
|
|
9427
|
+
let cleared = 0;
|
|
9428
|
+
for (let row = firstRow; row <= lastRow; row++) {
|
|
9429
|
+
for (let column = firstColumn; column <= lastColumn; column++) {
|
|
9430
|
+
const index = row * layout.width + column;
|
|
9431
|
+
if (field.thickness[index] > 0 && field.dryness[index] < maxDryness) {
|
|
9432
|
+
field.thickness[index] = 0;
|
|
9433
|
+
field.dryness[index] = 0;
|
|
9434
|
+
field.dampness[index] = 0;
|
|
9435
|
+
cleared++;
|
|
9436
|
+
}
|
|
9437
|
+
}
|
|
9438
|
+
}
|
|
9439
|
+
return cleared;
|
|
9440
|
+
},
|
|
8783
9441
|
clear() {
|
|
8784
9442
|
field.thickness.fill(0);
|
|
8785
9443
|
field.dryness.fill(0);
|
|
@@ -9292,11 +9950,11 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
9292
9950
|
const index = [];
|
|
9293
9951
|
for (let i = 0; i < this.ring; i++) index.push(0, 1 + i, 1 + (i + 1) % this.ring);
|
|
9294
9952
|
geometry.setIndex(index);
|
|
9295
|
-
const
|
|
9296
|
-
|
|
9297
|
-
|
|
9298
|
-
|
|
9299
|
-
return { mesh, position, color };
|
|
9953
|
+
const mesh2 = new T.Mesh(geometry);
|
|
9954
|
+
mesh2.name = name;
|
|
9955
|
+
mesh2.frustumCulled = false;
|
|
9956
|
+
mesh2.renderOrder = order;
|
|
9957
|
+
return { mesh: mesh2, position, color };
|
|
9300
9958
|
}
|
|
9301
9959
|
assign(def, materials) {
|
|
9302
9960
|
this.outer.mesh.material = materials.stainFilm(def);
|
|
@@ -10036,12 +10694,12 @@ void main(){
|
|
|
10036
10694
|
this.group = new THREE.Group();
|
|
10037
10695
|
this.group.name = "film_grid";
|
|
10038
10696
|
for (const region of layout.regions) {
|
|
10039
|
-
const
|
|
10040
|
-
|
|
10041
|
-
|
|
10042
|
-
|
|
10043
|
-
this.strips.push(
|
|
10044
|
-
this.group.add(
|
|
10697
|
+
const mesh2 = new THREE.Mesh(createStripGeometry(THREE, layout, region), this.material.material);
|
|
10698
|
+
mesh2.frustumCulled = false;
|
|
10699
|
+
mesh2.renderOrder = 3;
|
|
10700
|
+
mesh2.name = `film_${region.id}`;
|
|
10701
|
+
this.strips.push(mesh2);
|
|
10702
|
+
this.group.add(mesh2);
|
|
10045
10703
|
}
|
|
10046
10704
|
this.dropsView = createFilmDrops(THREE, layout.rules.dropCapacity, profile);
|
|
10047
10705
|
this.group.add(this.dropsView.drops, this.dropsView.bead);
|
|
@@ -10086,6 +10744,19 @@ void main(){
|
|
|
10086
10744
|
this.pending = this.union(this.pending, rect);
|
|
10087
10745
|
return this.takePending();
|
|
10088
10746
|
}
|
|
10747
|
+
/** Clears the cells less than `maxDryness` dry and sends the rectangle that held them up with the next update. Returns how many it cleared. */
|
|
10748
|
+
wash(maxDryness) {
|
|
10749
|
+
const cleared = this.film.wash(maxDryness);
|
|
10750
|
+
if (cleared > 0) {
|
|
10751
|
+
const bounds = this.film.simulator.bounds;
|
|
10752
|
+
if (bounds.lastRow >= 0) {
|
|
10753
|
+
const rect = { firstRow: bounds.firstRow, lastRow: bounds.lastRow, firstColumn: bounds.firstColumn, lastColumn: bounds.lastColumn };
|
|
10754
|
+
this.encode(rect);
|
|
10755
|
+
this.pending = this.union(this.pending, rect);
|
|
10756
|
+
}
|
|
10757
|
+
}
|
|
10758
|
+
return cleared;
|
|
10759
|
+
}
|
|
10089
10760
|
takePending() {
|
|
10090
10761
|
const rect = this.pending;
|
|
10091
10762
|
this.pending = null;
|
|
@@ -10141,7 +10812,7 @@ void main(){
|
|
|
10141
10812
|
return { firstRow: Math.min(a.firstRow, b.firstRow), lastRow: Math.max(a.lastRow, b.lastRow), firstColumn: Math.min(a.firstColumn, b.firstColumn), lastColumn: Math.max(a.lastColumn, b.lastColumn) };
|
|
10142
10813
|
}
|
|
10143
10814
|
dispose() {
|
|
10144
|
-
for (const
|
|
10815
|
+
for (const mesh2 of this.strips) mesh2.geometry.dispose();
|
|
10145
10816
|
this.material.dispose();
|
|
10146
10817
|
this.dropsView.dispose();
|
|
10147
10818
|
this.texture.dispose();
|
|
@@ -10157,11 +10828,12 @@ void main(){
|
|
|
10157
10828
|
var DEFAULT_GRID_METRES = 2;
|
|
10158
10829
|
var DEFAULT_CELL2 = 0.0125;
|
|
10159
10830
|
var BAKE_RANGE_FACTOR = 1.25;
|
|
10831
|
+
var DEFAULT_WASHABLE = ["blood", "old_blood"];
|
|
10160
10832
|
var EDGE_MARGIN = 0.35;
|
|
10161
10833
|
var FLOOR_REACH = 0.3;
|
|
10162
10834
|
var DROP_HEIGHT = 2.5;
|
|
10163
10835
|
var DEFAULT_DROP_RADIUS = 3;
|
|
10164
|
-
var
|
|
10836
|
+
var FALL_SPEED2 = 2;
|
|
10165
10837
|
var VISIBLE_THICKNESS3 = 0.035;
|
|
10166
10838
|
var DEFAULT_HALF = 50;
|
|
10167
10839
|
var FREE_AFTER_EMPTY = 2;
|
|
@@ -10182,6 +10854,7 @@ void main(){
|
|
|
10182
10854
|
__publicField(this, "staging", /* @__PURE__ */ new Map());
|
|
10183
10855
|
__publicField(this, "now");
|
|
10184
10856
|
__publicField(this, "rain", 0);
|
|
10857
|
+
__publicField(this, "drying", 1);
|
|
10185
10858
|
__publicField(this, "time", 0);
|
|
10186
10859
|
__publicField(this, "bakedCount", 0);
|
|
10187
10860
|
__publicField(this, "last", { grids: 0, drops: 0, wetCells: 0, simMs: 0, starved: 0, baked: 0, uploadedTexels: 0 });
|
|
@@ -10201,13 +10874,24 @@ void main(){
|
|
|
10201
10874
|
}
|
|
10202
10875
|
setWeather(weather) {
|
|
10203
10876
|
this.rain = Math.min(1, Math.max(0, weather.rain));
|
|
10204
|
-
|
|
10877
|
+
if (weather.drying !== void 0) this.drying = Math.max(0, weather.drying);
|
|
10878
|
+
for (const grid of this.grids) grid.film.setWeather({ rain: this.rain, drying: this.drying });
|
|
10879
|
+
}
|
|
10880
|
+
/**
|
|
10881
|
+
* Rain washes the fresh stain away (the visor's `ZG.wipe` with mode "chuva"): in the grids of the washable liquids (default blood and old blood), the
|
|
10882
|
+
* cells that are less than `maxDryness` dry (default 0.5) are cleared. Returns how many cells it cleared.
|
|
10883
|
+
*/
|
|
10884
|
+
wash(maxDryness) {
|
|
10885
|
+
const washable = this.options.washable ?? DEFAULT_WASHABLE;
|
|
10886
|
+
let cleared = 0;
|
|
10887
|
+
for (const grid of this.grids) if (washable.includes(grid.profile.id)) cleared += grid.wash(maxDryness);
|
|
10888
|
+
return cleared;
|
|
10205
10889
|
}
|
|
10206
10890
|
/** Throws a drop of a liquid: it lands in the grid under it (made on the spot) and leaves the impact splash. Null when it is out of range or has no surface. */
|
|
10207
10891
|
launch(request) {
|
|
10208
10892
|
const grid = this.gridFor(request.fluid, request.point, request.surfaces, request.tint);
|
|
10209
10893
|
if (!grid) return null;
|
|
10210
|
-
const velocity = request.velocity ?? [0, -
|
|
10894
|
+
const velocity = request.velocity ?? [0, -FALL_SPEED2, 0];
|
|
10211
10895
|
grid.film.launch(request.point, velocity, request.radius ?? DEFAULT_DROP_RADIUS);
|
|
10212
10896
|
return grid;
|
|
10213
10897
|
}
|
|
@@ -10232,7 +10916,7 @@ void main(){
|
|
|
10232
10916
|
const layout = layoutFromSurfaces({ ...found, center: point, columns: this.columns(), rows: this.columns(), cellSize: this.options.cellSize ?? DEFAULT_CELL2 });
|
|
10233
10917
|
if (this.grids.length >= (this.options.maxGrids ?? DEFAULT_MAX_GRIDS)) this.evict(point);
|
|
10234
10918
|
const grid = new FilmGrid(this.THREE, { layout, profile, random: this.options.random, center: point, ...tint ? { tint } : {}, ...this.options.base === void 0 ? {} : { base: this.options.base } });
|
|
10235
|
-
grid.film.setWeather({ rain: this.rain });
|
|
10919
|
+
grid.film.setWeather({ rain: this.rain, drying: this.drying });
|
|
10236
10920
|
this.grids.push(grid);
|
|
10237
10921
|
this.group.add(grid.group);
|
|
10238
10922
|
return grid;
|
|
@@ -10309,7 +10993,7 @@ void main(){
|
|
|
10309
10993
|
/** Whether `point` is over the grid, away from its edge, so a splash there does not fall off the strip. */
|
|
10310
10994
|
covers(grid, point) {
|
|
10311
10995
|
const layout = grid.film.layout;
|
|
10312
|
-
const
|
|
10996
|
+
const wide2 = layout.width * layout.cellSize;
|
|
10313
10997
|
for (const region of layout.regions) {
|
|
10314
10998
|
const local2 = [point[0] - region.origin[0], point[1] - region.origin[1], point[2] - region.origin[2]];
|
|
10315
10999
|
const above2 = local2[0] * region.normal[0] + local2[1] * region.normal[1] + local2[2] * region.normal[2];
|
|
@@ -10317,7 +11001,7 @@ void main(){
|
|
|
10317
11001
|
const sideways = local2[0] * region.columnAxis[0] + local2[1] * region.columnAxis[1] + local2[2] * region.columnAxis[2];
|
|
10318
11002
|
const down = local2[0] * region.rowAxis[0] + local2[1] * region.rowAxis[1] + local2[2] * region.rowAxis[2];
|
|
10319
11003
|
const length2 = region.rowCount * layout.cellSize;
|
|
10320
|
-
if (sideways > EDGE_MARGIN && sideways <
|
|
11004
|
+
if (sideways > EDGE_MARGIN && sideways < wide2 - EDGE_MARGIN && down > EDGE_MARGIN && down < length2 - EDGE_MARGIN) return true;
|
|
10321
11005
|
}
|
|
10322
11006
|
return false;
|
|
10323
11007
|
}
|
|
@@ -10470,6 +11154,7 @@ void main(){
|
|
|
10470
11154
|
return landed;
|
|
10471
11155
|
},
|
|
10472
11156
|
setWeather: (weather) => manager.setWeather(weather),
|
|
11157
|
+
wash: (maxDryness) => manager.wash(maxDryness),
|
|
10473
11158
|
update(dt) {
|
|
10474
11159
|
if (leaks.size === 0) return;
|
|
10475
11160
|
const streams = new Map(fluids.streams().map((stream) => [stream.id, stream]));
|