- map-zones type gains territory and country border (informational political boundaries that never gate placement, default fills amber 0.1 / violet 0.06) - map-roads labelVisible is tri-state: unset means auto, where paved roads always label and dirt/trail only label at 4 m/px or finer (roadLabelShown) - migration clears the old implicit label default on non-paved roads - new pure snapping lib: findSnap (vertices own their neighborhood, edges must be twice as close), closestPointOnSegment, segmentMidpoints - tests for label angles, tri-state rule, snapping, political zones
125 lines
3.3 KiB
TypeScript
125 lines
3.3 KiB
TypeScript
import { CollectionConfig } from "payload";
|
|
import { requirePermission } from "@/utils/access-control/hasPermission";
|
|
import { validateHexColor } from "@/lib/map/style";
|
|
import { validatePolygon } from "@/lib/map/points";
|
|
|
|
/**
|
|
* GM-drawn terrain zones. Land blueprints cannot be placed inside water
|
|
* polygons; water blueprints require one. Default terrain (no zones on the
|
|
* map) accepts everything.
|
|
*/
|
|
export const MapZones: CollectionConfig = {
|
|
slug: "map-zones",
|
|
admin: {
|
|
group: "World",
|
|
useAsTitle: "name",
|
|
},
|
|
access: {
|
|
read: ({ req }) => !!req.user,
|
|
create: requirePermission("maps:create"),
|
|
update: requirePermission("maps:update"),
|
|
delete: requirePermission("maps:delete"),
|
|
},
|
|
fields: [
|
|
{
|
|
name: "name",
|
|
type: "text",
|
|
admin: {
|
|
description: 'Zone label (e.g. "Altis bay", "Flood plain").',
|
|
},
|
|
},
|
|
{
|
|
name: "description",
|
|
type: "textarea",
|
|
admin: {
|
|
description: "Shown in the zone's tooltip and popup on the map.",
|
|
},
|
|
},
|
|
{
|
|
name: "map",
|
|
type: "relationship",
|
|
relationTo: "maps",
|
|
required: true,
|
|
},
|
|
{
|
|
name: "type",
|
|
type: "select",
|
|
required: true,
|
|
options: [
|
|
{ label: "Water", value: "water" },
|
|
{ label: "Land", value: "land" },
|
|
{ label: "Territory", value: "territory" },
|
|
{ label: "Country Border", value: "border" },
|
|
],
|
|
admin: {
|
|
description:
|
|
"Water zones block land-blueprint placement. Land zones are informational; default terrain is buildable land. Territory and Country Border are political boundaries (informational).",
|
|
},
|
|
},
|
|
{
|
|
name: "fillColor",
|
|
type: "text",
|
|
validate: validateHexColor,
|
|
admin: {
|
|
description: "Polygon fill as hex (e.g. #38bdf8). Empty = default color for the type.",
|
|
},
|
|
},
|
|
{
|
|
name: "strokeColor",
|
|
type: "text",
|
|
validate: validateHexColor,
|
|
admin: {
|
|
description: "Outline color as hex. Empty = default color for the type.",
|
|
},
|
|
},
|
|
{
|
|
name: "fillOpacity",
|
|
type: "number",
|
|
min: 0,
|
|
max: 1,
|
|
admin: {
|
|
description:
|
|
"Fill opacity 0-1. Empty = default (0.25 water, 0.08 land, 0.1 territory, 0.06 border).",
|
|
},
|
|
},
|
|
{
|
|
name: "strokeWeight",
|
|
type: "number",
|
|
min: 0,
|
|
max: 10,
|
|
defaultValue: 1,
|
|
admin: {
|
|
description: "Outline thickness in pixels. 0 hides the outline.",
|
|
},
|
|
},
|
|
{
|
|
name: "resources",
|
|
type: "relationship",
|
|
relationTo: "resources",
|
|
hasMany: true,
|
|
admin: {
|
|
description:
|
|
"Resources contained in this zone (e.g. an oil field). A zone with resources satisfies blueprint resourcesInRange requirements for any site inside it.",
|
|
},
|
|
},
|
|
{
|
|
name: "labelVisible",
|
|
type: "checkbox",
|
|
defaultValue: true,
|
|
label: "Show Name Label",
|
|
admin: {
|
|
description: "Renders the zone's name at the polygon's center.",
|
|
},
|
|
},
|
|
{
|
|
name: "points",
|
|
type: "json",
|
|
required: true,
|
|
validate: validatePolygon,
|
|
admin: {
|
|
description:
|
|
"Polygon ring as an array of [x, y] meter tuples (need not repeat the first point).",
|
|
},
|
|
},
|
|
],
|
|
};
|