feat(npcs): add groups, storyline bindings, and Foundry import
Nested NPC groups with color, graph filter, and scene/storyline binding; Foundry worlds/modules import actors into groups; storyline merge asks on NPC name conflicts and reports NPC counts. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,6 +1,15 @@
|
||||
import type { AssetId, GraphNodeId, MaterialId, NpcId, NpcRelationId, ProjectId, SceneId } from './ids';
|
||||
import type {
|
||||
AssetId,
|
||||
GraphNodeId,
|
||||
MaterialId,
|
||||
NpcGroupId,
|
||||
NpcId,
|
||||
NpcRelationId,
|
||||
ProjectId,
|
||||
SceneId,
|
||||
} from './ids';
|
||||
|
||||
export const PROJECT_SCHEMA_VERSION = 8 as const;
|
||||
export const PROJECT_SCHEMA_VERSION = 9 as const;
|
||||
|
||||
/** Материал кампании: изображение, показываемое поверх сцены во время игры. */
|
||||
export type ProjectMaterial = {
|
||||
@@ -10,6 +19,26 @@ export type ProjectMaterial = {
|
||||
rotationDeg: 0 | 90 | 180 | 270;
|
||||
};
|
||||
|
||||
/** Группа НПС (дерево через parentId). */
|
||||
export type ProjectNpcGroup = {
|
||||
id: NpcGroupId;
|
||||
name: string;
|
||||
/** Hex `#rrggbb`. */
|
||||
color: string;
|
||||
parentId: NpcGroupId | null;
|
||||
};
|
||||
|
||||
/** Привязка НПС к сюжетной линии. */
|
||||
export type NpcStorylineRef =
|
||||
| { kind: 'main' }
|
||||
| { kind: 'side'; startGraphNodeId: GraphNodeId };
|
||||
|
||||
/** Привязка НПС к линии или сцене; `none` — без привязки. */
|
||||
export type NpcBinding =
|
||||
| { kind: 'none' }
|
||||
| { kind: 'storyline'; storyline: NpcStorylineRef }
|
||||
| { kind: 'scene'; sceneId: SceneId };
|
||||
|
||||
/** НПС кампании: персонаж с аватаром, описанием и связями на графе. */
|
||||
export type ProjectNpc = {
|
||||
id: NpcId;
|
||||
@@ -20,6 +49,9 @@ export type ProjectNpc = {
|
||||
/** Позиция карточки на графе взаимосвязей. */
|
||||
x: number;
|
||||
y: number;
|
||||
/** `null` — системная секция «Без группы». */
|
||||
groupId: NpcGroupId | null;
|
||||
binding: NpcBinding;
|
||||
};
|
||||
|
||||
/** Однонаправленная связь: от `sourceNpcId` к `targetNpcId`; подпись на линии. */
|
||||
@@ -167,6 +199,8 @@ export type Project = {
|
||||
materials: ProjectMaterial[];
|
||||
/** НПС кампании (порядок = порядок в списке редактора/пульта). */
|
||||
npcs: ProjectNpc[];
|
||||
/** Группы НПС (порядок среди siblings = порядок в массиве). */
|
||||
npcGroups: ProjectNpcGroup[];
|
||||
/** Связи между НПС (однонаправленные; между одной парой направлений может быть несколько). */
|
||||
npcRelations: ProjectNpcRelation[];
|
||||
currentSceneId: SceneId | null;
|
||||
|
||||
@@ -7,6 +7,7 @@ export type GraphNodeId = Brand<string, 'GraphNodeId'>;
|
||||
export type MaterialId = Brand<string, 'MaterialId'>;
|
||||
export type NpcId = Brand<string, 'NpcId'>;
|
||||
export type NpcRelationId = Brand<string, 'NpcRelationId'>;
|
||||
export type NpcGroupId = Brand<string, 'NpcGroupId'>;
|
||||
|
||||
export function asProjectId(value: string): ProjectId {
|
||||
return value as ProjectId;
|
||||
@@ -35,3 +36,7 @@ export function asNpcId(value: string): NpcId {
|
||||
export function asNpcRelationId(value: string): NpcRelationId {
|
||||
return value as NpcRelationId;
|
||||
}
|
||||
|
||||
export function asNpcGroupId(value: string): NpcGroupId {
|
||||
return value as NpcGroupId;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user