import type { SceneRulebook } from "./contracts/rulebook"; export const DEFAULT_RULEBOOK_ID = "rulebook_default"; /** * Builds the default SceneRulebook, encoding all validation logic that was * previously hardcoded in truthEngine.ts as editable, data-driven rules. */ export function createDefaultRulebook(worldId: string): SceneRulebook { const now = Date.now(); return { id: DEFAULT_RULEBOOK_ID, worldId, name: "Default Rulebook", description: "Built-in scene rules for the CharacterGarden engine. Edit freely — the engine re-evaluates on every turn.", createdAt: now, updatedAt: now, rules: [ { actionType: "inspect", enabled: true, checks: [], }, { actionType: "take", enabled: true, checks: [ { id: "take_target_exists", description: "Target entity must exist in the world", condition: { op: "entityExists", role: "target" }, failReason: "target_not_found", failMessage: "Target '{target.id}' does not exist.", }, { id: "take_same_location", description: "Actor and target must be in the same location", condition: { op: "sameLocation", roleA: "actor", roleB: "target" }, failReason: "not_in_same_location", failMessage: "Target '{target.id}' is not in the same location as '{actor.id}'.", }, { id: "take_takeable", description: "Target must have takeable attribute set to true", condition: { op: "eq", role: "target", attribute: "takeable", value: true }, failReason: "not_takeable", failMessage: "Target '{target.id}' cannot be taken.", }, ], }, { actionType: "open", enabled: true, checks: [ { id: "open_target_exists", description: "Target entity must exist in the world", condition: { op: "entityExists", role: "target" }, failReason: "target_not_found", failMessage: "Target '{target.id}' does not exist.", }, { id: "open_openable", description: "Target must have openable attribute set to true", condition: { op: "eq", role: "target", attribute: "openable", value: true }, failReason: "not_openable", failMessage: "Target '{target.id}' is not openable.", }, { id: "open_lock_check", description: "If target is locked, actor must possess the required key (has_ attribute)", condition: { op: "or", conditions: [ { op: "not", condition: { op: "eq", role: "target", attribute: "locked", value: true }, }, { op: "attributeRef", checkRole: "actor", prefix: "has_", refRole: "target", refAttribute: "requiredKey", }, ], }, failReason: "locked_requires_key", failMessage: "Target '{target.id}' is locked and requires a key.", }, ], }, { actionType: "move", enabled: true, checks: [ { id: "move_target_is_room", description: "Target must be an existing entity of type 'room'", condition: { op: "and", conditions: [ { op: "entityExists", role: "target" }, { op: "entityType", role: "target", requiredType: "room" }, ], }, failReason: "target_not_found", failMessage: "Move target '{target.id}' is not a valid room.", }, ], }, { actionType: "introduce", enabled: true, checks: [ { id: "introduce_actor_authorized", description: "Only approved characters can introduce/create characters in-scene", condition: { op: "actorIdIn", allowedIds: ["player"], }, failReason: "actor_not_authorized", failMessage: "Actor '{actor.id}' is not allowed to introduce new characters.", }, { id: "introduce_actor_in_room", description: "Actor must be located in a valid room entity", condition: { op: "and", conditions: [ { op: "entityExists", role: "actorRoom" }, { op: "entityType", role: "actorRoom", requiredType: "room" }, ], }, failReason: "room_not_found", failMessage: "Actor '{actor.id}' is not currently in a valid room.", }, { id: "introduce_room_joinable", description: "Actor's room must allow new arrivals (is_joinable: true)", condition: { op: "eq", role: "actorRoom", attribute: "is_joinable", value: true }, failReason: "room_not_joinable", failMessage: "Room is not available for new arrivals.", }, { id: "introduce_target_is_character", description: "If target entity exists, it must be of type 'character'", condition: { op: "or", conditions: [ { op: "not", condition: { op: "entityExists", role: "target" } }, { op: "entityType", role: "target", requiredType: "character" }, ], }, failReason: "target_not_character", failMessage: "Target '{target.id}' is not a character and cannot join the scene.", }, { id: "introduce_target_social", description: "If target exists, it must be socially available (is_social: true)", condition: { op: "or", conditions: [ { op: "not", condition: { op: "entityExists", role: "target" } }, { op: "eq", role: "target", attribute: "is_social", value: true }, ], }, failReason: "target_not_social", failMessage: "Target '{target.id}' is not socially available to join the scene.", }, { id: "introduce_not_already_present", description: "If target exists, it must not already be in the same room as the actor", condition: { op: "or", conditions: [ { op: "not", condition: { op: "entityExists", role: "target" } }, { op: "not", condition: { op: "sameLocation", roleA: "actor", roleB: "target" }, }, ], }, failReason: "already_in_scene", failMessage: "Target '{target.id}' is already present in the scene.", }, { id: "introduce_no_name_duplicate", description: "When introducing a new character by name, no character with that name may already be in the room", condition: { op: "metaValueNotInRoom", metaKey: "characterName", entityType: "character", }, failReason: "already_in_scene", failMessage: "A character with this name is already present in the scene.", }, ], }, { actionType: "describe", enabled: true, checks: [ { id: "describe_target_exists", description: "Target must exist in the world or be created earlier in this turn", condition: { op: "entityExistsOrWillBeCreated", role: "target" }, failReason: "target_not_found", failMessage: "Target '{target.id}' does not exist.", }, { id: "describe_target_is_character", description: "If target exists, it must be of type 'character'", condition: { op: "or", conditions: [ { op: "not", condition: { op: "entityExists", role: "target" } }, { op: "entityType", role: "target", requiredType: "character" }, ], }, failReason: "target_not_character", failMessage: "Target '{target.id}' is not a character and cannot be described.", }, { id: "describe_same_location", description: "If target exists, actor and target must be in the same location", condition: { op: "or", conditions: [ { op: "not", condition: { op: "entityExists", role: "target" } }, { op: "sameLocation", roleA: "actor", roleB: "target" }, ], }, failReason: "not_in_same_location", failMessage: "Target '{target.id}' is not in the same location as '{actor.id}'.", }, ], }, ], }; }