*/ public static function geometry(City $city): array { $waterline = Beach::sandTo($city); // 264 for the shipped bounds $gridEast = (float) (ceil(((float) $city->bounds_max_x) / 40) * 40 + 40); // 200 $quayX = $waterline + 2; // quay straddles the shore $yardWest = $gridEast + 4; $yardEast = $waterline - 6; $yardCenterX = ($yardWest + $yardEast) / 2; return [ 'visit' => [ 'min_x' => self::VISIT_MIN_X, 'max_x' => $quayX + 2, // walk to the quay edge (266) 'min_z' => self::VISIT_MIN_Z, 'max_z' => self::VISIT_MAX_Z, ], 'water' => [ // The east sea extends north to cover the port basin // (initBeach widens its plane down to this Z). 'z_min' => self::VISIT_MIN_Z - 10, ], // Far-half layout (zone z −430..−290): terminal at the city // (south) gate, yard behind it, quay along the shore. 'quay' => ['center' => [$quayX, -360.0], 'size' => [8.0, 130.0]], 'yard' => ['center' => [$yardCenterX, -362.0], 'size' => [$yardEast - $yardWest, 116.0]], 'terminal' => ['center' => [$yardCenterX, -297.0], 'size' => [46.0, 14.0]], 'cranes' => [ ['center' => [$quayX, -330.0]], ['center' => [$quayX, -395.0]], ], // Berth centres spaced so full hulls never touch: 60-unit // container ship + 88-unit liner need >=82 between centres. 'berths' => [ ['id' => 1, 'center' => [$quayX + 16, -310.0]], ['id' => 2, 'center' => [$quayX + 20, -393.0]], ], 'ships' => [ ['id' => 'c1', 'name' => 'CITY VOYAGER', 'company' => 'City10 Cargo', 'kind' => 'container', 'berth' => 1], ['id' => 'c2', 'name' => 'AZUL MAR', 'company' => 'AzulCéu Cargo', 'kind' => 'container', 'berth' => null], ['id' => 'l1', 'name' => 'ATLÂNTICO CELESTE', 'company' => 'NorteLine', 'kind' => 'liner', 'berth' => 2], ], 'boats' => [ ['name' => 'Lancha V1'], ['name' => 'Lancha V2'], ['name' => 'Lancha V3'], ], ]; } /** * Whether a point is on the walkable port grounds/quay. */ public static function isOnPort(City $city, float $x, float $z): bool { $visit = self::geometry($city)['visit']; return $x >= $visit['min_x'] && $x <= $visit['max_x'] && $z >= $visit['min_z'] && $z <= $visit['max_z']; } }