# character.yaml — schema definition for Xyvera character content files # # Every file under content/data/characters/ must conform to this schema. # Run `tools/validate_content.py` to check all data files against schemas. # # Design notes from spec: # - Rarity: R / SR / SSR / UR (four-tier PoC model; full ladder naming deferred) # - Combat roles: recon, sabotage, healer, support, tank, glass_cannon # - Profession roles: miner, lumberjack, researcher, construction, farmer, trainer # - Male and female presentation variants are art/naming only; mechanics identical # - No duplicate-dependency model: progression uses universal materials, bonds, # and assignment mastery $schema: "xyvera/content-schema/character/v1" type: object required: - id - name - rarity - combat_role - profession - base_stats - skills - suitability_bonuses properties: id: type: string description: "Unique character identifier. Snake_case. Shared between male/female variants." pattern: "^[a-z][a-z0-9_]*$" example: "lyra_stoneheart" name: type: object description: "Display names for each presentation variant." required: [female] properties: female: type: string example: "Lyra Stoneheart" male: type: string example: "Leon Stoneheart" additionalProperties: false rarity: type: string enum: [R, SR, SSR, UR] description: "R = common filler, SR = reliable specialist, SSR = premium, UR = rare/prestige" combat_role: type: string enum: [recon, sabotage, healer, support, tank, glass_cannon] profession: type: string enum: [miner, lumberjack, researcher, construction, farmer, trainer] description: "Primary village assignment profession. Used to determine suitability bonuses." region_origin: type: string description: "World region this character is associated with. Affects banner pools and event tags." example: "heartwood_vale" element: type: string enum: [fire, water, earth, wind, light, shadow, null] description: "Optional elemental archetype. 'null' means no element." default: "null" personality: type: string description: "Short personality descriptor used for relationship flavor and dialogue tags." example: "stoic_protector" base_stats: type: object description: "Stats at level 1 / ascension 0. Scaling is applied by the server formula." required: [hp, attack, defense, speed] properties: hp: type: integer minimum: 1 attack: type: integer minimum: 1 defense: type: integer minimum: 1 speed: type: integer minimum: 1 crit_rate: type: number minimum: 0.0 maximum: 1.0 default: 0.05 crit_damage: type: number minimum: 1.0 default: 1.5 additionalProperties: false skills: type: array description: "Character skills. First entry is the combat passive; second is the signature active." minItems: 1 maxItems: 4 items: type: object required: [id, name, description, type] properties: id: type: string pattern: "^[a-z][a-z0-9_]*$" name: type: string description: type: string type: type: string enum: [passive, active, ultimate] max_level: type: integer minimum: 1 maximum: 10 default: 5 upgrade_cost_per_level: type: object description: "Resource costs to advance one skill level. Keys are resource IDs." additionalProperties: type: integer minimum: 0 suitability_bonuses: type: object description: > Multiplier applied to passive output when this character is assigned to a matching job slot. A character with their primary profession gets 1.5x; secondary gets 1.2x; unmatched gets 1.0x (no bonus). These values override the defaults. properties: primary_profession_multiplier: type: number minimum: 1.0 default: 1.5 secondary_professions: type: array items: type: string enum: [miner, lumberjack, researcher, construction, farmer, trainer] description: "Additional professions where this character earns the secondary bonus." additionalProperties: false bond_hooks: type: array description: "Relationship flavor tags used to unlock bond dialogue and minor stat bonuses." items: type: string example: ["loyalty", "mentor", "rival"] lore_summary: type: string description: "One or two sentence background. Minimal story as per spec."