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).", }, }, ], };