@adatechnology/game-urban 0.3.0 → 0.3.2

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 CHANGED
@@ -539,7 +539,10 @@ type PoleOptions = {
539
539
  /** Adds the transformer drum (single arm). */
540
540
  transformer?: boolean;
541
541
  };
542
- type PoleShapeBuilder = (b: UrbanBuilder, spec: any, o: PoleOptions) => void;
542
+ /** Draws a pole from its `spec`. Declared as a method so the registry can hold each builder with its own spec type (the `PoleDef` names the builder that reads its spec). */
543
+ type PoleShapeBuilder<TSpec extends object = object> = {
544
+ build(b: UrbanBuilder, spec: TSpec, o: PoleOptions): void;
545
+ }['build'];
543
546
  type PoleDef = {
544
547
  id: string;
545
548
  /** Key of the shape builder that reads `spec`. */
@@ -926,7 +929,13 @@ type ComposeContext<TParams = Record<string, unknown>> = {
926
929
  shop?: number;
927
930
  }): void;
928
931
  };
929
- type Composer<TParams = any> = (context: ComposeContext<TParams>) => void;
932
+ /**
933
+ * Draws a pattern from its params. Declared as a method so a registry of composers can hold each with its own params type
934
+ * (the pattern that names the composer carries the matching params).
935
+ */
936
+ type Composer<TParams = Record<string, unknown>> = {
937
+ compose(context: ComposeContext<TParams>): void;
938
+ }['compose'];
930
939
  type ComposeOptions = {
931
940
  locale?: Locale;
932
941
  providers?: Providers;
@@ -1134,9 +1143,9 @@ type Origin = {
1134
1143
  z: number;
1135
1144
  };
1136
1145
  /** Draws one pattern at `origin`: its composer, then the board with the title and the caption. */
1137
- declare function composePattern(kit: UrbanKitCore, pattern: NeighbourhoodPattern<any>, composer: Composer, b: UrbanBuilder, origin: Origin, options?: ComposeOptions): UrbanPlan;
1146
+ declare function composePattern(kit: UrbanKitCore, pattern: NeighbourhoodPattern, composer: Composer, b: UrbanBuilder, origin: Origin, options?: ComposeOptions): UrbanPlan;
1138
1147
  /** The marker (map pin) of a pattern at an origin: where it stands, how high, and what it says. */
1139
- declare function patternMarker(pattern: NeighbourhoodPattern<any>, origin: Origin, locale?: Locale): {
1148
+ declare function patternMarker(pattern: NeighbourhoodPattern, origin: Origin, locale?: Locale): {
1140
1149
  x: number;
1141
1150
  y: number;
1142
1151
  z: number;
@@ -1196,14 +1205,14 @@ type UrbanOptions = {
1196
1205
  /** Entries added to the catalogues (an entry with an existing id replaces it). */
1197
1206
  packs?: {
1198
1207
  poles?: readonly PoleDef[];
1199
- neighbourhoods?: readonly NeighbourhoodPattern<any>[];
1208
+ neighbourhoods?: readonly NeighbourhoodPattern[];
1200
1209
  districtKinds?: readonly DistrictKindDef[];
1201
1210
  cityPlans?: readonly CityPlanInput[];
1202
1211
  };
1203
1212
  /** Numbers changed on shipped entries, by id (objects merge, arrays replace). */
1204
1213
  patch?: {
1205
1214
  poles?: Record<string, DeepPartial<PoleDef>>;
1206
- neighbourhoods?: Record<string, DeepPartial<NeighbourhoodPattern<any>>>;
1215
+ neighbourhoods?: Record<string, DeepPartial<NeighbourhoodPattern>>;
1207
1216
  districtKinds?: Record<string, DeepPartial<DistrictKindDef>>;
1208
1217
  cityPlans?: Record<string, DeepPartial<CityPlanInput>>;
1209
1218
  };
@@ -1277,7 +1286,7 @@ declare function createUrban(options?: UrbanOptions): {
1277
1286
  neighbourhoods: {
1278
1287
  ids: () => string[];
1279
1288
  get(id: string): {
1280
- pattern: NeighbourhoodPattern<any>;
1289
+ pattern: NeighbourhoodPattern;
1281
1290
  /** Draws the pattern at `origin` and gives back what it put there. */
1282
1291
  compose: (b: UrbanBuilder, origin: Origin, o?: ComposeOptions) => UrbanPlan;
1283
1292
  marker: (origin: Origin, locale?: Locale) => {
@@ -1768,7 +1777,7 @@ declare const DEFAULT_PLANT_CONTEXTS: Readonly<Record<PlantRequest['kind'], stri
1768
1777
  declare function createPlantProvider(options?: PlantProviderOptions): PlantProvider;
1769
1778
 
1770
1779
  /** The ten patterns of the Galeria's sample sheet, in the order the page builds them. */
1771
- declare const DEFAULT_PATTERNS: readonly NeighbourhoodPattern<any>[];
1780
+ declare const DEFAULT_PATTERNS: readonly NeighbourhoodPattern[];
1772
1781
  /** Where the sample sheet puts each pattern: a 3 x 3 grid 80 by 56 m apart, and the military cell off to the east. */
1773
1782
  declare const SAMPLE_CELLS: Readonly<Record<string, {
1774
1783
  x: number;
@@ -1776,7 +1785,7 @@ declare const SAMPLE_CELLS: Readonly<Record<string, {
1776
1785
  }>>;
1777
1786
 
1778
1787
  /** The patterns of the tower pack. */
1779
- declare const TOWER_PATTERNS: readonly NeighbourhoodPattern<any>[];
1788
+ declare const TOWER_PATTERNS: readonly NeighbourhoodPattern[];
1780
1789
  /** Where the sample sheet puts them (pass it as `cells`). */
1781
1790
  declare const TOWER_SAMPLE_CELLS: Readonly<Record<string, {
1782
1791
  x: number;
@@ -99,6 +99,7 @@ var GameUrban = (() => {
99
99
  var createLightBudget = createLightAllowance;
100
100
 
101
101
  // ../game-contracts/dist/index.js
102
+ var DEFAULT_BLAST_IMPULSE = { bodyArea: 0.7, lift: 0.15, minSpeed: 0.3, tntPerJoule: 0.24 / 2e5 };
102
103
  var DEFAULT_COST_ALLOCATION_BYTES = 1024 * 1024;
103
104
  var DEFERRED_QUEUE_ID = {
104
105
  DESTRUCTION_EVENTS: "destruction.events",
@@ -650,6 +651,7 @@ var GameUrban = (() => {
650
651
  var MAX_CANDIDATES = 80;
651
652
  function carCandidates(slot, item, car) {
652
653
  const front = [slot.frontU, slot.frontV];
654
+ if (!slot._cell) throw new Error("Slot without a cell: " + slot.id);
653
655
  const zone = slot._cell.R;
654
656
  const alongV = Math.abs(front[1]) === 1;
655
657
  const [extentU, extentV] = extent([item.w, item.d], front);
@@ -869,6 +871,7 @@ var GameUrban = (() => {
869
871
  }
870
872
  function itemRect(slot, it, shift) {
871
873
  const c = slot._cell;
874
+ if (!c) throw new Error("Slot without a cell: " + slot.id);
872
875
  const f = c.f;
873
876
  const [extentU, extentV] = extent([it.w, it.d], f);
874
877
  const R = c.R;
@@ -973,7 +976,7 @@ var GameUrban = (() => {
973
976
  if (!parent) return null;
974
977
  for (const { it } of cands) {
975
978
  if (it.w > parent.w + EPS || it.d > parent.d + EPS) continue;
976
- const f = [parent.frontU, parent.frontV];
979
+ const f = [parent.frontU ?? 0, parent.frontV ?? 1];
977
980
  const r = parent.aabb;
978
981
  const [extentU, extentV] = extent([it.w, it.d], f);
979
982
  const cu = (r[0] + r[2]) / 2 - f[0] * (parent.d / 2 - it.d / 2);
@@ -1007,7 +1010,7 @@ var GameUrban = (() => {
1007
1010
  if (!car && !relax && s.clearance > 0 && !it.low) {
1008
1011
  cl2 = clearRect(r3, f, s.clearance);
1009
1012
  if (!insideUnion(cl2, inners)) continue;
1010
- if (items.some((m2) => !m2.low && !m2.flat && !m2.on && overlaps(cl2, m2._r))) continue;
1013
+ if (items.some((m2) => !m2.low && !m2.flat && !m2.on && overlaps(cl2, m2._r ?? m2.aabb))) continue;
1011
1014
  }
1012
1015
  if (!it.low && reserves.some((q) => overlaps(r3, q))) continue;
1013
1016
  let rimRect2 = null;
@@ -1191,7 +1194,7 @@ var GameUrban = (() => {
1191
1194
  if (!(opts.without && opts.without(r))) return r;
1192
1195
  continue;
1193
1196
  }
1194
- if (occupied.some((m) => !m.low && !m.flat && !m.on && !m.decor && m.clearance > 0 && overlaps(r, clearRect(m._r, [m.frontU, m.frontV], m.clearance)))) continue;
1197
+ if (occupied.some((m) => !m.low && !m.flat && !m.on && !m.decor && (m.clearance ?? 0) > 0 && overlaps(r, clearRect(m._r, [m.frontU ?? 0, m.frontV ?? 1], m.clearance ?? 0)))) continue;
1195
1198
  if (opts.without && opts.without(r)) continue;
1196
1199
  if (!reachable(opts.railing || gridOf(room), solidList.concat([r]), room.outdoor ? 0.16 : plan.playerRadius)) continue;
1197
1200
  return r;
@@ -1452,7 +1455,7 @@ var GameUrban = (() => {
1452
1455
  const far = m.built / area;
1453
1456
  if (far > zone.maxFar + 1e-9) out.push({ rule: "far", actual: r2(far), limit: zone.maxFar });
1454
1457
  let permeable = 0;
1455
- for (const z of lot.zones) if (registries().PERMEABLE_GROUNDS.has(z.ground)) for (const p of z.parts) permeable += (p[2] - p[0]) * (p[3] - p[1]);
1458
+ for (const z of lot.zones) if (z.ground && registries().PERMEABLE_GROUNDS.has(z.ground)) for (const p of z.parts) permeable += (p[2] - p[0]) * (p[3] - p[1]);
1456
1459
  const permeability = permeable / area;
1457
1460
  if (permeability < zone.permeableMin - 1e-9) out.push({ rule: "permeable", actual: r2(permeability), limit: zone.permeableMin });
1458
1461
  return out;
@@ -1495,12 +1498,12 @@ var GameUrban = (() => {
1495
1498
  const [u0, v0, u1, v1] = lot.rect;
1496
1499
  const area = (u1 - u0) * (v1 - v0);
1497
1500
  const areaOfZone = (z) => z.parts.reduce((s, p) => s + (p[2] - p[0]) * (p[3] - p[1]), 0);
1498
- let permeable = zones.filter((z) => registries().PERMEABLE_GROUNDS.has(z.ground)).reduce((s, z) => s + areaOfZone(z), 0);
1501
+ let permeable = zones.filter((z) => z.ground != null && registries().PERMEABLE_GROUNDS.has(z.ground)).reduce((s, z) => s + areaOfZone(z), 0);
1499
1502
  if (permeable / area >= zone.permeableMin) return;
1500
- const candidates = zones.filter((z) => ADJUSTABLE_ZONES.has(z.type) && !registries().PERMEABLE_GROUNDS.has(z.ground)).sort((a, b) => areaOfZone(b) - areaOfZone(a));
1503
+ const candidates = zones.filter((z) => ADJUSTABLE_ZONES.has(z.type) && !(z.ground != null && registries().PERMEABLE_GROUNDS.has(z.ground))).sort((a, b) => areaOfZone(b) - areaOfZone(a));
1501
1504
  for (const z of candidates) {
1502
1505
  if (permeable / area >= zone.permeableMin) break;
1503
- adjustments.push({ field: "ground:" + z.id, from: z.ground, to: target, reason: "permeable_min" });
1506
+ adjustments.push({ field: "ground:" + z.id, from: z.ground ?? "", to: target, reason: "permeable_min" });
1504
1507
  z.ground = target;
1505
1508
  permeable += areaOfZone(z);
1506
1509
  }
@@ -1767,9 +1770,9 @@ var GameUrban = (() => {
1767
1770
  height: type === "pedestrian" ? style.height : Math.min(style.height, 2.2),
1768
1771
  side,
1769
1772
  to: toTarget || null,
1770
- material: "iron"
1773
+ material: "iron",
1774
+ zones: openingZones(u, v, "u", width, openingDepth(width, type === "pedestrian" ? width : 0))
1771
1775
  };
1772
- g.zones = openingZones(u, v, "u", width, openingDepth(width, type === "pedestrian" ? width : 0));
1773
1776
  gates.push(g);
1774
1777
  return g;
1775
1778
  };
@@ -2052,7 +2055,7 @@ var GameUrban = (() => {
2052
2055
  };
2053
2056
  const invalid = (m) => Object.assign(base, { valid: false, reason: m, x: 0, z: 0, ry: 0, w: 0, d: 0, frontU: 0, frontV: 1, aabb: [0, 0, 0, 0], _cell: null });
2054
2057
  if (def.anchor === "on" || def.anchor === "inside") {
2055
- const parent = byId2[def.parent];
2058
+ const parent = def.parent ? byId2[def.parent] : void 0;
2056
2059
  if (!parent || !parent.valid) return invalid("invalid_parent");
2057
2060
  return Object.assign(base, { x: parent.x, z: parent.z, ry: parent.ry, w: parent.w, d: parent.d, frontU: parent.frontU, frontV: parent.frontV, aabb: parent.aabb, _cell: parent._cell });
2058
2061
  }
@@ -2093,9 +2096,10 @@ var GameUrban = (() => {
2093
2096
  const windowList = windowsOfRoom(plan, room);
2094
2097
  win = windowList[def.n];
2095
2098
  if (!win) return invalid("no_window");
2099
+ const found2 = win;
2096
2100
  side = room.outdoor ? SIDE_OPPOSITE[win.side] : WINDOW_SIDE[win.side];
2097
2101
  const cand = room.parts.map(inner).find(
2098
- (r) => (win.axis === "u" ? win.u >= r[0] - TOL && win.u <= r[2] + TOL : win.v >= r[1] - TOL && win.v <= r[3] + TOL) && (side === "left" && eq(r[0], win.pos + MARGIN) || side === "right" && eq(r[2], win.pos - MARGIN) || side === "front" && eq(r[1], win.pos + MARGIN) || side === "back" && eq(r[3], win.pos - MARGIN))
2102
+ (r) => (found2.axis === "u" ? found2.u >= r[0] - TOL && found2.u <= r[2] + TOL : found2.v >= r[1] - TOL && found2.v <= r[3] + TOL) && (side === "left" && eq(r[0], found2.pos + MARGIN) || side === "right" && eq(r[2], found2.pos - MARGIN) || side === "front" && eq(r[1], found2.pos + MARGIN) || side === "back" && eq(r[3], found2.pos - MARGIN))
2099
2103
  );
2100
2104
  if (!cand) return invalid("window_outside_room");
2101
2105
  R = cand;
@@ -2287,7 +2291,7 @@ var GameUrban = (() => {
2287
2291
  if (m.category) out.color = colorOf(m, seed);
2288
2292
  return out;
2289
2293
  });
2290
- const result = {
2294
+ const base = {
2291
2295
  template: tpl.id,
2292
2296
  name: translate("templates", tpl.id, locale),
2293
2297
  use: useOf(tpl),
@@ -2324,8 +2328,8 @@ var GameUrban = (() => {
2324
2328
  building: tpl.building ? tpl.building(plan.w, plan.d, op) : null,
2325
2329
  missing
2326
2330
  };
2327
- if (tpl.singleFloor) result.floorNumber = op.floor || 3;
2328
- result.partyWalls = tpl.partyWalls || [];
2331
+ if (tpl.singleFloor) base.floorNumber = op.floor || 3;
2332
+ const result = Object.assign(base, { partyWalls: tpl.partyWalls || [] });
2329
2333
  if (plan.config) result.config = plan.config;
2330
2334
  runResultExtensions(plan, result, seed, op);
2331
2335
  if (zone) {
@@ -10256,7 +10260,9 @@ var GameUrban = (() => {
10256
10260
  function fogLamp(c, s, r) {
10257
10261
  onSurf(c.cylinder(r * 1.4, r * 1.4, 0.014, LH, 0, 0, 0), s, 6e-3).castShadow = false;
10258
10262
  onSurf(c.cylinder(r, r, 0.012, REFL, 0, 0, 0), s, 0.012).castShadow = false;
10259
- onSurf(c.sphere(r * 0.45, MT.head, 0, 0, 0, 1, 0.5, 1), s, 0.016).castShadow = false;
10263
+ const bulb = onSurf(c.sphere(r * 0.45, MT.head, 0, 0, 0, 1, 0.5, 1), s, 0.016);
10264
+ bulb.castShadow = false;
10265
+ (c.fogBulbs ?? (c.fogBulbs = [])).push(bulb);
10260
10266
  }
10261
10267
  function crease(c, I, sd, pts, o) {
10262
10268
  o = o || {};
@@ -13533,6 +13539,7 @@ var GameUrban = (() => {
13533
13539
  hood: true
13534
13540
  },
13535
13541
  function(c) {
13542
+ c.meta.armor = "III";
13536
13543
  const f = 3.75, W = 2.32, len = 1.85, ax = 2.5, wr = 0.506, ww = 0.28, col = "#56616b";
13537
13544
  c.meta.bullet = true;
13538
13545
  c.meta.cabLength = len + 0.15;
@@ -19257,7 +19264,9 @@ var GameUrban = (() => {
19257
19264
  function fogLamp(c, s, r) {
19258
19265
  onSurf(c.cylinder(r * 1.4, r * 1.4, 0.014, LH, 0, 0, 0), s, 6e-3).castShadow = false;
19259
19266
  onSurf(c.cylinder(r, r, 0.012, REFL, 0, 0, 0), s, 0.012).castShadow = false;
19260
- onSurf(c.sphere(r * 0.45, MT.head, 0, 0, 0, 1, 0.5, 1), s, 0.016).castShadow = false;
19267
+ const bulb = onSurf(c.sphere(r * 0.45, MT.head, 0, 0, 0, 1, 0.5, 1), s, 0.016);
19268
+ bulb.castShadow = false;
19269
+ (c.fogBulbs ?? (c.fogBulbs = [])).push(bulb);
19261
19270
  }
19262
19271
  function crease(c, I, sd, pts, o) {
19263
19272
  o = o || {};
@@ -26466,7 +26475,7 @@ var GameUrban = (() => {
26466
26475
  const x = kit.profX(s.lower, s.bottomY + 0.14, true) + 0.09;
26467
26476
  [1, -1].forEach(function(sd) {
26468
26477
  c.roundBox(0.04, r * 2.6, r * 3.2, 0.015, MT.housing, x, y, sd * z);
26469
- kit.headlight(c, {
26478
+ const lamp = kit.headlight(c, {
26470
26479
  style: "round",
26471
26480
  x: x + 0.01,
26472
26481
  y,
@@ -26478,6 +26487,7 @@ var GameUrban = (() => {
26478
26487
  label: sd > 0 ? trl("labels.right_fog_light") : trl("labels.left_fog_light"),
26479
26488
  reach: 0.5
26480
26489
  });
26490
+ lamp.fog = true;
26481
26491
  });
26482
26492
  }
26483
26493
  function roofBars(c, z, h, r) {