feat(factions): add player-faction type, reputation, relationships, and cover image
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
parent
00919ceeb3
commit
b14e04c487
2 changed files with 146 additions and 1 deletions
|
|
@ -13,6 +13,30 @@ export const Factions: CollectionConfig = {
|
|||
delete: isDeveloper,
|
||||
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",
|
||||
|
|
@ -24,6 +48,10 @@ export const Factions: CollectionConfig = {
|
|||
name: "type",
|
||||
type: "select",
|
||||
options: [
|
||||
{
|
||||
label: "Player Faction",
|
||||
value: "playerFaction",
|
||||
},
|
||||
{
|
||||
label: "Major Faction",
|
||||
value: "majorFaction",
|
||||
|
|
@ -43,11 +71,68 @@ export const Factions: CollectionConfig = {
|
|||
],
|
||||
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",
|
||||
|
|
@ -70,5 +155,14 @@ export const Factions: CollectionConfig = {
|
|||
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.",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -986,7 +986,10 @@ export interface Vehicle {
|
|||
export interface Faction {
|
||||
id: number;
|
||||
name: string;
|
||||
type: 'majorFaction' | 'minorFaction' | 'corporation' | 'special';
|
||||
/**
|
||||
* Player Faction = the faction our unit is currently playing as. Only one faction can carry this type at a time.
|
||||
*/
|
||||
type: 'playerFaction' | 'majorFaction' | 'minorFaction' | 'corporation' | 'special';
|
||||
description?: {
|
||||
root: {
|
||||
type: string;
|
||||
|
|
@ -1002,6 +1005,30 @@ export interface Faction {
|
|||
};
|
||||
[k: string]: unknown;
|
||||
} | null;
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
reputation?: number | null;
|
||||
/**
|
||||
* Pairwise standing between this faction and another faction, from -100 (hostile) to 100 (allied). 0 is neutral. One entry per counterpart faction.
|
||||
*/
|
||||
relationships?:
|
||||
| {
|
||||
/**
|
||||
* The other faction in this pairwise relationship.
|
||||
*/
|
||||
targetFaction: number | Faction;
|
||||
/**
|
||||
* Standing from -100 (hostile) to 100 (allied). 0 is neutral.
|
||||
*/
|
||||
value: number;
|
||||
/**
|
||||
* Optional context for why this relationship stands where it does.
|
||||
*/
|
||||
notes?: string | null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
/**
|
||||
* Whether or not this faction is playable. Some factions may be specifically intended to be unplayable based on narrative requirements.
|
||||
*/
|
||||
|
|
@ -1011,6 +1038,10 @@ export interface Faction {
|
|||
*/
|
||||
startingFaction?: boolean | null;
|
||||
associatedCampaigns?: (number | Campaign)[] | null;
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
coverImage?: (number | null) | Media;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
|
|
@ -1040,6 +1071,10 @@ export interface Campaign {
|
|||
} | null;
|
||||
startDate?: string | null;
|
||||
endDate?: string | null;
|
||||
/**
|
||||
* Background image for the campaign selector card on the campaigns page. Renders translucent with hover effects. Recommended aspect ratio: 16:9 or square.
|
||||
*/
|
||||
coverImage?: (number | null) | Media;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
|
|
@ -1519,6 +1554,10 @@ export interface Mission {
|
|||
* Hash of the last attendance state rendered to Discord (managed by the bot).
|
||||
*/
|
||||
discordAttendanceHash?: string | null;
|
||||
/**
|
||||
* Background image for the mission page hero header. Renders translucent with a top-to-bottom fade to black. Recommended aspect ratio: 16:9 or wider.
|
||||
*/
|
||||
coverImage?: (number | null) | Media;
|
||||
classification: {
|
||||
map: number | Map;
|
||||
missionType: 'Zeus' | 'PvE' | 'PvP' | 'PvPvE' | 'Training' | 'Special';
|
||||
|
|
@ -2731,6 +2770,7 @@ export interface MissionsSelect<T extends boolean = true> {
|
|||
operationType?: T;
|
||||
discordMessageId?: T;
|
||||
discordAttendanceHash?: T;
|
||||
coverImage?: T;
|
||||
classification?:
|
||||
| T
|
||||
| {
|
||||
|
|
@ -2859,6 +2899,7 @@ export interface CampaignsSelect<T extends boolean = true> {
|
|||
description?: T;
|
||||
startDate?: T;
|
||||
endDate?: T;
|
||||
coverImage?: T;
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
}
|
||||
|
|
@ -2870,9 +2911,19 @@ export interface FactionsSelect<T extends boolean = true> {
|
|||
name?: T;
|
||||
type?: T;
|
||||
description?: T;
|
||||
reputation?: T;
|
||||
relationships?:
|
||||
| T
|
||||
| {
|
||||
targetFaction?: T;
|
||||
value?: T;
|
||||
notes?: T;
|
||||
id?: T;
|
||||
};
|
||||
playableFaction?: T;
|
||||
startingFaction?: T;
|
||||
associatedCampaigns?: T;
|
||||
coverImage?: T;
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue