feat(players): NPC disposition types and launch-with-players session tokens
Add Hostile/Neutral/Friendly ring types with session-only inactive overrides on control, plus launch-with-players flow and live player tokens on the map. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -60,6 +60,12 @@ import {
|
||||
normalizeSceneNpcToken,
|
||||
type SceneNpcToken,
|
||||
} from '../../shared/types/appPlayers';
|
||||
import {
|
||||
DEFAULT_NPC_DISPOSITION,
|
||||
normalizeNpcDisposition,
|
||||
npcDispositionRingColor,
|
||||
type NpcDisposition,
|
||||
} from '../../shared/types/npcDisposition';
|
||||
import { DEFAULT_SCENE_GRID, normalizeSceneGrid } from '../../shared/types/sceneGrid';
|
||||
import { normalizeSceneTrap } from '../../shared/types/sceneTraps';
|
||||
import type {
|
||||
@@ -1263,6 +1269,7 @@ export class ZipProjectStore {
|
||||
filePath?: string;
|
||||
groupId?: NpcGroupId | null;
|
||||
ringColor?: string;
|
||||
disposition?: NpcDisposition;
|
||||
imageOffset?: { x: number; y: number };
|
||||
imageScale?: number;
|
||||
},
|
||||
@@ -1344,6 +1351,12 @@ export class ZipProjectStore {
|
||||
...(input.ringColor !== undefined
|
||||
? { ringColor: normalizeHexColor(input.ringColor, DEFAULT_PLAYER_RING_COLOR) }
|
||||
: {}),
|
||||
...(input.disposition !== undefined
|
||||
? {
|
||||
disposition: normalizeNpcDisposition(input.disposition),
|
||||
ringColor: npcDispositionRingColor(normalizeNpcDisposition(input.disposition)),
|
||||
}
|
||||
: {}),
|
||||
...(input.imageOffset !== undefined
|
||||
? { imageOffset: clampPlayerImageOffset(input.imageOffset) }
|
||||
: {}),
|
||||
@@ -1354,6 +1367,7 @@ export class ZipProjectStore {
|
||||
} else {
|
||||
if (!nextAssetId) throw new Error('NPC avatar is required');
|
||||
const count = npcs.length;
|
||||
const disposition = normalizeNpcDisposition(input.disposition ?? DEFAULT_NPC_DISPOSITION);
|
||||
npcs.push({
|
||||
id: asNpcId(`npc_${this.randomId()}`),
|
||||
name,
|
||||
@@ -1362,7 +1376,8 @@ export class ZipProjectStore {
|
||||
x: 80 + (count % 4) * 220,
|
||||
y: 80 + Math.floor(count / 4) * 200,
|
||||
groupId: resolveGroup(input.groupId, null),
|
||||
ringColor: normalizeHexColor(input.ringColor, DEFAULT_PLAYER_RING_COLOR),
|
||||
disposition,
|
||||
ringColor: npcDispositionRingColor(disposition),
|
||||
imageOffset: clampPlayerImageOffset(input.imageOffset),
|
||||
imageScale: clampPlayerImageScale(input.imageScale),
|
||||
});
|
||||
@@ -1383,6 +1398,7 @@ export class ZipProjectStore {
|
||||
description?: string;
|
||||
groupId?: NpcGroupId | null;
|
||||
ringColor?: string;
|
||||
disposition?: NpcDisposition;
|
||||
imageOffset?: { x: number; y: number };
|
||||
imageScale?: number;
|
||||
},
|
||||
@@ -1405,14 +1421,22 @@ export class ZipProjectStore {
|
||||
if (patch.groupId !== undefined) {
|
||||
groupId = patch.groupId === null ? null : groupIds.has(patch.groupId) ? patch.groupId : null;
|
||||
}
|
||||
const disposition =
|
||||
patch.disposition !== undefined
|
||||
? normalizeNpcDisposition(patch.disposition)
|
||||
: normalizeNpcDisposition(n.disposition);
|
||||
return {
|
||||
...n,
|
||||
...(name !== undefined ? { name } : {}),
|
||||
...(typeof patch.description === 'string' ? { description: patch.description } : {}),
|
||||
groupId,
|
||||
...(patch.ringColor !== undefined
|
||||
? { ringColor: normalizeHexColor(patch.ringColor, DEFAULT_PLAYER_RING_COLOR) }
|
||||
: {}),
|
||||
disposition,
|
||||
ringColor:
|
||||
patch.disposition !== undefined
|
||||
? npcDispositionRingColor(disposition)
|
||||
: patch.ringColor !== undefined
|
||||
? normalizeHexColor(patch.ringColor, DEFAULT_PLAYER_RING_COLOR)
|
||||
: n.ringColor || npcDispositionRingColor(disposition),
|
||||
...(patch.imageOffset !== undefined
|
||||
? { imageOffset: clampPlayerImageOffset(patch.imageOffset) }
|
||||
: {}),
|
||||
@@ -2495,7 +2519,10 @@ function normalizeProject(p: Project): Project {
|
||||
x,
|
||||
y,
|
||||
groupId: resolveNpcGroupId(obj.groupId, groupIdSet),
|
||||
ringColor: normalizeHexColor(obj.ringColor, DEFAULT_PLAYER_RING_COLOR),
|
||||
disposition: normalizeNpcDisposition((obj as { disposition?: unknown }).disposition),
|
||||
ringColor: npcDispositionRingColor(
|
||||
normalizeNpcDisposition((obj as { disposition?: unknown }).disposition),
|
||||
),
|
||||
imageOffset: clampPlayerImageOffset(obj.imageOffset),
|
||||
imageScale: clampPlayerImageScale((obj as { imageScale?: unknown }).imageScale),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user