@adatechnology/game-urban 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts 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;
@@ -650,6 +650,7 @@ var GameUrban = (() => {
650
650
  var MAX_CANDIDATES = 80;
651
651
  function carCandidates(slot, item, car) {
652
652
  const front = [slot.frontU, slot.frontV];
653
+ if (!slot._cell) throw new Error("Slot without a cell: " + slot.id);
653
654
  const zone = slot._cell.R;
654
655
  const alongV = Math.abs(front[1]) === 1;
655
656
  const [extentU, extentV] = extent([item.w, item.d], front);
@@ -869,6 +870,7 @@ var GameUrban = (() => {
869
870
  }
870
871
  function itemRect(slot, it, shift) {
871
872
  const c = slot._cell;
873
+ if (!c) throw new Error("Slot without a cell: " + slot.id);
872
874
  const f = c.f;
873
875
  const [extentU, extentV] = extent([it.w, it.d], f);
874
876
  const R = c.R;
@@ -973,7 +975,7 @@ var GameUrban = (() => {
973
975
  if (!parent) return null;
974
976
  for (const { it } of cands) {
975
977
  if (it.w > parent.w + EPS || it.d > parent.d + EPS) continue;
976
- const f = [parent.frontU, parent.frontV];
978
+ const f = [parent.frontU ?? 0, parent.frontV ?? 1];
977
979
  const r = parent.aabb;
978
980
  const [extentU, extentV] = extent([it.w, it.d], f);
979
981
  const cu = (r[0] + r[2]) / 2 - f[0] * (parent.d / 2 - it.d / 2);
@@ -1007,7 +1009,7 @@ var GameUrban = (() => {
1007
1009
  if (!car && !relax && s.clearance > 0 && !it.low) {
1008
1010
  cl2 = clearRect(r3, f, s.clearance);
1009
1011
  if (!insideUnion(cl2, inners)) continue;
1010
- if (items.some((m2) => !m2.low && !m2.flat && !m2.on && overlaps(cl2, m2._r))) continue;
1012
+ if (items.some((m2) => !m2.low && !m2.flat && !m2.on && overlaps(cl2, m2._r ?? m2.aabb))) continue;
1011
1013
  }
1012
1014
  if (!it.low && reserves.some((q) => overlaps(r3, q))) continue;
1013
1015
  let rimRect2 = null;
@@ -1191,7 +1193,7 @@ var GameUrban = (() => {
1191
1193
  if (!(opts.without && opts.without(r))) return r;
1192
1194
  continue;
1193
1195
  }
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;
1196
+ 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
1197
  if (opts.without && opts.without(r)) continue;
1196
1198
  if (!reachable(opts.railing || gridOf(room), solidList.concat([r]), room.outdoor ? 0.16 : plan.playerRadius)) continue;
1197
1199
  return r;
@@ -1452,7 +1454,7 @@ var GameUrban = (() => {
1452
1454
  const far = m.built / area;
1453
1455
  if (far > zone.maxFar + 1e-9) out.push({ rule: "far", actual: r2(far), limit: zone.maxFar });
1454
1456
  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]);
1457
+ 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
1458
  const permeability = permeable / area;
1457
1459
  if (permeability < zone.permeableMin - 1e-9) out.push({ rule: "permeable", actual: r2(permeability), limit: zone.permeableMin });
1458
1460
  return out;
@@ -1495,12 +1497,12 @@ var GameUrban = (() => {
1495
1497
  const [u0, v0, u1, v1] = lot.rect;
1496
1498
  const area = (u1 - u0) * (v1 - v0);
1497
1499
  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);
1500
+ let permeable = zones.filter((z) => z.ground != null && registries().PERMEABLE_GROUNDS.has(z.ground)).reduce((s, z) => s + areaOfZone(z), 0);
1499
1501
  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));
1502
+ 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
1503
  for (const z of candidates) {
1502
1504
  if (permeable / area >= zone.permeableMin) break;
1503
- adjustments.push({ field: "ground:" + z.id, from: z.ground, to: target, reason: "permeable_min" });
1505
+ adjustments.push({ field: "ground:" + z.id, from: z.ground ?? "", to: target, reason: "permeable_min" });
1504
1506
  z.ground = target;
1505
1507
  permeable += areaOfZone(z);
1506
1508
  }
@@ -1767,9 +1769,9 @@ var GameUrban = (() => {
1767
1769
  height: type === "pedestrian" ? style.height : Math.min(style.height, 2.2),
1768
1770
  side,
1769
1771
  to: toTarget || null,
1770
- material: "iron"
1772
+ material: "iron",
1773
+ zones: openingZones(u, v, "u", width, openingDepth(width, type === "pedestrian" ? width : 0))
1771
1774
  };
1772
- g.zones = openingZones(u, v, "u", width, openingDepth(width, type === "pedestrian" ? width : 0));
1773
1775
  gates.push(g);
1774
1776
  return g;
1775
1777
  };
@@ -2052,7 +2054,7 @@ var GameUrban = (() => {
2052
2054
  };
2053
2055
  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
2056
  if (def.anchor === "on" || def.anchor === "inside") {
2055
- const parent = byId2[def.parent];
2057
+ const parent = def.parent ? byId2[def.parent] : void 0;
2056
2058
  if (!parent || !parent.valid) return invalid("invalid_parent");
2057
2059
  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
2060
  }
@@ -2093,9 +2095,10 @@ var GameUrban = (() => {
2093
2095
  const windowList = windowsOfRoom(plan, room);
2094
2096
  win = windowList[def.n];
2095
2097
  if (!win) return invalid("no_window");
2098
+ const found2 = win;
2096
2099
  side = room.outdoor ? SIDE_OPPOSITE[win.side] : WINDOW_SIDE[win.side];
2097
2100
  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))
2101
+ (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
2102
  );
2100
2103
  if (!cand) return invalid("window_outside_room");
2101
2104
  R = cand;
@@ -2287,7 +2290,7 @@ var GameUrban = (() => {
2287
2290
  if (m.category) out.color = colorOf(m, seed);
2288
2291
  return out;
2289
2292
  });
2290
- const result = {
2293
+ const base = {
2291
2294
  template: tpl.id,
2292
2295
  name: translate("templates", tpl.id, locale),
2293
2296
  use: useOf(tpl),
@@ -2324,8 +2327,8 @@ var GameUrban = (() => {
2324
2327
  building: tpl.building ? tpl.building(plan.w, plan.d, op) : null,
2325
2328
  missing
2326
2329
  };
2327
- if (tpl.singleFloor) result.floorNumber = op.floor || 3;
2328
- result.partyWalls = tpl.partyWalls || [];
2330
+ if (tpl.singleFloor) base.floorNumber = op.floor || 3;
2331
+ const result = Object.assign(base, { partyWalls: tpl.partyWalls || [] });
2329
2332
  if (plan.config) result.config = plan.config;
2330
2333
  runResultExtensions(plan, result, seed, op);
2331
2334
  if (zone) {
@@ -13533,6 +13536,7 @@ var GameUrban = (() => {
13533
13536
  hood: true
13534
13537
  },
13535
13538
  function(c) {
13539
+ c.meta.armor = "III";
13536
13540
  const f = 3.75, W = 2.32, len = 1.85, ax = 2.5, wr = 0.506, ww = 0.28, col = "#56616b";
13537
13541
  c.meta.bullet = true;
13538
13542
  c.meta.cabLength = len + 0.15;