import { CollectionConfig } from "payload"; import { requirePermission } from "@/utils/access-control/hasPermission"; export const Factions: CollectionConfig = { slug: "factions", admin: { group: "Intelligence", useAsTitle: "name", }, access: { create: requirePermission("factions:create"), update: requirePermission("factions:update"), delete: requirePermission("factions:delete"), read: ({ req }) => !!req.user, }, hooks: { beforeValidate: [ async ({ data, operation, originalDoc, req }) => { if (data?.type !== "playerFaction") return data; const payload = req.payload; const existing = await payload.find({ collection: "factions", where: { type: { equals: "playerFaction" } }, limit: 1, depth: 0, overrideAccess: true, }); const conflict = existing.docs.find((doc) => doc.id !== originalDoc?.id); if (conflict) { throw new Error( `Only one faction can be the Player Faction at a time. "${conflict.name}" is already the Player Faction.`, ); } return data; }, ], }, fields: [ { name: "name", type: "text", required: true, unique: true, }, { name: "type", type: "select", options: [ { label: "Player Faction", value: "playerFaction", }, { label: "Major Faction", value: "majorFaction", }, { label: "Minor Faction", value: "minorFaction", }, { label: "Corporation", value: "corporation", }, { label: "Special", value: "special", }, ], required: true, defaultValue: "minorFaction", admin: { description: "Player Faction = the faction our unit is currently playing as. Only one faction can carry this type at a time.", }, }, { name: "description", type: "richText", }, { name: "reputation", type: "number", admin: { description: "This faction's standing in the world, from -100 (reviled) to 100 (revered). 0 is neutral. Adjusted manually by admins/GMs as campaign events unfold.", }, defaultValue: 0, min: -100, max: 100, }, { name: "relationships", type: "array", labels: { singular: "Relationship", plural: "Relationships", }, admin: { description: "Pairwise standing between this faction and another faction, from -100 (hostile) to 100 (allied). 0 is neutral. One entry per counterpart faction.", }, fields: [ { name: "targetFaction", type: "relationship", relationTo: "factions", required: true, admin: { description: "The other faction in this pairwise relationship.", }, }, { name: "value", type: "number", required: true, defaultValue: 0, min: -100, max: 100, admin: { description: "Standing from -100 (hostile) to 100 (allied). 0 is neutral.", }, }, { name: "notes", type: "textarea", admin: { description: "Optional context for why this relationship stands where it does.", }, }, ], }, { name: "playableFaction", type: "checkbox", admin: { description: "Whether or not this faction is playable. Some factions may be specifically intended to be unplayable based on narrative requirements.", }, }, { name: "startingFaction", type: "checkbox", admin: { description: "Whether or not this faction is/was available as a starting faction at the beginning of the campaign.", }, }, { name: "associatedCampaigns", type: "relationship", relationTo: "campaigns", hasMany: true, }, { name: "coverImage", type: "upload", relationTo: "media", admin: { description: "Background image for the faction detail page hero. Renders translucent with a top-to-bottom fade to black. Recommended aspect ratio: 16:9 or wider.", }, }, ], };