@adatechnology/game-test-room 0.17.0 → 0.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2270,6 +2270,7 @@ var GameTestRoom = (() => {
2270
2270
  },
2271
2271
  hitDebris: "chips",
2272
2272
  breakDebris: "dust",
2273
+ visual: { innerColor: 10197652 },
2273
2274
  thermal: {
2274
2275
  conductivity: 0.15,
2275
2276
  heatCapacity: 2.5
@@ -2300,6 +2301,7 @@ var GameTestRoom = (() => {
2300
2301
  ],
2301
2302
  hitDebris: "chips",
2302
2303
  breakDebris: "dust",
2304
+ visual: { innerColor: 12085567 },
2303
2305
  thermal: {
2304
2306
  conductivity: 0.15,
2305
2307
  heatCapacity: 2.5
@@ -2330,6 +2332,7 @@ var GameTestRoom = (() => {
2330
2332
  ],
2331
2333
  hitDebris: "dust",
2332
2334
  breakDebris: "dust",
2335
+ visual: { innerColor: 14999507 },
2333
2336
  thermal: {
2334
2337
  conductivity: 0.1,
2335
2338
  heatCapacity: 1.5
@@ -2355,6 +2358,7 @@ var GameTestRoom = (() => {
2355
2358
  ],
2356
2359
  hitDebris: "chips",
2357
2360
  breakDebris: "dust",
2361
+ visual: { innerColor: 9407364 },
2358
2362
  thermal: {
2359
2363
  conductivity: 0.2,
2360
2364
  heatCapacity: 2.5
@@ -3117,6 +3121,7 @@ var GameTestRoom = (() => {
3117
3121
  var CHIP_ENERGY = 200;
3118
3122
  var CHIP_SPLASH = 0.5;
3119
3123
  var BAR_BOW = 0.08;
3124
+ var BULLET_JOINT_SPAN = 0.3;
3120
3125
  var CUT_SLICE = 1;
3121
3126
  var cutFactorOf = (shape) => clamp2(Math.max(...shapeDims(shape)) / CUT_SLICE, 1, 50);
3122
3127
  var clamp2 = (v, a, b) => Math.max(a, Math.min(b, v));
@@ -4243,7 +4248,7 @@ var GameTestRoom = (() => {
4243
4248
  emit2({ ...base(o, src), type: "crack", part: p.spec.id, crack, worldPoint: wp });
4244
4249
  setStage(o, p, 1, {}, src);
4245
4250
  };
4246
- const debris2 = (o, p, kind, point, normal, count, speed, src) => emit2({ ...base(o, src), type: "debris", part: p.spec.id, kind, point, normal, count, speed });
4251
+ const debris2 = (o, p, kind, point, normal, count, speed, src, material) => emit2({ ...base(o, src), type: "debris", part: p.spec.id, kind, point, normal, count, speed, ...material && material !== p.spec.material ? { material } : {} });
4247
4252
  const holeRate = (hole, pressurized) => (pressurized ? 0.5 : 0.1) * (hole.diameter / 9e-3);
4248
4253
  const detachEvents = (o, opened, by, src) => {
4249
4254
  for (const j of opened) emit2({ ...base(o, src), type: "detach", joint: j.spec.id, parts: [j.spec.a, j.spec.b], by, groups: o.st.groups.map((g) => [...g]) });
@@ -4284,7 +4289,13 @@ var GameTestRoom = (() => {
4284
4289
  const small = pa.dims[0] * pa.dims[1] * pa.dims[2] <= pb.dims[0] * pb.dims[1] * pb.dims[2] ? pa : pb;
4285
4290
  return Math.max(0.06, 0.5 * Math.min(small.dims[0], small.dims[1], small.dims[2]));
4286
4291
  };
4287
- const wearJoints = (o, p, amount, near, radius = 0.06, src, split = false) => {
4292
+ const jointLength = (o, j) => {
4293
+ const A = partWorldAabb(o, o.parts[j.ia]), B = partWorldAabb(o, o.parts[j.ib]);
4294
+ let len = 0;
4295
+ for (let k = 0; k < 3; k++) len = Math.max(len, Math.min(A.max[k], B.max[k]) - Math.max(A.min[k], B.min[k]));
4296
+ return len;
4297
+ };
4298
+ const wearJoints = (o, p, amount, near, radius = 0.06, src, split = false, span) => {
4288
4299
  if (amount <= 0) return;
4289
4300
  const mine = (o.byPart.get(p.spec.id) ?? []).filter((j) => !j.st.open);
4290
4301
  if (split && mine.length) amount /= mine.length;
@@ -4292,7 +4303,7 @@ var GameTestRoom = (() => {
4292
4303
  if (j.st.open) continue;
4293
4304
  if (j.spec.kind === "rebar" && (isReinforced(o.parts[j.ia].spec) || isReinforced(o.parts[j.ib].spec))) continue;
4294
4305
  if (near && jointReach(o, j, near) > Math.max(radius, jointReachLimit(o, j))) continue;
4295
- j.st.hp -= amount;
4306
+ j.st.hp -= span === void 0 ? amount : amount * Math.min(1, span / Math.max(jointLength(o, j), 1e-6));
4296
4307
  if (j.st.hp <= 0) {
4297
4308
  j.st.hp = 0;
4298
4309
  j.st.open = true;
@@ -4321,7 +4332,7 @@ var GameTestRoom = (() => {
4321
4332
  if (spalls.length > MAX_SPALLS) spalls.shift();
4322
4333
  markDamaged(p);
4323
4334
  emit2({ ...base(o, src), type: "spall", part: p.spec.id, layer: layer2.index, point: wp, area: Math.PI * radius * radius });
4324
- debris2(o, p, layer2.mat.hitDebris, wp, normal, 5, 2, src);
4335
+ debris2(o, p, layer2.mat.hitDebris, wp, normal, 5, 2, src, layer2.mat.id);
4325
4336
  setStage(o, p, 1, {}, src);
4326
4337
  };
4327
4338
  const crater = (o, p, wp, normal, radius, src) => {
@@ -4808,7 +4819,7 @@ var GameTestRoom = (() => {
4808
4819
  if (mat.fracture !== "shatter") addHole(o, p, entry, n, caliber / 1e3, false, void 0, src);
4809
4820
  } else addHole(o, p, entry, n, caliber / 1e3, false, void 0, src);
4810
4821
  debris2(o, p, mat.hitDebris, entry, n, clamp2(Math.round(E / 60) + 2, 2, 14), clamp2(Math.sqrt(E) / 6, 1, 8), src);
4811
- wearJoints(o, p, (penetrated ? thr : E) * 0.02, void 0, 0, src, true);
4822
+ wearJoints(o, p, (penetrated ? thr : E) * 0.02, void 0, 0, src, true, BULLET_JOINT_SPAN);
4812
4823
  const absorbed = penetrated && mat.ductility >= 0.5 && mat.fracture !== "tear" ? Math.min(E, thr) : E;
4813
4824
  const dmg = applyDamage(o, p, absorbed * DMG_PER_J * scale2, "ballistic", entry, d, absorbed * 0.1, 12, src);
4814
4825
  if (!isLost(p)) tearAt(o, p, "ballistic", entry, penetrated ? exitPoint : void 0, d, E, caliber / 1e3, src);
@@ -13935,6 +13946,24 @@ var GameTestRoom = (() => {
13935
13946
  for (const decal2 of this.decals) decal2.on = false;
13936
13947
  this.count = 0;
13937
13948
  }
13949
+ /**
13950
+ * Takes away the marks inside a box: world `center`, `half` extents along the axes of the world `rotation` (a quaternion, x y z w; none means the
13951
+ * world axes). The surface they were on is gone (a brick came out of a wall with its bullet holes). Returns how many went.
13952
+ */
13953
+ clearInside(center, half, rotation = [0, 0, 0, 1]) {
13954
+ const qx = -rotation[0], qy = -rotation[1], qz = -rotation[2], qw = rotation[3];
13955
+ let gone = 0;
13956
+ for (const decal2 of this.decals) {
13957
+ if (!decal2.on) continue;
13958
+ const vx2 = decal2.x - center[0], vy2 = decal2.y - center[1], vz2 = decal2.z - center[2];
13959
+ const tx = 2 * (qy * vz2 - qz * vy2), ty = 2 * (qz * vx2 - qx * vz2), tz = 2 * (qx * vy2 - qy * vx2);
13960
+ const lx = vx2 + qw * tx + (qy * tz - qz * ty), ly = vy2 + qw * ty + (qz * tx - qx * tz), lz = vz2 + qw * tz + (qx * ty - qy * tx);
13961
+ if (Math.abs(lx) > half[0] || Math.abs(ly) > half[1] || Math.abs(lz) > half[2]) continue;
13962
+ decal2.on = false;
13963
+ gone++;
13964
+ }
13965
+ return gone;
13966
+ }
13938
13967
  update(dt) {
13939
13968
  this.count = 0;
13940
13969
  for (const decal2 of this.decals) {
@@ -17759,6 +17788,21 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
17759
17788
  d.geometry?.dispose();
17760
17789
  this.decalCount = Math.max(0, this.decalCount - 1);
17761
17790
  }
17791
+ /**
17792
+ * Takes away the decals of a mesh that sit inside a box (world `center`, `half` extents along the axes of the world `rotation`): the surface they
17793
+ * marked is gone (a unit came out of the wall with its bullet holes and spalls).
17794
+ */
17795
+ clearDecals(mv, center, half, rotation) {
17796
+ const inv = rotation.clone().invert();
17797
+ const p = new this.THREE.Vector3();
17798
+ for (let i = mv.decals.length - 1; i >= 0; i--) {
17799
+ const d = mv.decals[i];
17800
+ d.obj.getWorldPosition(p).sub(center).applyQuaternion(inv);
17801
+ if (Math.abs(p.x) > half.x || Math.abs(p.y) > half.y || Math.abs(p.z) > half.z) continue;
17802
+ this.disposeDecal(d);
17803
+ mv.decals.splice(i, 1);
17804
+ }
17805
+ }
17762
17806
  addHole(mv, worldPoint, worldNormal, diameter) {
17763
17807
  const { s, pos, quat: quat2 } = this.decalPose(mv.mesh, worldPoint, worldNormal, 25e-4);
17764
17808
  const work = mv.host ? mv.host.work : mv.work;
@@ -18239,6 +18283,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
18239
18283
  };
18240
18284
  var rendererCount = 0;
18241
18285
  var COLLAPSE_CLOUD_KG = 1e3;
18286
+ var CHIP_DECAL_EDGE = 0.05;
18242
18287
  var IMPACT_TAGS = ["metal", "glass", "wood"];
18243
18288
  var GLOW_FROM_C = 430;
18244
18289
  var QUEUE_CAP = 4e3;
@@ -18795,7 +18840,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
18795
18840
  break;
18796
18841
  }
18797
18842
  case "debris":
18798
- this.vfx.burst(ev.kind, ev.point, ev.normal, ev.count, ev.speed > 0 ? ev.speed : DEFAULT_SPEED[ev.kind] ?? 1, this.debrisOptions(ev.kind, ev.object, ev.part));
18843
+ this.vfx.burst(ev.kind, ev.point, ev.normal, ev.count, ev.speed > 0 ? ev.speed : DEFAULT_SPEED[ev.kind] ?? 1, this.debrisOptions(ev.kind, ev.object, ev.part, ev.material));
18799
18844
  break;
18800
18845
  case "fracture":
18801
18846
  this.onFracture(ev);
@@ -18968,10 +19013,11 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
18968
19013
  }
18969
19014
  return def ? fallbackColor(def.id, def) : null;
18970
19015
  }
18971
- debrisOptions(kind, objectId, partId) {
19016
+ debrisOptions(kind, objectId, partId, material) {
18972
19017
  const pv = this.partVis(objectId, partId);
18973
- const def = pv ? this.world.materials.get(pv.material) : void 0;
19018
+ const def = this.world.materials.get(material ?? pv?.material ?? "");
18974
19019
  if (kind === "smoke") return { color: SMOKE_TONES[def?.thermal.smoke ?? "grey"] };
19020
+ if ((kind === "dust" || kind === "chips") && def?.visual?.innerColor !== void 0) return { color: def.visual.innerColor };
18975
19021
  if (kind === "fibers" || kind === "leaves") {
18976
19022
  if (def?.visual?.innerColor !== void 0) return { color: def.visual.innerColor };
18977
19023
  const c = pv ? this.visuals.baseColorHex(pv.meshes[0] ?? {}) : -1;
@@ -19079,8 +19125,11 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
19079
19125
  const mv = this.nearestMesh(pv, wp);
19080
19126
  if (!mv) return;
19081
19127
  const def = this.world.materials.get(pv.material);
19082
- this.playEvent({ kind: "spall", material: this.impactMaterial(def) }, ev.point);
19083
- this.visuals.addSpall(mv, wp, this.faceNormal(mv, wp), Math.sqrt(ev.area / Math.PI), fallbackColor(pv.material, def));
19128
+ const normal = this.faceNormal(mv, wp);
19129
+ const core = def?.visual?.innerColor;
19130
+ if (core !== void 0) this.vfx.burst("chips", ev.point, [normal.x, normal.y, normal.z], 5, 2.5, { color: core });
19131
+ else this.playEvent({ kind: "spall", material: this.impactMaterial(def) }, ev.point);
19132
+ this.visuals.addSpall(mv, wp, normal, Math.sqrt(ev.area / Math.PI), core ?? fallbackColor(pv.material, def));
19084
19133
  }
19085
19134
  /**
19086
19135
  * Stage 2 of a staged part: the unit-sized fragments come out and the part stays drawn (hiding it is what `fracture` does). The opening itself
@@ -19103,8 +19152,9 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
19103
19152
  this.sound(impactKey(def), ev.opening.center, 0.8);
19104
19153
  }
19105
19154
  /**
19106
- * A unit came out of a wall of units: the unit flies as a fragment with a puff of its dust. The gap itself is the drawing's (the house renderer redraws
19107
- * the wall as its courses without that unit); a part drawn as one box keeps its box.
19155
+ * A unit came out of a wall of units: the unit flies as a fragment with a puff of its dust, and the marks drawn on it (bullet holes, spalls, the impact
19156
+ * marks of the effects) go with it. The gap itself is the drawing's (the house renderer cuts the wall where the unit was); a part drawn as one box
19157
+ * keeps its box.
19108
19158
  */
19109
19159
  onChip(ev) {
19110
19160
  const pv = this.partVis(ev.object, ev.part);
@@ -19116,7 +19166,13 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
19116
19166
  const tone2 = fr.inner && fdef?.visual?.innerColor !== void 0 ? fdef.visual.innerColor : fdef === def ? color : fallbackColor(fr.material, fdef);
19117
19167
  this.fragments.spawn(fr, this.fragments.materialFor(fr.material, tone2, false), ev.object, maxAlive);
19118
19168
  }
19119
- if (!this.playEvent({ kind: "spall", material: this.impactMaterial(def) }, ev.center)) this.vfx.burst("dust", ev.center, [0, 1, 0], 6, 0.8, { color });
19169
+ const T = this.THREE;
19170
+ const center = new T.Vector3(ev.center[0], ev.center[1], ev.center[2]);
19171
+ const half = new T.Vector3(ev.size[0] / 2 + CHIP_DECAL_EDGE, ev.size[1] / 2 + CHIP_DECAL_EDGE, ev.size[2] / 2 + CHIP_DECAL_EDGE);
19172
+ const rotation = new T.Quaternion(ev.rotation[0], ev.rotation[1], ev.rotation[2], ev.rotation[3]);
19173
+ for (const part of this.bounds.get(ev.object)?.parts.values() ?? []) for (const mv of part.meshes) this.visuals.clearDecals(mv, center, half, rotation);
19174
+ this.vfx.peekWorkshop()?.decals.clearInside(ev.center, [half.x, half.y, half.z], ev.rotation);
19175
+ this.vfx.burst("dust", ev.center, [0, 1, 0], 8, 0.8, { color });
19120
19176
  this.sound(impactKey(def), ev.center, 0.7);
19121
19177
  }
19122
19178
  onFracture(ev) {