@adatechnology/game-test-room 0.9.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +6 -1
- package/dist/index.global.js +1110 -413
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +17 -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,148 @@ 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 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
9124
|
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])) };
|
|
9125
|
+
var GAME_EFFECTS = { ...WORKSHOP_EFFECTS, ...Object.fromEntries([...EVENT_EFFECTS, ...VIEWMODEL_EFFECTS].map((effect) => [effect.id, effect])) };
|
|
8706
9126
|
var LEHMER_MULTIPLIER = 16807;
|
|
8707
9127
|
var LEHMER_MODULUS = 2147483647;
|
|
8708
9128
|
var HASH_MIX = 2654435761;
|
|
@@ -8798,7 +9218,7 @@ var GameTestRoom = (() => {
|
|
|
8798
9218
|
}
|
|
8799
9219
|
var COLUMNS = 6;
|
|
8800
9220
|
var ROWS = 5;
|
|
8801
|
-
var
|
|
9221
|
+
var ORIGIN3 = [-2.2, 0, 2.6];
|
|
8802
9222
|
var BLOCK_SIZE = [0.5, 0.44, 0.25];
|
|
8803
9223
|
var OBJECT_ID_DRAWS2 = 4;
|
|
8804
9224
|
var FLOOR2 = 0.13;
|
|
@@ -8841,7 +9261,7 @@ var GameTestRoom = (() => {
|
|
|
8841
9261
|
const chipScale = random.between(0.8, 1.3) * scale2;
|
|
8842
9262
|
for (let draw2 = 0; draw2 < OBJECT_ID_DRAWS2; draw2++) random.next();
|
|
8843
9263
|
best.holes.push({ x: offsetX, y: offsetY, scale: scale2, chipTurn, chipScale });
|
|
8844
|
-
impact(host.engine, "concrete", [
|
|
9264
|
+
impact(host.engine, "concrete", [ORIGIN3[0] + x, y, ORIGIN3[2] + 0.13], [0, 0, 1], 0.8);
|
|
8845
9265
|
} else if (action === "collapse") {
|
|
8846
9266
|
const { x, y } = args;
|
|
8847
9267
|
for (const block of blocks) {
|
|
@@ -8891,7 +9311,7 @@ var GameTestRoom = (() => {
|
|
|
8891
9311
|
}
|
|
8892
9312
|
};
|
|
8893
9313
|
}
|
|
8894
|
-
var
|
|
9314
|
+
var ORIGIN4 = [5.6, 0, 0.8];
|
|
8895
9315
|
var MAX_TILT = 0.25;
|
|
8896
9316
|
function createCarBehavior() {
|
|
8897
9317
|
let y = 0;
|
|
@@ -8923,8 +9343,13 @@ var GameTestRoom = (() => {
|
|
|
8923
9343
|
}
|
|
8924
9344
|
}
|
|
8925
9345
|
},
|
|
8926
|
-
query(_host, name) {
|
|
8927
|
-
if (name === "position") return [
|
|
9346
|
+
query(_host, name, args) {
|
|
9347
|
+
if (name === "position") return [ORIGIN4[0], y, ORIGIN4[2]];
|
|
9348
|
+
if (name === "point") {
|
|
9349
|
+
const [x, py, z] = args;
|
|
9350
|
+
const point = carPoint(x, py, z);
|
|
9351
|
+
return [point[0], point[1] + y, point[2]];
|
|
9352
|
+
}
|
|
8928
9353
|
if (name === "roll") return roll;
|
|
8929
9354
|
throw new Error(`car: unknown query ${name}`);
|
|
8930
9355
|
},
|
|
@@ -9124,6 +9549,29 @@ var GameTestRoom = (() => {
|
|
|
9124
9549
|
}
|
|
9125
9550
|
};
|
|
9126
9551
|
}
|
|
9552
|
+
function createRainBehavior() {
|
|
9553
|
+
return {
|
|
9554
|
+
reset() {
|
|
9555
|
+
},
|
|
9556
|
+
act(host, action, args) {
|
|
9557
|
+
const { engine, camera: camera2 } = host;
|
|
9558
|
+
if (action === "init") {
|
|
9559
|
+
const { count, wind } = args;
|
|
9560
|
+
engine.rain.init(count, wind);
|
|
9561
|
+
} else if (action === "update") {
|
|
9562
|
+
const { dt, splash } = args;
|
|
9563
|
+
engine.rain.update(dt, splash, camera2.position);
|
|
9564
|
+
}
|
|
9565
|
+
},
|
|
9566
|
+
query(host, name) {
|
|
9567
|
+
if (name === "count") return host.engine.rain.count;
|
|
9568
|
+
if (name === "on") return host.engine.rain.on;
|
|
9569
|
+
throw new Error(`rain: unknown query ${name}`);
|
|
9570
|
+
},
|
|
9571
|
+
update() {
|
|
9572
|
+
}
|
|
9573
|
+
};
|
|
9574
|
+
}
|
|
9127
9575
|
var WALKER_COUNT = 10;
|
|
9128
9576
|
var ARRIVAL_DISTANCE = 0.05;
|
|
9129
9577
|
var SWAY_AMPLITUDE = 0.04;
|
|
@@ -9189,7 +9637,8 @@ var GameTestRoom = (() => {
|
|
|
9189
9637
|
blocks: () => createBlocksBehavior(),
|
|
9190
9638
|
plate: () => createPlateBehavior(),
|
|
9191
9639
|
cylinder: () => createCylinderBehavior(),
|
|
9192
|
-
car: () => createCarBehavior()
|
|
9640
|
+
car: () => createCarBehavior(),
|
|
9641
|
+
rain: () => createRainBehavior()
|
|
9193
9642
|
};
|
|
9194
9643
|
var NOOP = () => {
|
|
9195
9644
|
};
|
|
@@ -9260,6 +9709,8 @@ var GameTestRoom = (() => {
|
|
|
9260
9709
|
return Math.abs(asNumber(first));
|
|
9261
9710
|
case "sqrt":
|
|
9262
9711
|
return Math.sqrt(asNumber(first));
|
|
9712
|
+
case "exp":
|
|
9713
|
+
return Math.exp(asNumber(first));
|
|
9263
9714
|
case "sin":
|
|
9264
9715
|
return Math.sin(asNumber(first));
|
|
9265
9716
|
case "cos":
|
|
@@ -9378,7 +9829,7 @@ var GameTestRoom = (() => {
|
|
|
9378
9829
|
return evaluateCall(value.$, args.map((entry) => resolve(entry, context)));
|
|
9379
9830
|
}
|
|
9380
9831
|
}
|
|
9381
|
-
var
|
|
9832
|
+
var UP12 = [0, 1, 0];
|
|
9382
9833
|
var ZERO = [0, 0, 0];
|
|
9383
9834
|
var FULL_TURN_DRAWN = 6.283;
|
|
9384
9835
|
function scaledSizes(range2, factor) {
|
|
@@ -9391,7 +9842,7 @@ var GameTestRoom = (() => {
|
|
|
9391
9842
|
p: centre,
|
|
9392
9843
|
r: radius,
|
|
9393
9844
|
flat: true,
|
|
9394
|
-
dir: options.dir ??
|
|
9845
|
+
dir: options.dir ?? UP12,
|
|
9395
9846
|
cone: 0.35,
|
|
9396
9847
|
sp: [0.4, 1.4],
|
|
9397
9848
|
v: wind,
|
|
@@ -9408,7 +9859,7 @@ var GameTestRoom = (() => {
|
|
|
9408
9859
|
p: centre,
|
|
9409
9860
|
r: radius * 0.6,
|
|
9410
9861
|
flat: true,
|
|
9411
|
-
dir:
|
|
9862
|
+
dir: UP12,
|
|
9412
9863
|
cone: 0.3,
|
|
9413
9864
|
sp: [0.3, 0.8],
|
|
9414
9865
|
life: [0.2, 0.4],
|
|
@@ -9423,14 +9874,14 @@ var GameTestRoom = (() => {
|
|
|
9423
9874
|
if (engine.quality < 2) {
|
|
9424
9875
|
engine.emit(`${key}e`, "streak", 10 * factor, dt, () => {
|
|
9425
9876
|
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:
|
|
9877
|
+
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
9878
|
});
|
|
9428
9879
|
}
|
|
9429
9880
|
if (options.noSmoke) return;
|
|
9430
9881
|
engine.emit(`${key}s`, "normal", (options.smoke || 14) * factor, dt, () => ({
|
|
9431
9882
|
p: plus(centre, 0, 0.8 * sqrtFactor, 0),
|
|
9432
9883
|
r: radius * 0.7,
|
|
9433
|
-
dir:
|
|
9884
|
+
dir: UP12,
|
|
9434
9885
|
cone: 0.35,
|
|
9435
9886
|
sp: [0.6, 1.4],
|
|
9436
9887
|
v: wind,
|
|
@@ -9470,15 +9921,15 @@ var GameTestRoom = (() => {
|
|
|
9470
9921
|
engine.screen.shake += 0.7 * scale2;
|
|
9471
9922
|
engine.screen.white += 0.18 * scale2;
|
|
9472
9923
|
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:
|
|
9924
|
+
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
9925
|
engine.ring([plus(point, 0, 0.05, 0), 0.3, 7 * scale2, 0.55, 16767136]);
|
|
9475
9926
|
const toCamera = normalized([cameraPosition[0] - point[0], cameraPosition[1] - point[1], cameraPosition[2] - point[2]]);
|
|
9476
9927
|
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:
|
|
9928
|
+
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
9929
|
ringOfDust(engine, point, scale2);
|
|
9479
|
-
if (engine.quality < 2) engine.burst("streak", 44 * scale2, { p: point, dir:
|
|
9930
|
+
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
9931
|
for (let index = 0; index < engine.scaled(16 * scale2); index++) {
|
|
9481
|
-
engine.debrisPiece({ p: point, dir:
|
|
9932
|
+
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
9933
|
}
|
|
9483
9934
|
engine.decal([point[0], engine.context.groundAt(point[0], point[2]), point[2], 3 * scale2, 657930, { grow: 0.15, life: 60 }]);
|
|
9484
9935
|
}
|
|
@@ -9621,6 +10072,7 @@ var GameTestRoom = (() => {
|
|
|
9621
10072
|
if (!def) return;
|
|
9622
10073
|
this.schedule.clear();
|
|
9623
10074
|
this.variables.clear();
|
|
10075
|
+
for (const [name, value] of Object.entries(this.setup.values ?? {})) this.variables.set(name, value);
|
|
9624
10076
|
for (const behavior2 of this.deps.behaviors()) behavior2.reset(this.host);
|
|
9625
10077
|
this.time = 0;
|
|
9626
10078
|
this.within(() => {
|
|
@@ -9679,6 +10131,10 @@ var GameTestRoom = (() => {
|
|
|
9679
10131
|
return engine.spawn(step.system, this.value(step.spawn));
|
|
9680
10132
|
case "emit":
|
|
9681
10133
|
return engine.emit(step.key, step.system, this.value(step.rate), this.dt, () => this.value(step.spawn));
|
|
10134
|
+
case "mesh": {
|
|
10135
|
+
engine.mesh(this.value(step.spawn));
|
|
10136
|
+
return;
|
|
10137
|
+
}
|
|
9682
10138
|
case "debris":
|
|
9683
10139
|
return engine.debrisPiece(this.value(step.spawn));
|
|
9684
10140
|
case "decal":
|
|
@@ -9760,7 +10216,7 @@ var GameTestRoom = (() => {
|
|
|
9760
10216
|
this.index = previous;
|
|
9761
10217
|
}
|
|
9762
10218
|
};
|
|
9763
|
-
var
|
|
10219
|
+
var ORIGIN5 = [0, 0, 0];
|
|
9764
10220
|
var DEFAULT_HEADING = [0, 0, -1];
|
|
9765
10221
|
var DEFAULT_MAX_INSTANCES = 48;
|
|
9766
10222
|
var ENDLESS_SECONDS = 60;
|
|
@@ -9805,7 +10261,7 @@ var GameTestRoom = (() => {
|
|
|
9805
10261
|
}
|
|
9806
10262
|
function placementOf(entry) {
|
|
9807
10263
|
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 };
|
|
10264
|
+
return { origin, anchor: entry.anchor, yaw: entry.yaw, ...entry.orientation ? { orientation: entry.orientation } : {} };
|
|
9809
10265
|
}
|
|
9810
10266
|
function drawing(entry, action) {
|
|
9811
10267
|
const context = engine.context;
|
|
@@ -9829,8 +10285,9 @@ var GameTestRoom = (() => {
|
|
|
9829
10285
|
random: playOptions.seed !== void 0 ? streamOf(playOptions.seed) : void 0,
|
|
9830
10286
|
follow: playOptions.follow,
|
|
9831
10287
|
origin: point,
|
|
9832
|
-
anchor: def.anchor ??
|
|
10288
|
+
anchor: def.anchor ?? ORIGIN5,
|
|
9833
10289
|
yaw: yawOf(heading, playOptions.direction),
|
|
10290
|
+
orientation: playOptions.orientation,
|
|
9834
10291
|
seconds: playOptions.seconds ?? (def.loop && def.loop > 0 ? def.loop : ENDLESS_SECONDS)
|
|
9835
10292
|
};
|
|
9836
10293
|
playing.push(entry);
|
|
@@ -9839,7 +10296,8 @@ var GameTestRoom = (() => {
|
|
|
9839
10296
|
() => instance.begin(def, paramIndex(def, playOptions.param), {
|
|
9840
10297
|
placement: placementOf(entry),
|
|
9841
10298
|
...playOptions.direction ? { direction: playOptions.direction } : {},
|
|
9842
|
-
...playOptions.normal ? { normal: playOptions.normal } : {}
|
|
10299
|
+
...playOptions.normal ? { normal: playOptions.normal } : {},
|
|
10300
|
+
...playOptions.values ? { values: playOptions.values } : {}
|
|
9843
10301
|
})
|
|
9844
10302
|
);
|
|
9845
10303
|
return entry.handle;
|
|
@@ -10099,15 +10557,15 @@ var GameTestRoom = (() => {
|
|
|
10099
10557
|
return shock;
|
|
10100
10558
|
}
|
|
10101
10559
|
function pushPuffs(puffs, shock, reach, dt, age) {
|
|
10102
|
-
for (const
|
|
10103
|
-
if (
|
|
10104
|
-
const dx =
|
|
10105
|
-
const dz =
|
|
10560
|
+
for (const puff3 of puffs) {
|
|
10561
|
+
if (puff3.ring || puff3.t > PUSH_AGE_LIMIT) continue;
|
|
10562
|
+
const dx = puff3.x - shock.x;
|
|
10563
|
+
const dz = puff3.z - shock.z;
|
|
10106
10564
|
const distance4 = Math.hypot(dx, dz) + 1e-3;
|
|
10107
|
-
if (Math.abs(distance4 - reach) < PUSH_BAND &&
|
|
10565
|
+
if (Math.abs(distance4 - reach) < PUSH_BAND && puff3.y < PUSH_CEILING) {
|
|
10108
10566
|
const strength = 4 * dt * (1 - age);
|
|
10109
|
-
|
|
10110
|
-
|
|
10567
|
+
puff3.vx += dx / distance4 * strength * 6;
|
|
10568
|
+
puff3.vz += dz / distance4 * strength * 6;
|
|
10111
10569
|
}
|
|
10112
10570
|
}
|
|
10113
10571
|
}
|
|
@@ -10407,10 +10865,10 @@ var GameTestRoom = (() => {
|
|
|
10407
10865
|
const life = random.between(ring2.life * 0.75, ring2.life);
|
|
10408
10866
|
const h0 = random.between(1, 1.25);
|
|
10409
10867
|
const hl = random.between(0.9, 1.6);
|
|
10410
|
-
const
|
|
10411
|
-
|
|
10412
|
-
|
|
10413
|
-
|
|
10868
|
+
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 });
|
|
10869
|
+
puff3.ring = ring2;
|
|
10870
|
+
puff3.ph = random.next() * Math.PI * 2;
|
|
10871
|
+
puff3.th = random.next() * Math.PI * 2;
|
|
10414
10872
|
}
|
|
10415
10873
|
const stemCount = Math.round((spec.stem || 18) * Math.max(lod, 0.4));
|
|
10416
10874
|
for (let index = 0; index < stemCount; index++) {
|
|
@@ -11211,7 +11669,7 @@ var GameTestRoom = (() => {
|
|
|
11211
11669
|
};
|
|
11212
11670
|
var TWO_PI_ROUNDED = 6.2832;
|
|
11213
11671
|
var WIDE_CONE = 3.1;
|
|
11214
|
-
var
|
|
11672
|
+
var UP13 = [0, 1, 0];
|
|
11215
11673
|
function drawRange(random, range2) {
|
|
11216
11674
|
if (Array.isArray(range2)) return random.between(range2[0], range2[1]);
|
|
11217
11675
|
return range2 || 0;
|
|
@@ -11239,7 +11697,7 @@ var GameTestRoom = (() => {
|
|
|
11239
11697
|
}
|
|
11240
11698
|
function coneDirection(random, direction, cone, out) {
|
|
11241
11699
|
if (cone >= WIDE_CONE) return randomUnit(random, out);
|
|
11242
|
-
const [dx, dy, dz] = direction ??
|
|
11700
|
+
const [dx, dy, dz] = direction ?? UP13;
|
|
11243
11701
|
const cosTilt = 1 - random.next() * (1 - Math.cos(cone));
|
|
11244
11702
|
const sinTilt = Math.sqrt(1 - cosTilt * cosTilt);
|
|
11245
11703
|
const phase = random.next() * TWO_PI_ROUNDED;
|
|
@@ -11359,12 +11817,12 @@ var GameTestRoom = (() => {
|
|
|
11359
11817
|
}
|
|
11360
11818
|
};
|
|
11361
11819
|
var CAPACITY2 = 400;
|
|
11362
|
-
var
|
|
11820
|
+
var UP14 = [0, 1, 0];
|
|
11363
11821
|
var DEFAULT_LIFE2 = 60;
|
|
11364
11822
|
var DEFAULT_GROW = 1.2;
|
|
11365
11823
|
var EVAPORATION = { fuel: [6, 5], water: [40, 20] };
|
|
11366
11824
|
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:
|
|
11825
|
+
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
11826
|
}
|
|
11369
11827
|
var DecalPool = class {
|
|
11370
11828
|
constructor(context) {
|
|
@@ -11377,7 +11835,7 @@ var GameTestRoom = (() => {
|
|
|
11377
11835
|
const random = this.context.random;
|
|
11378
11836
|
const index = this.next++ % CAPACITY2;
|
|
11379
11837
|
const decal2 = this.decals[index];
|
|
11380
|
-
const normal = options.n ??
|
|
11838
|
+
const normal = options.n ?? UP14;
|
|
11381
11839
|
random.between(0, 6.28);
|
|
11382
11840
|
const offset = 4e-3 + index % 40 * 4e-4;
|
|
11383
11841
|
decal2.on = true;
|
|
@@ -11418,6 +11876,94 @@ var GameTestRoom = (() => {
|
|
|
11418
11876
|
}
|
|
11419
11877
|
}
|
|
11420
11878
|
};
|
|
11879
|
+
var CAPACITY3 = 400;
|
|
11880
|
+
var IDENTITY2 = [0, 0, 0, 1];
|
|
11881
|
+
function multiply(a, b) {
|
|
11882
|
+
const [ax, ay, az, aw] = a;
|
|
11883
|
+
const [bx, by, bz, bw] = b;
|
|
11884
|
+
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];
|
|
11885
|
+
}
|
|
11886
|
+
var aboutX = (angle) => [Math.sin(angle / 2), 0, 0, Math.cos(angle / 2)];
|
|
11887
|
+
var MeshPool = class {
|
|
11888
|
+
constructor(capacity = CAPACITY3) {
|
|
11889
|
+
__publicField(this, "capacity", capacity);
|
|
11890
|
+
__publicField(this, "particles", []);
|
|
11891
|
+
__publicField(this, "serial", 0);
|
|
11892
|
+
}
|
|
11893
|
+
get count() {
|
|
11894
|
+
return this.particles.length;
|
|
11895
|
+
}
|
|
11896
|
+
spawn(options, frame3 = IDENTITY2) {
|
|
11897
|
+
const velocity = options.v ?? [0, 0, 0];
|
|
11898
|
+
const world = options.wv ?? [0, 0, 0];
|
|
11899
|
+
const particle = {
|
|
11900
|
+
id: ++this.serial,
|
|
11901
|
+
shape: options.shape,
|
|
11902
|
+
radius: options.r,
|
|
11903
|
+
height: options.h ?? 0,
|
|
11904
|
+
segments: options.seg ?? 0,
|
|
11905
|
+
segments2: options.seg2 ?? 0,
|
|
11906
|
+
color: options.c0,
|
|
11907
|
+
additive: options.add === true,
|
|
11908
|
+
lit: options.lit === true,
|
|
11909
|
+
x: options.p[0],
|
|
11910
|
+
y: options.p[1],
|
|
11911
|
+
z: options.p[2],
|
|
11912
|
+
frame: options.roll ? multiply(frame3, aboutX(options.roll)) : frame3,
|
|
11913
|
+
at: options.at ?? [0, 0, 0],
|
|
11914
|
+
rx: options.rot?.[0] ?? 0,
|
|
11915
|
+
ry: options.rot?.[1] ?? 0,
|
|
11916
|
+
rz: options.rot?.[2] ?? 0,
|
|
11917
|
+
scale: 1,
|
|
11918
|
+
opacity: options.a,
|
|
11919
|
+
age: 0,
|
|
11920
|
+
life: options.life,
|
|
11921
|
+
vx: velocity[0] + world[0],
|
|
11922
|
+
vy: velocity[1] + world[1],
|
|
11923
|
+
vz: velocity[2] + world[2],
|
|
11924
|
+
spin: options.spin ?? [0, 0, 0],
|
|
11925
|
+
gravity: options.g ?? 0,
|
|
11926
|
+
drag: options.drag ?? 0,
|
|
11927
|
+
grow: options.grow ?? 0,
|
|
11928
|
+
ramp: options.ramp,
|
|
11929
|
+
fade: options.fade === true,
|
|
11930
|
+
startOpacity: options.a
|
|
11931
|
+
};
|
|
11932
|
+
this.particles.push(particle);
|
|
11933
|
+
if (this.particles.length > this.capacity) this.particles.shift();
|
|
11934
|
+
return particle;
|
|
11935
|
+
}
|
|
11936
|
+
update(dt) {
|
|
11937
|
+
const live = this.particles;
|
|
11938
|
+
for (let index = 0; index < live.length; index++) {
|
|
11939
|
+
const particle = live[index];
|
|
11940
|
+
particle.age += dt;
|
|
11941
|
+
if (particle.ramp ? particle.age >= particle.life : particle.age > particle.life) {
|
|
11942
|
+
live.splice(index--, 1);
|
|
11943
|
+
continue;
|
|
11944
|
+
}
|
|
11945
|
+
if (particle.fade) particle.opacity = Math.max(0, particle.startOpacity * (1 - particle.age / particle.life));
|
|
11946
|
+
particle.vy -= particle.gravity * dt;
|
|
11947
|
+
if (particle.drag) {
|
|
11948
|
+
const keep = Math.max(0, 1 - particle.drag * dt);
|
|
11949
|
+
particle.vx *= keep;
|
|
11950
|
+
particle.vy *= keep;
|
|
11951
|
+
particle.vz *= keep;
|
|
11952
|
+
}
|
|
11953
|
+
particle.x += particle.vx * dt;
|
|
11954
|
+
particle.y += particle.vy * dt;
|
|
11955
|
+
particle.z += particle.vz * dt;
|
|
11956
|
+
particle.rx += particle.spin[0] * dt;
|
|
11957
|
+
particle.ry += particle.spin[1] * dt;
|
|
11958
|
+
particle.rz += particle.spin[2] * dt;
|
|
11959
|
+
if (particle.grow) particle.scale *= 1 + particle.grow * dt;
|
|
11960
|
+
if (particle.ramp) particle.scale = particle.ramp[0] + Math.min(1, particle.age / particle.life) * particle.ramp[1];
|
|
11961
|
+
}
|
|
11962
|
+
}
|
|
11963
|
+
clear() {
|
|
11964
|
+
this.particles.length = 0;
|
|
11965
|
+
}
|
|
11966
|
+
};
|
|
11421
11967
|
var DEFAULT_FADE_IN = 0.1;
|
|
11422
11968
|
var FLOATS_PER_VECTOR = 3;
|
|
11423
11969
|
var BYTE_MAX2 = 255;
|
|
@@ -11707,11 +12253,11 @@ var GameTestRoom = (() => {
|
|
|
11707
12253
|
};
|
|
11708
12254
|
var RING_CAPACITY = 120;
|
|
11709
12255
|
var LIGHT_CAPACITY = 4;
|
|
11710
|
-
var
|
|
12256
|
+
var UP15 = [0, 1, 0];
|
|
11711
12257
|
var DEFAULT_LIGHT_DISTANCE = 14;
|
|
11712
12258
|
var WaveRingPool = class {
|
|
11713
12259
|
constructor() {
|
|
11714
|
-
__publicField(this, "rings", Array.from({ length: RING_CAPACITY }, () => ({ on: false, point:
|
|
12260
|
+
__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
12261
|
__publicField(this, "count", 0);
|
|
11716
12262
|
__publicField(this, "next", 0);
|
|
11717
12263
|
}
|
|
@@ -11724,7 +12270,7 @@ var GameTestRoom = (() => {
|
|
|
11724
12270
|
ring2.t = 0;
|
|
11725
12271
|
ring2.duration = duration;
|
|
11726
12272
|
ring2.color = color;
|
|
11727
|
-
ring2.normal = normal ??
|
|
12273
|
+
ring2.normal = normal ?? UP15;
|
|
11728
12274
|
ring2.hold = hold || 0;
|
|
11729
12275
|
}
|
|
11730
12276
|
clear() {
|
|
@@ -11744,7 +12290,7 @@ var GameTestRoom = (() => {
|
|
|
11744
12290
|
var FlashLightPool = class {
|
|
11745
12291
|
constructor(context) {
|
|
11746
12292
|
__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 })));
|
|
12293
|
+
__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
12294
|
__publicField(this, "fire", [
|
|
11749
12295
|
{ x: 0, y: 0, z: 0, intensity: 0 },
|
|
11750
12296
|
{ x: 0, y: 0, z: 0, intensity: 0 }
|
|
@@ -11754,7 +12300,7 @@ var GameTestRoom = (() => {
|
|
|
11754
12300
|
get lit() {
|
|
11755
12301
|
return this.lights.filter((light) => light.intensity > 0).length;
|
|
11756
12302
|
}
|
|
11757
|
-
flash(point, color, intensity, duration, distance4, force) {
|
|
12303
|
+
flash(point, color, intensity, duration, distance4, force, steady) {
|
|
11758
12304
|
const { level } = this.context.quality;
|
|
11759
12305
|
if (level >= 1 && !force) return;
|
|
11760
12306
|
if (level >= 2 && force !== "boom") return;
|
|
@@ -11767,6 +12313,7 @@ var GameTestRoom = (() => {
|
|
|
11767
12313
|
light.peak = intensity;
|
|
11768
12314
|
light.duration = duration;
|
|
11769
12315
|
light.t = 0;
|
|
12316
|
+
light.steady = steady === true;
|
|
11770
12317
|
light.intensity = intensity;
|
|
11771
12318
|
}
|
|
11772
12319
|
clear() {
|
|
@@ -11778,7 +12325,7 @@ var GameTestRoom = (() => {
|
|
|
11778
12325
|
if (light.intensity <= 0) continue;
|
|
11779
12326
|
light.t += dt;
|
|
11780
12327
|
const age = light.t / light.duration;
|
|
11781
|
-
light.intensity = age >= 1 ? 0 : light.peak * (1 - age) * (1 - age);
|
|
12328
|
+
light.intensity = age >= 1 ? 0 : light.steady ? light.peak : light.peak * (1 - age) * (1 - age);
|
|
11782
12329
|
}
|
|
11783
12330
|
}
|
|
11784
12331
|
};
|
|
@@ -11786,6 +12333,14 @@ var GameTestRoom = (() => {
|
|
|
11786
12333
|
var FIRE_FLICKER_SWAY = 0.25;
|
|
11787
12334
|
var FIRE_FLICKER_JITTER = 0.08;
|
|
11788
12335
|
var LENS_FADE = 0.16;
|
|
12336
|
+
function rotate(q, v) {
|
|
12337
|
+
const [qx, qy, qz, qw] = q;
|
|
12338
|
+
const ix = qw * v[0] + qy * v[2] - qz * v[1];
|
|
12339
|
+
const iy = qw * v[1] + qz * v[0] - qx * v[2];
|
|
12340
|
+
const iz = qw * v[2] + qx * v[1] - qy * v[0];
|
|
12341
|
+
const iw = -qx * v[0] - qy * v[1] - qz * v[2];
|
|
12342
|
+
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];
|
|
12343
|
+
}
|
|
11789
12344
|
function workshopGround(x, z) {
|
|
11790
12345
|
return z < -2.9 && z > -4.5 && Math.abs(x) < 13 ? 0.12 : 0;
|
|
11791
12346
|
}
|
|
@@ -11799,6 +12354,8 @@ var GameTestRoom = (() => {
|
|
|
11799
12354
|
__publicField(this, "decals");
|
|
11800
12355
|
__publicField(this, "rings", new WaveRingPool());
|
|
11801
12356
|
__publicField(this, "lights");
|
|
12357
|
+
__publicField(this, "rain", new RainField(this));
|
|
12358
|
+
__publicField(this, "meshes", new MeshPool());
|
|
11802
12359
|
__publicField(this, "screen", createScreenState());
|
|
11803
12360
|
__publicField(this, "lens", []);
|
|
11804
12361
|
__publicField(this, "post", {});
|
|
@@ -11831,7 +12388,11 @@ var GameTestRoom = (() => {
|
|
|
11831
12388
|
place(point) {
|
|
11832
12389
|
const placement = this.placement;
|
|
11833
12390
|
if (!placement) return point;
|
|
11834
|
-
const { anchor, origin, yaw } = placement;
|
|
12391
|
+
const { anchor, origin, yaw, orientation } = placement;
|
|
12392
|
+
if (orientation) {
|
|
12393
|
+
const turned = rotate(orientation, [point[0] - anchor[0], point[1] - anchor[1], point[2] - anchor[2]]);
|
|
12394
|
+
return [origin[0] + turned[0], origin[1] + turned[1], origin[2] + turned[2]];
|
|
12395
|
+
}
|
|
11835
12396
|
const x = point[0] - anchor[0];
|
|
11836
12397
|
const z = point[2] - anchor[2];
|
|
11837
12398
|
const cos2 = Math.cos(yaw);
|
|
@@ -11842,6 +12403,7 @@ var GameTestRoom = (() => {
|
|
|
11842
12403
|
turn(vector) {
|
|
11843
12404
|
const placement = this.placement;
|
|
11844
12405
|
if (!placement) return vector;
|
|
12406
|
+
if (placement.orientation) return rotate(placement.orientation, vector);
|
|
11845
12407
|
const cos2 = Math.cos(placement.yaw);
|
|
11846
12408
|
const sin2 = Math.sin(placement.yaw);
|
|
11847
12409
|
return [cos2 * vector[0] + sin2 * vector[2], vector[1], -sin2 * vector[0] + cos2 * vector[2]];
|
|
@@ -11870,6 +12432,14 @@ var GameTestRoom = (() => {
|
|
|
11870
12432
|
}
|
|
11871
12433
|
this.accumulators.set(key, carried);
|
|
11872
12434
|
}
|
|
12435
|
+
/** 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. */
|
|
12436
|
+
mesh(recipe) {
|
|
12437
|
+
const placement = this.placement;
|
|
12438
|
+
const options = placement ? { ...recipe, p: this.place(recipe.p), ...recipe.v ? { v: this.turn(recipe.v) } : {} } : recipe;
|
|
12439
|
+
this.context.trace?.("mesh", [options]);
|
|
12440
|
+
const grouped = recipe.at !== void 0 || recipe.roll !== void 0;
|
|
12441
|
+
return this.meshes.spawn(options, placement && grouped ? placement.orientation ?? [0, Math.sin(placement.yaw / 2), 0, Math.cos(placement.yaw / 2)] : void 0);
|
|
12442
|
+
}
|
|
11873
12443
|
debrisPiece(recipe) {
|
|
11874
12444
|
const options = this.placed(recipe);
|
|
11875
12445
|
this.context.trace?.("debris", [options]);
|
|
@@ -11890,10 +12460,11 @@ var GameTestRoom = (() => {
|
|
|
11890
12460
|
this.context.trace?.("ring", args);
|
|
11891
12461
|
this.rings.add(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
|
|
11892
12462
|
}
|
|
12463
|
+
/** `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
12464
|
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]);
|
|
12465
|
+
const args = this.placement ? [this.place(recipe[0]), recipe[1], recipe[2], recipe[3], recipe[4], recipe[5], recipe[6]] : recipe;
|
|
12466
|
+
this.context.trace?.("flash", args.slice(0, 6));
|
|
12467
|
+
this.lights.flash(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
|
|
11897
12468
|
}
|
|
11898
12469
|
/** `fireLight` (W400): sways with the clock and flickers with one draw. */
|
|
11899
12470
|
fireLight(slot, recipe, intensity, time) {
|
|
@@ -11918,6 +12489,7 @@ var GameTestRoom = (() => {
|
|
|
11918
12489
|
this.debris.update(dt);
|
|
11919
12490
|
this.decals.update(dt);
|
|
11920
12491
|
this.rings.update(dt);
|
|
12492
|
+
this.meshes.update(dt);
|
|
11921
12493
|
this.lights.update(dt);
|
|
11922
12494
|
updateScreen(this.screen, dt);
|
|
11923
12495
|
for (let index = this.lens.length - 1; index >= 0; index--) {
|
|
@@ -11934,7 +12506,9 @@ var GameTestRoom = (() => {
|
|
|
11934
12506
|
this.debris.clear();
|
|
11935
12507
|
this.decals.clear();
|
|
11936
12508
|
this.rings.clear();
|
|
12509
|
+
this.meshes.clear();
|
|
11937
12510
|
this.lights.clear();
|
|
12511
|
+
this.rain.clear();
|
|
11938
12512
|
this.accumulators.clear();
|
|
11939
12513
|
resetScreenState(this.screen);
|
|
11940
12514
|
this.lens.length = 0;
|
|
@@ -12080,16 +12654,16 @@ var GameTestRoom = (() => {
|
|
|
12080
12654
|
},
|
|
12081
12655
|
push(point, radius, speed) {
|
|
12082
12656
|
spriteSystem.push(point, radius, speed);
|
|
12083
|
-
for (const
|
|
12084
|
-
const dx =
|
|
12085
|
-
const dy =
|
|
12086
|
-
const dz =
|
|
12657
|
+
for (const puff3 of core.puffs.items) {
|
|
12658
|
+
const dx = puff3.x - point[0];
|
|
12659
|
+
const dy = puff3.y - point[1];
|
|
12660
|
+
const dz = puff3.z - point[2];
|
|
12087
12661
|
const distance4 = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
|
12088
12662
|
if (distance4 >= radius) continue;
|
|
12089
12663
|
const strength = speed * (1 - distance4 / radius) / (distance4 + 1e-3);
|
|
12090
|
-
|
|
12091
|
-
|
|
12092
|
-
|
|
12664
|
+
puff3.vx += dx * strength;
|
|
12665
|
+
puff3.vy += dy * strength;
|
|
12666
|
+
puff3.vz += dz * strength;
|
|
12093
12667
|
}
|
|
12094
12668
|
},
|
|
12095
12669
|
stop(handle) {
|
|
@@ -12106,6 +12680,12 @@ var GameTestRoom = (() => {
|
|
|
12106
12680
|
camera2.y = position[1];
|
|
12107
12681
|
camera2.z = position[2];
|
|
12108
12682
|
},
|
|
12683
|
+
setWind(next) {
|
|
12684
|
+
wind.x = next[0];
|
|
12685
|
+
wind.y = next[1];
|
|
12686
|
+
wind.z = next[2];
|
|
12687
|
+
},
|
|
12688
|
+
wind: () => [wind.x, wind.y, wind.z],
|
|
12109
12689
|
forceLod(scale2) {
|
|
12110
12690
|
core.clock.forcedLod = scale2;
|
|
12111
12691
|
},
|
|
@@ -12374,11 +12954,11 @@ void main(){
|
|
|
12374
12954
|
geometry.setAttribute("aC", attributes[2]);
|
|
12375
12955
|
geometry.instanceCount = 0;
|
|
12376
12956
|
const material = new THREE.ShaderMaterial({ uniforms, vertexShader: PUFF_VERTEX, fragmentShader: PUFF_FRAGMENT });
|
|
12377
|
-
const
|
|
12378
|
-
|
|
12379
|
-
|
|
12957
|
+
const mesh2 = new THREE.Mesh(geometry, material);
|
|
12958
|
+
mesh2.name = "vfx-puffs";
|
|
12959
|
+
mesh2.frustumCulled = false;
|
|
12380
12960
|
return {
|
|
12381
|
-
mesh,
|
|
12961
|
+
mesh: mesh2,
|
|
12382
12962
|
sync() {
|
|
12383
12963
|
let n = 0;
|
|
12384
12964
|
for (const p of pool.items) {
|
|
@@ -12419,12 +12999,12 @@ void main(){
|
|
|
12419
12999
|
geometry.setAttribute("aE", attributes[2]);
|
|
12420
13000
|
geometry.instanceCount = 0;
|
|
12421
13001
|
const material = new THREE.ShaderMaterial({ transparent: true, depthWrite: false, blending: THREE.AdditiveBlending, vertexShader: SPARK_VERTEX, fragmentShader: SPARK_FRAGMENT });
|
|
12422
|
-
const
|
|
12423
|
-
|
|
12424
|
-
|
|
12425
|
-
|
|
13002
|
+
const mesh2 = new THREE.Mesh(geometry, material);
|
|
13003
|
+
mesh2.name = "vfx-sparks";
|
|
13004
|
+
mesh2.frustumCulled = false;
|
|
13005
|
+
mesh2.renderOrder = 5;
|
|
12426
13006
|
return {
|
|
12427
|
-
mesh,
|
|
13007
|
+
mesh: mesh2,
|
|
12428
13008
|
sync() {
|
|
12429
13009
|
let n = 0;
|
|
12430
13010
|
for (const s of pool.items) {
|
|
@@ -12462,12 +13042,12 @@ void main(){
|
|
|
12462
13042
|
geometry.setAttribute("aC", attributes[1]);
|
|
12463
13043
|
geometry.instanceCount = 0;
|
|
12464
13044
|
const material = new THREE.ShaderMaterial({ transparent: true, depthWrite: false, blending: THREE.AdditiveBlending, vertexShader: GLOW_VERTEX, fragmentShader: GLOW_FRAGMENT });
|
|
12465
|
-
const
|
|
12466
|
-
|
|
12467
|
-
|
|
12468
|
-
|
|
13045
|
+
const mesh2 = new THREE.Mesh(geometry, material);
|
|
13046
|
+
mesh2.name = "vfx-glows";
|
|
13047
|
+
mesh2.frustumCulled = false;
|
|
13048
|
+
mesh2.renderOrder = 6;
|
|
12469
13049
|
return {
|
|
12470
|
-
mesh,
|
|
13050
|
+
mesh: mesh2,
|
|
12471
13051
|
sync() {
|
|
12472
13052
|
let n = 0;
|
|
12473
13053
|
for (const g of pool.items) {
|
|
@@ -12496,14 +13076,14 @@ void main(){
|
|
|
12496
13076
|
const rockMaterial = new THREE.MeshStandardMaterial({ color: 16777215, roughness: 0.85, flatShading: true });
|
|
12497
13077
|
const plateMaterial = rockMaterial.clone();
|
|
12498
13078
|
const make = (geometry, material) => {
|
|
12499
|
-
const
|
|
12500
|
-
|
|
12501
|
-
|
|
12502
|
-
|
|
12503
|
-
|
|
12504
|
-
|
|
12505
|
-
|
|
12506
|
-
return
|
|
13079
|
+
const mesh2 = new THREE.InstancedMesh(geometry, material, capacity);
|
|
13080
|
+
mesh2.instanceMatrix.setUsage(THREE.DynamicDrawUsage);
|
|
13081
|
+
mesh2.castShadow = true;
|
|
13082
|
+
mesh2.receiveShadow = true;
|
|
13083
|
+
mesh2.frustumCulled = false;
|
|
13084
|
+
mesh2.count = 0;
|
|
13085
|
+
mesh2.setColorAt(0, new THREE.Color(1, 1, 1));
|
|
13086
|
+
return mesh2;
|
|
12507
13087
|
};
|
|
12508
13088
|
const rocks = make(shapes.rock, rockMaterial);
|
|
12509
13089
|
const plates = make(shapes.plate, plateMaterial);
|
|
@@ -12522,20 +13102,20 @@ void main(){
|
|
|
12522
13102
|
euler.set(chunk.rx, chunk.ry, chunk.rz);
|
|
12523
13103
|
quaternion.setFromEuler(euler);
|
|
12524
13104
|
matrix.compose(position.set(chunk.x, chunk.y, chunk.z), quaternion, scale2.set(chunk.sx, chunk.sy, chunk.sz));
|
|
12525
|
-
const
|
|
13105
|
+
const mesh2 = chunk.plate ? plates : rocks;
|
|
12526
13106
|
const index = chunk.plate ? plateCount++ : rockCount++;
|
|
12527
|
-
|
|
13107
|
+
mesh2.setMatrixAt(index, matrix);
|
|
12528
13108
|
const color = colorOf2(chunk);
|
|
12529
|
-
const colors =
|
|
13109
|
+
const colors = mesh2.instanceColor.array;
|
|
12530
13110
|
colors[index * 3] = color[0];
|
|
12531
13111
|
colors[index * 3 + 1] = color[1];
|
|
12532
13112
|
colors[index * 3 + 2] = color[2];
|
|
12533
13113
|
}
|
|
12534
13114
|
rocks.count = rockCount;
|
|
12535
13115
|
plates.count = plateCount;
|
|
12536
|
-
for (const
|
|
12537
|
-
|
|
12538
|
-
|
|
13116
|
+
for (const mesh2 of [rocks, plates]) {
|
|
13117
|
+
mesh2.instanceMatrix.needsUpdate = true;
|
|
13118
|
+
mesh2.instanceColor.needsUpdate = true;
|
|
12539
13119
|
}
|
|
12540
13120
|
return rockCount + plateCount;
|
|
12541
13121
|
},
|
|
@@ -12719,28 +13299,28 @@ void main(){
|
|
|
12719
13299
|
position.setXYZ(index, worldX, (options.ground?.heightAt(worldX, worldZ) ?? 0) + mark.lift, worldZ);
|
|
12720
13300
|
}
|
|
12721
13301
|
geometry.computeVertexNormals();
|
|
12722
|
-
const
|
|
12723
|
-
|
|
12724
|
-
return
|
|
13302
|
+
const mesh2 = new THREE.Mesh(geometry, material);
|
|
13303
|
+
mesh2.receiveShadow = true;
|
|
13304
|
+
return mesh2;
|
|
12725
13305
|
}
|
|
12726
13306
|
function addRock(mark) {
|
|
12727
|
-
const
|
|
12728
|
-
|
|
12729
|
-
|
|
12730
|
-
|
|
12731
|
-
|
|
12732
|
-
|
|
12733
|
-
return
|
|
13307
|
+
const mesh2 = new THREE.Mesh(mark.plate ? options.plateGeometry : options.rockGeometry, rockMaterial(mark.color));
|
|
13308
|
+
mesh2.position.set(mark.x, mark.y, mark.z);
|
|
13309
|
+
mesh2.scale.set(mark.scale[0], mark.scale[1], mark.scale[2]);
|
|
13310
|
+
mesh2.rotation.set(mark.rotation[0], mark.rotation[1], mark.rotation[2]);
|
|
13311
|
+
mesh2.castShadow = true;
|
|
13312
|
+
mesh2.receiveShadow = true;
|
|
13313
|
+
return mesh2;
|
|
12734
13314
|
}
|
|
12735
13315
|
function addBlood(mark) {
|
|
12736
|
-
const
|
|
12737
|
-
|
|
12738
|
-
|
|
12739
|
-
|
|
12740
|
-
|
|
12741
|
-
|
|
12742
|
-
blood.push({ mesh, scaleX: mark.scaleX, scaleZ: mark.scaleZ, age: 0 });
|
|
12743
|
-
return
|
|
13316
|
+
const mesh2 = new THREE.Mesh(bloodGeometry, bloodMaterial);
|
|
13317
|
+
mesh2.position.set(mark.x, mark.y, mark.z);
|
|
13318
|
+
mesh2.scale.set(mark.scaleX, 1, mark.scaleZ);
|
|
13319
|
+
mesh2.rotation.y = mark.rotation;
|
|
13320
|
+
mesh2.receiveShadow = true;
|
|
13321
|
+
mesh2.scale.multiplyScalar(0.05);
|
|
13322
|
+
blood.push({ mesh: mesh2, scaleX: mark.scaleX, scaleZ: mark.scaleZ, age: 0 });
|
|
13323
|
+
return mesh2;
|
|
12744
13324
|
}
|
|
12745
13325
|
function build(mark) {
|
|
12746
13326
|
if (mark.kind === "scorch") return conform(mark, scorchMaterials[mark.variant]);
|
|
@@ -12951,6 +13531,73 @@ void main() {
|
|
|
12951
13531
|
}
|
|
12952
13532
|
};
|
|
12953
13533
|
}
|
|
13534
|
+
var SPHERE_DEFAULT_WIDTH = 8;
|
|
13535
|
+
var SPHERE_DEFAULT_HEIGHT = 6;
|
|
13536
|
+
function geometryOf(THREE, particle) {
|
|
13537
|
+
switch (particle.shape) {
|
|
13538
|
+
case "cone":
|
|
13539
|
+
return new THREE.ConeGeometry(particle.radius, particle.height, particle.segments || void 0, particle.segments2 || 1, false);
|
|
13540
|
+
case "cone_open":
|
|
13541
|
+
return new THREE.ConeGeometry(particle.radius, particle.height, particle.segments || void 0, particle.segments2 || 1, true);
|
|
13542
|
+
case "sphere":
|
|
13543
|
+
return new THREE.SphereGeometry(particle.radius, particle.segments || SPHERE_DEFAULT_WIDTH, particle.segments2 || SPHERE_DEFAULT_HEIGHT);
|
|
13544
|
+
case "icosahedron":
|
|
13545
|
+
return new THREE.IcosahedronGeometry(particle.radius, particle.segments);
|
|
13546
|
+
}
|
|
13547
|
+
}
|
|
13548
|
+
function materialOf(THREE, particle) {
|
|
13549
|
+
if (particle.lit) return new THREE.MeshStandardMaterial({ color: particle.color, roughness: 1, metalness: 0, transparent: true, opacity: particle.opacity, depthWrite: false });
|
|
13550
|
+
return new THREE.MeshBasicMaterial({ color: particle.color, transparent: true, opacity: particle.opacity, depthWrite: false, ...particle.additive ? { blending: THREE.AdditiveBlending } : {} });
|
|
13551
|
+
}
|
|
13552
|
+
function createMeshLayer(THREE, pool) {
|
|
13553
|
+
const group = new THREE.Group();
|
|
13554
|
+
group.name = "workshop-meshes";
|
|
13555
|
+
const drawn = /* @__PURE__ */ new Map();
|
|
13556
|
+
const frame3 = new THREE.Quaternion();
|
|
13557
|
+
const euler = new THREE.Euler();
|
|
13558
|
+
const turn = new THREE.Quaternion();
|
|
13559
|
+
const offset = new THREE.Vector3();
|
|
13560
|
+
function release(mesh2) {
|
|
13561
|
+
mesh2.removeFromParent();
|
|
13562
|
+
mesh2.geometry.dispose();
|
|
13563
|
+
mesh2.material.dispose();
|
|
13564
|
+
}
|
|
13565
|
+
return {
|
|
13566
|
+
group,
|
|
13567
|
+
sync() {
|
|
13568
|
+
const live = /* @__PURE__ */ new Set();
|
|
13569
|
+
for (const particle of pool.particles) {
|
|
13570
|
+
live.add(particle.id);
|
|
13571
|
+
let mesh2 = drawn.get(particle.id);
|
|
13572
|
+
if (!mesh2) {
|
|
13573
|
+
mesh2 = new THREE.Mesh(geometryOf(THREE, particle), materialOf(THREE, particle));
|
|
13574
|
+
mesh2.frustumCulled = false;
|
|
13575
|
+
mesh2.renderOrder = particle.additive ? 5 : 3;
|
|
13576
|
+
drawn.set(particle.id, mesh2);
|
|
13577
|
+
group.add(mesh2);
|
|
13578
|
+
}
|
|
13579
|
+
frame3.set(particle.frame[0], particle.frame[1], particle.frame[2], particle.frame[3]);
|
|
13580
|
+
offset.set(particle.at[0], particle.at[1], particle.at[2]).multiplyScalar(particle.scale).applyQuaternion(frame3);
|
|
13581
|
+
mesh2.position.set(particle.x + offset.x, particle.y + offset.y, particle.z + offset.z);
|
|
13582
|
+
turn.setFromEuler(euler.set(particle.rx, particle.ry, particle.rz));
|
|
13583
|
+
mesh2.quaternion.copy(frame3).multiply(turn);
|
|
13584
|
+
mesh2.scale.setScalar(particle.scale);
|
|
13585
|
+
mesh2.material.opacity = particle.opacity;
|
|
13586
|
+
}
|
|
13587
|
+
for (const [id, mesh2] of drawn) {
|
|
13588
|
+
if (live.has(id)) continue;
|
|
13589
|
+
release(mesh2);
|
|
13590
|
+
drawn.delete(id);
|
|
13591
|
+
}
|
|
13592
|
+
return pool.count;
|
|
13593
|
+
},
|
|
13594
|
+
dispose() {
|
|
13595
|
+
for (const mesh2 of drawn.values()) release(mesh2);
|
|
13596
|
+
drawn.clear();
|
|
13597
|
+
group.removeFromParent();
|
|
13598
|
+
}
|
|
13599
|
+
};
|
|
13600
|
+
}
|
|
12954
13601
|
var WORKSHOP_SPRITE_VERTEX = `attribute float size;attribute float alpha;attribute vec3 pcol;varying vec3 vC;varying float vA;uniform float uScale;
|
|
12955
13602
|
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
13603
|
var WORKSHOP_SPRITE_FRAGMENT = `uniform float uSoft;varying vec3 vC;varying float vA;
|
|
@@ -13026,13 +13673,37 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13026
13673
|
}
|
|
13027
13674
|
};
|
|
13028
13675
|
}
|
|
13676
|
+
function rainLayer(THREE, rain) {
|
|
13677
|
+
const geometry = new THREE.BufferGeometry();
|
|
13678
|
+
const position = new THREE.BufferAttribute(rain.positions, 3).setUsage(THREE.DynamicDrawUsage);
|
|
13679
|
+
geometry.setAttribute("position", position);
|
|
13680
|
+
geometry.setDrawRange(0, 0);
|
|
13681
|
+
const material = new THREE.LineBasicMaterial({ color: 10466255, transparent: true, opacity: 0.35, depthWrite: false });
|
|
13682
|
+
const lines = new THREE.LineSegments(geometry, material);
|
|
13683
|
+
lines.frustumCulled = false;
|
|
13684
|
+
lines.name = "workshop-rain";
|
|
13685
|
+
return {
|
|
13686
|
+
object: lines,
|
|
13687
|
+
sync() {
|
|
13688
|
+
const drawn = rain.on && rain.count > 0;
|
|
13689
|
+
lines.visible = drawn;
|
|
13690
|
+
geometry.setDrawRange(0, drawn ? rain.count * 2 : 0);
|
|
13691
|
+
position.needsUpdate = true;
|
|
13692
|
+
return drawn;
|
|
13693
|
+
},
|
|
13694
|
+
dispose() {
|
|
13695
|
+
geometry.dispose();
|
|
13696
|
+
material.dispose();
|
|
13697
|
+
}
|
|
13698
|
+
};
|
|
13699
|
+
}
|
|
13029
13700
|
function debrisLayer(THREE, pool) {
|
|
13030
13701
|
const geometry = new THREE.BoxGeometry(1, 1, 1);
|
|
13031
13702
|
const material = new THREE.MeshStandardMaterial({ color: 16777215, roughness: 0.45, metalness: 0.25, flatShading: true });
|
|
13032
|
-
const
|
|
13033
|
-
|
|
13034
|
-
|
|
13035
|
-
|
|
13703
|
+
const mesh2 = new THREE.InstancedMesh(geometry, material, DEBRIS_CAPACITY);
|
|
13704
|
+
mesh2.instanceMatrix.setUsage(THREE.DynamicDrawUsage);
|
|
13705
|
+
mesh2.frustumCulled = false;
|
|
13706
|
+
mesh2.name = "workshop-debris";
|
|
13036
13707
|
const euler = new THREE.Euler();
|
|
13037
13708
|
const quaternion = new THREE.Quaternion();
|
|
13038
13709
|
const position = new THREE.Vector3();
|
|
@@ -13040,16 +13711,16 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13040
13711
|
const matrix = new THREE.Matrix4();
|
|
13041
13712
|
const colour = new THREE.Color();
|
|
13042
13713
|
const hidden = new THREE.Matrix4().makeScale(0, 0, 0);
|
|
13043
|
-
for (let index = 0; index < DEBRIS_CAPACITY; index++)
|
|
13044
|
-
|
|
13714
|
+
for (let index = 0; index < DEBRIS_CAPACITY; index++) mesh2.setMatrixAt(index, hidden);
|
|
13715
|
+
mesh2.setColorAt(0, colour.setHex(16777215));
|
|
13045
13716
|
return {
|
|
13046
|
-
object:
|
|
13717
|
+
object: mesh2,
|
|
13047
13718
|
sync() {
|
|
13048
13719
|
let drawn = false;
|
|
13049
13720
|
for (let index = 0; index < DEBRIS_CAPACITY; index++) {
|
|
13050
13721
|
const piece = pool.pieces[index];
|
|
13051
13722
|
if (!piece.on) {
|
|
13052
|
-
|
|
13723
|
+
mesh2.setMatrixAt(index, hidden);
|
|
13053
13724
|
continue;
|
|
13054
13725
|
}
|
|
13055
13726
|
drawn = true;
|
|
@@ -13057,11 +13728,11 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13057
13728
|
euler.set(piece.rx, piece.ry, piece.rz);
|
|
13058
13729
|
quaternion.setFromEuler(euler);
|
|
13059
13730
|
matrix.compose(position.set(piece.x, piece.y, piece.z), quaternion, scale2.set(piece.sx * shrink, piece.sy * shrink, piece.sz * shrink));
|
|
13060
|
-
|
|
13061
|
-
|
|
13731
|
+
mesh2.setMatrixAt(index, matrix);
|
|
13732
|
+
mesh2.setColorAt(index, colour.setHex(piece.color));
|
|
13062
13733
|
}
|
|
13063
|
-
|
|
13064
|
-
if (
|
|
13734
|
+
mesh2.instanceMatrix.needsUpdate = true;
|
|
13735
|
+
if (mesh2.instanceColor) mesh2.instanceColor.needsUpdate = true;
|
|
13065
13736
|
return drawn;
|
|
13066
13737
|
},
|
|
13067
13738
|
dispose() {
|
|
@@ -13118,11 +13789,11 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13118
13789
|
const dryMesh = new THREE.InstancedMesh(geometry, dry, DECAL_CAPACITY);
|
|
13119
13790
|
const group = new THREE.Group();
|
|
13120
13791
|
group.name = "workshop-decals";
|
|
13121
|
-
for (const
|
|
13122
|
-
|
|
13123
|
-
|
|
13124
|
-
|
|
13125
|
-
group.add(
|
|
13792
|
+
for (const mesh2 of [wetMesh, dryMesh]) {
|
|
13793
|
+
mesh2.frustumCulled = false;
|
|
13794
|
+
mesh2.renderOrder = 1;
|
|
13795
|
+
mesh2.instanceMatrix.setUsage(THREE.DynamicDrawUsage);
|
|
13796
|
+
group.add(mesh2);
|
|
13126
13797
|
}
|
|
13127
13798
|
const hidden = new THREE.Matrix4().makeScale(0, 0, 0);
|
|
13128
13799
|
const colour = new THREE.Color();
|
|
@@ -13159,13 +13830,13 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13159
13830
|
quaternion.multiply(turn.setFromAxisAngle(forward, index * 2.399963));
|
|
13160
13831
|
const offset = 4e-3 + index % 40 * 4e-4;
|
|
13161
13832
|
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
|
-
|
|
13833
|
+
const mesh2 = look.dried ? dryMesh : wetMesh;
|
|
13834
|
+
mesh2.setMatrixAt(index, matrix);
|
|
13835
|
+
mesh2.setColorAt(index, colour);
|
|
13165
13836
|
}
|
|
13166
|
-
for (const
|
|
13167
|
-
|
|
13168
|
-
if (
|
|
13837
|
+
for (const mesh2 of [wetMesh, dryMesh]) {
|
|
13838
|
+
mesh2.instanceMatrix.needsUpdate = true;
|
|
13839
|
+
if (mesh2.instanceColor) mesh2.instanceColor.needsUpdate = true;
|
|
13169
13840
|
}
|
|
13170
13841
|
return drawn;
|
|
13171
13842
|
},
|
|
@@ -13179,10 +13850,10 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13179
13850
|
function ringLayer(THREE, pool) {
|
|
13180
13851
|
const geometry = new THREE.RingGeometry(0.86, 1, 40);
|
|
13181
13852
|
const material = new THREE.MeshBasicMaterial({ color: 16777215, transparent: true, blending: THREE.AdditiveBlending, depthWrite: false, side: THREE.DoubleSide });
|
|
13182
|
-
const
|
|
13183
|
-
|
|
13184
|
-
|
|
13185
|
-
|
|
13853
|
+
const mesh2 = new THREE.InstancedMesh(geometry, material, RING_CAPACITY3);
|
|
13854
|
+
mesh2.frustumCulled = false;
|
|
13855
|
+
mesh2.instanceMatrix.setUsage(THREE.DynamicDrawUsage);
|
|
13856
|
+
mesh2.name = "workshop-rings";
|
|
13186
13857
|
const hidden = new THREE.Matrix4().makeScale(0, 0, 0);
|
|
13187
13858
|
const colour = new THREE.Color();
|
|
13188
13859
|
const normal = new THREE.Vector3();
|
|
@@ -13191,16 +13862,16 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13191
13862
|
const position = new THREE.Vector3();
|
|
13192
13863
|
const scale2 = new THREE.Vector3();
|
|
13193
13864
|
const matrix = new THREE.Matrix4();
|
|
13194
|
-
|
|
13195
|
-
for (let index = 0; index < RING_CAPACITY3; index++)
|
|
13865
|
+
mesh2.setColorAt(0, colour.setHex(0));
|
|
13866
|
+
for (let index = 0; index < RING_CAPACITY3; index++) mesh2.setMatrixAt(index, hidden);
|
|
13196
13867
|
return {
|
|
13197
|
-
object:
|
|
13868
|
+
object: mesh2,
|
|
13198
13869
|
sync() {
|
|
13199
13870
|
let drawn = false;
|
|
13200
13871
|
for (let index = 0; index < RING_CAPACITY3; index++) {
|
|
13201
13872
|
const ring2 = pool.rings[index];
|
|
13202
13873
|
if (!ring2.on) {
|
|
13203
|
-
|
|
13874
|
+
mesh2.setMatrixAt(index, hidden);
|
|
13204
13875
|
continue;
|
|
13205
13876
|
}
|
|
13206
13877
|
drawn = true;
|
|
@@ -13208,11 +13879,11 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13208
13879
|
const radius = ring2.from + (ring2.to - ring2.from) * (1 - Math.pow(1 - k, 2));
|
|
13209
13880
|
quaternion.setFromUnitVectors(forward, normal.set(ring2.normal[0], ring2.normal[1], ring2.normal[2]));
|
|
13210
13881
|
matrix.compose(position.set(ring2.point[0], ring2.point[1], ring2.point[2]), quaternion, scale2.set(radius, radius, 1));
|
|
13211
|
-
|
|
13212
|
-
|
|
13882
|
+
mesh2.setMatrixAt(index, matrix);
|
|
13883
|
+
mesh2.setColorAt(index, colour.setHex(ring2.color).multiplyScalar(ring2.hold ? ring2.hold : 1 - k));
|
|
13213
13884
|
}
|
|
13214
|
-
|
|
13215
|
-
if (
|
|
13885
|
+
mesh2.instanceMatrix.needsUpdate = true;
|
|
13886
|
+
if (mesh2.instanceColor) mesh2.instanceColor.needsUpdate = true;
|
|
13216
13887
|
return drawn;
|
|
13217
13888
|
},
|
|
13218
13889
|
dispose() {
|
|
@@ -13228,11 +13899,14 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13228
13899
|
spriteLayer(THREE, engine.add, true, 1, pointScale),
|
|
13229
13900
|
spriteLayer(THREE, engine.normal, false, 0.55, pointScale),
|
|
13230
13901
|
streakLayer(THREE, engine.streaks),
|
|
13902
|
+
rainLayer(THREE, engine.rain),
|
|
13231
13903
|
debrisLayer(THREE, engine.debris),
|
|
13232
13904
|
decalLayer(THREE, engine.decals),
|
|
13233
13905
|
ringLayer(THREE, engine.rings)
|
|
13234
13906
|
];
|
|
13235
13907
|
for (const layer2 of layers) group.add(layer2.object);
|
|
13908
|
+
const meshes = createMeshLayer(THREE, engine.meshes);
|
|
13909
|
+
group.add(meshes.group);
|
|
13236
13910
|
const flashLights = engine.lights.lights.map(() => new THREE.PointLight(16760944, 0, 14));
|
|
13237
13911
|
const fireLights = engine.lights.fire.map(() => new THREE.PointLight(FIRE_LIGHT_COLOR, 0, FIRE_LIGHT_DISTANCE));
|
|
13238
13912
|
for (const light of [...flashLights, ...fireLights]) group.add(light);
|
|
@@ -13241,6 +13915,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13241
13915
|
sync() {
|
|
13242
13916
|
let drawCalls = 0;
|
|
13243
13917
|
for (const layer2 of layers) if (layer2.sync()) drawCalls++;
|
|
13918
|
+
drawCalls += meshes.sync();
|
|
13244
13919
|
engine.lights.lights.forEach((source, index) => {
|
|
13245
13920
|
const light = flashLights[index];
|
|
13246
13921
|
light.position.set(source.x, source.y, source.z);
|
|
@@ -13257,6 +13932,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13257
13932
|
},
|
|
13258
13933
|
dispose() {
|
|
13259
13934
|
for (const layer2 of layers) layer2.dispose();
|
|
13935
|
+
meshes.dispose();
|
|
13260
13936
|
group.clear();
|
|
13261
13937
|
}
|
|
13262
13938
|
};
|
|
@@ -13372,8 +14048,10 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13372
14048
|
return world.play(request.effect, request.point, {
|
|
13373
14049
|
...request.direction ? { direction: request.direction } : {},
|
|
13374
14050
|
...request.normal ? { normal: request.normal } : {},
|
|
14051
|
+
...request.orientation ? { orientation: request.orientation } : {},
|
|
13375
14052
|
...request.seed !== void 0 ? { seed: request.seed } : {},
|
|
13376
|
-
...request.param !== void 0 ? { param: request.param } : {}
|
|
14053
|
+
...request.param !== void 0 ? { param: request.param } : {},
|
|
14054
|
+
...request.values ? { values: request.values } : {}
|
|
13377
14055
|
});
|
|
13378
14056
|
},
|
|
13379
14057
|
stop: (handle) => world.stop(handle),
|
|
@@ -13438,8 +14116,8 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13438
14116
|
const uv = geometry.attributes.uv;
|
|
13439
14117
|
for (let index = 0; index < position.count; index++) uv.setXY(index, position.getX(index) / metres, position.getZ(index) / metres);
|
|
13440
14118
|
const material = options.material ?? new THREE.MeshStandardMaterial({ color: 2829359, roughness: 0.93, flatShading: true });
|
|
13441
|
-
const
|
|
13442
|
-
|
|
14119
|
+
const mesh2 = new THREE.Mesh(geometry, material);
|
|
14120
|
+
mesh2.receiveShadow = true;
|
|
13443
14121
|
let version = -1;
|
|
13444
14122
|
function sync() {
|
|
13445
14123
|
if (field.version === version) return false;
|
|
@@ -13450,7 +14128,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13450
14128
|
return true;
|
|
13451
14129
|
}
|
|
13452
14130
|
return {
|
|
13453
|
-
mesh,
|
|
14131
|
+
mesh: mesh2,
|
|
13454
14132
|
sync,
|
|
13455
14133
|
dispose() {
|
|
13456
14134
|
geometry.dispose();
|
|
@@ -13564,11 +14242,11 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13564
14242
|
* 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
14243
|
* 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
14244
|
*/
|
|
13567
|
-
addMarks(
|
|
14245
|
+
addMarks(mesh2, f) {
|
|
13568
14246
|
if (!f.marks?.length) return;
|
|
13569
14247
|
this.markGeometry ?? (this.markGeometry = new this.THREE.CircleGeometry(1, 10));
|
|
13570
14248
|
this.markMaterial ?? (this.markMaterial = new this.THREE.MeshBasicMaterial({ color: 723465, depthWrite: false, polygonOffset: true, polygonOffsetFactor: -4, polygonOffsetUnits: -4 }));
|
|
13571
|
-
const sc =
|
|
14249
|
+
const sc = mesh2.scale;
|
|
13572
14250
|
for (const mark of f.marks) {
|
|
13573
14251
|
const disc = new this.THREE.Mesh(this.markGeometry, this.markMaterial);
|
|
13574
14252
|
const radius = Math.max(4e-3, mark.diameter) * 0.6;
|
|
@@ -13576,22 +14254,22 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13576
14254
|
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
14255
|
disc.quaternion.setFromUnitVectors(this.w.set(0, 0, 1), n);
|
|
13578
14256
|
disc.scale.set(radius / sc.x, radius / sc.y, radius / sc.z);
|
|
13579
|
-
|
|
14257
|
+
mesh2.add(disc);
|
|
13580
14258
|
}
|
|
13581
14259
|
}
|
|
13582
14260
|
/** Create the mesh of a fragment and start its motion. `maxAllowed` is the live budget. */
|
|
13583
14261
|
spawn(f, material, home, maxAllowed) {
|
|
13584
14262
|
const geo = f.shape === "shard" ? this.shardGeometry(hashString(f.id)) : this.box;
|
|
13585
|
-
const
|
|
13586
|
-
|
|
13587
|
-
|
|
14263
|
+
const mesh2 = new this.THREE.Mesh(geo, material);
|
|
14264
|
+
mesh2.position.set(f.center[0], f.center[1], f.center[2]);
|
|
14265
|
+
mesh2.quaternion.set(f.rotation[0], f.rotation[1], f.rotation[2], f.rotation[3]).normalize();
|
|
13588
14266
|
const sz = f.size;
|
|
13589
14267
|
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(
|
|
14268
|
+
mesh2.scale.copy(sc);
|
|
14269
|
+
mesh2.castShadow = true;
|
|
14270
|
+
this.o.scene.add(mesh2);
|
|
13593
14271
|
const live = {
|
|
13594
|
-
mesh,
|
|
14272
|
+
mesh: mesh2,
|
|
13595
14273
|
home,
|
|
13596
14274
|
vel: new this.THREE.Vector3(f.velocity[0], f.velocity[1], f.velocity[2]),
|
|
13597
14275
|
ang: new this.THREE.Vector3(f.angularVelocity[0], f.angularVelocity[1], f.angularVelocity[2]),
|
|
@@ -13612,8 +14290,8 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13612
14290
|
alive--;
|
|
13613
14291
|
}
|
|
13614
14292
|
}
|
|
13615
|
-
this.addMarks(
|
|
13616
|
-
return
|
|
14293
|
+
this.addMarks(mesh2, f);
|
|
14294
|
+
return mesh2;
|
|
13617
14295
|
}
|
|
13618
14296
|
/** Add velocity to every fragment within `radius` of a point (blasts). */
|
|
13619
14297
|
blast(point, radius, speed) {
|
|
@@ -13652,24 +14330,24 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13652
14330
|
}
|
|
13653
14331
|
}
|
|
13654
14332
|
step(f, dt, g) {
|
|
13655
|
-
const
|
|
14333
|
+
const mesh2 = f.mesh;
|
|
13656
14334
|
f.vel.y -= g * dt;
|
|
13657
|
-
|
|
14335
|
+
mesh2.position.addScaledVector(f.vel, dt);
|
|
13658
14336
|
const w = f.ang.length();
|
|
13659
14337
|
if (w > 1e-5) {
|
|
13660
14338
|
this.dq.setFromAxisAngle(this.v.copy(f.ang).multiplyScalar(1 / w), w * dt);
|
|
13661
|
-
|
|
14339
|
+
mesh2.quaternion.premultiply(this.dq).normalize();
|
|
13662
14340
|
}
|
|
13663
|
-
this.m.makeRotationFromQuaternion(
|
|
14341
|
+
this.m.makeRotationFromQuaternion(mesh2.quaternion);
|
|
13664
14342
|
const e = this.m.elements;
|
|
13665
14343
|
const h = f.half;
|
|
13666
14344
|
const sc = f.dying ? f.fade : 1;
|
|
13667
14345
|
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(
|
|
14346
|
+
const gy = this.o.groundAt(mesh2.position.x, mesh2.position.z);
|
|
13669
14347
|
let contact = false;
|
|
13670
|
-
if (
|
|
14348
|
+
if (mesh2.position.y - ext < gy) {
|
|
13671
14349
|
contact = true;
|
|
13672
|
-
|
|
14350
|
+
mesh2.position.y = gy + ext;
|
|
13673
14351
|
if (f.vel.y < -0.6) {
|
|
13674
14352
|
f.vel.y = -f.vel.y * 0.25;
|
|
13675
14353
|
f.vel.x *= 0.7;
|
|
@@ -13702,8 +14380,8 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13702
14380
|
}
|
|
13703
14381
|
/** Tip the fragment towards lying on its flattest face. */
|
|
13704
14382
|
settle(f, dt) {
|
|
13705
|
-
const
|
|
13706
|
-
this.m.makeRotationFromQuaternion(
|
|
14383
|
+
const mesh2 = f.mesh;
|
|
14384
|
+
this.m.makeRotationFromQuaternion(mesh2.quaternion);
|
|
13707
14385
|
const e = this.m.elements;
|
|
13708
14386
|
const up = [e[1], e[5], e[9]];
|
|
13709
14387
|
const half = [f.half.x, f.half.y, f.half.z];
|
|
@@ -13718,8 +14396,8 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13718
14396
|
this.v.set(e[axis2 * 4], e[axis2 * 4 + 1], e[axis2 * 4 + 2]).multiplyScalar(sign);
|
|
13719
14397
|
this.w.set(0, 1, 0);
|
|
13720
14398
|
this.dq.setFromUnitVectors(this.v, this.w);
|
|
13721
|
-
this.q.copy(this.dq).multiply(
|
|
13722
|
-
|
|
14399
|
+
this.q.copy(this.dq).multiply(mesh2.quaternion);
|
|
14400
|
+
mesh2.quaternion.slerp(this.q, clamp6(dt * 7, 0, 1));
|
|
13723
14401
|
}
|
|
13724
14402
|
/** Remove the fragments of one object (after `restore`). */
|
|
13725
14403
|
removeHome(home) {
|
|
@@ -13789,13 +14467,13 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13789
14467
|
}
|
|
13790
14468
|
}
|
|
13791
14469
|
while (this.spots.length >= this.cap) this.remove(this.spots[0]);
|
|
13792
|
-
const
|
|
14470
|
+
const mesh2 = new this.THREE.Mesh(this.geometry, this.material(kind, color));
|
|
13793
14471
|
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) });
|
|
14472
|
+
mesh2.position.set(x, y, z);
|
|
14473
|
+
mesh2.scale.setScalar(1e-3);
|
|
14474
|
+
mesh2.renderOrder = 1;
|
|
14475
|
+
this.scene.add(mesh2);
|
|
14476
|
+
this.spots.push({ mesh: mesh2, kind, home, x, z, radius: 1e-3, target: Math.min(MAX_RADIUS, radius) });
|
|
13799
14477
|
}
|
|
13800
14478
|
remove(s) {
|
|
13801
14479
|
const i = this.spots.indexOf(s);
|
|
@@ -14171,7 +14849,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
14171
14849
|
/** Bars drawn now, over every part. */
|
|
14172
14850
|
get count() {
|
|
14173
14851
|
let n = 0;
|
|
14174
|
-
for (const
|
|
14852
|
+
for (const mesh2 of this.cages.values()) n += mesh2.count;
|
|
14175
14853
|
return n;
|
|
14176
14854
|
}
|
|
14177
14855
|
/** Meshes of the live cages (tests and picking). */
|
|
@@ -14182,25 +14860,25 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
14182
14860
|
set(key, bars) {
|
|
14183
14861
|
this.remove(key);
|
|
14184
14862
|
if (bars.length === 0) return;
|
|
14185
|
-
const
|
|
14863
|
+
const mesh2 = new this.THREE.InstancedMesh(this.geometry, this.material, bars.length);
|
|
14186
14864
|
bars.forEach(([a, b], i) => {
|
|
14187
14865
|
this.dir.set(b[0] - a[0], b[1] - a[1], b[2] - a[2]);
|
|
14188
14866
|
const length3 = this.dir.length();
|
|
14189
14867
|
this.mid.set((a[0] + b[0]) / 2, (a[1] + b[1]) / 2, (a[2] + b[2]) / 2);
|
|
14190
14868
|
this.q.setFromUnitVectors(this.up, length3 > 1e-9 ? this.dir.divideScalar(length3) : this.up);
|
|
14191
14869
|
this.m.compose(this.mid, this.q, this.scale.set(1, Math.max(length3, 1e-4), 1));
|
|
14192
|
-
|
|
14870
|
+
mesh2.setMatrixAt(i, this.m);
|
|
14193
14871
|
});
|
|
14194
|
-
|
|
14195
|
-
|
|
14196
|
-
this.scene.add(
|
|
14197
|
-
this.cages.set(key,
|
|
14872
|
+
mesh2.instanceMatrix.needsUpdate = true;
|
|
14873
|
+
mesh2.castShadow = true;
|
|
14874
|
+
this.scene.add(mesh2);
|
|
14875
|
+
this.cages.set(key, mesh2);
|
|
14198
14876
|
}
|
|
14199
14877
|
remove(key) {
|
|
14200
|
-
const
|
|
14201
|
-
if (!
|
|
14202
|
-
this.scene.remove(
|
|
14203
|
-
|
|
14878
|
+
const mesh2 = this.cages.get(key);
|
|
14879
|
+
if (!mesh2) return;
|
|
14880
|
+
this.scene.remove(mesh2);
|
|
14881
|
+
mesh2.dispose();
|
|
14204
14882
|
this.cages.delete(key);
|
|
14205
14883
|
}
|
|
14206
14884
|
/** Remove the cages of every part of `object` (keys are `object|part`). */
|
|
@@ -14484,25 +15162,25 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
14484
15162
|
/**
|
|
14485
15163
|
* @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
15164
|
*/
|
|
14487
|
-
makeMeshVis(
|
|
15165
|
+
makeMeshVis(mesh2, home, range2, hosts) {
|
|
14488
15166
|
let host = null;
|
|
14489
15167
|
if (range2) {
|
|
14490
|
-
host = hosts?.get(
|
|
15168
|
+
host = hosts?.get(mesh2) ?? null;
|
|
14491
15169
|
if (!host) {
|
|
14492
|
-
host = { mesh, origGeometry:
|
|
14493
|
-
hosts?.set(
|
|
15170
|
+
host = { mesh: mesh2, origGeometry: mesh2.geometry, origMaterial: mesh2.material, ownGeo: false, work: null, ownMat: false, sharers: [] };
|
|
15171
|
+
hosts?.set(mesh2, host);
|
|
14494
15172
|
}
|
|
14495
15173
|
}
|
|
14496
15174
|
const mv = {
|
|
14497
|
-
mesh,
|
|
15175
|
+
mesh: mesh2,
|
|
14498
15176
|
home,
|
|
14499
|
-
origGeometry:
|
|
14500
|
-
origMaterial:
|
|
14501
|
-
origVisible:
|
|
14502
|
-
origParent:
|
|
14503
|
-
origPosition:
|
|
14504
|
-
origQuaternion:
|
|
14505
|
-
origScale:
|
|
15177
|
+
origGeometry: mesh2.geometry,
|
|
15178
|
+
origMaterial: mesh2.material,
|
|
15179
|
+
origVisible: mesh2.visible,
|
|
15180
|
+
origParent: mesh2.parent,
|
|
15181
|
+
origPosition: mesh2.position.clone(),
|
|
15182
|
+
origQuaternion: mesh2.quaternion.clone(),
|
|
15183
|
+
origScale: mesh2.scale.clone(),
|
|
14506
15184
|
ownMat: false,
|
|
14507
15185
|
ownGeo: false,
|
|
14508
15186
|
work: null,
|
|
@@ -14627,15 +15305,15 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
14627
15305
|
* Returns false when nothing was changed (too far, low quality on a heavy mesh, or no editable positions).
|
|
14628
15306
|
*/
|
|
14629
15307
|
applyDent(mv, worldPoint, worldNormal, dent) {
|
|
14630
|
-
const
|
|
15308
|
+
const mesh2 = mv.mesh;
|
|
14631
15309
|
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(
|
|
15310
|
+
mesh2.updateWorldMatrix(true, false);
|
|
15311
|
+
const s = mesh2.matrixWorld.getMaxScaleOnAxis() || 1;
|
|
15312
|
+
const lp = mesh2.worldToLocal(this.a.copy(worldPoint));
|
|
15313
|
+
const ln = this.b.copy(worldNormal).transformDirection(this.m4.copy(mesh2.matrixWorld).invert()).normalize();
|
|
14636
15314
|
const r = dent.radius / s;
|
|
14637
15315
|
const depth = dent.depth / s;
|
|
14638
|
-
const geo =
|
|
15316
|
+
const geo = mesh2.geometry;
|
|
14639
15317
|
let bb;
|
|
14640
15318
|
if (mv.host) bb = this.localBox(mv, this.lbox);
|
|
14641
15319
|
else {
|
|
@@ -14645,7 +15323,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
14645
15323
|
if (bb && !bb.isEmpty() && bb.distanceToPoint(lp) > r) return false;
|
|
14646
15324
|
if (!this.ownGeometry(mv)) return false;
|
|
14647
15325
|
const work = mv.host ? mv.host.work : mv.work;
|
|
14648
|
-
const pos = positionAttr(
|
|
15326
|
+
const pos = positionAttr(mesh2.geometry);
|
|
14649
15327
|
const r2 = r * r;
|
|
14650
15328
|
let touched = false;
|
|
14651
15329
|
const px = lp.x;
|
|
@@ -14711,11 +15389,11 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
14711
15389
|
// Decals
|
|
14712
15390
|
// ------------------------------------------------------------------------------------------------------------------------------------
|
|
14713
15391
|
/** 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 =
|
|
15392
|
+
decalPose(mesh2, worldPoint, worldNormal, lift) {
|
|
15393
|
+
mesh2.updateWorldMatrix(true, false);
|
|
15394
|
+
const s = mesh2.matrixWorld.getMaxScaleOnAxis() || 1;
|
|
15395
|
+
const ln = worldNormal.clone().transformDirection(this.m4.copy(mesh2.matrixWorld).invert()).normalize();
|
|
15396
|
+
const pos = mesh2.worldToLocal(worldPoint.clone()).addScaledVector(ln, lift / s);
|
|
14719
15397
|
const quat2 = new this.THREE.Quaternion().setFromUnitVectors(new this.THREE.Vector3(0, 0, 1), ln);
|
|
14720
15398
|
return { s, pos, quat: quat2 };
|
|
14721
15399
|
}
|
|
@@ -14851,7 +15529,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
14851
15529
|
if (Math.abs(m - pv.meltApplied) < 0.01) return;
|
|
14852
15530
|
pv.meltApplied = m;
|
|
14853
15531
|
for (const mv of pv.meshes) {
|
|
14854
|
-
const
|
|
15532
|
+
const mesh2 = mv.mesh;
|
|
14855
15533
|
if (mv.host) {
|
|
14856
15534
|
mv.meltApplied = m;
|
|
14857
15535
|
mv.touched = true;
|
|
@@ -14859,27 +15537,27 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
14859
15537
|
continue;
|
|
14860
15538
|
}
|
|
14861
15539
|
if (mv.meltApplied === 0 && m > 0) {
|
|
14862
|
-
|
|
14863
|
-
mv.bottomY = this.box.setFromObject(
|
|
15540
|
+
mesh2.updateWorldMatrix(true, false);
|
|
15541
|
+
mv.bottomY = this.box.setFromObject(mesh2).min.y;
|
|
14864
15542
|
}
|
|
14865
15543
|
mv.meltApplied = m;
|
|
14866
15544
|
mv.moved = true;
|
|
14867
15545
|
const sy = lerp5(1, 0.25, m);
|
|
14868
15546
|
const sxz = 1 + 0.18 * m;
|
|
14869
|
-
|
|
14870
|
-
|
|
14871
|
-
|
|
14872
|
-
const bottom = this.box.setFromObject(
|
|
15547
|
+
mesh2.scale.set(mv.origScale.x * sxz, mv.origScale.y * sy, mv.origScale.z * sxz);
|
|
15548
|
+
mesh2.position.copy(mv.origPosition);
|
|
15549
|
+
mesh2.updateWorldMatrix(true, false);
|
|
15550
|
+
const bottom = this.box.setFromObject(mesh2).min.y;
|
|
14873
15551
|
const dy = mv.bottomY - bottom;
|
|
14874
|
-
if (Math.abs(dy) > 1e-6 &&
|
|
14875
|
-
|
|
14876
|
-
const inv = this.m4.copy(
|
|
15552
|
+
if (Math.abs(dy) > 1e-6 && mesh2.parent) {
|
|
15553
|
+
mesh2.parent.updateWorldMatrix(true, false);
|
|
15554
|
+
const inv = this.m4.copy(mesh2.parent.matrixWorld).invert();
|
|
14877
15555
|
this.a.set(0, dy, 0).applyMatrix4(inv);
|
|
14878
15556
|
this.b.set(0, 0, 0).applyMatrix4(inv);
|
|
14879
|
-
|
|
15557
|
+
mesh2.position.copy(mv.origPosition).add(this.a.sub(this.b));
|
|
14880
15558
|
}
|
|
14881
15559
|
if (!(this.lowQuality && this.vertexCount(mv) > 2e4) && this.ownGeometry(mv)) {
|
|
14882
|
-
this.writePositions(mv, positionAttr(
|
|
15560
|
+
this.writePositions(mv, positionAttr(mesh2.geometry));
|
|
14883
15561
|
}
|
|
14884
15562
|
}
|
|
14885
15563
|
}
|
|
@@ -15152,30 +15830,30 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
15152
15830
|
this.restoreRanged(mv);
|
|
15153
15831
|
return;
|
|
15154
15832
|
}
|
|
15155
|
-
const
|
|
15833
|
+
const mesh2 = mv.mesh;
|
|
15156
15834
|
for (const d of mv.decals) this.disposeDecal(d);
|
|
15157
15835
|
mv.decals.length = 0;
|
|
15158
15836
|
if (mv.ownGeo) {
|
|
15159
|
-
|
|
15160
|
-
|
|
15837
|
+
mesh2.geometry.dispose();
|
|
15838
|
+
mesh2.geometry = mv.origGeometry;
|
|
15161
15839
|
mv.ownGeo = false;
|
|
15162
15840
|
mv.work = null;
|
|
15163
15841
|
}
|
|
15164
15842
|
if (mv.ownMat) {
|
|
15165
|
-
for (const m of materialsOf(
|
|
15166
|
-
|
|
15843
|
+
for (const m of materialsOf(mesh2.material)) m.dispose();
|
|
15844
|
+
mesh2.material = mv.origMaterial;
|
|
15167
15845
|
mv.ownMat = false;
|
|
15168
15846
|
mv.baseColors = null;
|
|
15169
15847
|
}
|
|
15170
|
-
|
|
15171
|
-
if (mv.origParent &&
|
|
15172
|
-
mv.origParent.add(
|
|
15848
|
+
mesh2.visible = mv.origVisible;
|
|
15849
|
+
if (mv.origParent && mesh2.parent !== mv.origParent) {
|
|
15850
|
+
mv.origParent.add(mesh2);
|
|
15173
15851
|
mv.moved = true;
|
|
15174
15852
|
}
|
|
15175
15853
|
if (mv.moved) {
|
|
15176
|
-
|
|
15177
|
-
|
|
15178
|
-
|
|
15854
|
+
mesh2.position.copy(mv.origPosition);
|
|
15855
|
+
mesh2.quaternion.copy(mv.origQuaternion);
|
|
15856
|
+
mesh2.scale.copy(mv.origScale);
|
|
15179
15857
|
mv.moved = false;
|
|
15180
15858
|
}
|
|
15181
15859
|
mv.meltApplied = 0;
|
|
@@ -16223,88 +16901,42 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
16223
16901
|
this.disposed = true;
|
|
16224
16902
|
}
|
|
16225
16903
|
};
|
|
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
|
-
});
|
|
16904
|
+
var scene = (id, layers, line, vars) => sceneRecipe(id, layers, line, vars ? { vars } : {});
|
|
16273
16905
|
var boomLayers = (big) => [
|
|
16274
|
-
|
|
16275
|
-
|
|
16276
|
-
|
|
16277
|
-
...big ? [
|
|
16278
|
-
...
|
|
16906
|
+
sceneNoise({ f: 1200, f2: 120, d: 1.8, vol: 2, wet: 1.2 }),
|
|
16907
|
+
sceneTone({ f: 65, f2: 24, d: 1, vol: 1.8 }),
|
|
16908
|
+
sceneNoise({ type: "highpass", f: 1500, d: 0.2, vol: 0.8 }),
|
|
16909
|
+
...big ? [sceneNoise({ f: 500, f2: 90, a: 0.2, d: 2.4, vol: 1.2, wet: 1, delay: 0.15 })] : [],
|
|
16910
|
+
...sceneMany(8, () => sceneTone({ f: [2600, 5600], d: 0.05, vol: 0.08, delay: [0.4, 1.6] }))
|
|
16279
16911
|
];
|
|
16280
16912
|
var SCENE_SOUNDS = [
|
|
16281
16913
|
scene(
|
|
16282
16914
|
"glass_shatter",
|
|
16283
|
-
[
|
|
16915
|
+
[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
16916
|
"L1359 glass"
|
|
16285
16917
|
),
|
|
16286
16918
|
scene(
|
|
16287
16919
|
"wood_hit",
|
|
16288
|
-
[
|
|
16920
|
+
[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
16921
|
"L1360 wood"
|
|
16290
16922
|
),
|
|
16291
|
-
scene("thunk", [
|
|
16292
|
-
scene("ping", [
|
|
16293
|
-
scene("clang", [
|
|
16294
|
-
scene("chip", [
|
|
16923
|
+
scene("thunk", [sceneNoise({ type: "bandpass", f: 700, q: 2, d: 0.07, vol: 0.4 })], "L1361 thunk"),
|
|
16924
|
+
scene("ping", [sceneTone({ f: [2600, 3500], f2: 1400, d: 0.14, vol: 0.18, wet: 0.3 })], "L1362 ping"),
|
|
16925
|
+
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"),
|
|
16926
|
+
scene("chip", [sceneNoise({ type: "bandpass", f: 1600, q: 1.2, d: 0.06, vol: 0.5 })], "L1364 chip"),
|
|
16295
16927
|
scene(
|
|
16296
16928
|
"crumble",
|
|
16297
|
-
[
|
|
16929
|
+
[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
16930
|
"L1365 crumble"
|
|
16299
16931
|
),
|
|
16300
16932
|
// `thud(x, z, v)`: `v` is the `scale` param (default 1)
|
|
16301
|
-
scene("thud", [
|
|
16933
|
+
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
16934
|
// `hiss(x, z, d)`: `seconds` is the param `d` (default 1.2)
|
|
16303
|
-
scene("hiss", [
|
|
16935
|
+
scene("hiss", [sceneNoise({ type: "highpass", f: 3500, a: 0.05, d: { param: "seconds" }, vol: 0.35 })], "L1366 hiss", { seconds: 1.2 }),
|
|
16304
16936
|
scene("boom", boomLayers(false), "L1367 boom"),
|
|
16305
16937
|
scene("boom_big", boomLayers(true), "L1367 boom (big)"),
|
|
16306
|
-
scene("burst", [
|
|
16307
|
-
scene("crack", [
|
|
16938
|
+
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"),
|
|
16939
|
+
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
16940
|
];
|
|
16309
16941
|
var EXPLOSION_BOOM = {
|
|
16310
16942
|
id: "explosion_boom",
|
|
@@ -32046,7 +32678,7 @@ ${problems.map((problem) => ` - ${problem}`).join("\n")}`);
|
|
|
32046
32678
|
if (lastRow < 0) return;
|
|
32047
32679
|
const profile = profileOf2();
|
|
32048
32680
|
const rainScale = 1 - options.weather().rain;
|
|
32049
|
-
const seconds = dryingSeconds * rainScale;
|
|
32681
|
+
const seconds = dryingSeconds * rainScale * (options.weather().drying ?? 1);
|
|
32050
32682
|
for (let row = firstRow; row <= lastRow; row++) {
|
|
32051
32683
|
const offset = row * width;
|
|
32052
32684
|
for (let column = firstColumn; column <= lastColumn; column++) {
|
|
@@ -32170,6 +32802,7 @@ ${problems.map((problem) => ` - ${problem}`).join("\n")}`);
|
|
|
32170
32802
|
}
|
|
32171
32803
|
var DEFAULT_STEP_RATE = 180;
|
|
32172
32804
|
var DEFAULT_MAX_STEPS = 6;
|
|
32805
|
+
var WASH_BELOW_DRYNESS = 0.5;
|
|
32173
32806
|
function createFilm(options) {
|
|
32174
32807
|
const { layout, random } = options;
|
|
32175
32808
|
const cellCount = layout.width * layout.height;
|
|
@@ -32180,7 +32813,7 @@ ${problems.map((problem) => ` - ${problem}`).join("\n")}`);
|
|
|
32180
32813
|
dryness: new Float32Array(cellCount),
|
|
32181
32814
|
dampness: new Float32Array(cellCount)
|
|
32182
32815
|
};
|
|
32183
|
-
let weatherState = { rain: 0 };
|
|
32816
|
+
let weatherState = { rain: 0, drying: 1 };
|
|
32184
32817
|
let currentProfile = options.profile;
|
|
32185
32818
|
const context = { field, random, profile: () => currentProfile };
|
|
32186
32819
|
const drops = createDropPool(layout, context);
|
|
@@ -32218,9 +32851,29 @@ ${problems.map((problem) => ` - ${problem}`).join("\n")}`);
|
|
|
32218
32851
|
simulator.advance({ dt, dryingSeconds });
|
|
32219
32852
|
},
|
|
32220
32853
|
setWeather(weather) {
|
|
32221
|
-
weatherState = {
|
|
32854
|
+
weatherState = {
|
|
32855
|
+
rain: Math.min(1, Math.max(0, weather.rain ?? weatherState.rain)),
|
|
32856
|
+
drying: Math.max(0, weather.drying ?? weatherState.drying ?? 1)
|
|
32857
|
+
};
|
|
32222
32858
|
},
|
|
32223
32859
|
weather: () => ({ ...weatherState }),
|
|
32860
|
+
wash(maxDryness = WASH_BELOW_DRYNESS) {
|
|
32861
|
+
simulator.refreshBounds();
|
|
32862
|
+
const { firstRow, lastRow, firstColumn, lastColumn } = simulator.bounds;
|
|
32863
|
+
let cleared = 0;
|
|
32864
|
+
for (let row = firstRow; row <= lastRow; row++) {
|
|
32865
|
+
for (let column = firstColumn; column <= lastColumn; column++) {
|
|
32866
|
+
const index = row * layout.width + column;
|
|
32867
|
+
if (field.thickness[index] > 0 && field.dryness[index] < maxDryness) {
|
|
32868
|
+
field.thickness[index] = 0;
|
|
32869
|
+
field.dryness[index] = 0;
|
|
32870
|
+
field.dampness[index] = 0;
|
|
32871
|
+
cleared++;
|
|
32872
|
+
}
|
|
32873
|
+
}
|
|
32874
|
+
}
|
|
32875
|
+
return cleared;
|
|
32876
|
+
},
|
|
32224
32877
|
clear() {
|
|
32225
32878
|
field.thickness.fill(0);
|
|
32226
32879
|
field.dryness.fill(0);
|
|
@@ -32324,8 +32977,8 @@ ${problems.map((problem) => ` - ${problem}`).join("\n")}`);
|
|
|
32324
32977
|
bedHeight = roadY * 1e3 + z * 14 - (x - params.roadSlopeAnchorX) * 5;
|
|
32325
32978
|
roughness = 0.55;
|
|
32326
32979
|
}
|
|
32327
|
-
const
|
|
32328
|
-
bed[index] = bedHeight + (
|
|
32980
|
+
const noise = valueNoise(column * 0.35, row * 0.35) * 0.6 + valueNoise(column * 1.3, row * 1.3) * 0.4;
|
|
32981
|
+
bed[index] = bedHeight + (noise - 0.5) * roughness * 2;
|
|
32329
32982
|
vertical[index] = region === 0 || region === 2 ? 0.95 : 1;
|
|
32330
32983
|
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
32984
|
}
|
|
@@ -32482,8 +33135,8 @@ ${problems.map((problem) => ` - ${problem}`).join("\n")}`);
|
|
|
32482
33135
|
for (let column = 0; column < columns; column++) {
|
|
32483
33136
|
const index = (region.firstRow + row) * columns + column;
|
|
32484
33137
|
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 + (
|
|
33138
|
+
const noise = valueNoise(column * 0.35, (region.firstRow + row) * 0.35) * 0.6 + valueNoise(column * 1.3, (region.firstRow + row) * 1.3) * 0.4;
|
|
33139
|
+
bed[index] = centre[1] * 1e3 + (noise - 0.5) * strip.roughness * 2;
|
|
32487
33140
|
vertical[index] = region.isVertical ? 0.95 : 1;
|
|
32488
33141
|
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
33142
|
}
|
|
@@ -33150,11 +33803,11 @@ ${problems.map((problem) => ` - ${problem}`).join("\n")}`);
|
|
|
33150
33803
|
const index = [];
|
|
33151
33804
|
for (let i = 0; i < this.ring; i++) index.push(0, 1 + i, 1 + (i + 1) % this.ring);
|
|
33152
33805
|
geometry.setIndex(index);
|
|
33153
|
-
const
|
|
33154
|
-
|
|
33155
|
-
|
|
33156
|
-
|
|
33157
|
-
return { mesh, position, color };
|
|
33806
|
+
const mesh2 = new T.Mesh(geometry);
|
|
33807
|
+
mesh2.name = name;
|
|
33808
|
+
mesh2.frustumCulled = false;
|
|
33809
|
+
mesh2.renderOrder = order;
|
|
33810
|
+
return { mesh: mesh2, position, color };
|
|
33158
33811
|
}
|
|
33159
33812
|
assign(def, materials) {
|
|
33160
33813
|
this.outer.mesh.material = materials.stainFilm(def);
|
|
@@ -33877,12 +34530,12 @@ void main(){
|
|
|
33877
34530
|
this.group = new THREE.Group();
|
|
33878
34531
|
this.group.name = "film_grid";
|
|
33879
34532
|
for (const region of layout.regions) {
|
|
33880
|
-
const
|
|
33881
|
-
|
|
33882
|
-
|
|
33883
|
-
|
|
33884
|
-
this.strips.push(
|
|
33885
|
-
this.group.add(
|
|
34533
|
+
const mesh2 = new THREE.Mesh(createStripGeometry(THREE, layout, region), this.material.material);
|
|
34534
|
+
mesh2.frustumCulled = false;
|
|
34535
|
+
mesh2.renderOrder = 3;
|
|
34536
|
+
mesh2.name = `film_${region.id}`;
|
|
34537
|
+
this.strips.push(mesh2);
|
|
34538
|
+
this.group.add(mesh2);
|
|
33886
34539
|
}
|
|
33887
34540
|
this.dropsView = createFilmDrops(THREE, layout.rules.dropCapacity, profile);
|
|
33888
34541
|
this.group.add(this.dropsView.drops, this.dropsView.bead);
|
|
@@ -33927,6 +34580,19 @@ void main(){
|
|
|
33927
34580
|
this.pending = this.union(this.pending, rect);
|
|
33928
34581
|
return this.takePending();
|
|
33929
34582
|
}
|
|
34583
|
+
/** Clears the cells less than `maxDryness` dry and sends the rectangle that held them up with the next update. Returns how many it cleared. */
|
|
34584
|
+
wash(maxDryness) {
|
|
34585
|
+
const cleared = this.film.wash(maxDryness);
|
|
34586
|
+
if (cleared > 0) {
|
|
34587
|
+
const bounds = this.film.simulator.bounds;
|
|
34588
|
+
if (bounds.lastRow >= 0) {
|
|
34589
|
+
const rect = { firstRow: bounds.firstRow, lastRow: bounds.lastRow, firstColumn: bounds.firstColumn, lastColumn: bounds.lastColumn };
|
|
34590
|
+
this.encode(rect);
|
|
34591
|
+
this.pending = this.union(this.pending, rect);
|
|
34592
|
+
}
|
|
34593
|
+
}
|
|
34594
|
+
return cleared;
|
|
34595
|
+
}
|
|
33930
34596
|
takePending() {
|
|
33931
34597
|
const rect = this.pending;
|
|
33932
34598
|
this.pending = null;
|
|
@@ -33982,7 +34648,7 @@ void main(){
|
|
|
33982
34648
|
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
34649
|
}
|
|
33984
34650
|
dispose() {
|
|
33985
|
-
for (const
|
|
34651
|
+
for (const mesh2 of this.strips) mesh2.geometry.dispose();
|
|
33986
34652
|
this.material.dispose();
|
|
33987
34653
|
this.dropsView.dispose();
|
|
33988
34654
|
this.texture.dispose();
|
|
@@ -33996,11 +34662,12 @@ void main(){
|
|
|
33996
34662
|
var DEFAULT_GRID_METRES = 2;
|
|
33997
34663
|
var DEFAULT_CELL2 = 0.0125;
|
|
33998
34664
|
var BAKE_RANGE_FACTOR = 1.25;
|
|
34665
|
+
var DEFAULT_WASHABLE = ["blood", "old_blood"];
|
|
33999
34666
|
var EDGE_MARGIN = 0.35;
|
|
34000
34667
|
var FLOOR_REACH = 0.3;
|
|
34001
34668
|
var DROP_HEIGHT = 2.5;
|
|
34002
34669
|
var DEFAULT_DROP_RADIUS = 3;
|
|
34003
|
-
var
|
|
34670
|
+
var FALL_SPEED2 = 2;
|
|
34004
34671
|
var VISIBLE_THICKNESS22 = 0.035;
|
|
34005
34672
|
var DEFAULT_HALF = 50;
|
|
34006
34673
|
var FREE_AFTER_EMPTY = 2;
|
|
@@ -34021,6 +34688,7 @@ void main(){
|
|
|
34021
34688
|
__publicField5(this, "staging", /* @__PURE__ */ new Map());
|
|
34022
34689
|
__publicField5(this, "now");
|
|
34023
34690
|
__publicField5(this, "rain", 0);
|
|
34691
|
+
__publicField5(this, "drying", 1);
|
|
34024
34692
|
__publicField5(this, "time", 0);
|
|
34025
34693
|
__publicField5(this, "bakedCount", 0);
|
|
34026
34694
|
__publicField5(this, "last", { grids: 0, drops: 0, wetCells: 0, simMs: 0, starved: 0, baked: 0, uploadedTexels: 0 });
|
|
@@ -34040,13 +34708,24 @@ void main(){
|
|
|
34040
34708
|
}
|
|
34041
34709
|
setWeather(weather) {
|
|
34042
34710
|
this.rain = Math.min(1, Math.max(0, weather.rain));
|
|
34043
|
-
|
|
34711
|
+
if (weather.drying !== void 0) this.drying = Math.max(0, weather.drying);
|
|
34712
|
+
for (const grid of this.grids) grid.film.setWeather({ rain: this.rain, drying: this.drying });
|
|
34713
|
+
}
|
|
34714
|
+
/**
|
|
34715
|
+
* 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
|
|
34716
|
+
* cells that are less than `maxDryness` dry (default 0.5) are cleared. Returns how many cells it cleared.
|
|
34717
|
+
*/
|
|
34718
|
+
wash(maxDryness) {
|
|
34719
|
+
const washable = this.options.washable ?? DEFAULT_WASHABLE;
|
|
34720
|
+
let cleared = 0;
|
|
34721
|
+
for (const grid of this.grids) if (washable.includes(grid.profile.id)) cleared += grid.wash(maxDryness);
|
|
34722
|
+
return cleared;
|
|
34044
34723
|
}
|
|
34045
34724
|
/** 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
34725
|
launch(request) {
|
|
34047
34726
|
const grid = this.gridFor(request.fluid, request.point, request.surfaces, request.tint);
|
|
34048
34727
|
if (!grid) return null;
|
|
34049
|
-
const velocity = request.velocity ?? [0, -
|
|
34728
|
+
const velocity = request.velocity ?? [0, -FALL_SPEED2, 0];
|
|
34050
34729
|
grid.film.launch(request.point, velocity, request.radius ?? DEFAULT_DROP_RADIUS);
|
|
34051
34730
|
return grid;
|
|
34052
34731
|
}
|
|
@@ -34071,7 +34750,7 @@ void main(){
|
|
|
34071
34750
|
const layout = layoutFromSurfaces({ ...found, center: point, columns: this.columns(), rows: this.columns(), cellSize: this.options.cellSize ?? DEFAULT_CELL2 });
|
|
34072
34751
|
if (this.grids.length >= (this.options.maxGrids ?? DEFAULT_MAX_GRIDS)) this.evict(point);
|
|
34073
34752
|
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 });
|
|
34753
|
+
grid.film.setWeather({ rain: this.rain, drying: this.drying });
|
|
34075
34754
|
this.grids.push(grid);
|
|
34076
34755
|
this.group.add(grid.group);
|
|
34077
34756
|
return grid;
|
|
@@ -34148,7 +34827,7 @@ void main(){
|
|
|
34148
34827
|
/** Whether `point` is over the grid, away from its edge, so a splash there does not fall off the strip. */
|
|
34149
34828
|
covers(grid, point) {
|
|
34150
34829
|
const layout = grid.film.layout;
|
|
34151
|
-
const
|
|
34830
|
+
const wide2 = layout.width * layout.cellSize;
|
|
34152
34831
|
for (const region of layout.regions) {
|
|
34153
34832
|
const local2 = [point[0] - region.origin[0], point[1] - region.origin[1], point[2] - region.origin[2]];
|
|
34154
34833
|
const above2 = local2[0] * region.normal[0] + local2[1] * region.normal[1] + local2[2] * region.normal[2];
|
|
@@ -34156,7 +34835,7 @@ void main(){
|
|
|
34156
34835
|
const sideways = local2[0] * region.columnAxis[0] + local2[1] * region.columnAxis[1] + local2[2] * region.columnAxis[2];
|
|
34157
34836
|
const down = local2[0] * region.rowAxis[0] + local2[1] * region.rowAxis[1] + local2[2] * region.rowAxis[2];
|
|
34158
34837
|
const length3 = region.rowCount * layout.cellSize;
|
|
34159
|
-
if (sideways > EDGE_MARGIN && sideways <
|
|
34838
|
+
if (sideways > EDGE_MARGIN && sideways < wide2 - EDGE_MARGIN && down > EDGE_MARGIN && down < length3 - EDGE_MARGIN) return true;
|
|
34160
34839
|
}
|
|
34161
34840
|
return false;
|
|
34162
34841
|
}
|
|
@@ -34307,6 +34986,7 @@ void main(){
|
|
|
34307
34986
|
return landed;
|
|
34308
34987
|
},
|
|
34309
34988
|
setWeather: (weather) => manager.setWeather(weather),
|
|
34989
|
+
wash: (maxDryness) => manager.wash(maxDryness),
|
|
34310
34990
|
update(dt) {
|
|
34311
34991
|
if (leaks.size === 0) return;
|
|
34312
34992
|
const streams = new Map(fluids.streams().map((stream) => [stream.id, stream]));
|
|
@@ -34399,15 +35079,15 @@ void main(){
|
|
|
34399
35079
|
if (s.kind === "box") geo = new THREE.BoxGeometry(s.size[0], s.size[1], s.size[2]);
|
|
34400
35080
|
else if (s.kind === "cylinder") geo = new THREE.CylinderGeometry(s.radius, s.radius, s.height, seg);
|
|
34401
35081
|
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(
|
|
35082
|
+
const mesh2 = new THREE.Mesh(geo, materialFor(p));
|
|
35083
|
+
mesh2.name = p.id;
|
|
35084
|
+
mesh2.userData.destructionPart = p.id;
|
|
35085
|
+
mesh2.userData.destructionMaterial = p.material;
|
|
35086
|
+
mesh2.position.set(p.position[0], p.position[1], p.position[2]);
|
|
35087
|
+
if (p.rotation) mesh2.rotation.set(p.rotation[0], p.rotation[1], p.rotation[2], "XYZ");
|
|
35088
|
+
mesh2.castShadow = shadows && !TRANSPARENT[p.material];
|
|
35089
|
+
mesh2.receiveShadow = shadows;
|
|
35090
|
+
root.add(mesh2);
|
|
34411
35091
|
}
|
|
34412
35092
|
return root;
|
|
34413
35093
|
}
|
|
@@ -35732,16 +36412,16 @@ void main(){
|
|
|
35732
36412
|
const up = new THREE.Vector3(0, 1, 0);
|
|
35733
36413
|
const clear = () => {
|
|
35734
36414
|
projectiles.length = 0;
|
|
35735
|
-
for (const
|
|
36415
|
+
for (const mesh2 of meshes) mesh2.removeFromParent();
|
|
35736
36416
|
meshes.length = 0;
|
|
35737
36417
|
};
|
|
35738
36418
|
const addMesh = (geometry, color, metalness, at3) => {
|
|
35739
|
-
const
|
|
35740
|
-
|
|
35741
|
-
|
|
35742
|
-
scene2.add(
|
|
35743
|
-
meshes.push(
|
|
35744
|
-
return
|
|
36419
|
+
const mesh2 = new THREE.Mesh(geometry, new THREE.MeshStandardMaterial({ color, roughness: 0.6, metalness }));
|
|
36420
|
+
mesh2.castShadow = true;
|
|
36421
|
+
mesh2.position.set(at3[0], at3[1], at3[2]);
|
|
36422
|
+
scene2.add(mesh2);
|
|
36423
|
+
meshes.push(mesh2);
|
|
36424
|
+
return mesh2;
|
|
35745
36425
|
};
|
|
35746
36426
|
const remove = (projectile) => {
|
|
35747
36427
|
for (const extra of projectile.attached ?? []) {
|
|
@@ -35759,9 +36439,9 @@ void main(){
|
|
|
35759
36439
|
const isMolotov = !!use.fire;
|
|
35760
36440
|
const isRocket = use.trigger === "impact" && (use.armDistance ?? 0) > 0;
|
|
35761
36441
|
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
|
|
36442
|
+
const mesh2 = addMesh(geometry, isMolotov ? 3897915 : isRocket ? 7041116 : 4936480, isMolotov ? 0 : 0.4, use.origin);
|
|
35763
36443
|
projectiles.push({
|
|
35764
|
-
mesh,
|
|
36444
|
+
mesh: mesh2,
|
|
35765
36445
|
pos: new THREE.Vector3(use.origin[0], use.origin[1], use.origin[2]),
|
|
35766
36446
|
vel: new THREE.Vector3(use.velocity[0], use.velocity[1], use.velocity[2]),
|
|
35767
36447
|
weapon: context.toolId(),
|
|
@@ -35812,11 +36492,11 @@ void main(){
|
|
|
35812
36492
|
const placed = { ...use, origin: at3 };
|
|
35813
36493
|
const body = createExplosiveBody(placed, arsenal.explosives, arsenal.rules.explosives);
|
|
35814
36494
|
if (!body) return;
|
|
35815
|
-
const
|
|
35816
|
-
|
|
36495
|
+
const mesh2 = addMesh(new THREE.BoxGeometry(0.18, 0.06, 0.1), use.explosive === "claymore" ? 5597999 : 12757112, 0.1, at3);
|
|
36496
|
+
mesh2.rotation.y = Math.atan2(use.direction[0], use.direction[2]);
|
|
35817
36497
|
const attached = [markerAt(at3)];
|
|
35818
36498
|
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 };
|
|
36499
|
+
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
36500
|
if (segment) {
|
|
35821
36501
|
const wire = { from: segment.from, to: segment.to, letThrough: /* @__PURE__ */ new Set() };
|
|
35822
36502
|
for (const id of touching(wire)) wire.letThrough.add(id);
|
|
@@ -36493,13 +37173,13 @@ void main(){
|
|
|
36493
37173
|
if (!g || g.done) break;
|
|
36494
37174
|
g.done = true;
|
|
36495
37175
|
const [a, b] = ev.parts;
|
|
36496
|
-
const
|
|
37176
|
+
const many = g.list.length > 1;
|
|
36497
37177
|
c.log.add({
|
|
36498
37178
|
channel: "event",
|
|
36499
37179
|
type: "detach",
|
|
36500
37180
|
objectId: ev.object,
|
|
36501
37181
|
itemId: c.itemIdOf(ev.object),
|
|
36502
|
-
text:
|
|
37182
|
+
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
37183
|
data: { joint: ev.joint, joints: g.list.map((j) => j.joint), parts: ev.parts, by: ev.by, groups: g.groups }
|
|
36504
37184
|
});
|
|
36505
37185
|
break;
|
|
@@ -36783,6 +37463,9 @@ void main(){
|
|
|
36783
37463
|
const blocked = (x, z) => {
|
|
36784
37464
|
if (Math.abs(x) > o.limit - PLAYER_RADIUS || Math.abs(z) > o.limit - PLAYER_RADIUS) return true;
|
|
36785
37465
|
for (const c of o.colliders) if (x > c[0] - PLAYER_RADIUS && x < c[2] + PLAYER_RADIUS && z > c[1] - PLAYER_RADIUS && z < c[3] + PLAYER_RADIUS) return true;
|
|
37466
|
+
if (o.blockers) {
|
|
37467
|
+
for (const blocked2 of o.blockers) if (blocked2(x, z, PLAYER_RADIUS)) return true;
|
|
37468
|
+
}
|
|
36786
37469
|
return false;
|
|
36787
37470
|
};
|
|
36788
37471
|
const move = (dx, dz) => {
|
|
@@ -38431,10 +39114,12 @@ void main(){
|
|
|
38431
39114
|
log.setBeforeRead(flush);
|
|
38432
39115
|
let useHeld = false;
|
|
38433
39116
|
let useFirst = false;
|
|
39117
|
+
const blockers = /* @__PURE__ */ new Set();
|
|
38434
39118
|
const player = createPlayer(THREE, {
|
|
38435
39119
|
camera: camera2,
|
|
38436
39120
|
dom,
|
|
38437
39121
|
colliders: arena.colliders,
|
|
39122
|
+
blockers,
|
|
38438
39123
|
limit: arenaSize,
|
|
38439
39124
|
start: arena.playerStart,
|
|
38440
39125
|
hooks: {
|
|
@@ -38617,8 +39302,10 @@ void main(){
|
|
|
38617
39302
|
film.clear();
|
|
38618
39303
|
fluids.setTap(TAP_ID, false);
|
|
38619
39304
|
};
|
|
39305
|
+
const clearListeners = /* @__PURE__ */ new Set();
|
|
38620
39306
|
const clear = () => {
|
|
38621
39307
|
clearEverything();
|
|
39308
|
+
for (const listener of [...clearListeners]) listener();
|
|
38622
39309
|
restingTops.length = 0;
|
|
38623
39310
|
pending = [];
|
|
38624
39311
|
action("clear", t("act.clear"));
|
|
@@ -39817,6 +40504,14 @@ void main(){
|
|
|
39817
40504
|
},
|
|
39818
40505
|
log(text, data) {
|
|
39819
40506
|
action("module_note", text, { data });
|
|
40507
|
+
},
|
|
40508
|
+
addBlocker(blocked) {
|
|
40509
|
+
blockers.add(blocked);
|
|
40510
|
+
return () => blockers.delete(blocked);
|
|
40511
|
+
},
|
|
40512
|
+
onClear(listener) {
|
|
40513
|
+
clearListeners.add(listener);
|
|
40514
|
+
return () => clearListeners.delete(listener);
|
|
39820
40515
|
}
|
|
39821
40516
|
};
|
|
39822
40517
|
const lendBench = (store) => ({
|
|
@@ -40021,6 +40716,8 @@ void main(){
|
|
|
40021
40716
|
camera: camera2,
|
|
40022
40717
|
arsenal,
|
|
40023
40718
|
fluids,
|
|
40719
|
+
film: filmBridge,
|
|
40720
|
+
vfx: vfx.world,
|
|
40024
40721
|
fluidRenderer: fluidView,
|
|
40025
40722
|
audio,
|
|
40026
40723
|
environment,
|