<!-- SOLID CITY · part 2785 -->
i + 1].z });
      }
    });
    function segDist(px, pz, s) {
      var dx = s.x2 - s.x1, dz = s.z2 - s.z1, L2 = dx * dx + dz * dz;
      var t = L2 ? ((px - s.x1) * dx + (pz - s.z1) * dz) / L2 : 0; t = Math.max(0, Math.min(1, t));
      return Math.hypot(px - (s.x1 + dx * t), pz - (s.z1 + dz * t));
    }
    function foreignClear(px, pz, ownNm, ownI) {
      var cx = Math.floor(px / 16), cz = Math.floor(pz / 16);
      for (var a = -1; a <= 1; a++) for (var b = -1; b <= 1; b++) {
        var list = cells[(cx + a) + ',' + (cz + b)]; if (!list) continue;
        for (var q = 0; q < list.length; q++) {
          var s = list[q];
          if (s.nm === ownNm && Math.abs(s.i - ownI) <= 12) continue;
          if (segDist(px, pz, s) < 6.4) return false;
        }
      }
      return true;
    }
    names.forEach(function (nm) {
      var sts = smithRoads[nm].stations;
      [-1, 1].forEach(function (sd) {
        var run = null;
        function flush() {
          if (!run) return;
          var dx = run.x1 - run.x0, dz = run.z1 - run.z0;
          foot.push([(run.x0 + run.x1) / 2, (run.z0 + run.z1) / 2, Math.hypot(dx, dz) + 0.2, 1.1, run.y0, run.y1, Math.atan2(-dz, dx)]);
          run = null;
        }
        for (var i = 0; i < sts.length - 1; i++) {
          var A = sts[i], B = sts[i + 1];
          var ca = sd < 0 ? A.L : A.R, cb = sd < 0 ? B.L : B.R;
          var mx = (ca[0] + cb[0]) / 2, mz = (ca[2] + cb[2]) / 2;
          var rx = (A.rx + B.rx) / 2, rz = (A.rz + B.rz) / 2, rl = Math.hypot(rx, rz) || 1; rx /= rl; rz /= rl;
          var edgeY = (ca[1] + cb[1]) / 2;
          var drop = edgeY - groundAt(mx + sd * rx * 2.2, mz + sd * rz * 2.2);
          var skip = drop < 1.0;
          if (!skip) for (var j = 0; j < JX.length && !skip; j++) { if (Math.hypot(ca[0] - JX[j][0], ca[2] - JX[j][1]) < 11 || Math.hypot(cb[0] - JX[j][0], cb[2] - JX[j][1]) < 11) skip = true; }
          if (!skip) for (var k = 0; k < driveMouths.length && !skip; k++) if (Math.hypot(mx - driveMouths[k][0], mz - driveMouths[k][1]) < 4.5) skip = true;
          if (!skip && (!foreignClear(ca[0], ca[2], nm, i) || !foreignClear(cb[0], cb[2], nm, i))) skip = true;
          if (skip) { flush(); continue; }
          var y1 = Math.max(ca[1], cb[1]) - 0.5, y0 = Math.min(groundAt(ca[0], ca[2]), groundAt(cb[0], cb[2])) - 0.6;
          if (y1 - y0 < 0.7) { flush(); continue; }
          if (run) {
            var adx = cb[0] - run.x1, adz = cb[2] - run.z1, rdx = run.x1 - run.x0, rdz = run.z1 - run.z0;
            var turn = Math.abs(Math.atan2(-adz, adx) - Math.atan2(-rdz, rdx));
            if (turn > 0.06 || Math.hypot(run.x1 - run.x0, run.z1 - run.z0) > 10) flush();
          }
          /* a run's rise is capped at 0.8 m: the body's top is set
           * by its highest edge, and at the run's low end that top
           * must stay a full metre under the local surface, or the
           * collision step would nudge a walker on the shoulder.
           * On steep ground the runs simply shorten. */
          var segHi = Math.max(ca[1], cb[1]), segLo = Math.min(ca[1], cb[1]);
          if (run && (Math.max(run.hi, segHi) - Math.min(run.lo, segLo) > 0.8)) flush();
          if (!run) run = { x0: ca[0], z0: ca[2], x1: cb[0], z1: cb[2], y0: y0, y1: y1, hi: segHi, lo: segLo };
          else { run.x1 = cb[0]; run.z1 = cb[2]; if (y0 < run.y0) run.y0 = y0; if (y1 > run.y1) run.y1 = y1; if (segHi > run.hi) run.hi = segHi; if (segLo < run.lo) run.lo = segLo; }
        }
        flush();
      });
    });
  }
  buildRoads();
  compound(700, -1290, "THE GATE ROAD 'OHANA", 'plantation', ['waa', 'noa', 'plantation']);
  compound(880, -1180, "THE EAST PLAIN 'OHANA", 'plantation', ['dickey', 'waa', 'noa']);
  compound(-480, -1150, "THE SHORE ROAD 'OHANA", 'dickey', ['noa', 'plantation', 'waa']);
  singles(560, -1330, 'THE MERIDIAN BENCHES', 6, ['plantation', 'noa', 'waa', 'dickey']);
  compound(1080, -1620, 'THE EASTERN BENCHES', 'dickey', ['plantation', 'waa', 'mission'], { ring: 33 });
  singles(1270, -1560, 'THE HIGH BENCHES', 6, ['dickey', 'plantation', 'noa']);
  singles(950, -1830, 'THE OVERLOOK BENCHES', 4, ['waa', 'dickey', 'plantation']);
  singles(790, -1900, 'THE EAST CLIMB HOMES', 4, ['plantation', 'waa', 'noa']);
  compound(660, -2080, 'THE NORTH BENCHES', 'plantation', ['waa', 'plantation', 'noa']);
  singles(430, -2330, 'THE COLOSSEUM ROAD HOMES', 7, ['plantation', 'dickey', 'noa', 'waa']);
  compound(470, -2430, "THE FAR NORTH 'OHANA", 'noa', ['waa', 'plantation', 'noa']);
  singles(-350, -1080, 'THE WESTERN BENCHES', 5, ['noa', 'plantation', 'waa'], 100);
  // the base flats — two small apartment blocks where the ground gentles
  var aptSites = [[705, -1005, -Math.PI / 2], [-625, -1155, Math.PI / 2], [820, -1120, -Math.PI / 2]];
  for (var ai = 0; ai < aptSites.length && homes.filter(function (h) { return h.style === 'apartment'; }).length < 2; ai++) {
    var as = aptSites[ai];
    if (benchAt(as[0