@adatechnology/game-test-room 0.10.0 → 0.11.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 +6 -1
- package/dist/index.global.js +1104 -413
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/package.json +10 -10
package/dist/index.global.js
CHANGED
|
@@ -4587,6 +4587,56 @@ var GameTestRoom = (() => {
|
|
|
4587
4587
|
};
|
|
4588
4588
|
}
|
|
4589
4589
|
var GAME_SFX_BANK = { id: "game_sfx", sounds: [...GAME_SFX_CLASSES, GAME_SFX_FALLBACK].map((row) => noiseClassRecipe(row)) };
|
|
4590
|
+
var ATTACK = 2e-3;
|
|
4591
|
+
function lengthOf(d, attack) {
|
|
4592
|
+
if (typeof d === "number") return attack + d;
|
|
4593
|
+
if (Array.isArray(d)) return [attack + d[0], attack + d[1]];
|
|
4594
|
+
return { ...d, add: (d.add ?? 0) + attack };
|
|
4595
|
+
}
|
|
4596
|
+
var envelope = (attack) => [
|
|
4597
|
+
[0, 1e-4, "set", "fixed"],
|
|
4598
|
+
[attack, 1, "exp"],
|
|
4599
|
+
["1d", 1e-4, "exp", "fixed"]
|
|
4600
|
+
];
|
|
4601
|
+
function sceneNoise(o) {
|
|
4602
|
+
const a = o.a ?? ATTACK;
|
|
4603
|
+
const over = typeof o.d === "number" ? o.d : 0;
|
|
4604
|
+
return {
|
|
4605
|
+
filters: {
|
|
4606
|
+
mode: "serial",
|
|
4607
|
+
bank: [{ type: o.type ?? "lowpass", frequency: o.f2 === void 0 ? { set: o.f } : { set: o.f, to: o.f2, curve: "exp", over }, q: o.q ?? 0.7 }]
|
|
4608
|
+
},
|
|
4609
|
+
duration: lengthOf(o.d, a),
|
|
4610
|
+
gain: o.vol,
|
|
4611
|
+
...o.delay === void 0 ? {} : { at: o.delay },
|
|
4612
|
+
...o.wet === void 0 ? {} : { wet: o.wet },
|
|
4613
|
+
source: { kind: "noise", offset: "random", offsetScale: 1.5, loop: true },
|
|
4614
|
+
envelope: envelope(a)
|
|
4615
|
+
};
|
|
4616
|
+
}
|
|
4617
|
+
function sceneTone(o) {
|
|
4618
|
+
return {
|
|
4619
|
+
source: { kind: "osc", wave: o.wave ?? "sine", frequency: { from: o.f, to: o.f2 ?? "from", curve: "exp", over: "duration" } },
|
|
4620
|
+
duration: lengthOf(o.d, ATTACK),
|
|
4621
|
+
gain: o.vol,
|
|
4622
|
+
...o.delay === void 0 ? {} : { at: o.delay },
|
|
4623
|
+
...o.wet === void 0 ? {} : { wet: o.wet },
|
|
4624
|
+
envelope: envelope(ATTACK)
|
|
4625
|
+
};
|
|
4626
|
+
}
|
|
4627
|
+
var sceneMany = (count, make) => Array.from({ length: count }, make);
|
|
4628
|
+
function sceneRecipe(id, layers, line, options = {}) {
|
|
4629
|
+
return {
|
|
4630
|
+
id,
|
|
4631
|
+
bus: options.bus ?? "world",
|
|
4632
|
+
pan: true,
|
|
4633
|
+
layers,
|
|
4634
|
+
falloff: DISTANCE_CURVES.art_scene,
|
|
4635
|
+
...options.vars ? { vars: options.vars } : {},
|
|
4636
|
+
...options.group ? { group: options.group } : {},
|
|
4637
|
+
sources: [`cena:${line}`]
|
|
4638
|
+
};
|
|
4639
|
+
}
|
|
4590
4640
|
function fillNoise(random, length3) {
|
|
4591
4641
|
const samples = new Float32Array(length3);
|
|
4592
4642
|
for (let index = 0; index < length3; index++) samples[index] = random() * 2 - 1;
|
|
@@ -6859,77 +6909,77 @@ var GameTestRoom = (() => {
|
|
|
6859
6909
|
}));
|
|
6860
6910
|
}
|
|
6861
6911
|
function spawnPuff(pool, random, init) {
|
|
6862
|
-
const
|
|
6863
|
-
|
|
6864
|
-
|
|
6865
|
-
|
|
6866
|
-
|
|
6867
|
-
|
|
6868
|
-
|
|
6869
|
-
|
|
6870
|
-
|
|
6871
|
-
|
|
6872
|
-
|
|
6873
|
-
|
|
6874
|
-
|
|
6875
|
-
|
|
6876
|
-
|
|
6877
|
-
|
|
6878
|
-
|
|
6879
|
-
|
|
6880
|
-
|
|
6881
|
-
|
|
6882
|
-
|
|
6883
|
-
|
|
6884
|
-
|
|
6885
|
-
|
|
6886
|
-
|
|
6887
|
-
|
|
6888
|
-
|
|
6889
|
-
|
|
6890
|
-
|
|
6891
|
-
return
|
|
6892
|
-
}
|
|
6893
|
-
function ageOrKeep2(
|
|
6894
|
-
|
|
6895
|
-
return
|
|
6896
|
-
}
|
|
6897
|
-
function moveOnRing(
|
|
6912
|
+
const puff3 = pool.acquire();
|
|
6913
|
+
puff3.x = init.x ?? 0;
|
|
6914
|
+
puff3.y = init.y ?? 0;
|
|
6915
|
+
puff3.z = init.z ?? 0;
|
|
6916
|
+
puff3.vx = init.vx ?? 0;
|
|
6917
|
+
puff3.vy = init.vy ?? 0;
|
|
6918
|
+
puff3.vz = init.vz ?? 0;
|
|
6919
|
+
puff3.s0 = init.s0 ?? 0.2;
|
|
6920
|
+
puff3.s1 = init.s1 ?? 1;
|
|
6921
|
+
puff3.sg = init.sg ?? 0.1;
|
|
6922
|
+
puff3.gk = init.gk ?? 6;
|
|
6923
|
+
puff3.life = init.life ?? 3;
|
|
6924
|
+
puff3.t = 0;
|
|
6925
|
+
puff3.h0 = init.h0 ?? 0;
|
|
6926
|
+
puff3.hl = init.hl ?? 0.4;
|
|
6927
|
+
puff3.drag = init.drag ?? 3;
|
|
6928
|
+
puff3.buoy = init.buoy ?? 0.5;
|
|
6929
|
+
puff3.grav = init.grav ?? 0;
|
|
6930
|
+
puff3.kind = init.kind ?? 0;
|
|
6931
|
+
puff3.seed = random.next();
|
|
6932
|
+
puff3.wind = init.wind ?? 1;
|
|
6933
|
+
puff3.color = init.color ?? SMOKE_COLORS.grey;
|
|
6934
|
+
puff3.ring = init.ring ?? null;
|
|
6935
|
+
puff3.ph = init.ph ?? 0;
|
|
6936
|
+
puff3.th = init.th ?? 0;
|
|
6937
|
+
puff3.rng = random;
|
|
6938
|
+
puff3.age = 0;
|
|
6939
|
+
puff3.heat = 0;
|
|
6940
|
+
puff3.size = 0;
|
|
6941
|
+
return puff3;
|
|
6942
|
+
}
|
|
6943
|
+
function ageOrKeep2(puff3, dt) {
|
|
6944
|
+
puff3.t += dt;
|
|
6945
|
+
return puff3.t < puff3.life;
|
|
6946
|
+
}
|
|
6947
|
+
function moveOnRing(puff3, ring2, wind) {
|
|
6898
6948
|
const ringTime = ring2.t;
|
|
6899
6949
|
const centerY = ring2.y0 + ring2.rise * (1 - Math.exp(-ringTime * ring2.rk));
|
|
6900
6950
|
const majorRadius = ring2.R0 + (ring2.R1 - ring2.R0) * (1 - Math.exp(-ringTime * 1.6));
|
|
6901
|
-
const theta =
|
|
6951
|
+
const theta = puff3.th + ringTime * ring2.roll;
|
|
6902
6952
|
const minorRadius = ring2.r * (0.8 + 0.4 * Math.min(1, ringTime));
|
|
6903
6953
|
const radius = majorRadius + minorRadius * Math.cos(theta);
|
|
6904
|
-
|
|
6905
|
-
|
|
6906
|
-
|
|
6907
|
-
}
|
|
6908
|
-
function moveFree(
|
|
6909
|
-
const damping = Math.exp(-
|
|
6910
|
-
|
|
6911
|
-
|
|
6912
|
-
|
|
6913
|
-
|
|
6914
|
-
|
|
6915
|
-
|
|
6916
|
-
|
|
6917
|
-
if (
|
|
6918
|
-
|
|
6919
|
-
if (
|
|
6954
|
+
puff3.x = ring2.x + Math.cos(puff3.ph) * radius + wind.x * ringTime * 0.6;
|
|
6955
|
+
puff3.z = ring2.z + Math.sin(puff3.ph) * radius + wind.z * ringTime * 0.6;
|
|
6956
|
+
puff3.y = centerY + minorRadius * Math.sin(theta);
|
|
6957
|
+
}
|
|
6958
|
+
function moveFree(puff3, dt, age, heat, wind) {
|
|
6959
|
+
const damping = Math.exp(-puff3.drag * dt);
|
|
6960
|
+
puff3.vx *= damping;
|
|
6961
|
+
puff3.vy *= damping;
|
|
6962
|
+
puff3.vz *= damping;
|
|
6963
|
+
puff3.vy += (puff3.buoy * (heat > 0 ? 1.6 : 1) - puff3.grav) * dt;
|
|
6964
|
+
puff3.x += (puff3.vx + wind.x * puff3.wind * age) * dt;
|
|
6965
|
+
puff3.y += puff3.vy * dt;
|
|
6966
|
+
puff3.z += (puff3.vz + wind.z * puff3.wind * age) * dt;
|
|
6967
|
+
if (puff3.y < puff3.s0 * FLOOR_FRACTION) {
|
|
6968
|
+
puff3.y = puff3.s0 * FLOOR_FRACTION;
|
|
6969
|
+
if (puff3.vy < 0) puff3.vy *= FLOOR_BOUNCE;
|
|
6920
6970
|
}
|
|
6921
6971
|
}
|
|
6922
6972
|
function updatePuffs(pool, dt, wind) {
|
|
6923
6973
|
pool.compact(ageOrKeep2, dt);
|
|
6924
|
-
for (const
|
|
6925
|
-
const age =
|
|
6926
|
-
const heat =
|
|
6927
|
-
if (
|
|
6928
|
-
else moveFree(
|
|
6929
|
-
const size =
|
|
6930
|
-
|
|
6931
|
-
|
|
6932
|
-
|
|
6974
|
+
for (const puff3 of pool.items) {
|
|
6975
|
+
const age = puff3.t / puff3.life;
|
|
6976
|
+
const heat = puff3.h0 > 0 ? puff3.h0 * Math.pow(Math.max(0, 1 - puff3.t / puff3.hl), 1.25) : 0;
|
|
6977
|
+
if (puff3.ring) moveOnRing(puff3, puff3.ring, wind);
|
|
6978
|
+
else moveFree(puff3, dt, age, heat, wind);
|
|
6979
|
+
const size = puff3.s0 + (puff3.s1 - puff3.s0) * (1 - Math.exp(-puff3.t * puff3.gk)) + puff3.sg * Math.min(puff3.t, GROWTH_CAP_SECONDS);
|
|
6980
|
+
puff3.size = size * Math.min(1, puff3.t * ARRIVAL_FRAME + ARRIVAL_BASE);
|
|
6981
|
+
puff3.age = age;
|
|
6982
|
+
puff3.heat = heat;
|
|
6933
6983
|
}
|
|
6934
6984
|
}
|
|
6935
6985
|
var GROUND_LIFT = 0.02;
|
|
@@ -6986,9 +7036,9 @@ var GameTestRoom = (() => {
|
|
|
6986
7036
|
var HOT_GLOW_COLOR = [1, 0.45, 0.12];
|
|
6987
7037
|
function addPuff(core, random, init) {
|
|
6988
7038
|
core.spawned.puffs++;
|
|
6989
|
-
const
|
|
6990
|
-
core.trace?.puff?.(
|
|
6991
|
-
return
|
|
7039
|
+
const puff3 = spawnPuff(core.puffs, random, init);
|
|
7040
|
+
core.trace?.puff?.(puff3);
|
|
7041
|
+
return puff3;
|
|
6992
7042
|
}
|
|
6993
7043
|
function addSpark(core, init) {
|
|
6994
7044
|
core.spawned.sparks++;
|
|
@@ -7170,6 +7220,7 @@ var GameTestRoom = (() => {
|
|
|
7170
7220
|
var neg = call("neg");
|
|
7171
7221
|
var abs = call("abs");
|
|
7172
7222
|
var sqrt = call("sqrt");
|
|
7223
|
+
var exp = call("exp");
|
|
7173
7224
|
var sin = call("sin");
|
|
7174
7225
|
var cos = call("cos");
|
|
7175
7226
|
var atan2 = call("atan2");
|
|
@@ -7215,10 +7266,12 @@ var GameTestRoom = (() => {
|
|
|
7215
7266
|
var INDEX = { $: "index" };
|
|
7216
7267
|
var QUALITY = { $: "quality" };
|
|
7217
7268
|
var FRESH = { $: "fresh" };
|
|
7269
|
+
var DIRECTION = { $: "direction" };
|
|
7218
7270
|
var CAMERA_POSITION = { $: "cameraPosition" };
|
|
7219
7271
|
var burst = (system, count, spawn2) => ({ op: "burst", system, count, spawn: spawn2 });
|
|
7220
7272
|
var spawn = (system, options) => ({ op: "spawn", system, spawn: options });
|
|
7221
7273
|
var emit = (key, system, rate, options) => ({ op: "emit", key, system, rate, spawn: options });
|
|
7274
|
+
var mesh = (options) => ({ op: "mesh", spawn: options });
|
|
7222
7275
|
var debris = (options) => ({ op: "debris", spawn: options });
|
|
7223
7276
|
var decal = (...args) => ({ op: "decal", args });
|
|
7224
7277
|
var ring = (...args) => ({ op: "ring", args });
|
|
@@ -8230,6 +8283,241 @@ var GameTestRoom = (() => {
|
|
|
8230
8283
|
)
|
|
8231
8284
|
]
|
|
8232
8285
|
};
|
|
8286
|
+
var SPOTS_X = [-3, 1, 5];
|
|
8287
|
+
var SPOTS_Z = [-1, -2.4, 0.4];
|
|
8288
|
+
var FOG_AND_ASH = {
|
|
8289
|
+
id: "fog_and_ash",
|
|
8290
|
+
pageId: "neblina",
|
|
8291
|
+
team: "world",
|
|
8292
|
+
budget: { particles: 120, lights: 1 },
|
|
8293
|
+
loop: 0,
|
|
8294
|
+
view: { eye: [3, 1.8, 7.5], target: [-3, 1.2, -1] },
|
|
8295
|
+
setup: [
|
|
8296
|
+
cue("fog", { density: 0.075 }),
|
|
8297
|
+
cue("lamp_cone", { visible: true }),
|
|
8298
|
+
cue("zombie_visible", { index: -1, visible: false }),
|
|
8299
|
+
repeat(
|
|
8300
|
+
SPOTS_X.length,
|
|
8301
|
+
set("turn", rnd(-0.6, 0.6)),
|
|
8302
|
+
behavior("walkers", "place", { index: INDEX, x: pick(SPOTS_X, INDEX), z: pick(SPOTS_Z, INDEX), facing: variable("turn") })
|
|
8303
|
+
)
|
|
8304
|
+
],
|
|
8305
|
+
timeline: [],
|
|
8306
|
+
tick: [
|
|
8307
|
+
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 }),
|
|
8308
|
+
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 })
|
|
8309
|
+
]
|
|
8310
|
+
};
|
|
8311
|
+
var RAIN_CAPACITY = 4e3;
|
|
8312
|
+
var FALL_SPEED = 15;
|
|
8313
|
+
var WIND_PER_FALL = 0.07;
|
|
8314
|
+
var STREAK_SLANT = 0.04;
|
|
8315
|
+
var STREAK_LENGTH = 0.6;
|
|
8316
|
+
var BOX_X = [-15, 15];
|
|
8317
|
+
var BOX_Z = [-6, 16];
|
|
8318
|
+
var START_HEIGHT = [0, 16];
|
|
8319
|
+
var REENTRY_HEIGHT = [14, 17];
|
|
8320
|
+
var SPLASH_CHANCE = 0.35;
|
|
8321
|
+
var SPLASH_RANGE = 12;
|
|
8322
|
+
var SPRITE_CHANCE = 0.5;
|
|
8323
|
+
var UP9 = [0, 1, 0];
|
|
8324
|
+
var WORKSHOP_PUDDLES = [
|
|
8325
|
+
[-1.5, 2.2, 1.6, 0.9],
|
|
8326
|
+
[3, 3.6, 1.1, 0.7],
|
|
8327
|
+
[-6, 3.2, 1.3, 0.8],
|
|
8328
|
+
[1.4, -2.2, 0.9, 0.5]
|
|
8329
|
+
];
|
|
8330
|
+
var inPuddle = (puddles, x, z) => puddles.some((p) => ((x - p[0]) / p[2]) ** 2 + ((z - p[1]) / p[3]) ** 2 < 1);
|
|
8331
|
+
var RainField = class {
|
|
8332
|
+
constructor(engine) {
|
|
8333
|
+
__publicField(this, "engine", engine);
|
|
8334
|
+
__publicField(this, "positions", new Float32Array(RAIN_CAPACITY * 6));
|
|
8335
|
+
__publicField(this, "count", 0);
|
|
8336
|
+
__publicField(this, "wind", 1);
|
|
8337
|
+
__publicField(this, "on", false);
|
|
8338
|
+
__publicField(this, "centerX", 0);
|
|
8339
|
+
__publicField(this, "centerZ", 0);
|
|
8340
|
+
__publicField(this, "puddles", WORKSHOP_PUDDLES);
|
|
8341
|
+
__publicField(this, "puddleAt");
|
|
8342
|
+
}
|
|
8343
|
+
/** `initRain` (W321): `count` streaks (thinned by the quality), each drawn at a random place in the box. */
|
|
8344
|
+
init(count, wind) {
|
|
8345
|
+
const { random } = this.engine;
|
|
8346
|
+
this.count = Math.min(RAIN_CAPACITY, Math.round(count * this.engine.context.quality.mult));
|
|
8347
|
+
this.wind = wind;
|
|
8348
|
+
this.on = true;
|
|
8349
|
+
for (let index = 0; index < this.count; index++) {
|
|
8350
|
+
const offset = index * 6;
|
|
8351
|
+
const x = random.between(BOX_X[0], BOX_X[1]);
|
|
8352
|
+
const y = random.between(START_HEIGHT[0], START_HEIGHT[1]);
|
|
8353
|
+
const z = random.between(BOX_Z[0], BOX_Z[1]);
|
|
8354
|
+
this.set(offset, x, y, z);
|
|
8355
|
+
}
|
|
8356
|
+
}
|
|
8357
|
+
/**
|
|
8358
|
+
* 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
|
|
8359
|
+
* starts at a random place of the box, as `init` draws it) and the wind slants them. The golden never calls it.
|
|
8360
|
+
*/
|
|
8361
|
+
drive(count, wind, centerX, centerZ) {
|
|
8362
|
+
const { random } = this.engine;
|
|
8363
|
+
const target = Math.max(0, Math.min(RAIN_CAPACITY, Math.round(count * this.engine.context.quality.mult)));
|
|
8364
|
+
this.wind = wind;
|
|
8365
|
+
this.centerX = centerX;
|
|
8366
|
+
this.centerZ = centerZ;
|
|
8367
|
+
this.on = target > 0;
|
|
8368
|
+
for (let index = this.count; index < target; index++) {
|
|
8369
|
+
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);
|
|
8370
|
+
}
|
|
8371
|
+
this.count = target;
|
|
8372
|
+
}
|
|
8373
|
+
/** `updateRain` (W322-329). `camera` is where the eye is; `splash` lets the drops that land leave a splash. */
|
|
8374
|
+
update(dt, splash, camera2) {
|
|
8375
|
+
if (!this.on) return;
|
|
8376
|
+
const { random, context } = this.engine;
|
|
8377
|
+
const positions = this.positions;
|
|
8378
|
+
const fall = FALL_SPEED * dt;
|
|
8379
|
+
const slant = this.wind * fall * WIND_PER_FALL;
|
|
8380
|
+
const reach = SPLASH_RANGE / (1 + context.quality.level);
|
|
8381
|
+
for (let index = 0; index < this.count; index++) {
|
|
8382
|
+
const o = index * 6;
|
|
8383
|
+
positions[o] += slant;
|
|
8384
|
+
positions[o + 3] += slant;
|
|
8385
|
+
positions[o + 1] -= fall;
|
|
8386
|
+
positions[o + 4] -= fall;
|
|
8387
|
+
const ground = context.groundAt(positions[o], positions[o + 2]);
|
|
8388
|
+
if (positions[o + 4] < ground) {
|
|
8389
|
+
const x = positions[o];
|
|
8390
|
+
const z = positions[o + 2];
|
|
8391
|
+
if (splash && random.next() < SPLASH_CHANCE) {
|
|
8392
|
+
const distance4 = Math.hypot(x - camera2[0], z - camera2[2]);
|
|
8393
|
+
if (distance4 < reach) {
|
|
8394
|
+
if (random.next() < SPRITE_CHANCE) {
|
|
8395
|
+
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 });
|
|
8396
|
+
}
|
|
8397
|
+
if (this.puddleAt ? this.puddleAt(x, z) : inPuddle(this.puddles, x, z)) {
|
|
8398
|
+
this.engine.ring([[x, ground + 0.012, z], 0.01, random.between(0.12, 0.25), random.between(0.4, 0.6), 6978192]);
|
|
8399
|
+
}
|
|
8400
|
+
}
|
|
8401
|
+
}
|
|
8402
|
+
const nx = random.between(BOX_X[0], BOX_X[1]) + this.centerX;
|
|
8403
|
+
const ny = random.between(REENTRY_HEIGHT[0], REENTRY_HEIGHT[1]);
|
|
8404
|
+
const nz = random.between(BOX_Z[0], BOX_Z[1]) + this.centerZ;
|
|
8405
|
+
this.set(o, nx, ny, nz);
|
|
8406
|
+
}
|
|
8407
|
+
}
|
|
8408
|
+
}
|
|
8409
|
+
/** `rain.visible = false; RN.on = false` (W440): the field stops; the streaks stay where they were. */
|
|
8410
|
+
clear() {
|
|
8411
|
+
this.on = false;
|
|
8412
|
+
}
|
|
8413
|
+
set(offset, x, y, z) {
|
|
8414
|
+
const positions = this.positions;
|
|
8415
|
+
positions[offset] = x;
|
|
8416
|
+
positions[offset + 1] = y;
|
|
8417
|
+
positions[offset + 2] = z;
|
|
8418
|
+
positions[offset + 3] = x + this.wind * STREAK_SLANT;
|
|
8419
|
+
positions[offset + 4] = y - STREAK_LENGTH;
|
|
8420
|
+
positions[offset + 5] = z;
|
|
8421
|
+
}
|
|
8422
|
+
};
|
|
8423
|
+
var DROPS = [900, 2200, 4e3];
|
|
8424
|
+
var SLANT = [0.3, 1.2, 4.5];
|
|
8425
|
+
var STORM = 2;
|
|
8426
|
+
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)));
|
|
8427
|
+
var RAIN_AND_PUDDLES = {
|
|
8428
|
+
id: "rain_and_puddles",
|
|
8429
|
+
pageId: "chuva",
|
|
8430
|
+
team: "world",
|
|
8431
|
+
params: { id: "intensity", options: ["drizzle", "rain", "storm"], default: 1 },
|
|
8432
|
+
budget: { particles: 4e3, decals: 4 },
|
|
8433
|
+
loop: 0,
|
|
8434
|
+
view: { eye: [2, 2, 7], target: [-1, 0.6, 1] },
|
|
8435
|
+
setup: [
|
|
8436
|
+
cue("lamp_cone", { visible: true }),
|
|
8437
|
+
...WORKSHOP_PUDDLES.map(([x, z, radiusX, radiusZ]) => decal(x, 0, z, radiusX * 2, 790550, { grow: 0, life: 1e6, ar: radiusZ / radiusX }))
|
|
8438
|
+
],
|
|
8439
|
+
timeline: [
|
|
8440
|
+
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])) }),
|
|
8441
|
+
set("nextStrike", rnd(2, 4)),
|
|
8442
|
+
set("flash", -1)
|
|
8443
|
+
],
|
|
8444
|
+
tick: [
|
|
8445
|
+
behavior("rain", "update", { dt: DELTA, splash: gt(PARAM, 0) }),
|
|
8446
|
+
when(eq(PARAM, STORM), [
|
|
8447
|
+
when(gt(TIME, variable("nextStrike")), [set("nextStrike", add(TIME, rnd(3.5, 6))), set("flash", 0)]),
|
|
8448
|
+
when(ge(variable("flash"), 0), [
|
|
8449
|
+
set("flash", add(variable("flash"), DELTA)),
|
|
8450
|
+
set("light", FLASH_STEPS),
|
|
8451
|
+
cue("lightning", { intensity: variable("light") }),
|
|
8452
|
+
screen({ max: { white: mul(variable("light"), 0.12) } }),
|
|
8453
|
+
when(gt(variable("flash"), 0.4), [set("flash", -1), cue("lightning", { intensity: 0 })])
|
|
8454
|
+
]),
|
|
8455
|
+
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 })
|
|
8456
|
+
])
|
|
8457
|
+
]
|
|
8458
|
+
};
|
|
8459
|
+
var CAR_ORIGIN2 = [5.6, 0, 0.8];
|
|
8460
|
+
var CAR_ROTATION2 = [0, -0.4, 0];
|
|
8461
|
+
var carPoint = (x, y, z) => localToWorld(CAR_ORIGIN2, CAR_ROTATION2, [x, y, z]);
|
|
8462
|
+
var carDirection = (from, to) => normalized([to[0] - from[0], to[1] - from[1], to[2] - from[2]]);
|
|
8463
|
+
var BEAM_FROM = carPoint(0, 0.74, 2.15);
|
|
8464
|
+
var BEAM_DIRECTION = carDirection(BEAM_FROM, carPoint(0, 0.74, 3.15));
|
|
8465
|
+
var BEAM_SIDE = [BEAM_DIRECTION[2], 0, -BEAM_DIRECTION[0]];
|
|
8466
|
+
var WALKERS = 6;
|
|
8467
|
+
var WALK_SPEED2 = 0.7;
|
|
8468
|
+
var DROPS2 = 1800;
|
|
8469
|
+
var SLANT2 = 0.8;
|
|
8470
|
+
var startWalking = [
|
|
8471
|
+
set("spot", query("car", "point", rnd(-2, 2), 0, rnd(8, 18))),
|
|
8472
|
+
set("goal", query("car", "point", rnd(-0.6, 0.6), 0, 2.6)),
|
|
8473
|
+
behavior("walkers", "place", { index: INDEX, x: pick(variable("spot"), 0), z: pick(variable("spot"), 2), facing: 0 }),
|
|
8474
|
+
behavior("walkers", "walk", { index: INDEX, to: variable("goal"), speed: WALK_SPEED2 })
|
|
8475
|
+
];
|
|
8476
|
+
var HEADLIGHTS_IN_RAIN = {
|
|
8477
|
+
id: "headlights_in_rain",
|
|
8478
|
+
pageId: "farol",
|
|
8479
|
+
team: "vehicles",
|
|
8480
|
+
budget: { particles: 600, lights: 2 },
|
|
8481
|
+
loop: 0,
|
|
8482
|
+
view: { eye: [-2.5, 2, 5.5], target: [4, 1, 6] },
|
|
8483
|
+
setup: [
|
|
8484
|
+
cue("fog", { density: 0.05 }),
|
|
8485
|
+
cue("headlights", { on: true, intensity: 2.4, color: 16773584 }),
|
|
8486
|
+
behavior("rain", "init", { count: DROPS2, wind: SLANT2 }),
|
|
8487
|
+
repeat(WALKERS, ...startWalking)
|
|
8488
|
+
],
|
|
8489
|
+
timeline: [],
|
|
8490
|
+
tick: [
|
|
8491
|
+
behavior("rain", "update", { dt: DELTA, splash: true }),
|
|
8492
|
+
emit(
|
|
8493
|
+
"lit",
|
|
8494
|
+
"streak",
|
|
8495
|
+
600,
|
|
8496
|
+
local(
|
|
8497
|
+
"depth",
|
|
8498
|
+
rnd(1, 13),
|
|
8499
|
+
local(
|
|
8500
|
+
"spread",
|
|
8501
|
+
mul(variable("depth"), 0.33, sqrt(rand())),
|
|
8502
|
+
local(
|
|
8503
|
+
"turn",
|
|
8504
|
+
rnd(0, 6.283),
|
|
8505
|
+
local("base", vadd(BEAM_FROM, vscale(BEAM_DIRECTION, variable("depth")), vscale(BEAM_SIDE, mul(cos(variable("turn")), variable("spread")))), {
|
|
8506
|
+
p: vwith(variable("base"), 1, add(vy(variable("base")), mul(sin(variable("turn")), variable("spread"), 0.6))),
|
|
8507
|
+
v: [0.8, -14, 0],
|
|
8508
|
+
sp: 0,
|
|
8509
|
+
life: 0.06,
|
|
8510
|
+
len: 0.035,
|
|
8511
|
+
c0: 13622512,
|
|
8512
|
+
a: 0.9
|
|
8513
|
+
})
|
|
8514
|
+
)
|
|
8515
|
+
)
|
|
8516
|
+
)
|
|
8517
|
+
),
|
|
8518
|
+
repeat(WALKERS, when(not(query("walkers", "is_walking", INDEX)), startWalking))
|
|
8519
|
+
]
|
|
8520
|
+
};
|
|
8233
8521
|
var YAW = -Math.PI / 2;
|
|
8234
8522
|
var COS = Math.cos(YAW);
|
|
8235
8523
|
var SIN = Math.sin(YAW);
|
|
@@ -8257,10 +8545,6 @@ var GameTestRoom = (() => {
|
|
|
8257
8545
|
fireLight(0, [vx(variable("contact")), 0.34, vz(variable("contact"))], 1.6, mul(TIME, 3))
|
|
8258
8546
|
]
|
|
8259
8547
|
};
|
|
8260
|
-
var CAR_ORIGIN2 = [5.6, 0, 0.8];
|
|
8261
|
-
var CAR_ROTATION2 = [0, -0.4, 0];
|
|
8262
|
-
var carPoint = (x, y, z) => localToWorld(CAR_ORIGIN2, CAR_ROTATION2, [x, y, z]);
|
|
8263
|
-
var carDirection = (from, to) => normalized([to[0] - from[0], to[1] - from[1], to[2] - from[2]]);
|
|
8264
8548
|
var HOOD = carPoint(0, 1.02, 1.4);
|
|
8265
8549
|
var EXHAUST = carPoint(0.5, 0.3, -2.2);
|
|
8266
8550
|
var EXHAUST_DIRECTION = carDirection(EXHAUST, carPoint(0.5, 0.3, -3));
|
|
@@ -8294,7 +8578,7 @@ var GameTestRoom = (() => {
|
|
|
8294
8578
|
], [fireLightOff(0)])
|
|
8295
8579
|
]
|
|
8296
8580
|
};
|
|
8297
|
-
var
|
|
8581
|
+
var UP10 = [0, 1, 0];
|
|
8298
8582
|
var doorVelocity = (side) => {
|
|
8299
8583
|
const out = carPoint(side * 4, 3, 0.3);
|
|
8300
8584
|
const centre = carPoint(0, 0, 0.3);
|
|
@@ -8304,7 +8588,7 @@ var GameTestRoom = (() => {
|
|
|
8304
8588
|
call2("explode", vadd(query("car", "position"), [0, 0.6, 0]), 1.8, 2759188),
|
|
8305
8589
|
cue("car_burnt"),
|
|
8306
8590
|
behavior("car", "launch", { rise: 4.5, spin: 0.9 }),
|
|
8307
|
-
repeat(scaled(30), debris({ p: vadd(query("car", "position"), [0, 1.3, 0]), dir:
|
|
8591
|
+
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 })),
|
|
8308
8592
|
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 }),
|
|
8309
8593
|
...[-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 })),
|
|
8310
8594
|
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 })
|
|
@@ -8474,7 +8758,7 @@ var GameTestRoom = (() => {
|
|
|
8474
8758
|
])
|
|
8475
8759
|
]
|
|
8476
8760
|
};
|
|
8477
|
-
var
|
|
8761
|
+
var WALKERS2 = 6;
|
|
8478
8762
|
var NEAR = 9;
|
|
8479
8763
|
var RANGE = 7;
|
|
8480
8764
|
var RESTING_BPM = 70;
|
|
@@ -8490,7 +8774,7 @@ var GameTestRoom = (() => {
|
|
|
8490
8774
|
setup: [
|
|
8491
8775
|
cue("zombie_visible", { index: -1, visible: false }),
|
|
8492
8776
|
repeat(
|
|
8493
|
-
|
|
8777
|
+
WALKERS2,
|
|
8494
8778
|
set("startX", rnd(-4, 4)),
|
|
8495
8779
|
set("startZ", sub(rnd(-4, -2), mul(INDEX, 0.6))),
|
|
8496
8780
|
behavior("walkers", "place", { index: INDEX, x: variable("startX"), z: variable("startZ"), facing: 0 }),
|
|
@@ -8500,7 +8784,7 @@ var GameTestRoom = (() => {
|
|
|
8500
8784
|
timeline: [],
|
|
8501
8785
|
tick: [
|
|
8502
8786
|
set("nearest", 99),
|
|
8503
|
-
repeat(
|
|
8787
|
+
repeat(WALKERS2, set("nearest", min(variable("nearest"), vdist(walkerPoint, CAMERA_POSITION)))),
|
|
8504
8788
|
set("fear", clamp3(div(sub(NEAR, variable("nearest")), RANGE), 0, 1)),
|
|
8505
8789
|
set("bpm", add(RESTING_BPM, mul(BPM_RISE, variable("fear")))),
|
|
8506
8790
|
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"))) } })]),
|
|
@@ -8567,7 +8851,7 @@ var GameTestRoom = (() => {
|
|
|
8567
8851
|
]
|
|
8568
8852
|
};
|
|
8569
8853
|
var FACING4 = [0, 0, 1];
|
|
8570
|
-
var
|
|
8854
|
+
var UP11 = [0, 1, 0];
|
|
8571
8855
|
var ORIGIN = [0, 0, 0];
|
|
8572
8856
|
var FORWARD4 = [0, 0, -1];
|
|
8573
8857
|
var IMPACT_MATERIALS = ["concrete", "metal", "wood", "glass", "flesh", "water"];
|
|
@@ -8697,12 +8981,157 @@ var GameTestRoom = (() => {
|
|
|
8697
8981
|
team: "destruction",
|
|
8698
8982
|
budget: { particles: 20, debris: 8 },
|
|
8699
8983
|
loop: 2,
|
|
8700
|
-
timeline: [call2("chips", ORIGIN,
|
|
8984
|
+
timeline: [call2("chips", ORIGIN, UP11, 8, 0.9), call2("rust_at", ORIGIN, 6)]
|
|
8701
8985
|
}
|
|
8702
8986
|
];
|
|
8703
|
-
var
|
|
8987
|
+
var PI = Math.PI;
|
|
8988
|
+
var SMOKE = { color: 9079430, width: 10, height: 8, gravity: -0.08, drag: 2.2, growth: 2.1 };
|
|
8989
|
+
var FLASH_SECONDS = 0.055;
|
|
8990
|
+
var FLASH_RAMP = [0.6, 0.9];
|
|
8991
|
+
var FLASH_OPACITY = 0.95;
|
|
8992
|
+
var FLAME_COLORS = [16742946, 16760896, 13121050, 16773296];
|
|
8993
|
+
var FLAME_ADDITIVE = 3;
|
|
8994
|
+
var ORIGIN2 = [0, 0, 0];
|
|
8995
|
+
var SIZE = variable("size");
|
|
8996
|
+
var wide = (width) => mul(sub(rand(), 0.5), width);
|
|
8997
|
+
var puff2 = (point, velocity, world, radius, life, opacity) => mesh({
|
|
8998
|
+
shape: "sphere",
|
|
8999
|
+
p: point,
|
|
9000
|
+
v: velocity,
|
|
9001
|
+
wv: world,
|
|
9002
|
+
r: radius,
|
|
9003
|
+
seg: SMOKE.width,
|
|
9004
|
+
seg2: SMOKE.height,
|
|
9005
|
+
life,
|
|
9006
|
+
c0: SMOKE.color,
|
|
9007
|
+
a: opacity,
|
|
9008
|
+
fade: true,
|
|
9009
|
+
lit: true,
|
|
9010
|
+
g: SMOKE.gravity,
|
|
9011
|
+
drag: SMOKE.drag,
|
|
9012
|
+
grow: SMOKE.growth
|
|
9013
|
+
});
|
|
9014
|
+
var flameBit = (point, velocity, world, radius, life) => [
|
|
9015
|
+
set("bitPoint", point),
|
|
9016
|
+
set("bitVelocity", velocity),
|
|
9017
|
+
set("bitWorld", world),
|
|
9018
|
+
set("bitRadius", radius),
|
|
9019
|
+
set("bitLife", life),
|
|
9020
|
+
set("bitColour", floor(mul(rand(), FLAME_COLORS.length))),
|
|
9021
|
+
mesh({
|
|
9022
|
+
shape: "icosahedron",
|
|
9023
|
+
p: variable("bitPoint"),
|
|
9024
|
+
v: variable("bitVelocity"),
|
|
9025
|
+
wv: variable("bitWorld"),
|
|
9026
|
+
r: variable("bitRadius"),
|
|
9027
|
+
seg: 1,
|
|
9028
|
+
rot: [mul(rand(), 3), mul(rand(), 3), 0],
|
|
9029
|
+
spin: [3, 4, 2],
|
|
9030
|
+
life: variable("bitLife"),
|
|
9031
|
+
c0: pick(FLAME_COLORS, variable("bitColour")),
|
|
9032
|
+
add: eq(variable("bitColour"), FLAME_ADDITIVE),
|
|
9033
|
+
a: 0.9,
|
|
9034
|
+
fade: true,
|
|
9035
|
+
g: -1.4,
|
|
9036
|
+
drag: 1.4,
|
|
9037
|
+
grow: 2.2
|
|
9038
|
+
})
|
|
9039
|
+
];
|
|
9040
|
+
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 });
|
|
9041
|
+
var MUZZLE_FLASH2 = {
|
|
9042
|
+
id: "viewmodel_muzzle_flash",
|
|
9043
|
+
pageId: "event:viewmodel_muzzle_flash",
|
|
9044
|
+
team: "weapons",
|
|
9045
|
+
budget: { particles: 12, lights: 1 },
|
|
9046
|
+
loop: 0.1,
|
|
9047
|
+
timeline: [
|
|
9048
|
+
set("angles", []),
|
|
9049
|
+
repeat(4, append("angles", add(div(mul(INDEX, PI), 2), mul(rand(), 0.6)))),
|
|
9050
|
+
set("roll", mul(rand(), PI)),
|
|
9051
|
+
flash(ORIGIN2, 16756832, mul(4, SIZE), FLASH_SECONDS, mul(2, SIZE), true, true),
|
|
9052
|
+
flashPiece("cone_open", mul(0.013, SIZE), mul(0.085, SIZE), 10, [mul(0.042, SIZE), 0, 0], [0, 0, -PI / 2], 16757575),
|
|
9053
|
+
repeat(
|
|
9054
|
+
4,
|
|
9055
|
+
set("angle", pick(variable("angles"), INDEX)),
|
|
9056
|
+
flashPiece(
|
|
9057
|
+
"cone",
|
|
9058
|
+
mul(5e-3, SIZE),
|
|
9059
|
+
mul(0.04, SIZE),
|
|
9060
|
+
6,
|
|
9061
|
+
[mul(0.012, SIZE), mul(cos(variable("angle")), 0.016, SIZE), mul(sin(variable("angle")), 0.016, SIZE)],
|
|
9062
|
+
[variable("angle"), 0, -PI / 2],
|
|
9063
|
+
16757575
|
|
9064
|
+
)
|
|
9065
|
+
),
|
|
9066
|
+
flashPiece("sphere", mul(0.016, SIZE), void 0, 12, [mul(8e-3, SIZE), 0, 0], [0, 0, 0], 16773568),
|
|
9067
|
+
repeat(
|
|
9068
|
+
6,
|
|
9069
|
+
puff2(
|
|
9070
|
+
ORIGIN2,
|
|
9071
|
+
[add(0.15, mul(rand(), 0.35)), add(0.03, mul(rand(), 0.12)), mul(sub(rand(), 0.5), 0.14)],
|
|
9072
|
+
[0, 0, 0],
|
|
9073
|
+
mul(0.013, SIZE),
|
|
9074
|
+
add(1.3, mul(rand(), 0.6)),
|
|
9075
|
+
0.45
|
|
9076
|
+
)
|
|
9077
|
+
)
|
|
9078
|
+
]
|
|
9079
|
+
};
|
|
9080
|
+
var SMOKE_PUFF = {
|
|
9081
|
+
id: "weapon_smoke_puff",
|
|
9082
|
+
pageId: "event:weapon_smoke_puff",
|
|
9083
|
+
team: "weapons",
|
|
9084
|
+
budget: { particles: 1 },
|
|
9085
|
+
loop: 0.1,
|
|
9086
|
+
timeline: [puff2(ORIGIN2, void 0, [variable("vx"), variable("vy"), variable("vz")], variable("radius"), variable("life"), variable("opacity"))]
|
|
9087
|
+
};
|
|
9088
|
+
var BACKBLAST = {
|
|
9089
|
+
id: "launcher_backblast",
|
|
9090
|
+
pageId: "event:launcher_backblast",
|
|
9091
|
+
team: "weapons",
|
|
9092
|
+
budget: { particles: 40 },
|
|
9093
|
+
loop: 0.1,
|
|
9094
|
+
timeline: [
|
|
9095
|
+
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)),
|
|
9096
|
+
repeat(14, ...flameBit(ORIGIN2, [neg(add(2, mul(rand(), 2))), 0, 0], [wide(1), wide(0.6), wide(1)], 0.02, 0.25))
|
|
9097
|
+
]
|
|
9098
|
+
};
|
|
9099
|
+
var FLAME_JET = {
|
|
9100
|
+
id: "flame_jet",
|
|
9101
|
+
pageId: "event:flame_jet",
|
|
9102
|
+
team: "weapons",
|
|
9103
|
+
budget: { particles: 30 },
|
|
9104
|
+
loop: 0.1,
|
|
9105
|
+
timeline: [
|
|
9106
|
+
repeat(
|
|
9107
|
+
floor(mul(420, variable("dt"), variable("scale"))),
|
|
9108
|
+
set("speed", mul(add(2.2, mul(rand(), 1.1)), variable("scale"))),
|
|
9109
|
+
...flameBit(
|
|
9110
|
+
[mul(rand(), variable("speed"), min(variable("dt"), 0.3)), 0, 0],
|
|
9111
|
+
[variable("speed"), 0, 0],
|
|
9112
|
+
[wide(0.35), mul(sub(rand(), 0.3), 0.3), wide(0.35)],
|
|
9113
|
+
add(0.02, mul(rand(), 0.022)),
|
|
9114
|
+
add(0.4, mul(rand(), 0.35))
|
|
9115
|
+
)
|
|
9116
|
+
),
|
|
9117
|
+
when(lt(rand(), 0.5), [
|
|
9118
|
+
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)
|
|
9119
|
+
])
|
|
9120
|
+
]
|
|
9121
|
+
};
|
|
9122
|
+
var VIEWMODEL_EFFECTS = [MUZZLE_FLASH2, SMOKE_PUFF, BACKBLAST, FLAME_JET];
|
|
9123
|
+
var aliasOf = (base, id, changes) => ({ ...base, id, pageId: `vehicle:${id}`, anchor: CAR_ORIGIN2, ...changes });
|
|
9124
|
+
var VEHICLE_EFFECTS = [
|
|
9125
|
+
/** The engine on fire: `engine_smoke` at its worst condition (black smoke, flames in the hood, a light). */
|
|
9126
|
+
aliasOf(ENGINE_SMOKE, "vehicle_fire", { params: { id: "condition", options: ["100", "60", "30", "10"], default: 3 }, loop: 12 }),
|
|
9127
|
+
/** The exhaust of a car under way: `engine_smoke` in the best condition, for half a second so a moving car asks again. */
|
|
9128
|
+
aliasOf(ENGINE_SMOKE, "vehicle_exhaust", { params: { id: "condition", options: ["100", "60", "30", "10"], default: 0 }, loop: 0.5 }),
|
|
9129
|
+
/** A hole in the tank: the page's own petrol leak (drips, pool, sparks, fire running to the tank). */
|
|
9130
|
+
aliasOf(FUEL_LEAK, "vehicle_leak", {})
|
|
9131
|
+
];
|
|
9132
|
+
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];
|
|
8704
9133
|
var WORKSHOP_EFFECTS = Object.fromEntries(ALL_EFFECTS.map((effect) => [effect.id, effect]));
|
|
8705
|
-
var GAME_EFFECTS = { ...WORKSHOP_EFFECTS, ...Object.fromEntries(EVENT_EFFECTS.map((effect) => [effect.id, effect])) };
|
|
9134
|
+
var GAME_EFFECTS = { ...WORKSHOP_EFFECTS, ...Object.fromEntries([...EVENT_EFFECTS, ...VIEWMODEL_EFFECTS, ...VEHICLE_EFFECTS].map((effect) => [effect.id, effect])) };
|
|
8706
9135
|
var LEHMER_MULTIPLIER = 16807;
|
|
8707
9136
|
var LEHMER_MODULUS = 2147483647;
|
|
8708
9137
|
var HASH_MIX = 2654435761;
|
|
@@ -8798,7 +9227,7 @@ var GameTestRoom = (() => {
|
|
|
8798
9227
|
}
|
|
8799
9228
|
var COLUMNS = 6;
|
|
8800
9229
|
var ROWS = 5;
|
|
8801
|
-
var
|
|
9230
|
+
var ORIGIN3 = [-2.2, 0, 2.6];
|
|
8802
9231
|
var BLOCK_SIZE = [0.5, 0.44, 0.25];
|
|
8803
9232
|
var OBJECT_ID_DRAWS2 = 4;
|
|
8804
9233
|
var FLOOR2 = 0.13;
|
|
@@ -8841,7 +9270,7 @@ var GameTestRoom = (() => {
|
|
|
8841
9270
|
const chipScale = random.between(0.8, 1.3) * scale2;
|
|
8842
9271
|
for (let draw2 = 0; draw2 < OBJECT_ID_DRAWS2; draw2++) random.next();
|
|
8843
9272
|
best.holes.push({ x: offsetX, y: offsetY, scale: scale2, chipTurn, chipScale });
|
|
8844
|
-
impact(host.engine, "concrete", [
|
|
9273
|
+
impact(host.engine, "concrete", [ORIGIN3[0] + x, y, ORIGIN3[2] + 0.13], [0, 0, 1], 0.8);
|
|
8845
9274
|
} else if (action === "collapse") {
|
|
8846
9275
|
const { x, y } = args;
|
|
8847
9276
|
for (const block of blocks) {
|
|
@@ -8891,7 +9320,7 @@ var GameTestRoom = (() => {
|
|
|
8891
9320
|
}
|
|
8892
9321
|
};
|
|
8893
9322
|
}
|
|
8894
|
-
var
|
|
9323
|
+
var ORIGIN4 = [5.6, 0, 0.8];
|
|
8895
9324
|
var MAX_TILT = 0.25;
|
|
8896
9325
|
function createCarBehavior() {
|
|
8897
9326
|
let y = 0;
|
|
@@ -8923,8 +9352,13 @@ var GameTestRoom = (() => {
|
|
|
8923
9352
|
}
|
|
8924
9353
|
}
|
|
8925
9354
|
},
|
|
8926
|
-
query(_host, name) {
|
|
8927
|
-
if (name === "position") return [
|
|
9355
|
+
query(_host, name, args) {
|
|
9356
|
+
if (name === "position") return [ORIGIN4[0], y, ORIGIN4[2]];
|
|
9357
|
+
if (name === "point") {
|
|
9358
|
+
const [x, py, z] = args;
|
|
9359
|
+
const point = carPoint(x, py, z);
|
|
9360
|
+
return [point[0], point[1] + y, point[2]];
|
|
9361
|
+
}
|
|
8928
9362
|
if (name === "roll") return roll;
|
|
8929
9363
|
throw new Error(`car: unknown query ${name}`);
|
|
8930
9364
|
},
|
|
@@ -9124,6 +9558,29 @@ var GameTestRoom = (() => {
|
|
|
9124
9558
|
}
|
|
9125
9559
|
};
|
|
9126
9560
|
}
|
|
9561
|
+
function createRainBehavior() {
|
|
9562
|
+
return {
|
|
9563
|
+
reset() {
|
|
9564
|
+
},
|
|
9565
|
+
act(host, action, args) {
|
|
9566
|
+
const { engine, camera: camera2 } = host;
|
|
9567
|
+
if (action === "init") {
|
|
9568
|
+
const { count, wind } = args;
|
|
9569
|
+
engine.rain.init(count, wind);
|
|
9570
|
+
} else if (action === "update") {
|
|
9571
|
+
const { dt, splash } = args;
|
|
9572
|
+
engine.rain.update(dt, splash, camera2.position);
|
|
9573
|
+
}
|
|
9574
|
+
},
|
|
9575
|
+
query(host, name) {
|
|
9576
|
+
if (name === "count") return host.engine.rain.count;
|
|
9577
|
+
if (name === "on") return host.engine.rain.on;
|
|
9578
|
+
throw new Error(`rain: unknown query ${name}`);
|
|
9579
|
+
},
|
|
9580
|
+
update() {
|
|
9581
|
+
}
|
|
9582
|
+
};
|
|
9583
|
+
}
|
|
9127
9584
|
var WALKER_COUNT = 10;
|
|
9128
9585
|
var ARRIVAL_DISTANCE = 0.05;
|
|
9129
9586
|
var SWAY_AMPLITUDE = 0.04;
|
|
@@ -9189,7 +9646,8 @@ var GameTestRoom = (() => {
|
|
|
9189
9646
|
blocks: () => createBlocksBehavior(),
|
|
9190
9647
|
plate: () => createPlateBehavior(),
|
|
9191
9648
|
cylinder: () => createCylinderBehavior(),
|
|
9192
|
-
car: () => createCarBehavior()
|
|
9649
|
+
car: () => createCarBehavior(),
|
|
9650
|
+
rain: () => createRainBehavior()
|
|
9193
9651
|
};
|
|
9194
9652
|
var NOOP = () => {
|
|
9195
9653
|
};
|
|
@@ -9260,6 +9718,8 @@ var GameTestRoom = (() => {
|
|
|
9260
9718
|
return Math.abs(asNumber(first));
|
|
9261
9719
|
case "sqrt":
|
|
9262
9720
|
return Math.sqrt(asNumber(first));
|
|
9721
|
+
case "exp":
|
|
9722
|
+
return Math.exp(asNumber(first));
|
|
9263
9723
|
case "sin":
|
|
9264
9724
|
return Math.sin(asNumber(first));
|
|
9265
9725
|
case "cos":
|
|
@@ -9378,7 +9838,7 @@ var GameTestRoom = (() => {
|
|
|
9378
9838
|
return evaluateCall(value.$, args.map((entry) => resolve(entry, context)));
|
|
9379
9839
|
}
|
|
9380
9840
|
}
|
|
9381
|
-
var
|
|
9841
|
+
var UP12 = [0, 1, 0];
|
|
9382
9842
|
var ZERO = [0, 0, 0];
|
|
9383
9843
|
var FULL_TURN_DRAWN = 6.283;
|
|
9384
9844
|
function scaledSizes(range2, factor) {
|
|
@@ -9391,7 +9851,7 @@ var GameTestRoom = (() => {
|
|
|
9391
9851
|
p: centre,
|
|
9392
9852
|
r: radius,
|
|
9393
9853
|
flat: true,
|
|
9394
|
-
dir: options.dir ??
|
|
9854
|
+
dir: options.dir ?? UP12,
|
|
9395
9855
|
cone: 0.35,
|
|
9396
9856
|
sp: [0.4, 1.4],
|
|
9397
9857
|
v: wind,
|
|
@@ -9408,7 +9868,7 @@ var GameTestRoom = (() => {
|
|
|
9408
9868
|
p: centre,
|
|
9409
9869
|
r: radius * 0.6,
|
|
9410
9870
|
flat: true,
|
|
9411
|
-
dir:
|
|
9871
|
+
dir: UP12,
|
|
9412
9872
|
cone: 0.3,
|
|
9413
9873
|
sp: [0.3, 0.8],
|
|
9414
9874
|
life: [0.2, 0.4],
|
|
@@ -9423,14 +9883,14 @@ var GameTestRoom = (() => {
|
|
|
9423
9883
|
if (engine.quality < 2) {
|
|
9424
9884
|
engine.emit(`${key}e`, "streak", 10 * factor, dt, () => {
|
|
9425
9885
|
const jitter = plus(wind, engine.random.between(-0.4, 0.4), 0, engine.random.between(-0.4, 0.4));
|
|
9426
|
-
return { p: centre, box: [radius, 0, radius], dir:
|
|
9886
|
+
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 };
|
|
9427
9887
|
});
|
|
9428
9888
|
}
|
|
9429
9889
|
if (options.noSmoke) return;
|
|
9430
9890
|
engine.emit(`${key}s`, "normal", (options.smoke || 14) * factor, dt, () => ({
|
|
9431
9891
|
p: plus(centre, 0, 0.8 * sqrtFactor, 0),
|
|
9432
9892
|
r: radius * 0.7,
|
|
9433
|
-
dir:
|
|
9893
|
+
dir: UP12,
|
|
9434
9894
|
cone: 0.35,
|
|
9435
9895
|
sp: [0.6, 1.4],
|
|
9436
9896
|
v: wind,
|
|
@@ -9470,15 +9930,15 @@ var GameTestRoom = (() => {
|
|
|
9470
9930
|
engine.screen.shake += 0.7 * scale2;
|
|
9471
9931
|
engine.screen.white += 0.18 * scale2;
|
|
9472
9932
|
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 });
|
|
9473
|
-
engine.burst("add", 28 * scale2, { p: plus(point, 0, 0.3, 0), r: 0.3, dir:
|
|
9933
|
+
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 });
|
|
9474
9934
|
engine.ring([plus(point, 0, 0.05, 0), 0.3, 7 * scale2, 0.55, 16767136]);
|
|
9475
9935
|
const toCamera = normalized([cameraPosition[0] - point[0], cameraPosition[1] - point[1], cameraPosition[2] - point[2]]);
|
|
9476
9936
|
engine.ring([plus(point, 0, 1, 0), 0.3, 5 * scale2, 0.35, 16773328, toCamera]);
|
|
9477
|
-
engine.burst("normal", 32 * scale2, { p: plus(point, 0, 0.6, 0), r: 0.8 * scale2, dir:
|
|
9937
|
+
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 });
|
|
9478
9938
|
ringOfDust(engine, point, scale2);
|
|
9479
|
-
if (engine.quality < 2) engine.burst("streak", 44 * scale2, { p: point, dir:
|
|
9939
|
+
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 });
|
|
9480
9940
|
for (let index = 0; index < engine.scaled(16 * scale2); index++) {
|
|
9481
|
-
engine.debrisPiece({ p: point, dir:
|
|
9941
|
+
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 });
|
|
9482
9942
|
}
|
|
9483
9943
|
engine.decal([point[0], engine.context.groundAt(point[0], point[2]), point[2], 3 * scale2, 657930, { grow: 0.15, life: 60 }]);
|
|
9484
9944
|
}
|
|
@@ -9621,6 +10081,7 @@ var GameTestRoom = (() => {
|
|
|
9621
10081
|
if (!def) return;
|
|
9622
10082
|
this.schedule.clear();
|
|
9623
10083
|
this.variables.clear();
|
|
10084
|
+
for (const [name, value] of Object.entries(this.setup.values ?? {})) this.variables.set(name, value);
|
|
9624
10085
|
for (const behavior2 of this.deps.behaviors()) behavior2.reset(this.host);
|
|
9625
10086
|
this.time = 0;
|
|
9626
10087
|
this.within(() => {
|
|
@@ -9679,6 +10140,10 @@ var GameTestRoom = (() => {
|
|
|
9679
10140
|
return engine.spawn(step.system, this.value(step.spawn));
|
|
9680
10141
|
case "emit":
|
|
9681
10142
|
return engine.emit(step.key, step.system, this.value(step.rate), this.dt, () => this.value(step.spawn));
|
|
10143
|
+
case "mesh": {
|
|
10144
|
+
engine.mesh(this.value(step.spawn));
|
|
10145
|
+
return;
|
|
10146
|
+
}
|
|
9682
10147
|
case "debris":
|
|
9683
10148
|
return engine.debrisPiece(this.value(step.spawn));
|
|
9684
10149
|
case "decal":
|
|
@@ -9760,7 +10225,7 @@ var GameTestRoom = (() => {
|
|
|
9760
10225
|
this.index = previous;
|
|
9761
10226
|
}
|
|
9762
10227
|
};
|
|
9763
|
-
var
|
|
10228
|
+
var ORIGIN5 = [0, 0, 0];
|
|
9764
10229
|
var DEFAULT_HEADING = [0, 0, -1];
|
|
9765
10230
|
var DEFAULT_MAX_INSTANCES = 48;
|
|
9766
10231
|
var ENDLESS_SECONDS = 60;
|
|
@@ -9805,7 +10270,7 @@ var GameTestRoom = (() => {
|
|
|
9805
10270
|
}
|
|
9806
10271
|
function placementOf(entry) {
|
|
9807
10272
|
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;
|
|
9808
|
-
return { origin, anchor: entry.anchor, yaw: entry.yaw };
|
|
10273
|
+
return { origin, anchor: entry.anchor, yaw: entry.yaw, ...entry.orientation ? { orientation: entry.orientation } : {} };
|
|
9809
10274
|
}
|
|
9810
10275
|
function drawing(entry, action) {
|
|
9811
10276
|
const context = engine.context;
|
|
@@ -9829,8 +10294,9 @@ var GameTestRoom = (() => {
|
|
|
9829
10294
|
random: playOptions.seed !== void 0 ? streamOf(playOptions.seed) : void 0,
|
|
9830
10295
|
follow: playOptions.follow,
|
|
9831
10296
|
origin: point,
|
|
9832
|
-
anchor: def.anchor ??
|
|
10297
|
+
anchor: def.anchor ?? ORIGIN5,
|
|
9833
10298
|
yaw: yawOf(heading, playOptions.direction),
|
|
10299
|
+
orientation: playOptions.orientation,
|
|
9834
10300
|
seconds: playOptions.seconds ?? (def.loop && def.loop > 0 ? def.loop : ENDLESS_SECONDS)
|
|
9835
10301
|
};
|
|
9836
10302
|
playing.push(entry);
|
|
@@ -9839,7 +10305,8 @@ var GameTestRoom = (() => {
|
|
|
9839
10305
|
() => instance.begin(def, paramIndex(def, playOptions.param), {
|
|
9840
10306
|
placement: placementOf(entry),
|
|
9841
10307
|
...playOptions.direction ? { direction: playOptions.direction } : {},
|
|
9842
|
-
...playOptions.normal ? { normal: playOptions.normal } : {}
|
|
10308
|
+
...playOptions.normal ? { normal: playOptions.normal } : {},
|
|
10309
|
+
...playOptions.values ? { values: playOptions.values } : {}
|
|
9843
10310
|
})
|
|
9844
10311
|
);
|
|
9845
10312
|
return entry.handle;
|
|
@@ -10099,15 +10566,15 @@ var GameTestRoom = (() => {
|
|
|
10099
10566
|
return shock;
|
|
10100
10567
|
}
|
|
10101
10568
|
function pushPuffs(puffs, shock, reach, dt, age) {
|
|
10102
|
-
for (const
|
|
10103
|
-
if (
|
|
10104
|
-
const dx =
|
|
10105
|
-
const dz =
|
|
10569
|
+
for (const puff3 of puffs) {
|
|
10570
|
+
if (puff3.ring || puff3.t > PUSH_AGE_LIMIT) continue;
|
|
10571
|
+
const dx = puff3.x - shock.x;
|
|
10572
|
+
const dz = puff3.z - shock.z;
|
|
10106
10573
|
const distance4 = Math.hypot(dx, dz) + 1e-3;
|
|
10107
|
-
if (Math.abs(distance4 - reach) < PUSH_BAND &&
|
|
10574
|
+
if (Math.abs(distance4 - reach) < PUSH_BAND && puff3.y < PUSH_CEILING) {
|
|
10108
10575
|
const strength = 4 * dt * (1 - age);
|
|
10109
|
-
|
|
10110
|
-
|
|
10576
|
+
puff3.vx += dx / distance4 * strength * 6;
|
|
10577
|
+
puff3.vz += dz / distance4 * strength * 6;
|
|
10111
10578
|
}
|
|
10112
10579
|
}
|
|
10113
10580
|
}
|
|
@@ -10407,10 +10874,10 @@ var GameTestRoom = (() => {
|
|
|
10407
10874
|
const life = random.between(ring2.life * 0.75, ring2.life);
|
|
10408
10875
|
const h0 = random.between(1, 1.25);
|
|
10409
10876
|
const hl = random.between(0.9, 1.6);
|
|
10410
|
-
const
|
|
10411
|
-
|
|
10412
|
-
|
|
10413
|
-
|
|
10877
|
+
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 });
|
|
10878
|
+
puff3.ring = ring2;
|
|
10879
|
+
puff3.ph = random.next() * Math.PI * 2;
|
|
10880
|
+
puff3.th = random.next() * Math.PI * 2;
|
|
10414
10881
|
}
|
|
10415
10882
|
const stemCount = Math.round((spec.stem || 18) * Math.max(lod, 0.4));
|
|
10416
10883
|
for (let index = 0; index < stemCount; index++) {
|
|
@@ -11211,7 +11678,7 @@ var GameTestRoom = (() => {
|
|
|
11211
11678
|
};
|
|
11212
11679
|
var TWO_PI_ROUNDED = 6.2832;
|
|
11213
11680
|
var WIDE_CONE = 3.1;
|
|
11214
|
-
var
|
|
11681
|
+
var UP13 = [0, 1, 0];
|
|
11215
11682
|
function drawRange(random, range2) {
|
|
11216
11683
|
if (Array.isArray(range2)) return random.between(range2[0], range2[1]);
|
|
11217
11684
|
return range2 || 0;
|
|
@@ -11239,7 +11706,7 @@ var GameTestRoom = (() => {
|
|
|
11239
11706
|
}
|
|
11240
11707
|
function coneDirection(random, direction, cone, out) {
|
|
11241
11708
|
if (cone >= WIDE_CONE) return randomUnit(random, out);
|
|
11242
|
-
const [dx, dy, dz] = direction ??
|
|
11709
|
+
const [dx, dy, dz] = direction ?? UP13;
|
|
11243
11710
|
const cosTilt = 1 - random.next() * (1 - Math.cos(cone));
|
|
11244
11711
|
const sinTilt = Math.sqrt(1 - cosTilt * cosTilt);
|
|
11245
11712
|
const phase = random.next() * TWO_PI_ROUNDED;
|
|
@@ -11359,12 +11826,12 @@ var GameTestRoom = (() => {
|
|
|
11359
11826
|
}
|
|
11360
11827
|
};
|
|
11361
11828
|
var CAPACITY2 = 400;
|
|
11362
|
-
var
|
|
11829
|
+
var UP14 = [0, 1, 0];
|
|
11363
11830
|
var DEFAULT_LIFE2 = 60;
|
|
11364
11831
|
var DEFAULT_GROW = 1.2;
|
|
11365
11832
|
var EVAPORATION = { fuel: [6, 5], water: [40, 20] };
|
|
11366
11833
|
function createDecal() {
|
|
11367
|
-
return { on: false, x: 0, y: 0, z: 0, sx: 0, sy: 0, t: 0, life: 0, grow: 0, color: 0, normal:
|
|
11834
|
+
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 };
|
|
11368
11835
|
}
|
|
11369
11836
|
var DecalPool = class {
|
|
11370
11837
|
constructor(context) {
|
|
@@ -11377,7 +11844,7 @@ var GameTestRoom = (() => {
|
|
|
11377
11844
|
const random = this.context.random;
|
|
11378
11845
|
const index = this.next++ % CAPACITY2;
|
|
11379
11846
|
const decal2 = this.decals[index];
|
|
11380
|
-
const normal = options.n ??
|
|
11847
|
+
const normal = options.n ?? UP14;
|
|
11381
11848
|
random.between(0, 6.28);
|
|
11382
11849
|
const offset = 4e-3 + index % 40 * 4e-4;
|
|
11383
11850
|
decal2.on = true;
|
|
@@ -11418,6 +11885,94 @@ var GameTestRoom = (() => {
|
|
|
11418
11885
|
}
|
|
11419
11886
|
}
|
|
11420
11887
|
};
|
|
11888
|
+
var CAPACITY3 = 400;
|
|
11889
|
+
var IDENTITY2 = [0, 0, 0, 1];
|
|
11890
|
+
function multiply(a, b) {
|
|
11891
|
+
const [ax, ay, az, aw] = a;
|
|
11892
|
+
const [bx, by, bz, bw] = b;
|
|
11893
|
+
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];
|
|
11894
|
+
}
|
|
11895
|
+
var aboutX = (angle) => [Math.sin(angle / 2), 0, 0, Math.cos(angle / 2)];
|
|
11896
|
+
var MeshPool = class {
|
|
11897
|
+
constructor(capacity = CAPACITY3) {
|
|
11898
|
+
__publicField(this, "capacity", capacity);
|
|
11899
|
+
__publicField(this, "particles", []);
|
|
11900
|
+
__publicField(this, "serial", 0);
|
|
11901
|
+
}
|
|
11902
|
+
get count() {
|
|
11903
|
+
return this.particles.length;
|
|
11904
|
+
}
|
|
11905
|
+
spawn(options, frame3 = IDENTITY2) {
|
|
11906
|
+
const velocity = options.v ?? [0, 0, 0];
|
|
11907
|
+
const world = options.wv ?? [0, 0, 0];
|
|
11908
|
+
const particle = {
|
|
11909
|
+
id: ++this.serial,
|
|
11910
|
+
shape: options.shape,
|
|
11911
|
+
radius: options.r,
|
|
11912
|
+
height: options.h ?? 0,
|
|
11913
|
+
segments: options.seg ?? 0,
|
|
11914
|
+
segments2: options.seg2 ?? 0,
|
|
11915
|
+
color: options.c0,
|
|
11916
|
+
additive: options.add === true,
|
|
11917
|
+
lit: options.lit === true,
|
|
11918
|
+
x: options.p[0],
|
|
11919
|
+
y: options.p[1],
|
|
11920
|
+
z: options.p[2],
|
|
11921
|
+
frame: options.roll ? multiply(frame3, aboutX(options.roll)) : frame3,
|
|
11922
|
+
at: options.at ?? [0, 0, 0],
|
|
11923
|
+
rx: options.rot?.[0] ?? 0,
|
|
11924
|
+
ry: options.rot?.[1] ?? 0,
|
|
11925
|
+
rz: options.rot?.[2] ?? 0,
|
|
11926
|
+
scale: 1,
|
|
11927
|
+
opacity: options.a,
|
|
11928
|
+
age: 0,
|
|
11929
|
+
life: options.life,
|
|
11930
|
+
vx: velocity[0] + world[0],
|
|
11931
|
+
vy: velocity[1] + world[1],
|
|
11932
|
+
vz: velocity[2] + world[2],
|
|
11933
|
+
spin: options.spin ?? [0, 0, 0],
|
|
11934
|
+
gravity: options.g ?? 0,
|
|
11935
|
+
drag: options.drag ?? 0,
|
|
11936
|
+
grow: options.grow ?? 0,
|
|
11937
|
+
ramp: options.ramp,
|
|
11938
|
+
fade: options.fade === true,
|
|
11939
|
+
startOpacity: options.a
|
|
11940
|
+
};
|
|
11941
|
+
this.particles.push(particle);
|
|
11942
|
+
if (this.particles.length > this.capacity) this.particles.shift();
|
|
11943
|
+
return particle;
|
|
11944
|
+
}
|
|
11945
|
+
update(dt) {
|
|
11946
|
+
const live = this.particles;
|
|
11947
|
+
for (let index = 0; index < live.length; index++) {
|
|
11948
|
+
const particle = live[index];
|
|
11949
|
+
particle.age += dt;
|
|
11950
|
+
if (particle.ramp ? particle.age >= particle.life : particle.age > particle.life) {
|
|
11951
|
+
live.splice(index--, 1);
|
|
11952
|
+
continue;
|
|
11953
|
+
}
|
|
11954
|
+
if (particle.fade) particle.opacity = Math.max(0, particle.startOpacity * (1 - particle.age / particle.life));
|
|
11955
|
+
particle.vy -= particle.gravity * dt;
|
|
11956
|
+
if (particle.drag) {
|
|
11957
|
+
const keep = Math.max(0, 1 - particle.drag * dt);
|
|
11958
|
+
particle.vx *= keep;
|
|
11959
|
+
particle.vy *= keep;
|
|
11960
|
+
particle.vz *= keep;
|
|
11961
|
+
}
|
|
11962
|
+
particle.x += particle.vx * dt;
|
|
11963
|
+
particle.y += particle.vy * dt;
|
|
11964
|
+
particle.z += particle.vz * dt;
|
|
11965
|
+
particle.rx += particle.spin[0] * dt;
|
|
11966
|
+
particle.ry += particle.spin[1] * dt;
|
|
11967
|
+
particle.rz += particle.spin[2] * dt;
|
|
11968
|
+
if (particle.grow) particle.scale *= 1 + particle.grow * dt;
|
|
11969
|
+
if (particle.ramp) particle.scale = particle.ramp[0] + Math.min(1, particle.age / particle.life) * particle.ramp[1];
|
|
11970
|
+
}
|
|
11971
|
+
}
|
|
11972
|
+
clear() {
|
|
11973
|
+
this.particles.length = 0;
|
|
11974
|
+
}
|
|
11975
|
+
};
|
|
11421
11976
|
var DEFAULT_FADE_IN = 0.1;
|
|
11422
11977
|
var FLOATS_PER_VECTOR = 3;
|
|
11423
11978
|
var BYTE_MAX2 = 255;
|
|
@@ -11707,11 +12262,11 @@ var GameTestRoom = (() => {
|
|
|
11707
12262
|
};
|
|
11708
12263
|
var RING_CAPACITY = 120;
|
|
11709
12264
|
var LIGHT_CAPACITY = 4;
|
|
11710
|
-
var
|
|
12265
|
+
var UP15 = [0, 1, 0];
|
|
11711
12266
|
var DEFAULT_LIGHT_DISTANCE = 14;
|
|
11712
12267
|
var WaveRingPool = class {
|
|
11713
12268
|
constructor() {
|
|
11714
|
-
__publicField(this, "rings", Array.from({ length: RING_CAPACITY }, () => ({ on: false, point:
|
|
12269
|
+
__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 })));
|
|
11715
12270
|
__publicField(this, "count", 0);
|
|
11716
12271
|
__publicField(this, "next", 0);
|
|
11717
12272
|
}
|
|
@@ -11724,7 +12279,7 @@ var GameTestRoom = (() => {
|
|
|
11724
12279
|
ring2.t = 0;
|
|
11725
12280
|
ring2.duration = duration;
|
|
11726
12281
|
ring2.color = color;
|
|
11727
|
-
ring2.normal = normal ??
|
|
12282
|
+
ring2.normal = normal ?? UP15;
|
|
11728
12283
|
ring2.hold = hold || 0;
|
|
11729
12284
|
}
|
|
11730
12285
|
clear() {
|
|
@@ -11744,7 +12299,7 @@ var GameTestRoom = (() => {
|
|
|
11744
12299
|
var FlashLightPool = class {
|
|
11745
12300
|
constructor(context) {
|
|
11746
12301
|
__publicField(this, "context", context);
|
|
11747
|
-
__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 })));
|
|
12302
|
+
__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 })));
|
|
11748
12303
|
__publicField(this, "fire", [
|
|
11749
12304
|
{ x: 0, y: 0, z: 0, intensity: 0 },
|
|
11750
12305
|
{ x: 0, y: 0, z: 0, intensity: 0 }
|
|
@@ -11754,7 +12309,7 @@ var GameTestRoom = (() => {
|
|
|
11754
12309
|
get lit() {
|
|
11755
12310
|
return this.lights.filter((light) => light.intensity > 0).length;
|
|
11756
12311
|
}
|
|
11757
|
-
flash(point, color, intensity, duration, distance4, force) {
|
|
12312
|
+
flash(point, color, intensity, duration, distance4, force, steady) {
|
|
11758
12313
|
const { level } = this.context.quality;
|
|
11759
12314
|
if (level >= 1 && !force) return;
|
|
11760
12315
|
if (level >= 2 && force !== "boom") return;
|
|
@@ -11767,6 +12322,7 @@ var GameTestRoom = (() => {
|
|
|
11767
12322
|
light.peak = intensity;
|
|
11768
12323
|
light.duration = duration;
|
|
11769
12324
|
light.t = 0;
|
|
12325
|
+
light.steady = steady === true;
|
|
11770
12326
|
light.intensity = intensity;
|
|
11771
12327
|
}
|
|
11772
12328
|
clear() {
|
|
@@ -11778,7 +12334,7 @@ var GameTestRoom = (() => {
|
|
|
11778
12334
|
if (light.intensity <= 0) continue;
|
|
11779
12335
|
light.t += dt;
|
|
11780
12336
|
const age = light.t / light.duration;
|
|
11781
|
-
light.intensity = age >= 1 ? 0 : light.peak * (1 - age) * (1 - age);
|
|
12337
|
+
light.intensity = age >= 1 ? 0 : light.steady ? light.peak : light.peak * (1 - age) * (1 - age);
|
|
11782
12338
|
}
|
|
11783
12339
|
}
|
|
11784
12340
|
};
|
|
@@ -11786,6 +12342,14 @@ var GameTestRoom = (() => {
|
|
|
11786
12342
|
var FIRE_FLICKER_SWAY = 0.25;
|
|
11787
12343
|
var FIRE_FLICKER_JITTER = 0.08;
|
|
11788
12344
|
var LENS_FADE = 0.16;
|
|
12345
|
+
function rotate(q, v) {
|
|
12346
|
+
const [qx, qy, qz, qw] = q;
|
|
12347
|
+
const ix = qw * v[0] + qy * v[2] - qz * v[1];
|
|
12348
|
+
const iy = qw * v[1] + qz * v[0] - qx * v[2];
|
|
12349
|
+
const iz = qw * v[2] + qx * v[1] - qy * v[0];
|
|
12350
|
+
const iw = -qx * v[0] - qy * v[1] - qz * v[2];
|
|
12351
|
+
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];
|
|
12352
|
+
}
|
|
11789
12353
|
function workshopGround(x, z) {
|
|
11790
12354
|
return z < -2.9 && z > -4.5 && Math.abs(x) < 13 ? 0.12 : 0;
|
|
11791
12355
|
}
|
|
@@ -11799,6 +12363,8 @@ var GameTestRoom = (() => {
|
|
|
11799
12363
|
__publicField(this, "decals");
|
|
11800
12364
|
__publicField(this, "rings", new WaveRingPool());
|
|
11801
12365
|
__publicField(this, "lights");
|
|
12366
|
+
__publicField(this, "rain", new RainField(this));
|
|
12367
|
+
__publicField(this, "meshes", new MeshPool());
|
|
11802
12368
|
__publicField(this, "screen", createScreenState());
|
|
11803
12369
|
__publicField(this, "lens", []);
|
|
11804
12370
|
__publicField(this, "post", {});
|
|
@@ -11831,7 +12397,11 @@ var GameTestRoom = (() => {
|
|
|
11831
12397
|
place(point) {
|
|
11832
12398
|
const placement = this.placement;
|
|
11833
12399
|
if (!placement) return point;
|
|
11834
|
-
const { anchor, origin, yaw } = placement;
|
|
12400
|
+
const { anchor, origin, yaw, orientation } = placement;
|
|
12401
|
+
if (orientation) {
|
|
12402
|
+
const turned = rotate(orientation, [point[0] - anchor[0], point[1] - anchor[1], point[2] - anchor[2]]);
|
|
12403
|
+
return [origin[0] + turned[0], origin[1] + turned[1], origin[2] + turned[2]];
|
|
12404
|
+
}
|
|
11835
12405
|
const x = point[0] - anchor[0];
|
|
11836
12406
|
const z = point[2] - anchor[2];
|
|
11837
12407
|
const cos2 = Math.cos(yaw);
|
|
@@ -11842,6 +12412,7 @@ var GameTestRoom = (() => {
|
|
|
11842
12412
|
turn(vector) {
|
|
11843
12413
|
const placement = this.placement;
|
|
11844
12414
|
if (!placement) return vector;
|
|
12415
|
+
if (placement.orientation) return rotate(placement.orientation, vector);
|
|
11845
12416
|
const cos2 = Math.cos(placement.yaw);
|
|
11846
12417
|
const sin2 = Math.sin(placement.yaw);
|
|
11847
12418
|
return [cos2 * vector[0] + sin2 * vector[2], vector[1], -sin2 * vector[0] + cos2 * vector[2]];
|
|
@@ -11870,6 +12441,14 @@ var GameTestRoom = (() => {
|
|
|
11870
12441
|
}
|
|
11871
12442
|
this.accumulators.set(key, carried);
|
|
11872
12443
|
}
|
|
12444
|
+
/** 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. */
|
|
12445
|
+
mesh(recipe) {
|
|
12446
|
+
const placement = this.placement;
|
|
12447
|
+
const options = placement ? { ...recipe, p: this.place(recipe.p), ...recipe.v ? { v: this.turn(recipe.v) } : {} } : recipe;
|
|
12448
|
+
this.context.trace?.("mesh", [options]);
|
|
12449
|
+
const grouped = recipe.at !== void 0 || recipe.roll !== void 0;
|
|
12450
|
+
return this.meshes.spawn(options, placement && grouped ? placement.orientation ?? [0, Math.sin(placement.yaw / 2), 0, Math.cos(placement.yaw / 2)] : void 0);
|
|
12451
|
+
}
|
|
11873
12452
|
debrisPiece(recipe) {
|
|
11874
12453
|
const options = this.placed(recipe);
|
|
11875
12454
|
this.context.trace?.("debris", [options]);
|
|
@@ -11890,10 +12469,11 @@ var GameTestRoom = (() => {
|
|
|
11890
12469
|
this.context.trace?.("ring", args);
|
|
11891
12470
|
this.rings.add(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
|
|
11892
12471
|
}
|
|
12472
|
+
/** `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. */
|
|
11893
12473
|
flash(recipe) {
|
|
11894
|
-
const args = this.placement ? [this.place(recipe[0]), recipe[1], recipe[2], recipe[3], recipe[4], recipe[5]] : recipe;
|
|
11895
|
-
this.context.trace?.("flash", args);
|
|
11896
|
-
this.lights.flash(args[0], args[1], args[2], args[3], args[4], args[5]);
|
|
12474
|
+
const args = this.placement ? [this.place(recipe[0]), recipe[1], recipe[2], recipe[3], recipe[4], recipe[5], recipe[6]] : recipe;
|
|
12475
|
+
this.context.trace?.("flash", args.slice(0, 6));
|
|
12476
|
+
this.lights.flash(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
|
|
11897
12477
|
}
|
|
11898
12478
|
/** `fireLight` (W400): sways with the clock and flickers with one draw. */
|
|
11899
12479
|
fireLight(slot, recipe, intensity, time) {
|
|
@@ -11918,6 +12498,7 @@ var GameTestRoom = (() => {
|
|
|
11918
12498
|
this.debris.update(dt);
|
|
11919
12499
|
this.decals.update(dt);
|
|
11920
12500
|
this.rings.update(dt);
|
|
12501
|
+
this.meshes.update(dt);
|
|
11921
12502
|
this.lights.update(dt);
|
|
11922
12503
|
updateScreen(this.screen, dt);
|
|
11923
12504
|
for (let index = this.lens.length - 1; index >= 0; index--) {
|
|
@@ -11934,7 +12515,9 @@ var GameTestRoom = (() => {
|
|
|
11934
12515
|
this.debris.clear();
|
|
11935
12516
|
this.decals.clear();
|
|
11936
12517
|
this.rings.clear();
|
|
12518
|
+
this.meshes.clear();
|
|
11937
12519
|
this.lights.clear();
|
|
12520
|
+
this.rain.clear();
|
|
11938
12521
|
this.accumulators.clear();
|
|
11939
12522
|
resetScreenState(this.screen);
|
|
11940
12523
|
this.lens.length = 0;
|
|
@@ -12080,16 +12663,16 @@ var GameTestRoom = (() => {
|
|
|
12080
12663
|
},
|
|
12081
12664
|
push(point, radius, speed) {
|
|
12082
12665
|
spriteSystem.push(point, radius, speed);
|
|
12083
|
-
for (const
|
|
12084
|
-
const dx =
|
|
12085
|
-
const dy =
|
|
12086
|
-
const dz =
|
|
12666
|
+
for (const puff3 of core.puffs.items) {
|
|
12667
|
+
const dx = puff3.x - point[0];
|
|
12668
|
+
const dy = puff3.y - point[1];
|
|
12669
|
+
const dz = puff3.z - point[2];
|
|
12087
12670
|
const distance4 = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
|
12088
12671
|
if (distance4 >= radius) continue;
|
|
12089
12672
|
const strength = speed * (1 - distance4 / radius) / (distance4 + 1e-3);
|
|
12090
|
-
|
|
12091
|
-
|
|
12092
|
-
|
|
12673
|
+
puff3.vx += dx * strength;
|
|
12674
|
+
puff3.vy += dy * strength;
|
|
12675
|
+
puff3.vz += dz * strength;
|
|
12093
12676
|
}
|
|
12094
12677
|
},
|
|
12095
12678
|
stop(handle) {
|
|
@@ -12106,6 +12689,12 @@ var GameTestRoom = (() => {
|
|
|
12106
12689
|
camera2.y = position[1];
|
|
12107
12690
|
camera2.z = position[2];
|
|
12108
12691
|
},
|
|
12692
|
+
setWind(next) {
|
|
12693
|
+
wind.x = next[0];
|
|
12694
|
+
wind.y = next[1];
|
|
12695
|
+
wind.z = next[2];
|
|
12696
|
+
},
|
|
12697
|
+
wind: () => [wind.x, wind.y, wind.z],
|
|
12109
12698
|
forceLod(scale2) {
|
|
12110
12699
|
core.clock.forcedLod = scale2;
|
|
12111
12700
|
},
|
|
@@ -12374,11 +12963,11 @@ void main(){
|
|
|
12374
12963
|
geometry.setAttribute("aC", attributes[2]);
|
|
12375
12964
|
geometry.instanceCount = 0;
|
|
12376
12965
|
const material = new THREE.ShaderMaterial({ uniforms, vertexShader: PUFF_VERTEX, fragmentShader: PUFF_FRAGMENT });
|
|
12377
|
-
const
|
|
12378
|
-
|
|
12379
|
-
|
|
12966
|
+
const mesh2 = new THREE.Mesh(geometry, material);
|
|
12967
|
+
mesh2.name = "vfx-puffs";
|
|
12968
|
+
mesh2.frustumCulled = false;
|
|
12380
12969
|
return {
|
|
12381
|
-
mesh,
|
|
12970
|
+
mesh: mesh2,
|
|
12382
12971
|
sync() {
|
|
12383
12972
|
let n = 0;
|
|
12384
12973
|
for (const p of pool.items) {
|
|
@@ -12419,12 +13008,12 @@ void main(){
|
|
|
12419
13008
|
geometry.setAttribute("aE", attributes[2]);
|
|
12420
13009
|
geometry.instanceCount = 0;
|
|
12421
13010
|
const material = new THREE.ShaderMaterial({ transparent: true, depthWrite: false, blending: THREE.AdditiveBlending, vertexShader: SPARK_VERTEX, fragmentShader: SPARK_FRAGMENT });
|
|
12422
|
-
const
|
|
12423
|
-
|
|
12424
|
-
|
|
12425
|
-
|
|
13011
|
+
const mesh2 = new THREE.Mesh(geometry, material);
|
|
13012
|
+
mesh2.name = "vfx-sparks";
|
|
13013
|
+
mesh2.frustumCulled = false;
|
|
13014
|
+
mesh2.renderOrder = 5;
|
|
12426
13015
|
return {
|
|
12427
|
-
mesh,
|
|
13016
|
+
mesh: mesh2,
|
|
12428
13017
|
sync() {
|
|
12429
13018
|
let n = 0;
|
|
12430
13019
|
for (const s of pool.items) {
|
|
@@ -12462,12 +13051,12 @@ void main(){
|
|
|
12462
13051
|
geometry.setAttribute("aC", attributes[1]);
|
|
12463
13052
|
geometry.instanceCount = 0;
|
|
12464
13053
|
const material = new THREE.ShaderMaterial({ transparent: true, depthWrite: false, blending: THREE.AdditiveBlending, vertexShader: GLOW_VERTEX, fragmentShader: GLOW_FRAGMENT });
|
|
12465
|
-
const
|
|
12466
|
-
|
|
12467
|
-
|
|
12468
|
-
|
|
13054
|
+
const mesh2 = new THREE.Mesh(geometry, material);
|
|
13055
|
+
mesh2.name = "vfx-glows";
|
|
13056
|
+
mesh2.frustumCulled = false;
|
|
13057
|
+
mesh2.renderOrder = 6;
|
|
12469
13058
|
return {
|
|
12470
|
-
mesh,
|
|
13059
|
+
mesh: mesh2,
|
|
12471
13060
|
sync() {
|
|
12472
13061
|
let n = 0;
|
|
12473
13062
|
for (const g of pool.items) {
|
|
@@ -12496,14 +13085,14 @@ void main(){
|
|
|
12496
13085
|
const rockMaterial = new THREE.MeshStandardMaterial({ color: 16777215, roughness: 0.85, flatShading: true });
|
|
12497
13086
|
const plateMaterial = rockMaterial.clone();
|
|
12498
13087
|
const make = (geometry, material) => {
|
|
12499
|
-
const
|
|
12500
|
-
|
|
12501
|
-
|
|
12502
|
-
|
|
12503
|
-
|
|
12504
|
-
|
|
12505
|
-
|
|
12506
|
-
return
|
|
13088
|
+
const mesh2 = new THREE.InstancedMesh(geometry, material, capacity);
|
|
13089
|
+
mesh2.instanceMatrix.setUsage(THREE.DynamicDrawUsage);
|
|
13090
|
+
mesh2.castShadow = true;
|
|
13091
|
+
mesh2.receiveShadow = true;
|
|
13092
|
+
mesh2.frustumCulled = false;
|
|
13093
|
+
mesh2.count = 0;
|
|
13094
|
+
mesh2.setColorAt(0, new THREE.Color(1, 1, 1));
|
|
13095
|
+
return mesh2;
|
|
12507
13096
|
};
|
|
12508
13097
|
const rocks = make(shapes.rock, rockMaterial);
|
|
12509
13098
|
const plates = make(shapes.plate, plateMaterial);
|
|
@@ -12522,20 +13111,20 @@ void main(){
|
|
|
12522
13111
|
euler.set(chunk.rx, chunk.ry, chunk.rz);
|
|
12523
13112
|
quaternion.setFromEuler(euler);
|
|
12524
13113
|
matrix.compose(position.set(chunk.x, chunk.y, chunk.z), quaternion, scale2.set(chunk.sx, chunk.sy, chunk.sz));
|
|
12525
|
-
const
|
|
13114
|
+
const mesh2 = chunk.plate ? plates : rocks;
|
|
12526
13115
|
const index = chunk.plate ? plateCount++ : rockCount++;
|
|
12527
|
-
|
|
13116
|
+
mesh2.setMatrixAt(index, matrix);
|
|
12528
13117
|
const color = colorOf2(chunk);
|
|
12529
|
-
const colors =
|
|
13118
|
+
const colors = mesh2.instanceColor.array;
|
|
12530
13119
|
colors[index * 3] = color[0];
|
|
12531
13120
|
colors[index * 3 + 1] = color[1];
|
|
12532
13121
|
colors[index * 3 + 2] = color[2];
|
|
12533
13122
|
}
|
|
12534
13123
|
rocks.count = rockCount;
|
|
12535
13124
|
plates.count = plateCount;
|
|
12536
|
-
for (const
|
|
12537
|
-
|
|
12538
|
-
|
|
13125
|
+
for (const mesh2 of [rocks, plates]) {
|
|
13126
|
+
mesh2.instanceMatrix.needsUpdate = true;
|
|
13127
|
+
mesh2.instanceColor.needsUpdate = true;
|
|
12539
13128
|
}
|
|
12540
13129
|
return rockCount + plateCount;
|
|
12541
13130
|
},
|
|
@@ -12719,28 +13308,28 @@ void main(){
|
|
|
12719
13308
|
position.setXYZ(index, worldX, (options.ground?.heightAt(worldX, worldZ) ?? 0) + mark.lift, worldZ);
|
|
12720
13309
|
}
|
|
12721
13310
|
geometry.computeVertexNormals();
|
|
12722
|
-
const
|
|
12723
|
-
|
|
12724
|
-
return
|
|
13311
|
+
const mesh2 = new THREE.Mesh(geometry, material);
|
|
13312
|
+
mesh2.receiveShadow = true;
|
|
13313
|
+
return mesh2;
|
|
12725
13314
|
}
|
|
12726
13315
|
function addRock(mark) {
|
|
12727
|
-
const
|
|
12728
|
-
|
|
12729
|
-
|
|
12730
|
-
|
|
12731
|
-
|
|
12732
|
-
|
|
12733
|
-
return
|
|
13316
|
+
const mesh2 = new THREE.Mesh(mark.plate ? options.plateGeometry : options.rockGeometry, rockMaterial(mark.color));
|
|
13317
|
+
mesh2.position.set(mark.x, mark.y, mark.z);
|
|
13318
|
+
mesh2.scale.set(mark.scale[0], mark.scale[1], mark.scale[2]);
|
|
13319
|
+
mesh2.rotation.set(mark.rotation[0], mark.rotation[1], mark.rotation[2]);
|
|
13320
|
+
mesh2.castShadow = true;
|
|
13321
|
+
mesh2.receiveShadow = true;
|
|
13322
|
+
return mesh2;
|
|
12734
13323
|
}
|
|
12735
13324
|
function addBlood(mark) {
|
|
12736
|
-
const
|
|
12737
|
-
|
|
12738
|
-
|
|
12739
|
-
|
|
12740
|
-
|
|
12741
|
-
|
|
12742
|
-
blood.push({ mesh, scaleX: mark.scaleX, scaleZ: mark.scaleZ, age: 0 });
|
|
12743
|
-
return
|
|
13325
|
+
const mesh2 = new THREE.Mesh(bloodGeometry, bloodMaterial);
|
|
13326
|
+
mesh2.position.set(mark.x, mark.y, mark.z);
|
|
13327
|
+
mesh2.scale.set(mark.scaleX, 1, mark.scaleZ);
|
|
13328
|
+
mesh2.rotation.y = mark.rotation;
|
|
13329
|
+
mesh2.receiveShadow = true;
|
|
13330
|
+
mesh2.scale.multiplyScalar(0.05);
|
|
13331
|
+
blood.push({ mesh: mesh2, scaleX: mark.scaleX, scaleZ: mark.scaleZ, age: 0 });
|
|
13332
|
+
return mesh2;
|
|
12744
13333
|
}
|
|
12745
13334
|
function build(mark) {
|
|
12746
13335
|
if (mark.kind === "scorch") return conform(mark, scorchMaterials[mark.variant]);
|
|
@@ -12951,6 +13540,73 @@ void main() {
|
|
|
12951
13540
|
}
|
|
12952
13541
|
};
|
|
12953
13542
|
}
|
|
13543
|
+
var SPHERE_DEFAULT_WIDTH = 8;
|
|
13544
|
+
var SPHERE_DEFAULT_HEIGHT = 6;
|
|
13545
|
+
function geometryOf(THREE, particle) {
|
|
13546
|
+
switch (particle.shape) {
|
|
13547
|
+
case "cone":
|
|
13548
|
+
return new THREE.ConeGeometry(particle.radius, particle.height, particle.segments || void 0, particle.segments2 || 1, false);
|
|
13549
|
+
case "cone_open":
|
|
13550
|
+
return new THREE.ConeGeometry(particle.radius, particle.height, particle.segments || void 0, particle.segments2 || 1, true);
|
|
13551
|
+
case "sphere":
|
|
13552
|
+
return new THREE.SphereGeometry(particle.radius, particle.segments || SPHERE_DEFAULT_WIDTH, particle.segments2 || SPHERE_DEFAULT_HEIGHT);
|
|
13553
|
+
case "icosahedron":
|
|
13554
|
+
return new THREE.IcosahedronGeometry(particle.radius, particle.segments);
|
|
13555
|
+
}
|
|
13556
|
+
}
|
|
13557
|
+
function materialOf(THREE, particle) {
|
|
13558
|
+
if (particle.lit) return new THREE.MeshStandardMaterial({ color: particle.color, roughness: 1, metalness: 0, transparent: true, opacity: particle.opacity, depthWrite: false });
|
|
13559
|
+
return new THREE.MeshBasicMaterial({ color: particle.color, transparent: true, opacity: particle.opacity, depthWrite: false, ...particle.additive ? { blending: THREE.AdditiveBlending } : {} });
|
|
13560
|
+
}
|
|
13561
|
+
function createMeshLayer(THREE, pool) {
|
|
13562
|
+
const group = new THREE.Group();
|
|
13563
|
+
group.name = "workshop-meshes";
|
|
13564
|
+
const drawn = /* @__PURE__ */ new Map();
|
|
13565
|
+
const frame3 = new THREE.Quaternion();
|
|
13566
|
+
const euler = new THREE.Euler();
|
|
13567
|
+
const turn = new THREE.Quaternion();
|
|
13568
|
+
const offset = new THREE.Vector3();
|
|
13569
|
+
function release(mesh2) {
|
|
13570
|
+
mesh2.removeFromParent();
|
|
13571
|
+
mesh2.geometry.dispose();
|
|
13572
|
+
mesh2.material.dispose();
|
|
13573
|
+
}
|
|
13574
|
+
return {
|
|
13575
|
+
group,
|
|
13576
|
+
sync() {
|
|
13577
|
+
const live = /* @__PURE__ */ new Set();
|
|
13578
|
+
for (const particle of pool.particles) {
|
|
13579
|
+
live.add(particle.id);
|
|
13580
|
+
let mesh2 = drawn.get(particle.id);
|
|
13581
|
+
if (!mesh2) {
|
|
13582
|
+
mesh2 = new THREE.Mesh(geometryOf(THREE, particle), materialOf(THREE, particle));
|
|
13583
|
+
mesh2.frustumCulled = false;
|
|
13584
|
+
mesh2.renderOrder = particle.additive ? 5 : 3;
|
|
13585
|
+
drawn.set(particle.id, mesh2);
|
|
13586
|
+
group.add(mesh2);
|
|
13587
|
+
}
|
|
13588
|
+
frame3.set(particle.frame[0], particle.frame[1], particle.frame[2], particle.frame[3]);
|
|
13589
|
+
offset.set(particle.at[0], particle.at[1], particle.at[2]).multiplyScalar(particle.scale).applyQuaternion(frame3);
|
|
13590
|
+
mesh2.position.set(particle.x + offset.x, particle.y + offset.y, particle.z + offset.z);
|
|
13591
|
+
turn.setFromEuler(euler.set(particle.rx, particle.ry, particle.rz));
|
|
13592
|
+
mesh2.quaternion.copy(frame3).multiply(turn);
|
|
13593
|
+
mesh2.scale.setScalar(particle.scale);
|
|
13594
|
+
mesh2.material.opacity = particle.opacity;
|
|
13595
|
+
}
|
|
13596
|
+
for (const [id, mesh2] of drawn) {
|
|
13597
|
+
if (live.has(id)) continue;
|
|
13598
|
+
release(mesh2);
|
|
13599
|
+
drawn.delete(id);
|
|
13600
|
+
}
|
|
13601
|
+
return pool.count;
|
|
13602
|
+
},
|
|
13603
|
+
dispose() {
|
|
13604
|
+
for (const mesh2 of drawn.values()) release(mesh2);
|
|
13605
|
+
drawn.clear();
|
|
13606
|
+
group.removeFromParent();
|
|
13607
|
+
}
|
|
13608
|
+
};
|
|
13609
|
+
}
|
|
12954
13610
|
var WORKSHOP_SPRITE_VERTEX = `attribute float size;attribute float alpha;attribute vec3 pcol;varying vec3 vC;varying float vA;uniform float uScale;
|
|
12955
13611
|
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;}`;
|
|
12956
13612
|
var WORKSHOP_SPRITE_FRAGMENT = `uniform float uSoft;varying vec3 vC;varying float vA;
|
|
@@ -13026,13 +13682,37 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13026
13682
|
}
|
|
13027
13683
|
};
|
|
13028
13684
|
}
|
|
13685
|
+
function rainLayer(THREE, rain) {
|
|
13686
|
+
const geometry = new THREE.BufferGeometry();
|
|
13687
|
+
const position = new THREE.BufferAttribute(rain.positions, 3).setUsage(THREE.DynamicDrawUsage);
|
|
13688
|
+
geometry.setAttribute("position", position);
|
|
13689
|
+
geometry.setDrawRange(0, 0);
|
|
13690
|
+
const material = new THREE.LineBasicMaterial({ color: 10466255, transparent: true, opacity: 0.35, depthWrite: false });
|
|
13691
|
+
const lines = new THREE.LineSegments(geometry, material);
|
|
13692
|
+
lines.frustumCulled = false;
|
|
13693
|
+
lines.name = "workshop-rain";
|
|
13694
|
+
return {
|
|
13695
|
+
object: lines,
|
|
13696
|
+
sync() {
|
|
13697
|
+
const drawn = rain.on && rain.count > 0;
|
|
13698
|
+
lines.visible = drawn;
|
|
13699
|
+
geometry.setDrawRange(0, drawn ? rain.count * 2 : 0);
|
|
13700
|
+
position.needsUpdate = true;
|
|
13701
|
+
return drawn;
|
|
13702
|
+
},
|
|
13703
|
+
dispose() {
|
|
13704
|
+
geometry.dispose();
|
|
13705
|
+
material.dispose();
|
|
13706
|
+
}
|
|
13707
|
+
};
|
|
13708
|
+
}
|
|
13029
13709
|
function debrisLayer(THREE, pool) {
|
|
13030
13710
|
const geometry = new THREE.BoxGeometry(1, 1, 1);
|
|
13031
13711
|
const material = new THREE.MeshStandardMaterial({ color: 16777215, roughness: 0.45, metalness: 0.25, flatShading: true });
|
|
13032
|
-
const
|
|
13033
|
-
|
|
13034
|
-
|
|
13035
|
-
|
|
13712
|
+
const mesh2 = new THREE.InstancedMesh(geometry, material, DEBRIS_CAPACITY);
|
|
13713
|
+
mesh2.instanceMatrix.setUsage(THREE.DynamicDrawUsage);
|
|
13714
|
+
mesh2.frustumCulled = false;
|
|
13715
|
+
mesh2.name = "workshop-debris";
|
|
13036
13716
|
const euler = new THREE.Euler();
|
|
13037
13717
|
const quaternion = new THREE.Quaternion();
|
|
13038
13718
|
const position = new THREE.Vector3();
|
|
@@ -13040,16 +13720,16 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13040
13720
|
const matrix = new THREE.Matrix4();
|
|
13041
13721
|
const colour = new THREE.Color();
|
|
13042
13722
|
const hidden = new THREE.Matrix4().makeScale(0, 0, 0);
|
|
13043
|
-
for (let index = 0; index < DEBRIS_CAPACITY; index++)
|
|
13044
|
-
|
|
13723
|
+
for (let index = 0; index < DEBRIS_CAPACITY; index++) mesh2.setMatrixAt(index, hidden);
|
|
13724
|
+
mesh2.setColorAt(0, colour.setHex(16777215));
|
|
13045
13725
|
return {
|
|
13046
|
-
object:
|
|
13726
|
+
object: mesh2,
|
|
13047
13727
|
sync() {
|
|
13048
13728
|
let drawn = false;
|
|
13049
13729
|
for (let index = 0; index < DEBRIS_CAPACITY; index++) {
|
|
13050
13730
|
const piece = pool.pieces[index];
|
|
13051
13731
|
if (!piece.on) {
|
|
13052
|
-
|
|
13732
|
+
mesh2.setMatrixAt(index, hidden);
|
|
13053
13733
|
continue;
|
|
13054
13734
|
}
|
|
13055
13735
|
drawn = true;
|
|
@@ -13057,11 +13737,11 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13057
13737
|
euler.set(piece.rx, piece.ry, piece.rz);
|
|
13058
13738
|
quaternion.setFromEuler(euler);
|
|
13059
13739
|
matrix.compose(position.set(piece.x, piece.y, piece.z), quaternion, scale2.set(piece.sx * shrink, piece.sy * shrink, piece.sz * shrink));
|
|
13060
|
-
|
|
13061
|
-
|
|
13740
|
+
mesh2.setMatrixAt(index, matrix);
|
|
13741
|
+
mesh2.setColorAt(index, colour.setHex(piece.color));
|
|
13062
13742
|
}
|
|
13063
|
-
|
|
13064
|
-
if (
|
|
13743
|
+
mesh2.instanceMatrix.needsUpdate = true;
|
|
13744
|
+
if (mesh2.instanceColor) mesh2.instanceColor.needsUpdate = true;
|
|
13065
13745
|
return drawn;
|
|
13066
13746
|
},
|
|
13067
13747
|
dispose() {
|
|
@@ -13118,11 +13798,11 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13118
13798
|
const dryMesh = new THREE.InstancedMesh(geometry, dry, DECAL_CAPACITY);
|
|
13119
13799
|
const group = new THREE.Group();
|
|
13120
13800
|
group.name = "workshop-decals";
|
|
13121
|
-
for (const
|
|
13122
|
-
|
|
13123
|
-
|
|
13124
|
-
|
|
13125
|
-
group.add(
|
|
13801
|
+
for (const mesh2 of [wetMesh, dryMesh]) {
|
|
13802
|
+
mesh2.frustumCulled = false;
|
|
13803
|
+
mesh2.renderOrder = 1;
|
|
13804
|
+
mesh2.instanceMatrix.setUsage(THREE.DynamicDrawUsage);
|
|
13805
|
+
group.add(mesh2);
|
|
13126
13806
|
}
|
|
13127
13807
|
const hidden = new THREE.Matrix4().makeScale(0, 0, 0);
|
|
13128
13808
|
const colour = new THREE.Color();
|
|
@@ -13159,13 +13839,13 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13159
13839
|
quaternion.multiply(turn.setFromAxisAngle(forward, index * 2.399963));
|
|
13160
13840
|
const offset = 4e-3 + index % 40 * 4e-4;
|
|
13161
13841
|
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));
|
|
13162
|
-
const
|
|
13163
|
-
|
|
13164
|
-
|
|
13842
|
+
const mesh2 = look.dried ? dryMesh : wetMesh;
|
|
13843
|
+
mesh2.setMatrixAt(index, matrix);
|
|
13844
|
+
mesh2.setColorAt(index, colour);
|
|
13165
13845
|
}
|
|
13166
|
-
for (const
|
|
13167
|
-
|
|
13168
|
-
if (
|
|
13846
|
+
for (const mesh2 of [wetMesh, dryMesh]) {
|
|
13847
|
+
mesh2.instanceMatrix.needsUpdate = true;
|
|
13848
|
+
if (mesh2.instanceColor) mesh2.instanceColor.needsUpdate = true;
|
|
13169
13849
|
}
|
|
13170
13850
|
return drawn;
|
|
13171
13851
|
},
|
|
@@ -13179,10 +13859,10 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13179
13859
|
function ringLayer(THREE, pool) {
|
|
13180
13860
|
const geometry = new THREE.RingGeometry(0.86, 1, 40);
|
|
13181
13861
|
const material = new THREE.MeshBasicMaterial({ color: 16777215, transparent: true, blending: THREE.AdditiveBlending, depthWrite: false, side: THREE.DoubleSide });
|
|
13182
|
-
const
|
|
13183
|
-
|
|
13184
|
-
|
|
13185
|
-
|
|
13862
|
+
const mesh2 = new THREE.InstancedMesh(geometry, material, RING_CAPACITY3);
|
|
13863
|
+
mesh2.frustumCulled = false;
|
|
13864
|
+
mesh2.instanceMatrix.setUsage(THREE.DynamicDrawUsage);
|
|
13865
|
+
mesh2.name = "workshop-rings";
|
|
13186
13866
|
const hidden = new THREE.Matrix4().makeScale(0, 0, 0);
|
|
13187
13867
|
const colour = new THREE.Color();
|
|
13188
13868
|
const normal = new THREE.Vector3();
|
|
@@ -13191,16 +13871,16 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13191
13871
|
const position = new THREE.Vector3();
|
|
13192
13872
|
const scale2 = new THREE.Vector3();
|
|
13193
13873
|
const matrix = new THREE.Matrix4();
|
|
13194
|
-
|
|
13195
|
-
for (let index = 0; index < RING_CAPACITY3; index++)
|
|
13874
|
+
mesh2.setColorAt(0, colour.setHex(0));
|
|
13875
|
+
for (let index = 0; index < RING_CAPACITY3; index++) mesh2.setMatrixAt(index, hidden);
|
|
13196
13876
|
return {
|
|
13197
|
-
object:
|
|
13877
|
+
object: mesh2,
|
|
13198
13878
|
sync() {
|
|
13199
13879
|
let drawn = false;
|
|
13200
13880
|
for (let index = 0; index < RING_CAPACITY3; index++) {
|
|
13201
13881
|
const ring2 = pool.rings[index];
|
|
13202
13882
|
if (!ring2.on) {
|
|
13203
|
-
|
|
13883
|
+
mesh2.setMatrixAt(index, hidden);
|
|
13204
13884
|
continue;
|
|
13205
13885
|
}
|
|
13206
13886
|
drawn = true;
|
|
@@ -13208,11 +13888,11 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13208
13888
|
const radius = ring2.from + (ring2.to - ring2.from) * (1 - Math.pow(1 - k, 2));
|
|
13209
13889
|
quaternion.setFromUnitVectors(forward, normal.set(ring2.normal[0], ring2.normal[1], ring2.normal[2]));
|
|
13210
13890
|
matrix.compose(position.set(ring2.point[0], ring2.point[1], ring2.point[2]), quaternion, scale2.set(radius, radius, 1));
|
|
13211
|
-
|
|
13212
|
-
|
|
13891
|
+
mesh2.setMatrixAt(index, matrix);
|
|
13892
|
+
mesh2.setColorAt(index, colour.setHex(ring2.color).multiplyScalar(ring2.hold ? ring2.hold : 1 - k));
|
|
13213
13893
|
}
|
|
13214
|
-
|
|
13215
|
-
if (
|
|
13894
|
+
mesh2.instanceMatrix.needsUpdate = true;
|
|
13895
|
+
if (mesh2.instanceColor) mesh2.instanceColor.needsUpdate = true;
|
|
13216
13896
|
return drawn;
|
|
13217
13897
|
},
|
|
13218
13898
|
dispose() {
|
|
@@ -13228,11 +13908,14 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13228
13908
|
spriteLayer(THREE, engine.add, true, 1, pointScale),
|
|
13229
13909
|
spriteLayer(THREE, engine.normal, false, 0.55, pointScale),
|
|
13230
13910
|
streakLayer(THREE, engine.streaks),
|
|
13911
|
+
rainLayer(THREE, engine.rain),
|
|
13231
13912
|
debrisLayer(THREE, engine.debris),
|
|
13232
13913
|
decalLayer(THREE, engine.decals),
|
|
13233
13914
|
ringLayer(THREE, engine.rings)
|
|
13234
13915
|
];
|
|
13235
13916
|
for (const layer2 of layers) group.add(layer2.object);
|
|
13917
|
+
const meshes = createMeshLayer(THREE, engine.meshes);
|
|
13918
|
+
group.add(meshes.group);
|
|
13236
13919
|
const flashLights = engine.lights.lights.map(() => new THREE.PointLight(16760944, 0, 14));
|
|
13237
13920
|
const fireLights = engine.lights.fire.map(() => new THREE.PointLight(FIRE_LIGHT_COLOR, 0, FIRE_LIGHT_DISTANCE));
|
|
13238
13921
|
for (const light of [...flashLights, ...fireLights]) group.add(light);
|
|
@@ -13241,6 +13924,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13241
13924
|
sync() {
|
|
13242
13925
|
let drawCalls = 0;
|
|
13243
13926
|
for (const layer2 of layers) if (layer2.sync()) drawCalls++;
|
|
13927
|
+
drawCalls += meshes.sync();
|
|
13244
13928
|
engine.lights.lights.forEach((source, index) => {
|
|
13245
13929
|
const light = flashLights[index];
|
|
13246
13930
|
light.position.set(source.x, source.y, source.z);
|
|
@@ -13257,6 +13941,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13257
13941
|
},
|
|
13258
13942
|
dispose() {
|
|
13259
13943
|
for (const layer2 of layers) layer2.dispose();
|
|
13944
|
+
meshes.dispose();
|
|
13260
13945
|
group.clear();
|
|
13261
13946
|
}
|
|
13262
13947
|
};
|
|
@@ -13372,8 +14057,10 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13372
14057
|
return world.play(request.effect, request.point, {
|
|
13373
14058
|
...request.direction ? { direction: request.direction } : {},
|
|
13374
14059
|
...request.normal ? { normal: request.normal } : {},
|
|
14060
|
+
...request.orientation ? { orientation: request.orientation } : {},
|
|
13375
14061
|
...request.seed !== void 0 ? { seed: request.seed } : {},
|
|
13376
|
-
...request.param !== void 0 ? { param: request.param } : {}
|
|
14062
|
+
...request.param !== void 0 ? { param: request.param } : {},
|
|
14063
|
+
...request.values ? { values: request.values } : {}
|
|
13377
14064
|
});
|
|
13378
14065
|
},
|
|
13379
14066
|
stop: (handle) => world.stop(handle),
|
|
@@ -13438,8 +14125,8 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13438
14125
|
const uv = geometry.attributes.uv;
|
|
13439
14126
|
for (let index = 0; index < position.count; index++) uv.setXY(index, position.getX(index) / metres, position.getZ(index) / metres);
|
|
13440
14127
|
const material = options.material ?? new THREE.MeshStandardMaterial({ color: 2829359, roughness: 0.93, flatShading: true });
|
|
13441
|
-
const
|
|
13442
|
-
|
|
14128
|
+
const mesh2 = new THREE.Mesh(geometry, material);
|
|
14129
|
+
mesh2.receiveShadow = true;
|
|
13443
14130
|
let version = -1;
|
|
13444
14131
|
function sync() {
|
|
13445
14132
|
if (field.version === version) return false;
|
|
@@ -13450,7 +14137,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13450
14137
|
return true;
|
|
13451
14138
|
}
|
|
13452
14139
|
return {
|
|
13453
|
-
mesh,
|
|
14140
|
+
mesh: mesh2,
|
|
13454
14141
|
sync,
|
|
13455
14142
|
dispose() {
|
|
13456
14143
|
geometry.dispose();
|
|
@@ -13564,11 +14251,11 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13564
14251
|
* Bullet holes that stay on a fragment (`Fragment.marks`): dark discs that are children of its mesh, so they fall, spin and settle with it. The mesh is
|
|
13565
14252
|
* a unit box scaled to the fragment, so each disc is scaled back; exact for a mark on a face, which is where a bullet hole is.
|
|
13566
14253
|
*/
|
|
13567
|
-
addMarks(
|
|
14254
|
+
addMarks(mesh2, f) {
|
|
13568
14255
|
if (!f.marks?.length) return;
|
|
13569
14256
|
this.markGeometry ?? (this.markGeometry = new this.THREE.CircleGeometry(1, 10));
|
|
13570
14257
|
this.markMaterial ?? (this.markMaterial = new this.THREE.MeshBasicMaterial({ color: 723465, depthWrite: false, polygonOffset: true, polygonOffsetFactor: -4, polygonOffsetUnits: -4 }));
|
|
13571
|
-
const sc =
|
|
14258
|
+
const sc = mesh2.scale;
|
|
13572
14259
|
for (const mark of f.marks) {
|
|
13573
14260
|
const disc = new this.THREE.Mesh(this.markGeometry, this.markMaterial);
|
|
13574
14261
|
const radius = Math.max(4e-3, mark.diameter) * 0.6;
|
|
@@ -13576,22 +14263,22 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13576
14263
|
disc.position.set(mark.point[0] / sc.x + n.x * 2e-3 / sc.x, mark.point[1] / sc.y + n.y * 2e-3 / sc.y, mark.point[2] / sc.z + n.z * 2e-3 / sc.z);
|
|
13577
14264
|
disc.quaternion.setFromUnitVectors(this.w.set(0, 0, 1), n);
|
|
13578
14265
|
disc.scale.set(radius / sc.x, radius / sc.y, radius / sc.z);
|
|
13579
|
-
|
|
14266
|
+
mesh2.add(disc);
|
|
13580
14267
|
}
|
|
13581
14268
|
}
|
|
13582
14269
|
/** Create the mesh of a fragment and start its motion. `maxAllowed` is the live budget. */
|
|
13583
14270
|
spawn(f, material, home, maxAllowed) {
|
|
13584
14271
|
const geo = f.shape === "shard" ? this.shardGeometry(hashString(f.id)) : this.box;
|
|
13585
|
-
const
|
|
13586
|
-
|
|
13587
|
-
|
|
14272
|
+
const mesh2 = new this.THREE.Mesh(geo, material);
|
|
14273
|
+
mesh2.position.set(f.center[0], f.center[1], f.center[2]);
|
|
14274
|
+
mesh2.quaternion.set(f.rotation[0], f.rotation[1], f.rotation[2], f.rotation[3]).normalize();
|
|
13588
14275
|
const sz = f.size;
|
|
13589
14276
|
const sc = new this.THREE.Vector3(Math.max(5e-3, sz[0]), Math.max(5e-3, sz[1]), Math.max(3e-3, sz[2]));
|
|
13590
|
-
|
|
13591
|
-
|
|
13592
|
-
this.o.scene.add(
|
|
14277
|
+
mesh2.scale.copy(sc);
|
|
14278
|
+
mesh2.castShadow = true;
|
|
14279
|
+
this.o.scene.add(mesh2);
|
|
13593
14280
|
const live = {
|
|
13594
|
-
mesh,
|
|
14281
|
+
mesh: mesh2,
|
|
13595
14282
|
home,
|
|
13596
14283
|
vel: new this.THREE.Vector3(f.velocity[0], f.velocity[1], f.velocity[2]),
|
|
13597
14284
|
ang: new this.THREE.Vector3(f.angularVelocity[0], f.angularVelocity[1], f.angularVelocity[2]),
|
|
@@ -13612,8 +14299,8 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13612
14299
|
alive--;
|
|
13613
14300
|
}
|
|
13614
14301
|
}
|
|
13615
|
-
this.addMarks(
|
|
13616
|
-
return
|
|
14302
|
+
this.addMarks(mesh2, f);
|
|
14303
|
+
return mesh2;
|
|
13617
14304
|
}
|
|
13618
14305
|
/** Add velocity to every fragment within `radius` of a point (blasts). */
|
|
13619
14306
|
blast(point, radius, speed) {
|
|
@@ -13652,24 +14339,24 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13652
14339
|
}
|
|
13653
14340
|
}
|
|
13654
14341
|
step(f, dt, g) {
|
|
13655
|
-
const
|
|
14342
|
+
const mesh2 = f.mesh;
|
|
13656
14343
|
f.vel.y -= g * dt;
|
|
13657
|
-
|
|
14344
|
+
mesh2.position.addScaledVector(f.vel, dt);
|
|
13658
14345
|
const w = f.ang.length();
|
|
13659
14346
|
if (w > 1e-5) {
|
|
13660
14347
|
this.dq.setFromAxisAngle(this.v.copy(f.ang).multiplyScalar(1 / w), w * dt);
|
|
13661
|
-
|
|
14348
|
+
mesh2.quaternion.premultiply(this.dq).normalize();
|
|
13662
14349
|
}
|
|
13663
|
-
this.m.makeRotationFromQuaternion(
|
|
14350
|
+
this.m.makeRotationFromQuaternion(mesh2.quaternion);
|
|
13664
14351
|
const e = this.m.elements;
|
|
13665
14352
|
const h = f.half;
|
|
13666
14353
|
const sc = f.dying ? f.fade : 1;
|
|
13667
14354
|
const ext = (Math.abs(e[1]) * h.x + Math.abs(e[5]) * h.y + Math.abs(e[9]) * h.z) * sc;
|
|
13668
|
-
const gy = this.o.groundAt(
|
|
14355
|
+
const gy = this.o.groundAt(mesh2.position.x, mesh2.position.z);
|
|
13669
14356
|
let contact = false;
|
|
13670
|
-
if (
|
|
14357
|
+
if (mesh2.position.y - ext < gy) {
|
|
13671
14358
|
contact = true;
|
|
13672
|
-
|
|
14359
|
+
mesh2.position.y = gy + ext;
|
|
13673
14360
|
if (f.vel.y < -0.6) {
|
|
13674
14361
|
f.vel.y = -f.vel.y * 0.25;
|
|
13675
14362
|
f.vel.x *= 0.7;
|
|
@@ -13702,8 +14389,8 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13702
14389
|
}
|
|
13703
14390
|
/** Tip the fragment towards lying on its flattest face. */
|
|
13704
14391
|
settle(f, dt) {
|
|
13705
|
-
const
|
|
13706
|
-
this.m.makeRotationFromQuaternion(
|
|
14392
|
+
const mesh2 = f.mesh;
|
|
14393
|
+
this.m.makeRotationFromQuaternion(mesh2.quaternion);
|
|
13707
14394
|
const e = this.m.elements;
|
|
13708
14395
|
const up = [e[1], e[5], e[9]];
|
|
13709
14396
|
const half = [f.half.x, f.half.y, f.half.z];
|
|
@@ -13718,8 +14405,8 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13718
14405
|
this.v.set(e[axis2 * 4], e[axis2 * 4 + 1], e[axis2 * 4 + 2]).multiplyScalar(sign);
|
|
13719
14406
|
this.w.set(0, 1, 0);
|
|
13720
14407
|
this.dq.setFromUnitVectors(this.v, this.w);
|
|
13721
|
-
this.q.copy(this.dq).multiply(
|
|
13722
|
-
|
|
14408
|
+
this.q.copy(this.dq).multiply(mesh2.quaternion);
|
|
14409
|
+
mesh2.quaternion.slerp(this.q, clamp6(dt * 7, 0, 1));
|
|
13723
14410
|
}
|
|
13724
14411
|
/** Remove the fragments of one object (after `restore`). */
|
|
13725
14412
|
removeHome(home) {
|
|
@@ -13789,13 +14476,13 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13789
14476
|
}
|
|
13790
14477
|
}
|
|
13791
14478
|
while (this.spots.length >= this.cap) this.remove(this.spots[0]);
|
|
13792
|
-
const
|
|
14479
|
+
const mesh2 = new this.THREE.Mesh(this.geometry, this.material(kind, color));
|
|
13793
14480
|
const y = this.groundAt(x, z) + 4e-3 + this.spots.length % 8 * 4e-4;
|
|
13794
|
-
|
|
13795
|
-
|
|
13796
|
-
|
|
13797
|
-
this.scene.add(
|
|
13798
|
-
this.spots.push({ mesh, kind, home, x, z, radius: 1e-3, target: Math.min(MAX_RADIUS, radius) });
|
|
14481
|
+
mesh2.position.set(x, y, z);
|
|
14482
|
+
mesh2.scale.setScalar(1e-3);
|
|
14483
|
+
mesh2.renderOrder = 1;
|
|
14484
|
+
this.scene.add(mesh2);
|
|
14485
|
+
this.spots.push({ mesh: mesh2, kind, home, x, z, radius: 1e-3, target: Math.min(MAX_RADIUS, radius) });
|
|
13799
14486
|
}
|
|
13800
14487
|
remove(s) {
|
|
13801
14488
|
const i = this.spots.indexOf(s);
|
|
@@ -14171,7 +14858,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
14171
14858
|
/** Bars drawn now, over every part. */
|
|
14172
14859
|
get count() {
|
|
14173
14860
|
let n = 0;
|
|
14174
|
-
for (const
|
|
14861
|
+
for (const mesh2 of this.cages.values()) n += mesh2.count;
|
|
14175
14862
|
return n;
|
|
14176
14863
|
}
|
|
14177
14864
|
/** Meshes of the live cages (tests and picking). */
|
|
@@ -14182,25 +14869,25 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
14182
14869
|
set(key, bars) {
|
|
14183
14870
|
this.remove(key);
|
|
14184
14871
|
if (bars.length === 0) return;
|
|
14185
|
-
const
|
|
14872
|
+
const mesh2 = new this.THREE.InstancedMesh(this.geometry, this.material, bars.length);
|
|
14186
14873
|
bars.forEach(([a, b], i) => {
|
|
14187
14874
|
this.dir.set(b[0] - a[0], b[1] - a[1], b[2] - a[2]);
|
|
14188
14875
|
const length3 = this.dir.length();
|
|
14189
14876
|
this.mid.set((a[0] + b[0]) / 2, (a[1] + b[1]) / 2, (a[2] + b[2]) / 2);
|
|
14190
14877
|
this.q.setFromUnitVectors(this.up, length3 > 1e-9 ? this.dir.divideScalar(length3) : this.up);
|
|
14191
14878
|
this.m.compose(this.mid, this.q, this.scale.set(1, Math.max(length3, 1e-4), 1));
|
|
14192
|
-
|
|
14879
|
+
mesh2.setMatrixAt(i, this.m);
|
|
14193
14880
|
});
|
|
14194
|
-
|
|
14195
|
-
|
|
14196
|
-
this.scene.add(
|
|
14197
|
-
this.cages.set(key,
|
|
14881
|
+
mesh2.instanceMatrix.needsUpdate = true;
|
|
14882
|
+
mesh2.castShadow = true;
|
|
14883
|
+
this.scene.add(mesh2);
|
|
14884
|
+
this.cages.set(key, mesh2);
|
|
14198
14885
|
}
|
|
14199
14886
|
remove(key) {
|
|
14200
|
-
const
|
|
14201
|
-
if (!
|
|
14202
|
-
this.scene.remove(
|
|
14203
|
-
|
|
14887
|
+
const mesh2 = this.cages.get(key);
|
|
14888
|
+
if (!mesh2) return;
|
|
14889
|
+
this.scene.remove(mesh2);
|
|
14890
|
+
mesh2.dispose();
|
|
14204
14891
|
this.cages.delete(key);
|
|
14205
14892
|
}
|
|
14206
14893
|
/** Remove the cages of every part of `object` (keys are `object|part`). */
|
|
@@ -14484,25 +15171,25 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
14484
15171
|
/**
|
|
14485
15172
|
* @param range vertex range `[v0, v1)` of a merged mesh this part is drawn by (see `MeshRange`); `hosts` caches the shared state per mesh for one `bind`.
|
|
14486
15173
|
*/
|
|
14487
|
-
makeMeshVis(
|
|
15174
|
+
makeMeshVis(mesh2, home, range2, hosts) {
|
|
14488
15175
|
let host = null;
|
|
14489
15176
|
if (range2) {
|
|
14490
|
-
host = hosts?.get(
|
|
15177
|
+
host = hosts?.get(mesh2) ?? null;
|
|
14491
15178
|
if (!host) {
|
|
14492
|
-
host = { mesh, origGeometry:
|
|
14493
|
-
hosts?.set(
|
|
15179
|
+
host = { mesh: mesh2, origGeometry: mesh2.geometry, origMaterial: mesh2.material, ownGeo: false, work: null, ownMat: false, sharers: [] };
|
|
15180
|
+
hosts?.set(mesh2, host);
|
|
14494
15181
|
}
|
|
14495
15182
|
}
|
|
14496
15183
|
const mv = {
|
|
14497
|
-
mesh,
|
|
15184
|
+
mesh: mesh2,
|
|
14498
15185
|
home,
|
|
14499
|
-
origGeometry:
|
|
14500
|
-
origMaterial:
|
|
14501
|
-
origVisible:
|
|
14502
|
-
origParent:
|
|
14503
|
-
origPosition:
|
|
14504
|
-
origQuaternion:
|
|
14505
|
-
origScale:
|
|
15186
|
+
origGeometry: mesh2.geometry,
|
|
15187
|
+
origMaterial: mesh2.material,
|
|
15188
|
+
origVisible: mesh2.visible,
|
|
15189
|
+
origParent: mesh2.parent,
|
|
15190
|
+
origPosition: mesh2.position.clone(),
|
|
15191
|
+
origQuaternion: mesh2.quaternion.clone(),
|
|
15192
|
+
origScale: mesh2.scale.clone(),
|
|
14506
15193
|
ownMat: false,
|
|
14507
15194
|
ownGeo: false,
|
|
14508
15195
|
work: null,
|
|
@@ -14627,15 +15314,15 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
14627
15314
|
* Returns false when nothing was changed (too far, low quality on a heavy mesh, or no editable positions).
|
|
14628
15315
|
*/
|
|
14629
15316
|
applyDent(mv, worldPoint, worldNormal, dent) {
|
|
14630
|
-
const
|
|
15317
|
+
const mesh2 = mv.mesh;
|
|
14631
15318
|
if (this.lowQuality && this.vertexCount(mv) > 2e4) return false;
|
|
14632
|
-
|
|
14633
|
-
const s =
|
|
14634
|
-
const lp =
|
|
14635
|
-
const ln = this.b.copy(worldNormal).transformDirection(this.m4.copy(
|
|
15319
|
+
mesh2.updateWorldMatrix(true, false);
|
|
15320
|
+
const s = mesh2.matrixWorld.getMaxScaleOnAxis() || 1;
|
|
15321
|
+
const lp = mesh2.worldToLocal(this.a.copy(worldPoint));
|
|
15322
|
+
const ln = this.b.copy(worldNormal).transformDirection(this.m4.copy(mesh2.matrixWorld).invert()).normalize();
|
|
14636
15323
|
const r = dent.radius / s;
|
|
14637
15324
|
const depth = dent.depth / s;
|
|
14638
|
-
const geo =
|
|
15325
|
+
const geo = mesh2.geometry;
|
|
14639
15326
|
let bb;
|
|
14640
15327
|
if (mv.host) bb = this.localBox(mv, this.lbox);
|
|
14641
15328
|
else {
|
|
@@ -14645,7 +15332,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
14645
15332
|
if (bb && !bb.isEmpty() && bb.distanceToPoint(lp) > r) return false;
|
|
14646
15333
|
if (!this.ownGeometry(mv)) return false;
|
|
14647
15334
|
const work = mv.host ? mv.host.work : mv.work;
|
|
14648
|
-
const pos = positionAttr(
|
|
15335
|
+
const pos = positionAttr(mesh2.geometry);
|
|
14649
15336
|
const r2 = r * r;
|
|
14650
15337
|
let touched = false;
|
|
14651
15338
|
const px = lp.x;
|
|
@@ -14711,11 +15398,11 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
14711
15398
|
// Decals
|
|
14712
15399
|
// ------------------------------------------------------------------------------------------------------------------------------------
|
|
14713
15400
|
/** Decal pose in mesh space: position and a rotation taking +Z to the surface normal. */
|
|
14714
|
-
decalPose(
|
|
14715
|
-
|
|
14716
|
-
const s =
|
|
14717
|
-
const ln = worldNormal.clone().transformDirection(this.m4.copy(
|
|
14718
|
-
const pos =
|
|
15401
|
+
decalPose(mesh2, worldPoint, worldNormal, lift) {
|
|
15402
|
+
mesh2.updateWorldMatrix(true, false);
|
|
15403
|
+
const s = mesh2.matrixWorld.getMaxScaleOnAxis() || 1;
|
|
15404
|
+
const ln = worldNormal.clone().transformDirection(this.m4.copy(mesh2.matrixWorld).invert()).normalize();
|
|
15405
|
+
const pos = mesh2.worldToLocal(worldPoint.clone()).addScaledVector(ln, lift / s);
|
|
14719
15406
|
const quat2 = new this.THREE.Quaternion().setFromUnitVectors(new this.THREE.Vector3(0, 0, 1), ln);
|
|
14720
15407
|
return { s, pos, quat: quat2 };
|
|
14721
15408
|
}
|
|
@@ -14851,7 +15538,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
14851
15538
|
if (Math.abs(m - pv.meltApplied) < 0.01) return;
|
|
14852
15539
|
pv.meltApplied = m;
|
|
14853
15540
|
for (const mv of pv.meshes) {
|
|
14854
|
-
const
|
|
15541
|
+
const mesh2 = mv.mesh;
|
|
14855
15542
|
if (mv.host) {
|
|
14856
15543
|
mv.meltApplied = m;
|
|
14857
15544
|
mv.touched = true;
|
|
@@ -14859,27 +15546,27 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
14859
15546
|
continue;
|
|
14860
15547
|
}
|
|
14861
15548
|
if (mv.meltApplied === 0 && m > 0) {
|
|
14862
|
-
|
|
14863
|
-
mv.bottomY = this.box.setFromObject(
|
|
15549
|
+
mesh2.updateWorldMatrix(true, false);
|
|
15550
|
+
mv.bottomY = this.box.setFromObject(mesh2).min.y;
|
|
14864
15551
|
}
|
|
14865
15552
|
mv.meltApplied = m;
|
|
14866
15553
|
mv.moved = true;
|
|
14867
15554
|
const sy = lerp5(1, 0.25, m);
|
|
14868
15555
|
const sxz = 1 + 0.18 * m;
|
|
14869
|
-
|
|
14870
|
-
|
|
14871
|
-
|
|
14872
|
-
const bottom = this.box.setFromObject(
|
|
15556
|
+
mesh2.scale.set(mv.origScale.x * sxz, mv.origScale.y * sy, mv.origScale.z * sxz);
|
|
15557
|
+
mesh2.position.copy(mv.origPosition);
|
|
15558
|
+
mesh2.updateWorldMatrix(true, false);
|
|
15559
|
+
const bottom = this.box.setFromObject(mesh2).min.y;
|
|
14873
15560
|
const dy = mv.bottomY - bottom;
|
|
14874
|
-
if (Math.abs(dy) > 1e-6 &&
|
|
14875
|
-
|
|
14876
|
-
const inv = this.m4.copy(
|
|
15561
|
+
if (Math.abs(dy) > 1e-6 && mesh2.parent) {
|
|
15562
|
+
mesh2.parent.updateWorldMatrix(true, false);
|
|
15563
|
+
const inv = this.m4.copy(mesh2.parent.matrixWorld).invert();
|
|
14877
15564
|
this.a.set(0, dy, 0).applyMatrix4(inv);
|
|
14878
15565
|
this.b.set(0, 0, 0).applyMatrix4(inv);
|
|
14879
|
-
|
|
15566
|
+
mesh2.position.copy(mv.origPosition).add(this.a.sub(this.b));
|
|
14880
15567
|
}
|
|
14881
15568
|
if (!(this.lowQuality && this.vertexCount(mv) > 2e4) && this.ownGeometry(mv)) {
|
|
14882
|
-
this.writePositions(mv, positionAttr(
|
|
15569
|
+
this.writePositions(mv, positionAttr(mesh2.geometry));
|
|
14883
15570
|
}
|
|
14884
15571
|
}
|
|
14885
15572
|
}
|
|
@@ -15152,30 +15839,30 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
15152
15839
|
this.restoreRanged(mv);
|
|
15153
15840
|
return;
|
|
15154
15841
|
}
|
|
15155
|
-
const
|
|
15842
|
+
const mesh2 = mv.mesh;
|
|
15156
15843
|
for (const d of mv.decals) this.disposeDecal(d);
|
|
15157
15844
|
mv.decals.length = 0;
|
|
15158
15845
|
if (mv.ownGeo) {
|
|
15159
|
-
|
|
15160
|
-
|
|
15846
|
+
mesh2.geometry.dispose();
|
|
15847
|
+
mesh2.geometry = mv.origGeometry;
|
|
15161
15848
|
mv.ownGeo = false;
|
|
15162
15849
|
mv.work = null;
|
|
15163
15850
|
}
|
|
15164
15851
|
if (mv.ownMat) {
|
|
15165
|
-
for (const m of materialsOf(
|
|
15166
|
-
|
|
15852
|
+
for (const m of materialsOf(mesh2.material)) m.dispose();
|
|
15853
|
+
mesh2.material = mv.origMaterial;
|
|
15167
15854
|
mv.ownMat = false;
|
|
15168
15855
|
mv.baseColors = null;
|
|
15169
15856
|
}
|
|
15170
|
-
|
|
15171
|
-
if (mv.origParent &&
|
|
15172
|
-
mv.origParent.add(
|
|
15857
|
+
mesh2.visible = mv.origVisible;
|
|
15858
|
+
if (mv.origParent && mesh2.parent !== mv.origParent) {
|
|
15859
|
+
mv.origParent.add(mesh2);
|
|
15173
15860
|
mv.moved = true;
|
|
15174
15861
|
}
|
|
15175
15862
|
if (mv.moved) {
|
|
15176
|
-
|
|
15177
|
-
|
|
15178
|
-
|
|
15863
|
+
mesh2.position.copy(mv.origPosition);
|
|
15864
|
+
mesh2.quaternion.copy(mv.origQuaternion);
|
|
15865
|
+
mesh2.scale.copy(mv.origScale);
|
|
15179
15866
|
mv.moved = false;
|
|
15180
15867
|
}
|
|
15181
15868
|
mv.meltApplied = 0;
|
|
@@ -16223,88 +16910,42 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
16223
16910
|
this.disposed = true;
|
|
16224
16911
|
}
|
|
16225
16912
|
};
|
|
16226
|
-
var
|
|
16227
|
-
var lengthOf = (d, attack) => {
|
|
16228
|
-
if (typeof d === "number") return attack + d;
|
|
16229
|
-
if (Array.isArray(d)) return [attack + d[0], attack + d[1]];
|
|
16230
|
-
return { ...d, add: (d.add ?? 0) + attack };
|
|
16231
|
-
};
|
|
16232
|
-
var envelope = (attack) => [
|
|
16233
|
-
[0, 1e-4, "set", "fixed"],
|
|
16234
|
-
[attack, 1, "exp"],
|
|
16235
|
-
["1d", 1e-4, "exp", "fixed"]
|
|
16236
|
-
];
|
|
16237
|
-
function noise(o) {
|
|
16238
|
-
const a = o.a ?? ATTACK;
|
|
16239
|
-
const over = typeof o.d === "number" ? o.d : 0;
|
|
16240
|
-
return {
|
|
16241
|
-
filters: {
|
|
16242
|
-
mode: "serial",
|
|
16243
|
-
bank: [{ type: o.type ?? "lowpass", frequency: o.f2 === void 0 ? { set: o.f } : { set: o.f, to: o.f2, curve: "exp", over }, q: o.q ?? 0.7 }]
|
|
16244
|
-
},
|
|
16245
|
-
duration: lengthOf(o.d, a),
|
|
16246
|
-
gain: o.vol,
|
|
16247
|
-
...o.delay === void 0 ? {} : { at: o.delay },
|
|
16248
|
-
...o.wet === void 0 ? {} : { wet: o.wet },
|
|
16249
|
-
source: { kind: "noise", offset: "random", offsetScale: 1.5, loop: true },
|
|
16250
|
-
envelope: envelope(a)
|
|
16251
|
-
};
|
|
16252
|
-
}
|
|
16253
|
-
function tone(o) {
|
|
16254
|
-
return {
|
|
16255
|
-
source: { kind: "osc", wave: o.wave ?? "sine", frequency: { from: o.f, to: o.f2 ?? "from", curve: "exp", over: "duration" } },
|
|
16256
|
-
duration: lengthOf(o.d, ATTACK),
|
|
16257
|
-
gain: o.vol,
|
|
16258
|
-
...o.delay === void 0 ? {} : { at: o.delay },
|
|
16259
|
-
...o.wet === void 0 ? {} : { wet: o.wet },
|
|
16260
|
-
envelope: envelope(ATTACK)
|
|
16261
|
-
};
|
|
16262
|
-
}
|
|
16263
|
-
var many = (count, make) => Array.from({ length: count }, make);
|
|
16264
|
-
var scene = (id, layers, line, vars) => ({
|
|
16265
|
-
id,
|
|
16266
|
-
bus: "world",
|
|
16267
|
-
pan: true,
|
|
16268
|
-
layers,
|
|
16269
|
-
falloff: DISTANCE_CURVES.art_scene,
|
|
16270
|
-
...vars ? { vars } : {},
|
|
16271
|
-
sources: [`cena:${line}`]
|
|
16272
|
-
});
|
|
16913
|
+
var scene = (id, layers, line, vars) => sceneRecipe(id, layers, line, vars ? { vars } : {});
|
|
16273
16914
|
var boomLayers = (big) => [
|
|
16274
|
-
|
|
16275
|
-
|
|
16276
|
-
|
|
16277
|
-
...big ? [
|
|
16278
|
-
...
|
|
16915
|
+
sceneNoise({ f: 1200, f2: 120, d: 1.8, vol: 2, wet: 1.2 }),
|
|
16916
|
+
sceneTone({ f: 65, f2: 24, d: 1, vol: 1.8 }),
|
|
16917
|
+
sceneNoise({ type: "highpass", f: 1500, d: 0.2, vol: 0.8 }),
|
|
16918
|
+
...big ? [sceneNoise({ f: 500, f2: 90, a: 0.2, d: 2.4, vol: 1.2, wet: 1, delay: 0.15 })] : [],
|
|
16919
|
+
...sceneMany(8, () => sceneTone({ f: [2600, 5600], d: 0.05, vol: 0.08, delay: [0.4, 1.6] }))
|
|
16279
16920
|
];
|
|
16280
16921
|
var SCENE_SOUNDS = [
|
|
16281
16922
|
scene(
|
|
16282
16923
|
"glass_shatter",
|
|
16283
|
-
[
|
|
16924
|
+
[sceneNoise({ type: "highpass", f: 2800, d: 0.45, vol: 0.9, wet: 0.5 }), ...sceneMany(12, () => sceneTone({ f: [3e3, 7500], d: [0.06, 0.14], vol: 0.18, delay: [0, 0.55] }))],
|
|
16284
16925
|
"L1359 glass"
|
|
16285
16926
|
),
|
|
16286
16927
|
scene(
|
|
16287
16928
|
"wood_hit",
|
|
16288
|
-
[
|
|
16929
|
+
[sceneNoise({ type: "bandpass", f: 850, q: 1, d: 0.25, vol: 0.9, wet: 0.3 }), sceneTone({ f: 210, f2: 90, d: 0.1, vol: 0.6 }), sceneNoise({ type: "highpass", f: 2e3, d: 0.04, vol: 0.5 })],
|
|
16289
16930
|
"L1360 wood"
|
|
16290
16931
|
),
|
|
16291
|
-
scene("thunk", [
|
|
16292
|
-
scene("ping", [
|
|
16293
|
-
scene("clang", [
|
|
16294
|
-
scene("chip", [
|
|
16932
|
+
scene("thunk", [sceneNoise({ type: "bandpass", f: 700, q: 2, d: 0.07, vol: 0.4 })], "L1361 thunk"),
|
|
16933
|
+
scene("ping", [sceneTone({ f: [2600, 3500], f2: 1400, d: 0.14, vol: 0.18, wet: 0.3 })], "L1362 ping"),
|
|
16934
|
+
scene("clang", [sceneTone({ f: [520, 720], f2: 480, d: 0.5, vol: 0.35, wet: 0.4 }), sceneTone({ f: 1370, f2: 1300, d: 0.3, vol: 0.15 }), sceneNoise({ type: "highpass", f: 2e3, d: 0.05, vol: 0.5 })], "L1363 clang"),
|
|
16935
|
+
scene("chip", [sceneNoise({ type: "bandpass", f: 1600, q: 1.2, d: 0.06, vol: 0.5 })], "L1364 chip"),
|
|
16295
16936
|
scene(
|
|
16296
16937
|
"crumble",
|
|
16297
|
-
[
|
|
16938
|
+
[sceneNoise({ f: 900, f2: 200, d: 0.6, vol: 0.9, wet: 0.3 }), ...sceneMany(5, () => sceneNoise({ type: "bandpass", f: [500, 1400], q: 2, d: 0.05, vol: 0.4, delay: [0.1, 0.5] }))],
|
|
16298
16939
|
"L1365 crumble"
|
|
16299
16940
|
),
|
|
16300
16941
|
// `thud(x, z, v)`: `v` is the `scale` param (default 1)
|
|
16301
|
-
scene("thud", [
|
|
16942
|
+
scene("thud", [sceneTone({ f: 75, f2: 38, d: 0.22, vol: { param: "scale", scale: 0.6 } }), sceneNoise({ f: 420, d: 0.16, vol: { param: "scale", scale: 0.45 } })], "L1358 thud", { scale: 1 }),
|
|
16302
16943
|
// `hiss(x, z, d)`: `seconds` is the param `d` (default 1.2)
|
|
16303
|
-
scene("hiss", [
|
|
16944
|
+
scene("hiss", [sceneNoise({ type: "highpass", f: 3500, a: 0.05, d: { param: "seconds" }, vol: 0.35 })], "L1366 hiss", { seconds: 1.2 }),
|
|
16304
16945
|
scene("boom", boomLayers(false), "L1367 boom"),
|
|
16305
16946
|
scene("boom_big", boomLayers(true), "L1367 boom (big)"),
|
|
16306
|
-
scene("burst", [
|
|
16307
|
-
scene("crack", [
|
|
16947
|
+
scene("burst", [sceneNoise({ f: 700, f2: 120, d: 0.7, vol: 1.4, wet: 0.5 }), sceneNoise({ type: "highpass", f: 3e3, a: 0.05, d: 1.2, vol: 0.4, delay: 0.1 })], "L1357 burst"),
|
|
16948
|
+
scene("crack", [sceneNoise({ type: "highpass", f: 1800, d: 0.05, vol: 0.8 }), sceneTone({ f: 420, f2: 180, d: 0.06, vol: 0.4 })], "L1354 crack")
|
|
16308
16949
|
];
|
|
16309
16950
|
var EXPLOSION_BOOM = {
|
|
16310
16951
|
id: "explosion_boom",
|
|
@@ -32046,7 +32687,7 @@ ${problems.map((problem) => ` - ${problem}`).join("\n")}`);
|
|
|
32046
32687
|
if (lastRow < 0) return;
|
|
32047
32688
|
const profile = profileOf2();
|
|
32048
32689
|
const rainScale = 1 - options.weather().rain;
|
|
32049
|
-
const seconds = dryingSeconds * rainScale;
|
|
32690
|
+
const seconds = dryingSeconds * rainScale * (options.weather().drying ?? 1);
|
|
32050
32691
|
for (let row = firstRow; row <= lastRow; row++) {
|
|
32051
32692
|
const offset = row * width;
|
|
32052
32693
|
for (let column = firstColumn; column <= lastColumn; column++) {
|
|
@@ -32170,6 +32811,7 @@ ${problems.map((problem) => ` - ${problem}`).join("\n")}`);
|
|
|
32170
32811
|
}
|
|
32171
32812
|
var DEFAULT_STEP_RATE = 180;
|
|
32172
32813
|
var DEFAULT_MAX_STEPS = 6;
|
|
32814
|
+
var WASH_BELOW_DRYNESS = 0.5;
|
|
32173
32815
|
function createFilm(options) {
|
|
32174
32816
|
const { layout, random } = options;
|
|
32175
32817
|
const cellCount = layout.width * layout.height;
|
|
@@ -32180,7 +32822,7 @@ ${problems.map((problem) => ` - ${problem}`).join("\n")}`);
|
|
|
32180
32822
|
dryness: new Float32Array(cellCount),
|
|
32181
32823
|
dampness: new Float32Array(cellCount)
|
|
32182
32824
|
};
|
|
32183
|
-
let weatherState = { rain: 0 };
|
|
32825
|
+
let weatherState = { rain: 0, drying: 1 };
|
|
32184
32826
|
let currentProfile = options.profile;
|
|
32185
32827
|
const context = { field, random, profile: () => currentProfile };
|
|
32186
32828
|
const drops = createDropPool(layout, context);
|
|
@@ -32218,9 +32860,29 @@ ${problems.map((problem) => ` - ${problem}`).join("\n")}`);
|
|
|
32218
32860
|
simulator.advance({ dt, dryingSeconds });
|
|
32219
32861
|
},
|
|
32220
32862
|
setWeather(weather) {
|
|
32221
|
-
weatherState = {
|
|
32863
|
+
weatherState = {
|
|
32864
|
+
rain: Math.min(1, Math.max(0, weather.rain ?? weatherState.rain)),
|
|
32865
|
+
drying: Math.max(0, weather.drying ?? weatherState.drying ?? 1)
|
|
32866
|
+
};
|
|
32222
32867
|
},
|
|
32223
32868
|
weather: () => ({ ...weatherState }),
|
|
32869
|
+
wash(maxDryness = WASH_BELOW_DRYNESS) {
|
|
32870
|
+
simulator.refreshBounds();
|
|
32871
|
+
const { firstRow, lastRow, firstColumn, lastColumn } = simulator.bounds;
|
|
32872
|
+
let cleared = 0;
|
|
32873
|
+
for (let row = firstRow; row <= lastRow; row++) {
|
|
32874
|
+
for (let column = firstColumn; column <= lastColumn; column++) {
|
|
32875
|
+
const index = row * layout.width + column;
|
|
32876
|
+
if (field.thickness[index] > 0 && field.dryness[index] < maxDryness) {
|
|
32877
|
+
field.thickness[index] = 0;
|
|
32878
|
+
field.dryness[index] = 0;
|
|
32879
|
+
field.dampness[index] = 0;
|
|
32880
|
+
cleared++;
|
|
32881
|
+
}
|
|
32882
|
+
}
|
|
32883
|
+
}
|
|
32884
|
+
return cleared;
|
|
32885
|
+
},
|
|
32224
32886
|
clear() {
|
|
32225
32887
|
field.thickness.fill(0);
|
|
32226
32888
|
field.dryness.fill(0);
|
|
@@ -32324,8 +32986,8 @@ ${problems.map((problem) => ` - ${problem}`).join("\n")}`);
|
|
|
32324
32986
|
bedHeight = roadY * 1e3 + z * 14 - (x - params.roadSlopeAnchorX) * 5;
|
|
32325
32987
|
roughness = 0.55;
|
|
32326
32988
|
}
|
|
32327
|
-
const
|
|
32328
|
-
bed[index] = bedHeight + (
|
|
32989
|
+
const noise = valueNoise(column * 0.35, row * 0.35) * 0.6 + valueNoise(column * 1.3, row * 1.3) * 0.4;
|
|
32990
|
+
bed[index] = bedHeight + (noise - 0.5) * roughness * 2;
|
|
32329
32991
|
vertical[index] = region === 0 || region === 2 ? 0.95 : 1;
|
|
32330
32992
|
pin[index] = 0.62 + 0.76 * (valueNoise(column * 0.21 + 40, row * 0.21) * 0.5 + hashCell(column, row) * 0.5) * (region === 3 ? 1.25 : 1);
|
|
32331
32993
|
}
|
|
@@ -32482,8 +33144,8 @@ ${problems.map((problem) => ` - ${problem}`).join("\n")}`);
|
|
|
32482
33144
|
for (let column = 0; column < columns; column++) {
|
|
32483
33145
|
const index = (region.firstRow + row) * columns + column;
|
|
32484
33146
|
const centre = add2(add2(region.origin, scale(columnAxis, (column + 0.5) * cell)), scale(region.rowAxis, (row + 0.5) * cell));
|
|
32485
|
-
const
|
|
32486
|
-
bed[index] = centre[1] * 1e3 + (
|
|
33147
|
+
const noise = valueNoise(column * 0.35, (region.firstRow + row) * 0.35) * 0.6 + valueNoise(column * 1.3, (region.firstRow + row) * 1.3) * 0.4;
|
|
33148
|
+
bed[index] = centre[1] * 1e3 + (noise - 0.5) * strip.roughness * 2;
|
|
32487
33149
|
vertical[index] = region.isVertical ? 0.95 : 1;
|
|
32488
33150
|
pin[index] = 0.62 + 0.76 * (valueNoise(column * 0.21 + 40, (region.firstRow + row) * 0.21) * 0.5 + valueNoise(column * 0.9, row * 0.9) * 0.5);
|
|
32489
33151
|
}
|
|
@@ -33150,11 +33812,11 @@ ${problems.map((problem) => ` - ${problem}`).join("\n")}`);
|
|
|
33150
33812
|
const index = [];
|
|
33151
33813
|
for (let i = 0; i < this.ring; i++) index.push(0, 1 + i, 1 + (i + 1) % this.ring);
|
|
33152
33814
|
geometry.setIndex(index);
|
|
33153
|
-
const
|
|
33154
|
-
|
|
33155
|
-
|
|
33156
|
-
|
|
33157
|
-
return { mesh, position, color };
|
|
33815
|
+
const mesh2 = new T.Mesh(geometry);
|
|
33816
|
+
mesh2.name = name;
|
|
33817
|
+
mesh2.frustumCulled = false;
|
|
33818
|
+
mesh2.renderOrder = order;
|
|
33819
|
+
return { mesh: mesh2, position, color };
|
|
33158
33820
|
}
|
|
33159
33821
|
assign(def, materials) {
|
|
33160
33822
|
this.outer.mesh.material = materials.stainFilm(def);
|
|
@@ -33877,12 +34539,12 @@ void main(){
|
|
|
33877
34539
|
this.group = new THREE.Group();
|
|
33878
34540
|
this.group.name = "film_grid";
|
|
33879
34541
|
for (const region of layout.regions) {
|
|
33880
|
-
const
|
|
33881
|
-
|
|
33882
|
-
|
|
33883
|
-
|
|
33884
|
-
this.strips.push(
|
|
33885
|
-
this.group.add(
|
|
34542
|
+
const mesh2 = new THREE.Mesh(createStripGeometry(THREE, layout, region), this.material.material);
|
|
34543
|
+
mesh2.frustumCulled = false;
|
|
34544
|
+
mesh2.renderOrder = 3;
|
|
34545
|
+
mesh2.name = `film_${region.id}`;
|
|
34546
|
+
this.strips.push(mesh2);
|
|
34547
|
+
this.group.add(mesh2);
|
|
33886
34548
|
}
|
|
33887
34549
|
this.dropsView = createFilmDrops(THREE, layout.rules.dropCapacity, profile);
|
|
33888
34550
|
this.group.add(this.dropsView.drops, this.dropsView.bead);
|
|
@@ -33927,6 +34589,19 @@ void main(){
|
|
|
33927
34589
|
this.pending = this.union(this.pending, rect);
|
|
33928
34590
|
return this.takePending();
|
|
33929
34591
|
}
|
|
34592
|
+
/** Clears the cells less than `maxDryness` dry and sends the rectangle that held them up with the next update. Returns how many it cleared. */
|
|
34593
|
+
wash(maxDryness) {
|
|
34594
|
+
const cleared = this.film.wash(maxDryness);
|
|
34595
|
+
if (cleared > 0) {
|
|
34596
|
+
const bounds = this.film.simulator.bounds;
|
|
34597
|
+
if (bounds.lastRow >= 0) {
|
|
34598
|
+
const rect = { firstRow: bounds.firstRow, lastRow: bounds.lastRow, firstColumn: bounds.firstColumn, lastColumn: bounds.lastColumn };
|
|
34599
|
+
this.encode(rect);
|
|
34600
|
+
this.pending = this.union(this.pending, rect);
|
|
34601
|
+
}
|
|
34602
|
+
}
|
|
34603
|
+
return cleared;
|
|
34604
|
+
}
|
|
33930
34605
|
takePending() {
|
|
33931
34606
|
const rect = this.pending;
|
|
33932
34607
|
this.pending = null;
|
|
@@ -33982,7 +34657,7 @@ void main(){
|
|
|
33982
34657
|
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) };
|
|
33983
34658
|
}
|
|
33984
34659
|
dispose() {
|
|
33985
|
-
for (const
|
|
34660
|
+
for (const mesh2 of this.strips) mesh2.geometry.dispose();
|
|
33986
34661
|
this.material.dispose();
|
|
33987
34662
|
this.dropsView.dispose();
|
|
33988
34663
|
this.texture.dispose();
|
|
@@ -33996,11 +34671,12 @@ void main(){
|
|
|
33996
34671
|
var DEFAULT_GRID_METRES = 2;
|
|
33997
34672
|
var DEFAULT_CELL2 = 0.0125;
|
|
33998
34673
|
var BAKE_RANGE_FACTOR = 1.25;
|
|
34674
|
+
var DEFAULT_WASHABLE = ["blood", "old_blood"];
|
|
33999
34675
|
var EDGE_MARGIN = 0.35;
|
|
34000
34676
|
var FLOOR_REACH = 0.3;
|
|
34001
34677
|
var DROP_HEIGHT = 2.5;
|
|
34002
34678
|
var DEFAULT_DROP_RADIUS = 3;
|
|
34003
|
-
var
|
|
34679
|
+
var FALL_SPEED2 = 2;
|
|
34004
34680
|
var VISIBLE_THICKNESS22 = 0.035;
|
|
34005
34681
|
var DEFAULT_HALF = 50;
|
|
34006
34682
|
var FREE_AFTER_EMPTY = 2;
|
|
@@ -34021,6 +34697,7 @@ void main(){
|
|
|
34021
34697
|
__publicField5(this, "staging", /* @__PURE__ */ new Map());
|
|
34022
34698
|
__publicField5(this, "now");
|
|
34023
34699
|
__publicField5(this, "rain", 0);
|
|
34700
|
+
__publicField5(this, "drying", 1);
|
|
34024
34701
|
__publicField5(this, "time", 0);
|
|
34025
34702
|
__publicField5(this, "bakedCount", 0);
|
|
34026
34703
|
__publicField5(this, "last", { grids: 0, drops: 0, wetCells: 0, simMs: 0, starved: 0, baked: 0, uploadedTexels: 0 });
|
|
@@ -34040,13 +34717,24 @@ void main(){
|
|
|
34040
34717
|
}
|
|
34041
34718
|
setWeather(weather) {
|
|
34042
34719
|
this.rain = Math.min(1, Math.max(0, weather.rain));
|
|
34043
|
-
|
|
34720
|
+
if (weather.drying !== void 0) this.drying = Math.max(0, weather.drying);
|
|
34721
|
+
for (const grid of this.grids) grid.film.setWeather({ rain: this.rain, drying: this.drying });
|
|
34722
|
+
}
|
|
34723
|
+
/**
|
|
34724
|
+
* 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
|
|
34725
|
+
* cells that are less than `maxDryness` dry (default 0.5) are cleared. Returns how many cells it cleared.
|
|
34726
|
+
*/
|
|
34727
|
+
wash(maxDryness) {
|
|
34728
|
+
const washable = this.options.washable ?? DEFAULT_WASHABLE;
|
|
34729
|
+
let cleared = 0;
|
|
34730
|
+
for (const grid of this.grids) if (washable.includes(grid.profile.id)) cleared += grid.wash(maxDryness);
|
|
34731
|
+
return cleared;
|
|
34044
34732
|
}
|
|
34045
34733
|
/** 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. */
|
|
34046
34734
|
launch(request) {
|
|
34047
34735
|
const grid = this.gridFor(request.fluid, request.point, request.surfaces, request.tint);
|
|
34048
34736
|
if (!grid) return null;
|
|
34049
|
-
const velocity = request.velocity ?? [0, -
|
|
34737
|
+
const velocity = request.velocity ?? [0, -FALL_SPEED2, 0];
|
|
34050
34738
|
grid.film.launch(request.point, velocity, request.radius ?? DEFAULT_DROP_RADIUS);
|
|
34051
34739
|
return grid;
|
|
34052
34740
|
}
|
|
@@ -34071,7 +34759,7 @@ void main(){
|
|
|
34071
34759
|
const layout = layoutFromSurfaces({ ...found, center: point, columns: this.columns(), rows: this.columns(), cellSize: this.options.cellSize ?? DEFAULT_CELL2 });
|
|
34072
34760
|
if (this.grids.length >= (this.options.maxGrids ?? DEFAULT_MAX_GRIDS)) this.evict(point);
|
|
34073
34761
|
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 } });
|
|
34074
|
-
grid.film.setWeather({ rain: this.rain });
|
|
34762
|
+
grid.film.setWeather({ rain: this.rain, drying: this.drying });
|
|
34075
34763
|
this.grids.push(grid);
|
|
34076
34764
|
this.group.add(grid.group);
|
|
34077
34765
|
return grid;
|
|
@@ -34148,7 +34836,7 @@ void main(){
|
|
|
34148
34836
|
/** Whether `point` is over the grid, away from its edge, so a splash there does not fall off the strip. */
|
|
34149
34837
|
covers(grid, point) {
|
|
34150
34838
|
const layout = grid.film.layout;
|
|
34151
|
-
const
|
|
34839
|
+
const wide2 = layout.width * layout.cellSize;
|
|
34152
34840
|
for (const region of layout.regions) {
|
|
34153
34841
|
const local2 = [point[0] - region.origin[0], point[1] - region.origin[1], point[2] - region.origin[2]];
|
|
34154
34842
|
const above2 = local2[0] * region.normal[0] + local2[1] * region.normal[1] + local2[2] * region.normal[2];
|
|
@@ -34156,7 +34844,7 @@ void main(){
|
|
|
34156
34844
|
const sideways = local2[0] * region.columnAxis[0] + local2[1] * region.columnAxis[1] + local2[2] * region.columnAxis[2];
|
|
34157
34845
|
const down = local2[0] * region.rowAxis[0] + local2[1] * region.rowAxis[1] + local2[2] * region.rowAxis[2];
|
|
34158
34846
|
const length3 = region.rowCount * layout.cellSize;
|
|
34159
|
-
if (sideways > EDGE_MARGIN && sideways <
|
|
34847
|
+
if (sideways > EDGE_MARGIN && sideways < wide2 - EDGE_MARGIN && down > EDGE_MARGIN && down < length3 - EDGE_MARGIN) return true;
|
|
34160
34848
|
}
|
|
34161
34849
|
return false;
|
|
34162
34850
|
}
|
|
@@ -34307,6 +34995,7 @@ void main(){
|
|
|
34307
34995
|
return landed;
|
|
34308
34996
|
},
|
|
34309
34997
|
setWeather: (weather) => manager.setWeather(weather),
|
|
34998
|
+
wash: (maxDryness) => manager.wash(maxDryness),
|
|
34310
34999
|
update(dt) {
|
|
34311
35000
|
if (leaks.size === 0) return;
|
|
34312
35001
|
const streams = new Map(fluids.streams().map((stream) => [stream.id, stream]));
|
|
@@ -34399,15 +35088,15 @@ void main(){
|
|
|
34399
35088
|
if (s.kind === "box") geo = new THREE.BoxGeometry(s.size[0], s.size[1], s.size[2]);
|
|
34400
35089
|
else if (s.kind === "cylinder") geo = new THREE.CylinderGeometry(s.radius, s.radius, s.height, seg);
|
|
34401
35090
|
else geo = new THREE.SphereGeometry(s.radius, seg, Math.max(6, seg - 4));
|
|
34402
|
-
const
|
|
34403
|
-
|
|
34404
|
-
|
|
34405
|
-
|
|
34406
|
-
|
|
34407
|
-
if (p.rotation)
|
|
34408
|
-
|
|
34409
|
-
|
|
34410
|
-
root.add(
|
|
35091
|
+
const mesh2 = new THREE.Mesh(geo, materialFor(p));
|
|
35092
|
+
mesh2.name = p.id;
|
|
35093
|
+
mesh2.userData.destructionPart = p.id;
|
|
35094
|
+
mesh2.userData.destructionMaterial = p.material;
|
|
35095
|
+
mesh2.position.set(p.position[0], p.position[1], p.position[2]);
|
|
35096
|
+
if (p.rotation) mesh2.rotation.set(p.rotation[0], p.rotation[1], p.rotation[2], "XYZ");
|
|
35097
|
+
mesh2.castShadow = shadows && !TRANSPARENT[p.material];
|
|
35098
|
+
mesh2.receiveShadow = shadows;
|
|
35099
|
+
root.add(mesh2);
|
|
34411
35100
|
}
|
|
34412
35101
|
return root;
|
|
34413
35102
|
}
|
|
@@ -35732,16 +36421,16 @@ void main(){
|
|
|
35732
36421
|
const up = new THREE.Vector3(0, 1, 0);
|
|
35733
36422
|
const clear = () => {
|
|
35734
36423
|
projectiles.length = 0;
|
|
35735
|
-
for (const
|
|
36424
|
+
for (const mesh2 of meshes) mesh2.removeFromParent();
|
|
35736
36425
|
meshes.length = 0;
|
|
35737
36426
|
};
|
|
35738
36427
|
const addMesh = (geometry, color, metalness, at3) => {
|
|
35739
|
-
const
|
|
35740
|
-
|
|
35741
|
-
|
|
35742
|
-
scene2.add(
|
|
35743
|
-
meshes.push(
|
|
35744
|
-
return
|
|
36428
|
+
const mesh2 = new THREE.Mesh(geometry, new THREE.MeshStandardMaterial({ color, roughness: 0.6, metalness }));
|
|
36429
|
+
mesh2.castShadow = true;
|
|
36430
|
+
mesh2.position.set(at3[0], at3[1], at3[2]);
|
|
36431
|
+
scene2.add(mesh2);
|
|
36432
|
+
meshes.push(mesh2);
|
|
36433
|
+
return mesh2;
|
|
35745
36434
|
};
|
|
35746
36435
|
const remove = (projectile) => {
|
|
35747
36436
|
for (const extra of projectile.attached ?? []) {
|
|
@@ -35759,9 +36448,9 @@ void main(){
|
|
|
35759
36448
|
const isMolotov = !!use.fire;
|
|
35760
36449
|
const isRocket = use.trigger === "impact" && (use.armDistance ?? 0) > 0;
|
|
35761
36450
|
const geometry = isRocket ? new THREE.CylinderGeometry(0.04, 0.04, 0.5, 8) : isMolotov ? new THREE.CylinderGeometry(0.035, 0.04, 0.2, 8) : new THREE.SphereGeometry(0.045, 8, 6);
|
|
35762
|
-
const
|
|
36451
|
+
const mesh2 = addMesh(geometry, isMolotov ? 3897915 : isRocket ? 7041116 : 4936480, isMolotov ? 0 : 0.4, use.origin);
|
|
35763
36452
|
projectiles.push({
|
|
35764
|
-
mesh,
|
|
36453
|
+
mesh: mesh2,
|
|
35765
36454
|
pos: new THREE.Vector3(use.origin[0], use.origin[1], use.origin[2]),
|
|
35766
36455
|
vel: new THREE.Vector3(use.velocity[0], use.velocity[1], use.velocity[2]),
|
|
35767
36456
|
weapon: context.toolId(),
|
|
@@ -35812,11 +36501,11 @@ void main(){
|
|
|
35812
36501
|
const placed = { ...use, origin: at3 };
|
|
35813
36502
|
const body = createExplosiveBody(placed, arsenal.explosives, arsenal.rules.explosives);
|
|
35814
36503
|
if (!body) return;
|
|
35815
|
-
const
|
|
35816
|
-
|
|
36504
|
+
const mesh2 = addMesh(new THREE.BoxGeometry(0.18, 0.06, 0.1), use.explosive === "claymore" ? 5597999 : 12757112, 0.1, at3);
|
|
36505
|
+
mesh2.rotation.y = Math.atan2(use.direction[0], use.direction[2]);
|
|
35817
36506
|
const attached = [markerAt(at3)];
|
|
35818
36507
|
const segment = tripwireSegment(placed);
|
|
35819
|
-
const projectile = { mesh, pos: new THREE.Vector3(at3[0], at3[1], at3[2]), vel: new THREE.Vector3(), weapon: context.toolId(), fuse: 0, burstOnImpact: false, energy: use.energy, radius: use.radius, age: 0, body, placed: true, attached };
|
|
36508
|
+
const projectile = { mesh: mesh2, pos: new THREE.Vector3(at3[0], at3[1], at3[2]), vel: new THREE.Vector3(), weapon: context.toolId(), fuse: 0, burstOnImpact: false, energy: use.energy, radius: use.radius, age: 0, body, placed: true, attached };
|
|
35820
36509
|
if (segment) {
|
|
35821
36510
|
const wire = { from: segment.from, to: segment.to, letThrough: /* @__PURE__ */ new Set() };
|
|
35822
36511
|
for (const id of touching(wire)) wire.letThrough.add(id);
|
|
@@ -36493,13 +37182,13 @@ void main(){
|
|
|
36493
37182
|
if (!g || g.done) break;
|
|
36494
37183
|
g.done = true;
|
|
36495
37184
|
const [a, b] = ev.parts;
|
|
36496
|
-
const
|
|
37185
|
+
const many = g.list.length > 1;
|
|
36497
37186
|
c.log.add({
|
|
36498
37187
|
channel: "event",
|
|
36499
37188
|
type: "detach",
|
|
36500
37189
|
objectId: ev.object,
|
|
36501
37190
|
itemId: c.itemIdOf(ev.object),
|
|
36502
|
-
text:
|
|
37191
|
+
text: many ? t(`ev.detach.many.${ev.by === "tool" ? "tool" : "break"}`, { obj: c.nameOf(ev.object), joints: joints(g.list.length), pieces: pieces(g.groups) }) : t("ev.detach", { obj: c.nameOf(ev.object), a, b, by: t(`by.${ev.by}`), pieces: pieces(g.groups) }),
|
|
36503
37192
|
data: { joint: ev.joint, joints: g.list.map((j) => j.joint), parts: ev.parts, by: ev.by, groups: g.groups }
|
|
36504
37193
|
});
|
|
36505
37194
|
break;
|
|
@@ -40036,6 +40725,8 @@ void main(){
|
|
|
40036
40725
|
camera: camera2,
|
|
40037
40726
|
arsenal,
|
|
40038
40727
|
fluids,
|
|
40728
|
+
film: filmBridge,
|
|
40729
|
+
vfx: vfx.world,
|
|
40039
40730
|
fluidRenderer: fluidView,
|
|
40040
40731
|
audio,
|
|
40041
40732
|
environment,
|