{"$schema":"https://json-schema.org/draft/2020-12/schema","title":"Kit","description":"A kit: its content and how it joins a story.","type":"object","properties":{"formatVersion":{"description":"The content format its content is written in (migrated as a project's is).","type":"integer","format":"uint32","minimum":0},"id":{"description":"`kit_…`, kept across its versions.","type":"string"},"version":{"description":"1, 2, … one per published change.","type":"integer","format":"uint32","minimum":0},"name":{"type":"string"},"description":{"type":"string","default":""},"needs":{"description":"Features switched on when it is added (their starter packs not).","type":"array","items":{"$ref":"#/$defs/Feature"}},"bundle":{"description":"The bundle it is made for (L-199, `rpg`): adding it to a game without that bundle offers\nthe bundle too.","type":["string","null"]},"content":{"$ref":"#/$defs/KitContent"},"hooks":{"description":"Its open ways: exits of its passages without a target in the kit, where the creator\nconnects it to the story.","type":"array","items":{"$ref":"#/$defs/KitHook"}},"help":{"description":"How to use it, shown when it is added.","type":"array","items":{"$ref":"#/$defs/KitHelp"}}},"required":["formatVersion","id","version","name","content"],"$defs":{"Feature":{"type":"string","enum":["scenes","characters","things","equipment","documents","collections","checks","battles","skills","levels","talk_sounds","maps","camp","time","weather","dungeons"]},"KitContent":{"description":"What a kit brings: the lists of a project it may fill (a project's settings, look and book\nstay the project's own).","type":"object","properties":{"values":{"type":"array","items":{"$ref":"#/$defs/ValueDef"}},"formulas":{"type":"array","items":{"$ref":"#/$defs/SharedFormula"}},"chapters":{"type":"array","items":{"$ref":"#/$defs/Chapter"}},"rules":{"type":"array","items":{"$ref":"#/$defs/EveryPassageRule"}},"passages":{"type":"array","items":{"$ref":"#/$defs/Passage"}},"decks":{"type":"array","items":{"$ref":"#/$defs/Deck"}},"endings":{"type":"array","items":{"$ref":"#/$defs/Ending"}},"characters":{"type":"array","items":{"$ref":"#/$defs/Character"}},"things":{"type":"array","items":{"$ref":"#/$defs/Thing"}},"combinations":{"type":"array","items":{"$ref":"#/$defs/Combination"}},"storages":{"type":"array","items":{"$ref":"#/$defs/Storage"}},"collections":{"type":"array","items":{"$ref":"#/$defs/Collection"}},"statusEffects":{"type":"array","items":{"$ref":"#/$defs/StatusEffect"}},"skills":{"type":"array","items":{"$ref":"#/$defs/Skill"}}}},"ValueDef":{"type":"object","properties":{"id":{"type":"string"},"key":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"type":{"$ref":"#/$defs/ValueType"},"states":{"description":"Type `state`: its states in order; `default` is a state key.","type":["array","null"],"items":{"$ref":"#/$defs/StateDef"}},"items":{"description":"Type `list`: the items it may hold; `default` holds the keys of its starting entries in\norder (L-20).","type":["array","null"],"items":{"$ref":"#/$defs/ListItem"}},"scope":{"$ref":"#/$defs/ValueScope"},"appliesTo":{"description":"Scope `character`: default `characters`.","anyOf":[{"$ref":"#/$defs/AppliesTo"},{"type":"null"}]},"chapterId":{"description":"A game value kept within one chapter (L-147): back at its default whenever the story moves\ninto another chapter; only that chapter's passages name it (`value.outside_chapter`).","type":["string","null"]},"default":{"$ref":"#/$defs/Scalar"},"min":{"type":["number","null"],"format":"double"},"max":{"type":["number","null"],"format":"double"},"bar":{"anyOf":[{"$ref":"#/$defs/Bar"},{"type":"null"}]},"shown":{"type":"boolean"},"stats":{"description":"How a shown game value appears on the Stats page (none: as a number, also in the status\nline).","anyOf":[{"$ref":"#/$defs/ValueStats"},{"type":"null"}]},"notice":{"type":["string","null"]},"codeword":{"type":["string","null"]},"maxLength":{"type":["integer","null"],"format":"uint32","minimum":0},"keep":{"description":"A game value kept across playthroughs (L-88): `MetaState.values` holds it, and a new game\nstarts with it.","$ref":"#/$defs/ValueKeep","x-default":"playthrough"}},"required":["id","key","name","type","scope","default","shown"]},"ValueType":{"oneOf":[{"type":"string","enum":["yesno","number","text"]},{"description":"One of a named list of states (a quest: not started → accepted → done); stored as its key.","type":"string","const":"state"},{"description":"Entries of its items in the order added, repeats allowed (L-20); stored as item IDs.","type":"string","const":"list"}]},"StateDef":{"description":"A state of a state value.","type":"object","properties":{"id":{"type":"string"},"key":{"description":"What formulas compare with: `quest == \"key_found\"`.","type":"string"},"name":{"type":"string"},"description":{"description":"Shown under the name where players choose it (character creation, L-32).","type":["string","null"]},"picture":{"description":"Its picture where players choose it, and the portrait of a character whose\n`portraitFromValueId` is this value (L-32).","anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]}},"required":["id","key","name"]},"ImageRef":{"type":"object","properties":{"assetId":{"type":"string"},"alt":{"type":["string","null"]}},"required":["assetId"]},"ListItem":{"description":"An item a list value may hold (L-20): `itm_…`, a key for formulas, a name players read.","type":"object","properties":{"id":{"type":"string"},"key":{"type":"string"},"name":{"type":"string"}},"required":["id","key","name"]},"ValueScope":{"type":"string","enum":["game","character"]},"AppliesTo":{"anyOf":[{"$ref":"#/$defs/AppliesToGroup"},{"type":"object","properties":{"characterIds":{"type":"array","items":{"type":"string"}}},"required":["characterIds"]}]},"AppliesToGroup":{"oneOf":[{"type":"string","enum":["characters"]},{"description":"Characters and enemies.","type":"string","const":"everyone"},{"description":"The characters who can be in the party.","type":"string","const":"party"}]},"Scalar":{"description":"A value of a `ValueDef`: yes/no, number, text or a list's entries (L-20: item keys in a\n`default`, item IDs in a game state).","anyOf":[{"type":"boolean"},{"type":"number","format":"double"},{"type":"string"},{"type":"array","items":{"type":"string"}}]},"Bar":{"description":"A number clamped to a maximum (`hp` with maximum `max_hp`).","type":"object","properties":{"max":{"$ref":"#/$defs/BarMax"},"color":{"type":["string","null"]}},"required":["max"]},"BarMax":{"anyOf":[{"type":"object","properties":{"valueId":{"type":"string"}},"required":["valueId"]},{"type":"object","properties":{"fixed":{"type":"number","format":"double"}},"required":["fixed"]}]},"ValueStats":{"description":"A value on the Stats page (docs/game_systems_spec.md, \"Values\").","type":"object","properties":{"group":{"description":"A heading (\"Personality\", \"Skills\").","type":["string","null"]},"display":{"$ref":"#/$defs/StatDisplay"},"opposite":{"description":"`opposed`: the name of the other side (\"Cautious\" for \"Brave\").","type":["string","null"]},"statusLine":{"description":"Also in the status line.","type":"boolean","default":true}},"required":["display"]},"StatDisplay":{"type":"string","enum":["number","percent","opposed"]},"ValueKeep":{"description":"How long a value lasts (L-88).","oneOf":[{"description":"One playthrough: a new game starts at the default.","type":"string","const":"playthrough"},{"description":"Every playthrough in this browser.","type":"string","const":"all_playthroughs"}]},"SharedFormula":{"description":"A shared formula (docs/game_systems_spec.md, \"Shared formulas\").","type":"object","properties":{"id":{"description":"`fml_…`","type":"string"},"key":{"description":"The name formulas call it by (`trust_bonus`).","type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"params":{"description":"The inputs' names inside the body (numbers): `[\"base\", \"bonus\"]`.","type":"array","items":{"type":"string"},"default":[]},"body":{"description":"A formula of the `world` context using the params.","type":"string"}},"required":["id","key","name","body"]},"Chapter":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"color":{"type":"string"},"card":{"description":"A title card when the story enters the chapter (none: no card).","anyOf":[{"$ref":"#/$defs/ChapterCard"},{"type":"null"}]},"complete":{"description":"\"Chapter complete\" when the story leaves the chapter for a passage outside it.","type":"boolean"},"choiceStats":{"description":"L-186: when the story leaves it, the player shows what other players chose at its choices\n(the release's play statistics).","type":"boolean"},"room":{"description":"The room its passages play in when they name none (L-58).","anyOf":[{"$ref":"#/$defs/Room"},{"type":"null"}]},"music":{"description":"Its music (L-191): it starts when the story enters the chapter from outside it, before\nthe passage's own steps and scene (they win), and plays on until something changes it.","type":["string","null"]},"encounterAreaId":{"description":"Encounters on the way in its passages that name no area (L-63).","type":["string","null"]},"ground":{"description":"The ground underfoot in its passages that name none (L-57).","anyOf":[{"$ref":"#/$defs/Ground"},{"type":"null"}]},"background":{"description":"The picture behind its passages that set none of their own (P6-06; a scene's picture\nstands over it). Only the player's view reads it.","anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"backgroundVariants":{"description":"The background by time of day, season or weather (P6-09): the most specific that holds.","type":"array","items":{"$ref":"#/$defs/PictureVariant"}},"indoors":{"description":"Its passages are indoors (Weather, P6-10): no weather falls, its sound is muffled.","type":"boolean"},"weatherKinds":{"description":"A weather of its own (Weather, P6-10): only these kinds here (the desert: never snow);\nthe first is what the weather becomes on arriving when the one before is not among them.","type":"array","items":{"type":"string"}}},"required":["id","title","color"]},"ChapterCard":{"description":"A chapter's title card: the title with a number above it, a picture and a sound.","type":"object","properties":{"number":{"description":"Above the title: \"Chapter 2\", \"Part II\" (none: the title alone).","type":["string","null"]},"image":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"sound":{"description":"Played once as the card appears (sound-effects volume).","type":["string","null"]}}},"Room":{"description":"The room a passage plays in (L-58, \"Room sound\"): its sound effects, talk sounds and voices\n(music and ambience with `music`) pass through a reverb or a filter. Only the player's audio\nreads it: the engine plays every passage the same. `kind` is a name, not an enum, so the\nplayer's build carries no parser for it; the player ignores a name it does not know, and\nvalidation reports it (`room.unknown`).","type":"object","properties":{"kind":{"$ref":"#/$defs/RoomKind"},"amount":{"description":"How much of the room is heard, 0–1 (none: 0.5).","type":["number","null"],"format":"double","minimum":0,"maximum":1},"music":{"description":"Music and ambience pass through the room too (else they stay dry).","type":"boolean"}},"required":["kind"]},"RoomKind":{"description":"The rooms that come with Talebench (L-58); only in the schema.","type":"string","enum":["none","small_room","hall","cave","cathedral","stairwell","forest","underwater","radio"]},"Ground":{"description":"The grounds footsteps are made for (L-57, \"Sounds on the way\"); only in the schema.","type":"string","enum":["stone","wood","grass","gravel","sand","snow","mud","water","wet","carpet","metal"]},"PictureVariant":{"description":"A picture for a time of day, a season or a weather: \"the harbour at night\". Every named part\nmust hold; the most specific variant wins.","type":"object","properties":{"id":{"description":"`var_…`: the address of its picture's alt text.","type":"string"},"part":{"description":"A day part's ID.","type":["string","null"]},"season":{"description":"A season's ID.","type":["string","null"]},"weather":{"description":"A weather kind's ID.","type":["string","null"]},"image":{"$ref":"#/$defs/ImageRef"}},"required":["id","image"]},"EveryPassageRule":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"chapterIds":{"type":["array","null"],"items":{"type":"string"}},"onlyIf":{"type":["string","null"]},"effects":{"type":"array","items":{"$ref":"#/$defs/Effect"},"default":[]},"when":{"description":"When it runs (none: each time a passage is entered): a new day, a new time of day, a\nseason, a change of weather (P6-09, P6-10).","anyOf":[{"$ref":"#/$defs/RuleWhen"},{"type":"null"}]}},"required":["id","name"]},"Effect":{"description":"One vocabulary for every effect list (section 5). Effects never move the story; exits do.\nRead by a hand-written reader (`tagged.rs`) that keeps the player's engine small.","oneOf":[{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"valueId":{"type":"string"},"characterId":{"type":["string","null"]},"to":{"type":"string"},"type":{"type":"string","const":"set"}},"required":["type","valueId","to"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"valueId":{"type":"string"},"characterId":{"type":["string","null"]},"by":{"type":"string"},"type":{"type":"string","const":"change"}},"required":["type","valueId","by"]},{"description":"An entry at the end of a list value (L-20).","type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"valueId":{"type":"string"},"characterId":{"type":["string","null"]},"itemId":{"type":"string"},"type":{"type":"string","const":"add_to_list"}},"required":["type","valueId","itemId"]},{"description":"The item's earliest entry out of a list value; without an item its first entry (L-20).","type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"valueId":{"type":"string"},"characterId":{"type":["string","null"]},"itemId":{"type":["string","null"]},"type":{"type":"string","const":"remove_from_list"}},"required":["type","valueId"]},{"description":"Empties a list value (L-20).","type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"valueId":{"type":"string"},"characterId":{"type":["string","null"]},"type":{"type":"string","const":"clear_list"}},"required":["type","valueId"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"thingId":{"type":"string"},"qty":{"type":"string"},"storageId":{"description":"Into this storage instead of the inventory (reachable or not).","type":["string","null"]},"randomParts":{"description":"L-176: a made thing's parts drawn from the random stream (one draw per group).","type":"boolean"},"parts":{"description":"L-176: a made thing with these parts (none and no `randomParts`: no parts).","type":"array","items":{"type":"string"}},"type":{"type":"string","const":"give"}},"required":["type","thingId","qty"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"thingId":{"type":"string"},"qty":{"type":"string"},"storageId":{"type":["string","null"]},"type":{"type":"string","const":"take"}},"required":["type","thingId","qty"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"characterId":{"type":"string"},"mountId":{"type":"string"},"type":{"type":"string","const":"mount"}},"required":["type","characterId","mountId"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"characterId":{"type":"string"},"type":{"type":"string","const":"dismount"}},"required":["type","characterId"]},{"description":"Weapons and shields (L-106): a thing put on a party member (none: the first) in its slot,\ngiven first when none is carried; what it takes the place of goes back to the inventory.","type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"thingId":{"type":"string"},"characterId":{"type":["string","null"]},"type":{"type":"string","const":"wear"}},"required":["type","thingId"]},{"description":"P8-87: a thing kept as a party member's (none: the first) second set in its slot, given\nfirst when none is carried (a weapon rack's choice for swapping in a dice battle).","type":"object","properties":{"onlyIf":{"type":["string","null"]},"thingId":{"type":"string"},"characterId":{"type":["string","null"]},"type":{"type":"string","const":"second_set"}},"required":["type","thingId"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"lootTableId":{"type":"string"},"type":{"type":"string","const":"give_loot"}},"required":["type","lootTableId"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"characterId":{"type":"string"},"type":{"type":"string","const":"join_party"}},"required":["type","characterId"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"characterId":{"type":"string"},"type":{"type":"string","const":"leave_party"}},"required":["type","characterId"]},{"description":"`who`: `party` or a character ID.","type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"who":{"type":"string"},"amount":{"type":"string"},"type":{"type":"string","const":"gain_xp"}},"required":["type","who","amount"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"who":{"type":"string"},"levels":{"type":"integer","format":"uint32","minimum":0},"type":{"type":"string","const":"gain_level"}},"required":["type","who","levels"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"who":{"type":"string"},"points":{"type":"integer","format":"uint32","minimum":0},"type":{"type":"string","const":"grant_skill_points"}},"required":["type","who","points"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"who":{"type":"string"},"points":{"type":"integer","format":"uint32","minimum":0},"type":{"type":"string","const":"grant_stat_points"}},"required":["type","who","points"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"characterId":{"type":"string"},"skillId":{"type":"string"},"type":{"type":"string","const":"learn_skill"}},"required":["type","characterId","skillId"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"characterId":{"type":"string"},"skillId":{"type":"string"},"type":{"type":"string","const":"forget_skill"}},"required":["type","characterId","skillId"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"who":{"type":"string"},"type":{"type":"string","const":"restore"}},"required":["type","who"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"who":{"type":"string"},"statusId":{"type":"string"},"type":{"type":"string","const":"add_status"}},"required":["type","who","statusId"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"who":{"type":"string"},"statusId":{"type":"string"},"type":{"type":"string","const":"remove_status"}},"required":["type","who","statusId"]},{"description":"Maps: the place is found.","type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"placeId":{"type":"string"},"type":{"type":"string","const":"discover_place"}},"required":["type","placeId"]},{"description":"Maps: a vehicle that waits where it was left now waits at this place (L-64).","type":"object","properties":{"onlyIf":{"type":["string","null"]},"vehicleId":{"type":"string"},"placeId":{"type":"string"},"type":{"type":"string","const":"place_vehicle"}},"required":["type","vehicleId","placeId"]},{"description":"Time: time passes (\"2 hours\"), then waits until a time of day or an hour (P6-09).","type":"object","properties":{"onlyIf":{"type":["string","null"]},"minutes":{"description":"Minutes that pass (a formula; the editor shows hours and days as 60 and 1440).","type":["string","null"]},"untilPart":{"description":"Then waits until this day part begins (\"wait until morning\"; nothing while it lasts).","type":["string","null"]},"untilHour":{"description":"Then waits until this hour, 0–23 (nothing when it is that hour on the dot).","type":["integer","null"],"format":"uint32","minimum":0},"type":{"type":"string","const":"time"}},"required":["type"]},{"description":"Weather: the weather becomes this kind (\"the storm breaks\", P6-10).","type":"object","properties":{"onlyIf":{"type":["string","null"]},"set":{"type":"string"},"type":{"type":"string","const":"weather"}},"required":["type","set"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"entryId":{"type":"string"},"sectionId":{"type":["string","null"]},"type":{"type":"string","const":"reveal"}},"required":["type","entryId"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"thingId":{"type":"string"},"type":{"type":"string","const":"mark_read"}},"required":["type","thingId"]},{"description":"L-221: _Play with a friend_ opened for this fight (an encounter played with a friend); the\ngame's state does not change (the player makes the match).","type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"encounterId":{"type":"string"},"type":{"type":"string","const":"play_with_friend"}},"required":["type","encounterId"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"assetId":{"type":["string","null"]},"fadeMs":{"type":"integer","format":"uint32","minimum":0},"volume":{"description":"Its loudness, 0–100 % under the player's own volume (L-192; none: 100).","type":["integer","null"],"format":"uint8","minimum":0,"maximum":255},"type":{"type":"string","const":"music"}},"required":["type","fadeMs"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"assetId":{"type":["string","null"]},"fadeMs":{"type":"integer","format":"uint32","minimum":0},"volume":{"description":"Its loudness, 0–100 % under the player's own volume (L-192; none: 100).","type":["integer","null"],"format":"uint8","minimum":0,"maximum":255},"type":{"type":"string","const":"ambience"}},"required":["type","fadeMs"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"assetId":{"type":"string"},"volume":{"description":"Its loudness, 0–100 % under the player's own volume (L-192; none: 100).","type":["integer","null"],"format":"uint8","minimum":0,"maximum":255},"type":{"type":"string","const":"sound"}},"required":["type","assetId"]},{"description":"The weather's own sound quiet (faded out over `fadeMs`) or back (L-192): it stays quiet\nuntil the weather changes.","type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"quiet":{"type":"boolean"},"fadeMs":{"type":"integer","format":"uint32","minimum":0},"type":{"type":"string","const":"weather_sound"}},"required":["type","quiet","fadeMs"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"damageTypeId":{"type":"string"},"formula":{"type":["string","null"]},"type":{"type":"string","const":"damage"}},"required":["type","damageTypeId"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"barId":{"type":"string"},"formula":{"type":["string","null"]},"type":{"type":"string","const":"heal"}},"required":["type","barId"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"percent":{"type":"number","format":"double"},"type":{"type":"string","const":"revive"}},"required":["type","percent"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"statusId":{"type":"string"},"chance":{"type":"string"},"type":{"type":"string","const":"apply_status"}},"required":["type","statusId","chance"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"kind":{"$ref":"#/$defs/CleanseKind"},"type":{"type":"string","const":"cleanse"}},"required":["type","kind"]},{"description":"Defeated at once after one draw of `chance` (1 = always); `defeat` immunity resists it.","type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"chance":{"type":"string"},"type":{"type":"string","const":"defeat"}},"required":["type","chance"]},{"description":"Takes one thing a foe carries (`CombatProfile.carries`) after one draw of `chance` (L-70);\na foe is robbed once; on an ally it does nothing.","type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"chance":{"type":"string"},"type":{"type":"string","const":"steal"}},"required":["type","chance"]},{"description":"Adds `amount` to each target's morale (L-96; negative lowers it, no draw); a target without\nmorale is left alone.","type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"amount":{"type":"string"},"type":{"type":"string","const":"change_morale"}},"required":["type","amount"]},{"description":"Dice tricks (L-101): the skill or thing changes dice on the table in a dice battle, one's\nown after the throw or the opponent's before defending; never an action of its own.","type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"trick":{"$ref":"#/$defs/DiceTrickKind"},"on":{"$ref":"#/$defs/DiceTrickOn"},"when":{"$ref":"#/$defs/DiceTrickWhen"},"uses":{"description":"Uses per battle (none: no limit; always at most once per turn).","type":["integer","null"],"format":"uint32","minimum":0},"useWhen":{"description":"A foe's rule for using it (none: when it turns a blocked throw into a hit).","anyOf":[{"$ref":"#/$defs/DiceTrickUse"},{"type":"null"}]},"amount":{"description":"`plus` and `minus` (L-102): how much each die changes (none: 1).","type":["string","null"]},"before":{"description":"`plus` and `minus` on face-down dice: applied at once (none: at the reveal).","type":["boolean","null"]},"type":{"type":"string","const":"dice_trick"}},"required":["type","trick","on","when"]},{"description":"A package's own effect (L-197 e1): carried out by the package `module` (its\n`effect:<name>`); in a game without it, `effects.unsupported`.","type":"object","properties":{"onlyIf":{"type":["string","null"]},"module":{"type":"string"},"name":{"type":"string"},"data":true,"type":{"type":"string","const":"module"}},"required":["type","module","name"]}]},"CleanseKind":{"type":"string","enum":["harmful","helpful","all"]},"DiceTrickKind":{"description":"Dice tricks (L-101; docs/game_systems_spec.md, \"Dice battles\", \"Dice tricks\"): what a\n`dice_trick` effect does to the dice on the table.","oneOf":[{"description":"One chosen die thrown again.","type":"string","const":"reroll_one"},{"description":"One chosen die turned up or down by one (1 and 6 stay in range).","type":"string","const":"nudge"},{"description":"One chosen die turned to 6.","type":"string","const":"set_six"},{"description":"One more die thrown, the best ones kept (on the opponent's throw: the worst).","type":"string","const":"add_die"},{"description":"The opponent's rerolls do not count this turn.","type":"string","const":"lock"},{"description":"The opponent's combination does not count this throw (the sum stays).","type":"string","const":"break"},{"description":"Hidden throws (L-102): one chosen face-down die of the opponent's throw turns face up.","type":"string","const":"peek_one"},{"description":"Hidden throws (L-102): the opponent's whole throw is shown before defending.","type":"string","const":"peek_all"},{"description":"`amount` added to each of one's own dice (at most 6): the attack throw, or the defence.","type":"string","const":"plus"},{"description":"`amount` taken from each of the opponent's dice (at least 1).","type":"string","const":"minus"}]},"DiceTrickOn":{"description":"Whose dice a trick changes: one's own attack throw or the opponent's.","type":"string","enum":["own","opponent"]},"DiceTrickWhen":{"description":"When a trick is used: after one's own throw, before attacking; or on the opponent's attack\nthrow, before defending.","type":"string","enum":["after_throw","before_defence"]},"DiceTrickUse":{"description":"A foe's rule for a trick: when it turns a blocked throw into a hit (on the opponent's throw: a\nhit into a block), when the opponent's throw has a combination, or at random, one in three.","type":"string","enum":["turns_block_into_hit","against_combination","one_in_three"]},"RuleWhen":{"description":"When an every-passage rule runs (none: each time a passage is entered).","oneOf":[{"description":"Each time a passage is entered (the default).","type":"string","const":"passage"},{"description":"When a new day begins (once for each day begun).","type":"string","const":"new_day"},{"description":"When the time of day changes.","type":"string","const":"part_changes"},{"description":"When a season begins.","type":"string","const":"season_begins"},{"description":"When the weather changes.","type":"string","const":"weather_changes"}]},"Passage":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"chapterId":{"type":["string","null"]},"steps":{"type":"array","items":{"$ref":"#/$defs/Step"},"default":[]},"next":{"$ref":"#/$defs/Next"},"scene":{"description":"Scenes feature.","anyOf":[{"$ref":"#/$defs/SceneLayout"},{"type":"null"}]},"story":{"description":"What stays on screen in this passage (none: the look's `story`; P4-29). Only the player's\nview reads it: the engine plays every passage the same.","anyOf":[{"$ref":"#/$defs/StoryView"},{"type":"null"}]},"room":{"description":"The room this passage plays in (none: its chapter's; L-58).","anyOf":[{"$ref":"#/$defs/Room"},{"type":"null"}]},"savePoint":{"description":"Players may save here when the game saves only at save points (L-68).","type":"boolean"},"encounterAreaId":{"description":"Battles by chance when it is entered by a way on (none: its chapter's; L-63).","type":["string","null"]},"ground":{"description":"The ground underfoot here (none: its chapter's), for the footsteps of a way's `auto` sound\n(L-57). A name, as `room.kind`; the player plays none for a name it does not know.","anyOf":[{"$ref":"#/$defs/Ground"},{"type":"null"}]},"background":{"description":"The picture behind the story from this passage on, until another passage sets one (none:\nits chapter's, else the one before; P6-06). A scene's picture stands over it. Only the\nplayer's view reads it.","anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"backgroundVariants":{"description":"The background by time of day, season or weather (P6-09): the most specific that holds.","type":"array","items":{"$ref":"#/$defs/PictureVariant"}},"indoors":{"description":"Indoors (Weather, P6-10; none: its chapter's): no weather falls, its sound is muffled.","type":["boolean","null"]},"takes":{"description":"Minutes entering it takes (Time, P6-09; none: the game's `perPassage`).","type":["integer","null"],"format":"uint32","minimum":0},"dungeon":{"description":"A dungeon on this passage (L-155): its kind is _Dungeon_ while it has one.","anyOf":[{"$ref":"#/$defs/Dungeon"},{"type":"null"}]},"runMap":{"description":"A run map on this passage (L-90): made anew for every playthrough.","anyOf":[{"$ref":"#/$defs/RunMap"},{"type":"null"}]}},"required":["id","title","next"]},"Step":{"description":"Read by a hand-written reader (`tagged.rs`) that keeps the player's engine small.","type":"object","properties":{"id":{"type":"string"},"onlyIf":{"type":["string","null"]}},"required":["id"],"oneOf":[{"type":"object","properties":{"speakerId":{"type":["string","null"]},"expressionId":{"type":["string","null"]},"text":{"type":"string"},"image":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"voice":{"type":["string","null"]},"voiceLine":{"description":"The line's number in voice scripts, given once (docs/book_export_spec.md, \"Stable line\nnumbers\"); never read in play.","type":["integer","null"],"format":"uint32","minimum":0},"voiceFor":{"description":"The fingerprint of the text `voice` was recorded for (8 hex digits of FNV-1a); never\nread in play.","type":["string","null"]},"place":{"description":"This line's own place while the dialogue box stands on one screen.","anyOf":[{"$ref":"#/$defs/LinePlace"},{"type":"null"}]},"type":{"type":"string","const":"text"}},"required":["type","text"]},{"type":"object","properties":{"kind":{"$ref":"#/$defs/MediaKind"},"assetId":{"type":"string"},"alt":{"type":["string","null"]},"mode":{"$ref":"#/$defs/MediaMode"},"transition":{"$ref":"#/$defs/Transition"},"waitFor":{"$ref":"#/$defs/WaitFor"},"skippable":{"type":"boolean"},"caption":{"type":["string","null"]},"print":{"type":"boolean"},"type":{"type":"string","const":"media"}},"required":["type","kind","assetId","mode","transition","waitFor","skippable","print"]},{"type":"object","properties":{"effects":{"type":"array","items":{"$ref":"#/$defs/Effect"},"default":[]},"type":{"type":"string","const":"do"}},"required":["type"]},{"type":"object","properties":{"prompt":{"type":"string"},"valueId":{"type":"string"},"type":{"type":"string","const":"ask"}},"required":["type","prompt","valueId"]},{"type":"object","properties":{"thingId":{"type":"string"},"type":{"type":"string","const":"read"}},"required":["type","thingId"]},{"description":"Opens a shop over the story and waits until it closes.","type":"object","properties":{"shopId":{"type":"string"},"type":{"type":"string","const":"shop"}},"required":["type","shopId"]},{"type":"object","properties":{"characterId":{"type":"string"},"action":{"$ref":"#/$defs/StageAction"},"position":{"anyOf":[{"$ref":"#/$defs/StagePosition"},{"type":"null"}]},"expressionId":{"type":["string","null"]},"outfitId":{"description":"The character's outfit from now on (kept off stage too).","type":["string","null"]},"flip":{"description":"Faces the other way (kept until a step says otherwise).","type":["boolean","null"]},"transition":{"description":"How it enters or leaves (default fade).","anyOf":[{"$ref":"#/$defs/Transition"},{"type":"null"}]},"type":{"type":"string","const":"stage"}},"required":["type","characterId","action"]},{"description":"A screen effect: a shake or a flash (moments), a tint, a filter or weather (lasting).","type":"object","properties":{"effect":{"$ref":"#/$defs/ScreenEffectKind"},"strength":{"anyOf":[{"$ref":"#/$defs/ShakeStrength"},{"type":"null"}]},"color":{"description":"`#rrggbb`: the flash's (default white) and the tint's colour.","type":["string","null"]},"amount":{"description":"The tint: 0–1, how strongly (0 clears it).","type":["number","null"],"format":"double"},"weather":{"anyOf":[{"$ref":"#/$defs/Weather"},{"type":"null"}]},"filter":{"description":"The filter over the scene and stage (`none` takes it away).","anyOf":[{"$ref":"#/$defs/ScreenFilter"},{"type":"null"}]},"variant":{"description":"`look`: the look variant from here on (none: the one the passage's labels or chapter\nchoose, L-48).","type":["string","null"]},"zoom":{"description":"`camera` (L-37): 1–4, how close (default 1: the whole picture).","type":["number","null"],"format":"double"},"x":{"description":"`camera`: 0–1, the point of the picture in the middle of the view, from the left\n(default 0.5).","type":["number","null"],"format":"double"},"y":{"description":"`camera`: 0–1, the same from the top (default 0.5).","type":["number","null"],"format":"double"},"durationMs":{"description":"A shake's or flash's time: 100–3000 ms (default 500); a camera move's: 0–10000 ms\n(default 1000; 0: at once).","type":["integer","null"],"format":"uint32","minimum":0},"type":{"type":"string","const":"screen"}},"required":["type","effect"]},{"description":"Offers to save right here: the player opens the save slots (L-68).","type":"object","properties":{"type":{"type":"string","const":"save"}},"required":["type"]},{"description":"The player makes their character on one screen (L-32): a name typed in, a choice among\nnamed options (pronouns, a class, a look with pictures), numbers rolled or chosen, points\nto spread; every answer is a value.","type":"object","properties":{"title":{"description":"The screen's heading (none: the player text `create.title`, \"Make your character\").","type":["string","null"]},"characterId":{"description":"The character being made: the character values asked for are theirs, and their\nportrait shows on the screen.","type":["string","null"]},"fields":{"type":"array","items":{"$ref":"#/$defs/CreateField"},"default":[]},"points":{"description":"Points the player spreads over values.","anyOf":[{"$ref":"#/$defs/CreatePoints"},{"type":"null"}]},"rerolls":{"description":"How often the player may roll the rolled numbers again (none: never).","type":["integer","null"],"format":"uint32","minimum":0},"type":{"type":"string","const":"create"}},"required":["type"]},{"description":"A package's own step (L-197 v2): taken by the package `module` (its `step:<name>`), shown\nin the story as its view (`surface` \"step\") and waiting there until the player goes on.","type":"object","properties":{"module":{"type":"string"},"name":{"type":"string"},"data":true,"type":{"type":"string","const":"module"}},"required":["type","module","name"]}]},"LinePlace":{"description":"A text step's own place while the box stands on one screen.","type":"string","enum":["top","middle","bottom"]},"MediaKind":{"type":"string","enum":["image","video"]},"MediaMode":{"type":"string","enum":["panel","fullscreen","background"]},"Transition":{"type":"string","enum":["cut","fade","slide"]},"WaitFor":{"type":"string","enum":["click","end","none"]},"StageAction":{"type":"string","enum":["enter","leave","move"]},"StagePosition":{"type":"string","enum":["left","left_center","center","center_right","right"]},"ScreenEffectKind":{"oneOf":[{"type":"string","enum":["shake","flash","tint","weather","filter"]},{"description":"A look variant from here on (L-48).","type":"string","const":"look"},{"description":"The camera zooms into or pans across the scene picture, kept until changed (L-37).","type":"string","const":"camera"}]},"ShakeStrength":{"type":"string","enum":["light","strong"]},"Weather":{"type":"string","enum":["none","rain","snow","fog","petals","leaves","embers","dust","fireflies"]},"ScreenFilter":{"description":"A filter over the scene picture and the stage, kept until changed like the tint.","type":"string","enum":["none","sepia","greyscale","blur","vignette"]},"CreateField":{"description":"What a character-creation screen asks for (docs/game_systems_spec.md, \"Making your\ncharacter\"): the value's type decides how — a text is typed in, a state is chosen among its\nstates, a yes/no is a switch, a number is rolled (`roll`) or chosen between its `min` and\n`max`.","type":"object","properties":{"id":{"type":"string"},"valueId":{"type":"string"},"label":{"description":"The field's label (none: the value's name).","type":["string","null"]},"roll":{"description":"A number value: rolled when the screen opens (`1d6 + 6`).","type":["string","null"]}},"required":["id","valueId"]},"CreatePoints":{"description":"Points spread on a character-creation screen: each raise adds `step` to the value for `cost`\npoints, up to `max`.","type":"object","properties":{"amount":{"type":"integer","format":"uint32","minimum":0},"raise":{"type":"array","items":{"$ref":"#/$defs/RaisableValue"},"default":[]}},"required":["amount"]},"RaisableValue":{"description":"A value stat points raise.","type":"object","properties":{"valueId":{"description":"A character number value (Strength, Max HP).","type":"string"},"step":{"description":"Added to the base value per raise.","type":"number","format":"double"},"cost":{"description":"Stat points per raise.","type":"integer","format":"uint32","minimum":0,"default":1},"max":{"description":"The highest base value reachable by raising.","type":["number","null"],"format":"double","default":null}},"required":["valueId","step"]},"Next":{"description":"What happens after a passage's steps. Read by a hand-written reader (`tagged.rs`).","oneOf":[{"description":"One way on.","type":"object","properties":{"exit":{"$ref":"#/$defs/Exit"},"type":{"type":"string","const":"continue"}},"required":["type","exit"]},{"type":"object","properties":{"exits":{"type":"array","items":{"$ref":"#/$defs/Exit"}},"timeLimitMs":{"type":["integer","null"],"format":"uint32","minimum":0},"onTimeout":{"type":["string","null"]},"type":{"type":"string","const":"choices"}},"required":["type","exits"]},{"description":"Decided by the game.","type":"object","properties":{"cases":{"type":"array","items":{"$ref":"#/$defs/BranchCase"}},"otherwise":{"$ref":"#/$defs/Exit"},"type":{"type":"string","const":"branch"}},"required":["type","cases","otherwise"]}]},"Exit":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":["string","null"]},"onlyIf":{"type":["string","null"]},"ifUnavailable":{"$ref":"#/$defs/IfUnavailable","default":"hide"},"once":{"type":"boolean","default":false},"use":{"type":["string","null"]},"hotspot":{"anyOf":[{"$ref":"#/$defs/Hotspot"},{"type":"null"}]},"fallback":{"description":"Offered only when no other option of the choice is available (never stuck).","type":"boolean"},"unavailableText":{"description":"The creator's reason, shown under a greyed option in place of what it needs.","type":["string","null"]},"effects":{"type":"array","items":{"$ref":"#/$defs/Effect"},"default":[]},"to":{"$ref":"#/$defs/Target"},"sound":{"description":"The way's sound as it is taken (L-57): an audio asset, `way:<name>` (one that comes with\nTalebench), `chip:<name>`, `auto` or `none`; unset is `auto`, which plays only when the\nlook's `sounds.ways` is on. Only the player reads it.","type":["string","null"]},"screen":{"description":"Screen effects on the way (L-152): a shake or a flash as the exit is taken, a tint, filter,\nweather or look from the next passage on; never `camera`.","type":"array","items":{"$ref":"#/$defs/ExitScreen"}}},"required":["id","to"]},"IfUnavailable":{"type":"string","enum":["hide","disable"]},"Hotspot":{"type":"object","properties":{"x":{"type":"number","format":"double"},"y":{"type":"number","format":"double"},"w":{"type":"number","format":"double"},"h":{"type":"number","format":"double"},"door":{"description":"A door: the way's `auto` sound is a door opening (L-57).","type":"boolean"},"cursor":{"description":"The hotspot's own cursor (P6-16: a keyhole, a ladder), over the set's.","anyOf":[{"$ref":"#/$defs/CursorLook"},{"type":"null"}]},"does":{"description":"Which of the set's hotspot cursors it shows (P6-16; none: from its target).","anyOf":[{"$ref":"#/$defs/HotspotDoes"},{"type":"null"}]}},"required":["x","y","w","h"]},"CursorLook":{"description":"A cursor on pointer devices: one that comes with Talebench or an uploaded picture with its tip\n(none: the top left).","anyOf":[{"type":"object","properties":{"builtin":{"$ref":"#/$defs/CursorName"}},"required":["builtin"]},{"type":"object","properties":{"image":{"$ref":"#/$defs/ImageRef"},"tip":{"description":"Where it points, in the picture's pixels (P6-16; none: the top left).","anyOf":[{"$ref":"#/$defs/CursorTip"},{"type":"null"}]}},"required":["image"]}]},"CursorName":{"description":"The cursors that come with Talebench (`none`: the browser's own).","type":"string","enum":["none","quill","gauntlet","wand","pixel","crosshair"]},"CursorTip":{"description":"A cursor picture's point, in the picture's pixels from its top left (P6-16).","type":"object","properties":{"x":{"type":"integer","format":"uint32","minimum":0},"y":{"type":"integer","format":"uint32","minimum":0}},"required":["x","y"]},"HotspotDoes":{"description":"What a hotspot does: which of the set's hotspot cursors it shows (none: `go` for a door or a\nway to another passage, else `choose`).","type":"string","enum":["look","talk","take","use","go"]},"Target":{"description":"Read by a hand-written reader (`tagged.rs`) that keeps the player's engine small.","oneOf":[{"type":"object","properties":{"passageId":{"type":"string"},"type":{"type":"string","const":"passage"}},"required":["type","passageId"]},{"description":"Go there; `back` returns here.","type":"object","properties":{"passageId":{"type":"string"},"type":{"type":"string","const":"visit"}},"required":["type","passageId"]},{"description":"Resume the visiting passage at its `next`.","type":"object","properties":{"type":{"type":"string","const":"back"}},"required":["type"]},{"description":"Choices only: reply, then choose again (or, with `choices`, these options: a level\ndeeper, L-20).","type":"object","properties":{"reply":{"type":"array","items":{"$ref":"#/$defs/Step"}},"choices":{"type":["array","null"],"items":{"$ref":"#/$defs/Exit"}},"type":{"type":"string","const":"stay"}},"required":["type","reply"]},{"description":"Inside a reply's options only (L-20): the reply, then the options one level up\n(`previous`, the default) or the passage's own options (`passage`).","type":"object","properties":{"reply":{"type":"array","items":{"$ref":"#/$defs/Step"}},"to":{"anyOf":[{"$ref":"#/$defs/UpTo"},{"type":"null"}]},"type":{"type":"string","const":"up"}},"required":["type"]},{"type":"object","properties":{"options":{"type":"array","items":{"$ref":"#/$defs/RandomOption"}},"otherwise":{"$ref":"#/$defs/Exit"},"type":{"type":"string","const":"random"}},"required":["type","options","otherwise"]},{"type":"object","properties":{"check":{"$ref":"#/$defs/Check"},"success":{"$ref":"#/$defs/Exit"},"failure":{"$ref":"#/$defs/Exit"},"type":{"type":"string","const":"check"}},"required":["type","check","success","failure"]},{"type":"object","properties":{"encounterId":{"type":"string"},"win":{"$ref":"#/$defs/Exit"},"lose":{"$ref":"#/$defs/Exit"},"flee":{"anyOf":[{"$ref":"#/$defs/Exit"},{"type":"null"}]},"spared":{"description":"No foe fights on and one surrendered (L-96; none: `win`).","anyOf":[{"$ref":"#/$defs/Exit"},{"type":"null"}]},"joined":{"description":"No foe fights on and one joined the party (L-96; none: `win`).","anyOf":[{"$ref":"#/$defs/Exit"},{"type":"null"}]},"fledFoes":{"description":"No foe fights on and the last of them fled (L-96; none: `win`).","anyOf":[{"$ref":"#/$defs/Exit"},{"type":"null"}]},"type":{"type":"string","const":"battle"}},"required":["type","encounterId","win","lose"]},{"type":"object","properties":{"endingId":{"type":"string"},"type":{"type":"string","const":"ending"}},"required":["type","endingId"]},{"description":"Decks (L-29): draw a card and visit its passage (`visit: false`: go to it); `otherwise` when no card fits. `offer`\n(an option only): up to that many fitting cards as options of their own.","type":"object","properties":{"deckId":{"type":"string"},"otherwise":{"$ref":"#/$defs/Exit"},"offer":{"type":["integer","null"],"format":"uint32","minimum":0},"visit":{"description":"`false`: the card's passage is gone to, not visited (nothing on the return stack);\nwritten only when `false`.","type":"boolean","x-default":true},"type":{"type":"string","const":"deck"}},"required":["type","deckId","otherwise"]},{"description":"Maps: pick a place on the map; `cancel` is taken by *Stay here*.","type":"object","properties":{"mapId":{"type":"string"},"cancel":{"anyOf":[{"$ref":"#/$defs/Exit"},{"type":"null"}]},"type":{"type":"string","const":"travel"}},"required":["type","mapId"]}]},"UpTo":{"description":"Where *Reply and go back* returns to (L-20).","oneOf":[{"description":"The options one level up.","type":"string","const":"previous"},{"description":"The passage's own options.","type":"string","const":"passage"}]},"RandomOption":{"type":"object","properties":{"passageId":{"type":"string"},"weight":{"type":"number","format":"double"},"onlyIf":{"type":["string","null"]}},"required":["passageId","weight"]},"Check":{"type":"object","properties":{"label":{"description":"\"Climb the wall\"","type":"string"},"dice":{"description":"Six-sided dice, 0–3.","type":"integer","format":"uint8","minimum":0,"maximum":255},"plus":{"type":"string"},"target":{"type":"string"}},"required":["label","dice","plus","target"]},"ExitScreen":{"description":"A screen effect on the way (L-152): the `screen` step's fields but the camera's.","type":"object","properties":{"effect":{"$ref":"#/$defs/ScreenEffectKind"},"strength":{"anyOf":[{"$ref":"#/$defs/ShakeStrength"},{"type":"null"}]},"color":{"description":"`#rrggbb`: the flash's (default white) and the tint's colour.","type":["string","null"]},"amount":{"description":"The tint: 0–1, how strongly (0 clears it).","type":["number","null"],"format":"double"},"weather":{"anyOf":[{"$ref":"#/$defs/Weather"},{"type":"null"}]},"filter":{"anyOf":[{"$ref":"#/$defs/ScreenFilter"},{"type":"null"}]},"variant":{"description":"`look`: the look variant from here on.","type":["string","null"]},"durationMs":{"description":"A shake's or flash's time: 100–3000 ms (default 500).","type":["integer","null"],"format":"uint32","minimum":0}},"required":["effect"]},"BranchCase":{"type":"object","properties":{"when":{"type":"string"},"exit":{"$ref":"#/$defs/Exit"}},"required":["when","exit"]},"SceneLayout":{"type":"object","properties":{"background":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"music":{"type":["string","null"]},"ambience":{"type":["string","null"]},"sprites":{"type":"array","items":{"$ref":"#/$defs/Sprite"},"default":[]},"wrongThing":{"description":"Reply when a thing is used where no exit accepts it.","type":["array","null"],"items":{"$ref":"#/$defs/Step"}},"transition":{"description":"How this scene's picture comes in (none: the look's `motion.pictures`).","anyOf":[{"$ref":"#/$defs/PassageChange"},{"type":"null"}]},"variants":{"description":"The picture by time of day, season or weather (P6-09): the most specific that holds.","type":"array","items":{"$ref":"#/$defs/PictureVariant"}},"musicVariants":{"description":"The music by time of day, season or weather.","type":"array","items":{"$ref":"#/$defs/SoundVariant"}},"ambienceVariants":{"description":"The ambience by time of day, season or weather.","type":"array","items":{"$ref":"#/$defs/SoundVariant"}}}},"Sprite":{"type":"object","properties":{"id":{"type":"string"},"assetId":{"type":"string"},"frame":{"type":["integer","null"],"format":"uint32","minimum":0},"x":{"type":"number","format":"double"},"y":{"type":"number","format":"double"},"w":{"type":"number","format":"double"},"h":{"type":"number","format":"double"},"layer":{"type":"integer","format":"int32"},"visibleWhen":{"type":["string","null"]},"animation":{"anyOf":[{"$ref":"#/$defs/Animation"},{"type":"null"}]}},"required":["id","assetId","x","y","w","h","layer"]},"Animation":{"type":"object","properties":{"frames":{"type":"array","items":{"type":"integer","format":"uint32","minimum":0}},"fps":{"type":"number","format":"double"},"loop":{"type":"boolean"}},"required":["frames","fps","loop"]},"PassageChange":{"description":"How one passage gives way to the next when the screen is cleared.","oneOf":[{"type":"string","enum":["none","fade","slide"]},{"description":"The new picture or text appears through the old (L-46).","type":"string","const":"dissolve"},{"description":"The new one wipes across from the left.","type":"string","const":"wipe"},{"description":"A circle opens from the middle.","type":"string","const":"iris"},{"description":"The old one turns away like a page.","type":"string","const":"page_turn"},{"description":"The old one breaks into blocks, the new one forms from them.","type":"string","const":"pixelate"}]},"SoundVariant":{"description":"Music or ambience for a time of day, a season or a weather.","type":"object","properties":{"part":{"type":["string","null"]},"season":{"type":["string","null"]},"weather":{"type":["string","null"]},"assetId":{"type":"string"}},"required":["assetId"]},"StoryView":{"description":"What stays on screen: the whole story, only the current passage, one line at a time, or\nlines while they fit (the oldest fade when the next would not; P4-29).","type":"string","enum":["all","passage","line","fit"]},"Dungeon":{"type":"object","properties":{"floors":{"type":"array","items":{"$ref":"#/$defs/DungeonFloor"}},"start":{"$ref":"#/$defs/DungeonPlace"},"move":{"anyOf":[{"$ref":"#/$defs/DungeonMove"},{"type":"null"}]},"view":{"anyOf":[{"$ref":"#/$defs/DungeonViewKind"},{"type":"null"}]},"automap":{"anyOf":[{"$ref":"#/$defs/Automap"},{"type":"null"}]},"screen":{"description":"Seen from inside: its screen (L-178; none: the crawler's).","anyOf":[{"$ref":"#/$defs/DungeonScreen"},{"type":"null"}]},"tiles":{"description":"Seen from inside: its walls, floor and ceiling made from this recipe (L-179; none: the\nlook's own set).","anyOf":[{"$ref":"#/$defs/TileRecipe"},{"type":"null"}]},"look":{"description":"A built-in set (`stone`, `cave`, `crypt`, `wood`, `ship`, `station`, `pixel`; none: stone).","type":["string","null"]},"sounds":{"description":"Its own sounds for a step, a turn, a door passed and a shut door tried (L-169).","anyOf":[{"$ref":"#/$defs/DungeonSounds"},{"type":"null"}]},"roamers":{"description":"Foes that walk the dungeon (L-170).","type":"array","items":{"$ref":"#/$defs/Roamer"}},"regions":{"type":"array","items":{"$ref":"#/$defs/DungeonRegion"}},"stepEffects":{"description":"Run on every step (a torch burns down).","type":"array","items":{"$ref":"#/$defs/Effect"}},"encounterAreaId":{"type":["string","null"]},"music":{"type":["string","null"]},"ambience":{"type":["string","null"]}},"required":["floors","start"]},"DungeonFloor":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"width":{"description":"At most 64.","type":"integer","format":"uint32","minimum":0},"height":{"description":"At most 64.","type":"integer","format":"uint32","minimum":0},"cells":{"description":"The open cells; everything else is rock.","type":"array","items":{"$ref":"#/$defs/DungeonCell"},"default":[]},"edges":{"description":"What stands between two open cells (none: open).","type":"array","items":{"$ref":"#/$defs/DungeonEdge"}},"mapWhen":{"description":"While it holds the whole floor shows on the map, seen or not: a found map (L-168).","type":["string","null"]}},"required":["id","name","width","height"]},"DungeonCell":{"type":"object","properties":{"x":{"type":"integer","format":"uint32","minimum":0},"y":{"type":"integer","format":"uint32","minimum":0},"regionId":{"type":["string","null"]},"text":{"description":"Its own words (none: the region's, else words the player makes from what is there).","type":["string","null"]},"picture":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"feature":{"anyOf":[{"$ref":"#/$defs/CellFeature"},{"type":"null"}]},"looks":{"description":"What its feature looks like in the view from inside (L-181): a lever, a bell, a desk …;\nnone: the feature's own picture.","anyOf":[{"$ref":"#/$defs/FeatureLook"},{"type":"null"}]}},"required":["x","y"]},"CellFeature":{"description":"What a cell holds. Read by a hand-written reader (`tagged.rs`, L-160).","oneOf":[{"description":"Out into the story.","type":"object","properties":{"exit":{"$ref":"#/$defs/Exit"},"type":{"type":"string","const":"exit"}},"required":["type","exit"]},{"description":"A passage played, then back on this cell (`auto`: on stepping in; else an option).","type":"object","properties":{"passageId":{"type":"string"},"once":{"type":"boolean"},"auto":{"type":"boolean"},"type":{"type":"string","const":"visit"}},"required":["type","passageId"]},{"type":"object","properties":{"floorId":{"type":"string"},"x":{"type":"integer","format":"uint32","minimum":0},"y":{"type":"integer","format":"uint32","minimum":0},"type":{"type":"string","const":"stairs"}},"required":["type","floorId","x","y"]},{"description":"Opened once, stays open.","type":"object","properties":{"things":{"type":"array","items":{"$ref":"#/$defs/ThingQty"}},"effects":{"type":"array","items":{"$ref":"#/$defs/Effect"}},"type":{"type":"string","const":"chest"}},"required":["type"]},{"description":"Fought once on stepping in; won, the cell is clear.","type":"object","properties":{"encounterId":{"type":"string"},"lose":{"anyOf":[{"$ref":"#/$defs/Exit"},{"type":"null"}]},"type":{"type":"string","const":"battle"}},"required":["type","encounterId"]},{"description":"Flips a yes/no value (gates read it). L-167: `auto`, a plate pressed (yes) as the party steps\non it, no option; `hold`, back to no as the party steps off.","type":"object","properties":{"valueId":{"type":"string"},"auto":{"type":"boolean"},"hold":{"type":"boolean"},"type":{"type":"string","const":"lever"}},"required":["type","valueId"]},{"description":"L-158: changes on stepping in, a check may avoid them.","type":"object","properties":{"effects":{"type":"array","items":{"$ref":"#/$defs/Effect"}},"check":{"description":"A check the party rolls as it steps in: success avoids it (L-158).","anyOf":[{"$ref":"#/$defs/Check"},{"type":"null"}]},"hidden":{"description":"Not on the map until sprung.","type":"boolean"},"type":{"type":"string","const":"trap"}},"required":["type","effects"]},{"description":"L-158; L-166: it may turn the party (a spinner: a teleport to its own cell), run changes on\narriving (a pit), ask a check that, passed, keeps the party where it stood, and be hidden\nuntil used.","type":"object","properties":{"floorId":{"type":"string"},"x":{"type":"integer","format":"uint32","minimum":0},"y":{"type":"integer","format":"uint32","minimum":0},"turn":{"anyOf":[{"$ref":"#/$defs/TurnTo"},{"type":"null"}]},"effects":{"type":"array","items":{"$ref":"#/$defs/Effect"}},"check":{"anyOf":[{"$ref":"#/$defs/Check"},{"type":"null"}]},"hidden":{"type":"boolean"},"type":{"type":"string","const":"teleport"}},"required":["type","floorId","x","y"]},{"type":"object","properties":{"type":{"type":"string","const":"save"}},"required":["type"]},{"type":"object","properties":{"type":{"type":"string","const":"camp"}},"required":["type"]},{"description":"L-158: shows nothing and offers no way on until `seeWhen` holds.","type":"object","properties":{"seeWhen":{"type":"string"},"type":{"type":"string","const":"dark"}},"required":["type","seeWhen"]}]},"ThingQty":{"type":"object","properties":{"thingId":{"type":"string"},"qty":{"type":"integer","format":"uint32","minimum":0},"made":{"description":"L-176: a made thing's ID (`mad_<n>`, its parts in `GameState.made`; never stacked: `qty`\n1); none: a plain thing.","type":["string","null"]}},"required":["thingId","qty"]},"TurnTo":{"description":"Where a teleport leaves the party facing (L-166): a direction, or a turn from the way it faced.","type":"string","enum":["n","e","s","w","left","right","around"]},"FeatureLook":{"description":"The pictures a cell's feature may look like from inside (L-181), each drawn in pixel art.","type":"string","enum":["lever","bell","desk","statue","fountain","altar","bones","barrel","books","sign","well","brazier","crates","gears"]},"DungeonEdge":{"type":"object","properties":{"x":{"type":"integer","format":"uint32","minimum":0},"y":{"type":"integer","format":"uint32","minimum":0},"side":{"$ref":"#/$defs/Dir"},"kind":{"$ref":"#/$defs/WallKind"},"key":{"type":["string","null"]},"openWhen":{"type":["string","null"]},"findWhen":{"description":"secret: found, and a door from then on, once this holds (carrying the lantern, a value a\nsearch set; L-158); none: never found","type":["string","null"]},"switch":{"description":"A switch set into this wall on the side of this edge's own cell (L-188): pressed from that\ncell, it sets its yes/no value, which the gates it opens read (`openWhen`).","anyOf":[{"$ref":"#/$defs/WallSwitch"},{"type":"null"}]}},"required":["x","y","side","kind"]},"Dir":{"description":"A side of a cell, as the compass names it: north is up on the map.","type":"string","enum":["n","e","s","w"]},"WallKind":{"description":"What stands on a side of a cell (and so between it and its neighbour).","oneOf":[{"type":"string","enum":["wall","door"]},{"description":"A door that needs `key` carried; once passed it stays open.","type":"string","const":"locked"},{"description":"A wall until found (L-158).","type":"string","const":"secret"},{"description":"Passable only from this cell's side.","type":"string","const":"one_way"},{"description":"Open while `openWhen` holds (a lever's value).","type":"string","const":"gate"}]},"WallSwitch":{"description":"A switch in a wall (L-188): what pressing it does to its yes/no value.","type":"object","properties":{"valueId":{"type":"string"},"mode":{"$ref":"#/$defs/SwitchMode"},"once":{"description":"Pressed once only: then it stays as it is.","type":"boolean"}},"required":["valueId"]},"SwitchMode":{"description":"`toggle`: yes becomes no and no yes; `on` and `off` set it so.","type":"string","enum":["toggle","on","off"]},"DungeonPlace":{"description":"A cell of a floor, and (where it matters) the way the party faces.","type":"object","properties":{"floorId":{"type":"string"},"x":{"type":"integer","format":"uint32","minimum":0},"y":{"type":"integer","format":"uint32","minimum":0},"facing":{"anyOf":[{"$ref":"#/$defs/Dir"},{"type":"null"}]}},"required":["floorId","x","y"]},"DungeonMove":{"description":"How the party moves (none: by the compass).","type":"string","enum":["compass","facing"]},"DungeonViewKind":{"description":"How the player shows it (none: the map from above).","type":"string","enum":["map","inside","text"]},"Automap":{"description":"What of the map shows (none: the cells seen).","type":"string","enum":["explored","all","none"]},"DungeonScreen":{"description":"The screen of a dungeon seen from inside (L-178): a crawler's (the view, the party beside it,\na six-way pad with a compass, a message line) or the story's (the view above the words and\noptions).","type":"string","enum":["crawler","story"]},"TileRecipe":{"description":"Made tiles (L-179): the walls, floor, ceiling and doors of a dungeon seen from inside, made by\nthe player from this recipe (the same pixels for the same recipe everywhere).","type":"object","properties":{"material":{"$ref":"#/$defs/TileMaterial"},"colours":{"$ref":"#/$defs/TileColours"},"size":{"description":"How large its blocks are, 1 (small) to 4 (large); none: 2.","type":["integer","null"],"format":"uint8","minimum":0,"maximum":255},"wear":{"anyOf":[{"$ref":"#/$defs/TileWear"},{"type":"null"}]},"light":{"anyOf":[{"$ref":"#/$defs/TileLight"},{"type":"null"}]},"pixel":{"description":"Drawn as coarse pixels (a pixel-art look).","type":"boolean"},"seed":{"type":["integer","null"],"format":"uint32","minimum":0},"pictures":{"description":"The writer's own pictures per tile kind (L-179): each given one is drawn in place of the\nmade tile, in perspective and light like it.","anyOf":[{"$ref":"#/$defs/TilePictures"},{"type":"null"}]},"floor":{"description":"The floor its own way (L-189; none: as the walls' material goes, planks on planks …).","anyOf":[{"$ref":"#/$defs/TileSurface"},{"type":"null"}]},"ceiling":{"description":"The ceiling its own way (L-189; none: as the walls' material goes).","anyOf":[{"$ref":"#/$defs/TileSurface"},{"type":"null"}]}},"required":["material","colours"]},"TileMaterial":{"type":"string","enum":["stone","bricks","cave","planks","metal","hedge","ice","crystal","bone"]},"TileColours":{"description":"The base colour and the accent (mortar, grain, rivets …), `#rrggbb`.","type":"object","properties":{"base":{"type":"string"},"accent":{"type":"string"}},"required":["base","accent"]},"TileWear":{"description":"How worn, each 0–3.","type":"object","properties":{"cracks":{"type":["integer","null"],"format":"uint8","minimum":0,"maximum":255},"moss":{"type":["integer","null"],"format":"uint8","minimum":0,"maximum":255},"damp":{"type":["integer","null"],"format":"uint8","minimum":0,"maximum":255},"soot":{"type":["integer","null"],"format":"uint8","minimum":0,"maximum":255}}},"TileLight":{"type":"string","enum":["torch","cold","none"]},"TilePictures":{"description":"The writer's own pictures of a dungeon's walls, floor, ceiling and doors (L-179).","type":"object","properties":{"wall":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"floor":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"ceiling":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"door":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]}}},"TileSurface":{"description":"A floor or a ceiling made apart from the walls (L-189): its own material, and its own colours\n(none: the recipe's); the wear and the light stay the recipe's.","type":"object","properties":{"material":{"$ref":"#/$defs/TileMaterial"},"colours":{"anyOf":[{"$ref":"#/$defs/TileColours"},{"type":"null"}]}},"required":["material"]},"DungeonSounds":{"description":"A dungeon's own sounds (L-169), played as the interface sounds are.","type":"object","properties":{"step":{"type":["string","null"]},"turn":{"type":["string","null"]},"door":{"description":"A door passed (opened).","type":["string","null"]},"locked":{"description":"A way tried where a door is shut (locked, or a gate closed).","type":["string","null"]}}},"Roamer":{"description":"A group of foes that walks a floor (L-170): along its round, or towards the party once it saw it.","type":"object","properties":{"id":{"description":"`rom_…`","type":"string"},"name":{"type":"string"},"encounterId":{"description":"The battle when it meets the party.","type":"string"},"floorId":{"type":"string"},"x":{"type":"integer","format":"uint32","minimum":0},"y":{"type":"integer","format":"uint32","minimum":0},"round":{"description":"The cells it walks in turn, one per step of the party, the first where it stands, then back\nto the first; none: it stands.","type":"array","items":{"$ref":"#/$defs/CellAt"}},"chase":{"description":"Once it sees the party it walks towards it instead.","type":"boolean"},"sight":{"description":"How far it sees along an open row or column (none: 3 cells).","type":["integer","null"],"format":"uint32","minimum":0},"onlyIf":{"description":"Walks the floor only while this holds.","type":["string","null"]},"lose":{"description":"A battle lost: where it leads (none: back on the cell).","anyOf":[{"$ref":"#/$defs/Exit"},{"type":"null"}]},"picture":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]}},"required":["id","name","encounterId","floorId","x","y"]},"CellAt":{"description":"A cell of a floor, by its place.","type":"object","properties":{"x":{"type":"integer","format":"uint32","minimum":0},"y":{"type":"integer","format":"uint32","minimum":0}},"required":["x","y"]},"DungeonRegion":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"color":{"type":["string","null"]},"text":{"type":["string","null"]},"picture":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"music":{"type":["string","null"]},"encounterAreaId":{"type":["string","null"]},"room":{"description":"Its cells are one room, played as one place (L-172).","type":"boolean"},"tiles":{"description":"Its own made tiles (L-179: a mossy grotto in a cave).","anyOf":[{"$ref":"#/$defs/TileRecipe"},{"type":"null"}]}},"required":["id","name"]},"RunMap":{"description":"The recipe a passage's run map is made from.","type":"object","properties":{"rows":{"description":"Rows of places (2–15), the goal above the last.","type":"integer","format":"uint32","minimum":0},"perRow":{"description":"Places per row, min–max (1–6).","type":"array","items":{"type":"integer","format":"uint32","minimum":0},"minItems":2,"maxItems":2},"links":{"description":"How many places of the next row a place leads to, at most (1–3).","type":"integer","format":"uint32","minimum":0},"kinds":{"type":"array","items":{"$ref":"#/$defs/RunPlaceKind"}},"goal":{"description":"After the last row: the boss, a passage, an ending.","$ref":"#/$defs/Exit"}},"required":["rows","perRow","links","kinds","goal"]},"RunPlaceKind":{"description":"A kind of place: its name and icon on the map, how often it comes, where, what it does.","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"icon":{"$ref":"#/$defs/RunIcon"},"weight":{"type":"number","format":"double"},"rows":{"description":"The rows it may stand in, 1-based (none: all).","type":["array","null"],"items":{"type":"integer","format":"uint32","minimum":0},"minItems":2,"maxItems":2},"exit":{"$ref":"#/$defs/Exit"}},"required":["id","name","icon","weight","exit"]},"RunIcon":{"type":"string","enum":["fight","elite","shop","rest","event","treasure","boss"]},"Deck":{"description":"Storylets (L-29, docs/game_systems_spec.md, \"Decks\"): cards the game draws by the state.","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"draw":{"description":"How a card is drawn: the best fit (default) or by chance.","$ref":"#/$defs/DeckDraw","default":"best"},"notTwice":{"description":"By chance: the card drawn last is never drawn next.","type":"boolean"},"cards":{"type":"array","items":{"$ref":"#/$defs/Card"},"default":[]}},"required":["id","name"]},"DeckDraw":{"oneOf":[{"description":"The fitting card with the highest priority (the first of equals).","type":"string","const":"best"},{"description":"One fitting card by weight, from the game's seed.","type":"string","const":"chance"}]},"Card":{"description":"A card of a deck: a passage and when it fits.","type":"object","properties":{"id":{"type":"string"},"passageId":{"type":"string"},"onlyIf":{"type":["string","null"]},"priority":{"description":"The best fit: the highest first (default 0).","type":["number","null"],"format":"double"},"weight":{"description":"By chance: how likely among the fitting cards (default 1).","type":["number","null"],"format":"double"},"repeatable":{"description":"Drawn again and again; else used up once drawn.","type":"boolean"},"label":{"description":"Its option's text where the deck is offered as options (a player text).","type":["string","null"]}},"required":["id","passageId"]},"Ending":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"$ref":"#/$defs/EndingKind"},"image":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"text":{"type":["string","null"]},"recap":{"description":"A recap under the ending: play time, endings found of all, achievements, these values.","anyOf":[{"$ref":"#/$defs/EndingRecap"},{"type":"null"}]},"credits":{"description":"Rolls the project's credits (`settings.credits`) after the ending.","type":"boolean"}},"required":["id","name","kind"]},"EndingKind":{"type":"string","enum":["good","neutral","bad","defeat"]},"EndingRecap":{"description":"What an ending's recap lists besides play time, endings and achievements.","type":"object","properties":{"valueIds":{"description":"Game values shown with what they ended at, in this order.","type":"array","items":{"type":"string"},"default":[]}}},"Character":{"type":"object","properties":{"id":{"type":"string"},"key":{"type":"string"},"name":{"type":"string"},"listName":{"description":"The name in the creator's lists only (\"Dura as a child\" for a \"Dura\", P6-04); none: the name.\nThe engine, the player and the book never read it.","type":["string","null"]},"description":{"type":["string","null"]},"nameFromValueId":{"description":"A game-scope text value, e.g. the name the player typed.","type":["string","null"]},"portrait":{"description":"The default expression.","anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"portraitFromValueId":{"description":"A state value whose current state's picture is the portrait instead (the look the player\nchose, L-32); a state without a picture keeps `portrait`.","type":["string","null"]},"portraitFrame":{"description":"The part of the character's picture a dialogue shows as their portrait (P4-23); none: the\nhead and shoulders of a standing figure.","anyOf":[{"$ref":"#/$defs/PortraitFrame"},{"type":"null"}]},"expressions":{"type":"array","items":{"$ref":"#/$defs/Expression"},"default":[]},"outfits":{"description":"Layered pictures: the body and clothes, the expression drawn on top; the first is worn at\nthe start.","type":"array","items":{"$ref":"#/$defs/Outfit"}},"talk":{"description":"Talk sounds: how its lines sound while they appear.","anyOf":[{"$ref":"#/$defs/TalkVoice"},{"type":"null"}]},"cry":{"description":"In battle: its cry when a hard blow strikes it (P8-80; none: the action look's pain sound).","type":["string","null"]},"nameColor":{"description":"The colour of its name on its lines (`#rrggbb`).","type":["string","null"]},"sprite":{"type":["string","null"]},"battleSprite":{"type":["string","null"]},"battlePoses":{"description":"Its figure in battle with poses (L-66; none: `battle_sprite` as it is).","anyOf":[{"$ref":"#/$defs/BattlePoses"},{"type":"null"}]},"values":{"description":"Starting values by value ID.","type":"object","additionalProperties":{"$ref":"#/$defs/Scalar"},"default":{}},"classId":{"type":["string","null"]},"startLevel":{"type":"integer","format":"uint32","minimum":0},"skills":{"type":"array","items":{"type":"string"},"default":[]},"equipment":{"description":"Slot ID → thing ID.","type":"object","additionalProperties":{"type":"string"},"default":{}},"combat":{"description":"Can be fought, e.g. a boss the player also talks to.","anyOf":[{"$ref":"#/$defs/CombatProfile"},{"type":"null"}]},"fightsInBattle":{"description":"Default true; false: travels with the party, sits out battles (a pack animal, a child).","type":["boolean","null"],"x-default":true},"mount":{"description":"Can be ridden: a horse, a donkey, a boat, a dragon.","anyOf":[{"$ref":"#/$defs/Mount"},{"type":"null"}]},"defeat":{"description":"How it falls in battle (none: the battle look's).","anyOf":[{"$ref":"#/$defs/DefeatLook"},{"type":"null"}]},"row":{"description":"Its starting row in battle while the battle rules have rows (L-69; none: front).","anyOf":[{"$ref":"#/$defs/Row"},{"type":"null"}]}},"required":["id","key","name","startLevel"]},"PortraitFrame":{"description":"A part of a picture as shares (0–1) of its width and height: what a dialogue shows as the\nspeaker's portrait (P4-23).","type":"object","properties":{"x":{"description":"The left edge, from 0 (the picture's left) to 1.","type":"number","format":"double"},"y":{"description":"The top edge, from 0 (the picture's top) to 1.","type":"number","format":"double"},"w":{"description":"The width, a share of the picture's width (above 0, at most 1).","type":"number","format":"double"},"h":{"description":"The height, a share of the picture's height (above 0, at most 1).","type":"number","format":"double"}},"required":["x","y","w","h"]},"Expression":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"image":{"$ref":"#/$defs/ImageRef"},"talk":{"description":"Talk sounds: how the voice changes in this expression.","anyOf":[{"$ref":"#/$defs/TalkMood"},{"type":"null"}]},"blink":{"description":"The same picture with the eyes closed: the figure blinks now and then (L-46).","anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"mouth":{"description":"The same picture with the mouth open: it moves while the figure speaks.","anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"portraitFrame":{"description":"This expression's own portrait frame (none: the character's).","anyOf":[{"$ref":"#/$defs/PortraitFrame"},{"type":"null"}]}},"required":["id","name","image"]},"TalkMood":{"description":"An expression's change to the speaker's voice.","type":"object","properties":{"pitch":{"description":"Semitones added: −12 to 12.","type":"number","format":"double"},"speed":{"description":"Factor: 0.5 to 2.","type":"number","format":"double"},"variance":{"description":"Semitones added to the variance: −6 to 6.","type":"number","format":"double"},"volume":{"description":"Factor: 0.5 to 1.5.","type":"number","format":"double"}},"required":["pitch","speed","variance","volume"]},"Outfit":{"description":"An outfit of a character with layered pictures.","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"image":{"$ref":"#/$defs/ImageRef"}},"required":["id","name","image"]},"TalkVoice":{"description":"A voice for talk sounds (docs/game_systems_spec.md, \"Talk sounds\"): short sounds per syllable\nwhile a line appears. The engine only carries it; the player makes the sounds.","type":"object","properties":{"preset":{"description":"The preset the creator started from (sliders changed since keep it).","type":["string","null"]},"sound":{"$ref":"#/$defs/TalkSound"},"pitch":{"description":"The voice's middle note: semitones from A4, −24 to 24.","type":"number","format":"double"},"variance":{"description":"How far a syllable may move from it: 0 to 12 semitones.","type":"number","format":"double"},"speed":{"description":"Syllables per second, 4 to 20 (also how fast the line appears).","type":"number","format":"double"},"volume":{"description":"0 to 1, under the player's voice volume.","type":"number","format":"double"}},"required":["sound","pitch","variance","speed","volume"]},"TalkSound":{"oneOf":[{"description":"Made by the player: a short tone of this wave.","type":"object","properties":{"wave":{"$ref":"#/$defs/Wave"},"type":{"type":"string","const":"wave"}},"required":["type","wave"]},{"description":"A short recorded sound, played at each syllable's note.","type":"object","properties":{"assetId":{"type":"string"},"type":{"type":"string","const":"sample"}},"required":["type","assetId"]}]},"Wave":{"type":"string","enum":["sine","square","triangle","saw"]},"BattlePoses":{"description":"A figure in battle with poses (L-66): one row of frames `frame_width` pixels wide, each pose\na run of them. Presentation only: the engine never reads it.","type":"object","properties":{"sheet":{"type":"string"},"frameWidth":{"type":"integer","format":"uint32","minimum":0},"faces":{"description":"The way the figure looks as drawn (none: party left, foes right).","anyOf":[{"$ref":"#/$defs/Facing"},{"type":"null"}]},"poses":{"$ref":"#/$defs/PoseSet","default":{}}},"required":["sheet","frameWidth"]},"Facing":{"type":"string","enum":["left","right"]},"PoseSet":{"description":"Each pose's frames; a missing pose falls back to `idle`, `idle` to the sheet's first frame.","type":"object","properties":{"idle":{"anyOf":[{"$ref":"#/$defs/Pose"},{"type":"null"}]},"ready":{"anyOf":[{"$ref":"#/$defs/Pose"},{"type":"null"}]},"attack":{"anyOf":[{"$ref":"#/$defs/Pose"},{"type":"null"}]},"cast":{"anyOf":[{"$ref":"#/$defs/Pose"},{"type":"null"}]},"item":{"anyOf":[{"$ref":"#/$defs/Pose"},{"type":"null"}]},"hit":{"anyOf":[{"$ref":"#/$defs/Pose"},{"type":"null"}]},"guard":{"anyOf":[{"$ref":"#/$defs/Pose"},{"type":"null"}]},"weak":{"anyOf":[{"$ref":"#/$defs/Pose"},{"type":"null"}]},"victory":{"anyOf":[{"$ref":"#/$defs/Pose"},{"type":"null"}]},"defeated":{"anyOf":[{"$ref":"#/$defs/Pose"},{"type":"null"}]}}},"Pose":{"description":"One pose: frame numbers from 0 in playing order, at `fps`, looping or holding the last.","type":"object","properties":{"frames":{"type":"array","items":{"type":"integer","format":"uint32","minimum":0}},"fps":{"type":"integer","format":"uint32","minimum":0},"loop":{"type":"boolean","default":false}},"required":["frames","fps"]},"CombatProfile":{"type":"object","properties":{"skills":{"type":"array","items":{"type":"string"},"default":[]},"ai":{"type":"array","items":{"$ref":"#/$defs/AiRule"},"default":[]},"weaknesses":{"description":"Damage type ID → multiplier.","type":"object","additionalProperties":{"type":"number","format":"double"},"default":{}},"immunities":{"description":"Status IDs never applied, and/or `defeat`.","type":"array","items":{"type":"string"},"default":[]},"statuses":{"description":"Statuses held from the start of every battle (\"Undead\").","type":"array","items":{"type":"string"},"default":[]},"rewards":{"$ref":"#/$defs/Rewards"},"carries":{"description":"What can be stolen from it (L-70): one draw of the loot table's entries on a success.","anyOf":[{"$ref":"#/$defs/Carries"},{"type":"null"}]},"morale":{"description":"A morale bar beside its defeat bar (L-96): at or below `yields_at` it gives in. Read for a\nfoe only (an enemy, or a character fought as a foe).","anyOf":[{"$ref":"#/$defs/Morale"},{"type":"null"}]},"zones":{"description":"Hit zones (L-104): its top, middle and bottom in a dice battle with `zones`.","anyOf":[{"$ref":"#/$defs/Zones"},{"type":"null"}]},"gear":{"description":"Weapons and shields (L-106): things it fights with as if worn (their `wear.dice` and\n`wear.shield`). Read for an enemy; a character wears its own.","type":"array","items":{"type":"string"}},"secondSet":{"description":"P8-87: the things it swaps to in a dice battle with `swap`, and when.","type":"array","items":{"type":"string"}},"swapWhen":{"anyOf":[{"$ref":"#/$defs/SwapWhen"},{"type":"null"}]},"temper":{"description":"P8-95: how it fights, in one line on its card on the VS screen (\"swings a great axe,\nnever backs down\").","type":["string","null"]},"skill":{"description":"P8-98: how well it plays (none: `master`, as every foe played before).","anyOf":[{"$ref":"#/$defs/FoeSkill"},{"type":"null"}]},"style":{"description":"P8-98: what it plays for (none: `balanced`).","anyOf":[{"$ref":"#/$defs/FoeStyle"},{"type":"null"}]},"diceTells":{"description":"Dice tells (L-108): a line for a high and one for a low throw, shown while its attack's\ndice lie face down (hidden throws). Read for a foe.","anyOf":[{"$ref":"#/$defs/DiceTells"},{"type":"null"}]},"boss":{"description":"A boss (L-108): the win-rate simulator expects its fights to last longer (6–10 exchanges\nrather than 3–6).","type":"boolean"},"defenceCombinations":{"description":"Defence combinations of its own (L-109): replace the battle's `defence.combinations`\nwhen it defends (a slow golem only Brace). Read for a foe, in battles with defence throws.","anyOf":[{"$ref":"#/$defs/DiceCombinations"},{"type":"null"}]}},"required":["rewards"]},"AiRule":{"type":"object","properties":{"id":{"description":"`air_…`: given to a row with a `tell` (L-98), the address of its line's translations.","type":["string","null"]},"when":{"type":"string"},"skillId":{"type":"string"},"target":{"$ref":"#/$defs/AiTarget"},"tell":{"description":"Intents told in words (L-98): a line of story text shown before the round when this row\nchooses the foe's next action (\"The bruiser draws back his club\").","type":["string","null"]}},"required":["when","skillId","target"]},"AiTarget":{"type":"string","enum":["random_foe","weakest_foe","strongest_foe","random_ally","weakest_ally","self"]},"Rewards":{"type":"object","properties":{"xp":{"type":["string","null"]},"effects":{"type":"array","items":{"$ref":"#/$defs/Effect"},"default":[]},"lootTableId":{"type":["string","null"]}}},"Carries":{"description":"What a foe carries for a `steal` effect (L-70).","type":"object","properties":{"lootTableId":{"type":"string"}},"required":["lootTableId"]},"Morale":{"description":"A foe's morale (L-96): its size and when it gives in (both worked out at the battle's start,\n`self` the foe), and what it does then.","type":"object","properties":{"max":{"type":"string"},"yieldsAt":{"type":"string"},"then":{"$ref":"#/$defs/MoraleThen"}},"required":["max","yieldsAt","then"]},"MoraleThen":{"description":"How a foe gives in (L-96): it flees, it surrenders (stays, harmless), or it joins the party (a\ncharacter foe only).","type":"string","enum":["flee","surrender","join"]},"Zones":{"description":"Hit zones (L-104): a fighter's three zones.","type":"object","properties":{"top":{"anyOf":[{"$ref":"#/$defs/ZoneDef"},{"type":"null"}]},"middle":{"anyOf":[{"$ref":"#/$defs/ZoneDef"},{"type":"null"}]},"bottom":{"anyOf":[{"$ref":"#/$defs/ZoneDef"},{"type":"null"}]},"feet":{"description":"L-187: with four zones (top, middle, bottom are then the head, the torso, the legs).","anyOf":[{"$ref":"#/$defs/ZoneDef"},{"type":"null"}]},"hands":{"description":"P8-111: with five zones, the hands.","anyOf":[{"$ref":"#/$defs/ZoneDef"},{"type":"null"}]}}},"ZoneDef":{"description":"Hit zones (L-104): one zone of a fighter.","type":"object","properties":{"armour":{"description":"Added to the fighter's armour on this zone.","type":["string","null"]},"none":{"description":"The zone cannot be hit (a flying foe has no `bottom`): a die aimed here misses.","type":["boolean","null"]},"effect":{"description":"Runs on a hit here (on the fighter hit).","type":"array","items":{"$ref":"#/$defs/Effect"}}}},"SwapWhen":{"description":"When a foe swaps to its second set (P8-87).","oneOf":[{"type":"string","enum":["never"]},{"description":"Its own HP under a third: to the set that guards best.","type":"string","const":"own_hp_low"},{"description":"Its target within two of its blows: to the set that hits hardest.","type":"string","const":"foe_hp_low"},{"description":"Either.","type":"string","const":"both"}]},"FoeSkill":{"description":"How well a foe plays (P8-98; docs/dice_battles_spec.md, \"How well a foe plays\"): at each choice\non the table the best (master), mostly the best (veteran), one of the three best (trained), or\nwith a player's mistakes (novice).","type":"string","enum":["novice","trained","veteran","master"]},"FoeStyle":{"description":"What a foe plays for (P8-98): even, what it deals, what it takes, combinations.","type":"string","enum":["balanced","aggressive","cautious","gambler"]},"DiceTells":{"description":"Dice tells (L-108; docs/game_systems_spec.md, \"Dice battles\", \"Fairer and clearer dice\nbattles\"): a foe's line while its attack lies face down, for a high throw (its sum at least 4\na die) and for a low one (at most 3 a die). Lines are story text (variations, values).","type":"object","properties":{"high":{"type":["string","null"]},"low":{"type":["string","null"]}}},"DiceCombinations":{"description":"The combinations of a dice battle, each with its effects (none: it does not count).","type":"object","properties":{"pair":{"type":["array","null"],"items":{"$ref":"#/$defs/DiceEffect"}},"twoPairs":{"description":"With 4 dice.","type":["array","null"],"items":{"$ref":"#/$defs/DiceEffect"}},"run":{"description":"Every die in a row (1-2-3 … 4-5-6, with 4 dice 1-2-3-4 … 3-4-5-6).","type":["array","null"],"items":{"$ref":"#/$defs/DiceEffect"}},"threeOfAKind":{"type":["array","null"],"items":{"$ref":"#/$defs/DiceEffect"}},"fourOfAKind":{"description":"With 4 dice.","type":["array","null"],"items":{"$ref":"#/$defs/DiceEffect"}},"fullHouse":{"description":"P8-111: with 5 dice, three of one face and two of another.","type":["array","null"],"items":{"$ref":"#/$defs/DiceEffect"}},"fiveOfAKind":{"description":"P8-111: with 5 dice.","type":["array","null"],"items":{"$ref":"#/$defs/DiceEffect"}}}},"DiceEffect":{"description":"What a dice combination does: `{\"type\": \"extraDamage\", \"amount\": 3}`, `{\"type\": \"wound\",\n\"statusId\": \"st_wounded\"}` (a flat struct rather than a tagged enum keeps the player's engine\nsmall).","type":"object","properties":{"type":{"$ref":"#/$defs/DiceEffectKind"},"amount":{"description":"`extraDamage`: added to the sum; `critical`: the extra damage in percent (none: 50; 100\ndoubles); `ignoreArmour`: the Armour ignored (none: 2).","type":["number","null"],"format":"double"},"statusId":{"description":"`wound` and `status`.","type":["string","null"]},"on":{"description":"`status`: on the target (none) or on the thrower.","anyOf":[{"$ref":"#/$defs/DiceOn"},{"type":"null"}]},"color":{"description":"L-107: the combination's own colour (`#rrggbb`) for its glow, line or bracket and name\n(none: its default); the first of a combination's effects that names one counts. Only\nthe player reads it, from the throw's event.","type":["string","null"]},"sound":{"description":"L-107: the combination's own sound (an audio asset, or a chip sound) in place of its\ndefault stinger; the first of a combination's effects that names one counts.","type":["string","null"]},"shake":{"description":"L-190: the combination shakes the battle and rumbles a phone as it shows, harder the rarer\nit is; the first of a combination's effects that says so counts. Only the player reads it.","type":["boolean","null"]}},"required":["type"]},"DiceEffectKind":{"description":"`extraDamage`: added to the sum; `unblockable`: a blocked throw still deals 1; `critical`:\nmore damage (`amount` percent, none: 50, rounded down, at least 1 more); `wound`: a status on the target that lasts (see `StatusEffect.lasts`);\n`status`: a status on the target or the thrower; `extraTurn`: the thrower acts once more.\nL-108: `ignoreArmour`: the throw ignores `amount` (none: 2) of the target's Armour (with hit\nzones, of each zone's); `foeFewerDice`: the target throws one die fewer at its next throw\n(never below one); `keepInitiative`: the thrower acts again before the foe's next turn, once\na round; `breakGuard`: the target's Armour, shield and defence count nothing until the end of\nthe thrower's next turn. Like statuses, these four act when the throw hit.\nL-109, a defence throw's combinations: `brace` (the attack's `ignoreArmour` and\n`unblockable` do not count), `footwork` (half damage; with hit zones the highest attack die\nmoves to the better guarded neighbouring zone), `riposte` (the attack is turned away and the\ndefender strikes back), `disarm` (the attacker's weapons count nothing until the end of its\nnext turn), `perfectGuard` (the attack's damage goes back to the attacker); `clash` names the\nclash in a defence's event (not a combination's effect).","oneOf":[{"type":"string","enum":["extraDamage","unblockable","critical","wound","status","extraTurn","ignoreArmour","foeFewerDice","keepInitiative","breakGuard","brace","footwork","riposte","disarm","perfectGuard","clash"]},{"description":"P8-30, on a set defence throw: two of the attack's dice swap places (zones), the swap that\ngets most through.","type":"string","const":"feint"},{"description":"P8-30: the defence die that blocks most is taken away.","type":"string","const":"shatter"},{"description":"P8-30: no defence die counts on this blow (armour and shields still do).","type":"string","const":"breakthrough"},{"description":"P8-39, a run's: the run's dice all count as its highest die (3 · 4 · 5 → 5 · 5 · 5), turned\nbefore the defence meets them.","type":"string","const":"raiseToHighest"},{"description":"P8-42: the combination's dice count `amount` more each (a pair of 3s counts 4 · 4; a 6\ncounts 7), changed before the defence meets them.","type":"string","const":"raise"}]},"DiceOn":{"type":"string","enum":["target","self"]},"Mount":{"description":"What riding a character gives (docs/game_systems_spec.md, \"Characters and classes\").","type":"object","properties":{"seats":{"description":"Riders at once (at least 1).","type":"integer","format":"uint32","minimum":1},"modifiers":{"description":"What riding gives the rider (+2 Speed).","type":"array","items":{"$ref":"#/$defs/Modifier"},"default":[]},"grantsSkills":{"description":"Skills the rider has while riding (Charge).","type":"array","items":{"type":"string"},"default":[]}},"required":["seats"]},"Modifier":{"type":"object","properties":{"valueId":{"type":"string"},"op":{"$ref":"#/$defs/ModifierOp"},"value":{"type":"number","format":"double"}},"required":["valueId","op","value"]},"ModifierOp":{"type":"string","enum":["add","multiply"]},"DefeatLook":{"description":"How a combatant falls.","type":"object","properties":{"sound":{"type":["string","null"]},"effect":{"anyOf":[{"$ref":"#/$defs/DefeatEffect"},{"type":"null"}]}}},"DefeatEffect":{"type":"string","enum":["fade","sink","burst","none"]},"Row":{"description":"A fighter's row (L-69).","type":"string","enum":["front","back"]},"Thing":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"listName":{"description":"The name in the creator's lists only (\"Dura as a child\" for a \"Dura\", P6-04); none: the name.\nThe engine, the player and the book never read it.","type":["string","null"]},"description":{"type":["string","null"]},"icon":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"carry":{"anyOf":[{"$ref":"#/$defs/Carry"},{"type":"null"}]},"use":{"anyOf":[{"$ref":"#/$defs/ThingUse"},{"type":"null"}]},"wear":{"anyOf":[{"$ref":"#/$defs/Wear"},{"type":"null"}]},"pages":{"anyOf":[{"$ref":"#/$defs/Pages"},{"type":"null"}]},"onScreen":{"description":"Carried, it has a button on the game screen that reads or uses it (L-174: a diary at\nhand); off by default.","type":"boolean"},"made":{"description":"L-176: a pattern whose things the game makes with random parts; none: a plain thing.","anyOf":[{"$ref":"#/$defs/MadePattern"},{"type":"null"}]},"grammar":{"description":"L-176: how the words round its name agree with it (German: _Rostiges Schwert_).","anyOf":[{"$ref":"#/$defs/Grammar"},{"type":"null"}]}},"required":["id","name"]},"Carry":{"type":"object","properties":{"maxStack":{"type":["integer","null"],"format":"uint32","minimum":0},"price":{"type":["number","null"],"format":"double"}}},"ThingUse":{"type":"object","properties":{"where":{"$ref":"#/$defs/Where"},"target":{"description":"`null` = no target (lighting a lamp).","anyOf":[{"$ref":"#/$defs/TargetSpec"},{"type":"null"}]},"consumed":{"type":"boolean"},"effects":{"type":"array","items":{"$ref":"#/$defs/Effect"},"default":[]}},"required":["where","consumed"]},"Where":{"type":"string","enum":["anywhere","battle","outside_battle"]},"TargetSpec":{"type":"object","properties":{"side":{"$ref":"#/$defs/Side"},"switchSides":{"description":"Single targets: the player may move the choice to the other side (P4-30).","type":["boolean","null"]},"scope":{"$ref":"#/$defs/TargetScope"},"count":{"type":["integer","null"],"format":"uint32","minimum":0},"includeDefeated":{"type":["boolean","null"]}},"required":["side","scope"]},"Side":{"oneOf":[{"type":"string","enum":["foe","ally","self"]},{"description":"The player picks a foe or a companion (P4-30).","type":"string","const":"any"}]},"TargetScope":{"type":"string","enum":["single","all","random"]},"Wear":{"type":"object","properties":{"slotId":{"type":"string"},"modifiers":{"type":"array","items":{"$ref":"#/$defs/Modifier"},"default":[]},"grantsSkills":{"type":"array","items":{"type":"string"},"default":[]},"allowedClasses":{"type":"array","items":{"type":"string"},"default":[]},"reach":{"description":"`far`: the wearer's basic attack reaches far, from and into the back row alike (L-69).","anyOf":[{"$ref":"#/$defs/Reach"},{"type":"null"}]},"fills":{"description":"Two hands (L-106): the other slots this thing fills while worn (a greatsword fills the\nshield slot too); what is worn there comes off.","type":"array","items":{"type":"string"}},"dice":{"description":"Weapons in dice battles (L-106): how the wearer's attack dice change.","anyOf":[{"$ref":"#/$defs/GearDice"},{"type":"null"}]},"shield":{"description":"Shields in dice battles (L-106): armour held in one or two zones.","anyOf":[{"$ref":"#/$defs/Shield"},{"type":"null"}]}},"required":["slotId"]},"Reach":{"description":"How far a damage type's hits reach (L-69): `close` hits are weaker from and into the back row.","type":"string","enum":["close","far"]},"GearDice":{"description":"Weapons in dice battles (L-106; docs/game_systems_spec.md, \"Dice battles\", \"Weapons and\nshields\"): what a worn thing does to its wearer's attack throws.","type":"object","properties":{"extraDice":{"description":"Dice more (or fewer) in each attack throw (1 to 6 in all).","type":["integer","null"],"format":"int32"},"perDie":{"description":"Added to every die of an attack throw (each kept between 1 and 6).","type":["integer","null"],"format":"int32"},"combinations":{"description":"Effects added to a combination (it counts with this thing even where the rules leave it\nout).","$ref":"#/$defs/DiceCombinations","default":{}},"reach":{"description":"Hit zones: zones it reaches even where the foe has `none`.","type":"array","items":{"$ref":"#/$defs/Zone"}},"zoneEffect":{"description":"Hit zones: what a hit in one zone (or a shielded zone) does.","anyOf":[{"$ref":"#/$defs/GearZoneEffect"},{"type":"null"}]},"noParry":{"description":"Defence throws: its attacks cannot be parried or countered.","type":["boolean","null"]},"firstStrike":{"description":"With the throw for who starts: its wearer attacks once before it.","type":["boolean","null"]},"boost":{"description":"P8-86: chosen dice raised once a throw is final (the weapon set-ups: two-handed, two\nweapons, sword and shield).","anyOf":[{"$ref":"#/$defs/GearBoost"},{"type":"null"}]},"kind":{"description":"P8-88: what kind of weapon it is, and so its one trait die against die.","anyOf":[{"$ref":"#/$defs/WeaponKind"},{"type":"null"}]}}},"Zone":{"description":"Hit zones (L-104; docs/game_systems_spec.md, \"Dice battles\", \"Hit zones\"): where a die is aimed,\nthe first die `top`, the second `middle`, the third `bottom`; with four zones (L-187,\n`DiceRules.fourZones`) the same three are the head, the torso and the legs (`head`, `torso`,\n`legs` read as them) and the fourth die goes to the `feet`.","oneOf":[{"type":"string","enum":["top","middle","bottom"]},{"description":"L-187: only with four zones.","type":"string","const":"feet"},{"description":"P8-111: only with five zones, between the torso and the legs (gloves).","type":"string","const":"hands"}]},"GearZoneEffect":{"description":"A weapon's effect on a hit in a zone (L-106).","type":"object","properties":{"zone":{"description":"`top`, `middle`, `bottom`, or `shield`: a zone the target's shield covers.","$ref":"#/$defs/GearZone"},"effects":{"description":"Run on the target after a hit there.","type":"array","items":{"$ref":"#/$defs/Effect"}},"breakShield":{"description":"A hit there breaks the target's shield: its armour counts nothing until the end of the\ntarget's next turn.","type":["boolean","null"]}},"required":["zone"]},"GearZone":{"description":"Where a weapon's zone effect works (L-106).","oneOf":[{"type":"string","enum":["top","middle","bottom","shield"]},{"description":"L-187: with four zones.","type":"string","const":"feet"}]},"GearBoost":{"description":"A weapon set-up's boosts (P8-86): what it adds to an attack's and a defence's chosen dice.","type":"object","properties":{"attack":{"description":"Once an attack throw is final, before the defence.","anyOf":[{"$ref":"#/$defs/Boost"},{"type":"null"}]},"defence":{"description":"Once a defence is thrown, before it is paired.","anyOf":[{"$ref":"#/$defs/Boost"},{"type":"null"}]}}},"Boost":{"description":"`amount` added to `dice` dice of a throw (P8-86); with `neighbours` to dice in neighbouring\nzones (or places in the row) only.","type":"object","properties":{"dice":{"description":"1 to 3.","type":"integer","format":"uint32","minimum":0},"amount":{"description":"What each chosen die counts more (1 in the standard).","type":"integer","format":"int32"},"neighbours":{"type":["boolean","null"]}},"required":["dice","amount"]},"WeaponKind":{"description":"A weapon's kind (P8-88): one trait each, die against die.","oneOf":[{"description":"Riposte: defending, each defence die 4 or more above its attack die strikes back for 1.","type":"string","const":"sword"},{"description":"Bite: the best hit of its attack deals 1 more.","type":"string","const":"axe"},{"description":"Crush: each of its attack dice blocked by exactly 1 still deals 1.","type":"string","const":"hammer"}]},"Shield":{"description":"Shields in dice battles (L-106): `armour` in the zone it is held in (two neighbouring ones with\n`covers: 2`); in a game without hit zones, everywhere.","type":"object","properties":{"armour":{"type":"number","format":"double"},"covers":{"description":"1 or 2 zones (none: 1).","type":["integer","null"],"format":"uint32","minimum":0},"move":{"description":"When the defender moves it (none: `before_defence`).","anyOf":[{"$ref":"#/$defs/ShieldMove"},{"type":"null"}]}},"required":["armour"]},"ShieldMove":{"description":"When a shield is moved (L-106): after seeing the attack's dice, or (a buckler) after one\nface-down die of a hidden throw is shown.","type":"string","enum":["before_defence","after_one_die"]},"Pages":{"type":"object","properties":{"pages":{"type":"array","items":{"$ref":"#/$defs/Page"}},"onFirstRead":{"type":"array","items":{"$ref":"#/$defs/Effect"},"default":[]}},"required":["pages"]},"Page":{"type":"object","properties":{"id":{"description":"The page's own ID: its texts' address (`pag_…/text`).","type":"string"},"title":{"type":["string","null"]},"text":{"type":"string"},"image":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"onlyIf":{"type":["string","null"]}},"required":["id","text"]},"MadePattern":{"description":"L-176: the groups a made thing's parts are drawn from, one weighted draw per group.","type":"object","properties":{"groups":{"type":"array","items":{"$ref":"#/$defs/PartGroup"}}},"required":["groups"]},"PartGroup":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"none":{"description":"How often the group gives no part (as a part's weight); none: always one.","type":["number","null"],"format":"double"},"parts":{"type":"array","items":{"$ref":"#/$defs/Part"}}},"required":["id","name","parts"]},"Part":{"type":"object","properties":{"id":{"type":"string"},"words":{"description":"Its words round the thing's name (\"Rusty\", \"of the Bear\").","type":"string"},"forms":{"description":"The words per gender of the thing (German: rostiger, rostige, rostiges); none: `words`.","type":"object","properties":{"feminine":{"type":"string"},"masculine":{"type":"string"},"neuter":{"type":"string"}},"additionalProperties":false},"place":{"$ref":"#/$defs/PartPlace"},"weight":{"type":"number","format":"double"},"rarity":{"anyOf":[{"$ref":"#/$defs/Rarity"},{"type":"null"}]},"modifiers":{"description":"What it changes while the thing is worn.","type":"array","items":{"$ref":"#/$defs/Modifier"}},"effects":{"description":"What it does when the thing is used (after the thing's own).","type":"array","items":{"$ref":"#/$defs/Effect"}},"price":{"description":"Added to the thing's price.","type":["number","null"],"format":"double"}},"required":["id","words","place","weight"]},"PartPlace":{"type":"string","enum":["before","after"]},"Rarity":{"description":"A made thing's rarity, lowest first.","type":"string","enum":["common","uncommon","rare","epic","legendary"]},"Grammar":{"type":"object","properties":{"gender":{"$ref":"#/$defs/Gender"}},"required":["gender"]},"Gender":{"type":"string","enum":["masculine","feminine","neuter"]},"Combination":{"description":"Two carried things combined in the inventory; order does not matter.","type":"object","properties":{"thingIds":{"type":"array","items":{"type":"string"},"minItems":2,"maxItems":2},"onlyIf":{"type":["string","null"]},"consume":{"type":"boolean"},"reply":{"type":["array","null"],"items":{"$ref":"#/$defs/Step"}},"effects":{"type":"array","items":{"$ref":"#/$defs/Effect"},"default":[]}},"required":["thingIds","consume"]},"Storage":{"description":"A place to keep things besides the party's inventory: a donkey's saddlebags, a chest, a vault\n(docs/game_systems_spec.md, \"Storages\").","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"owner":{"$ref":"#/$defs/StorageOwner"},"onlyIf":{"description":"Reachable only while this holds, e.g. `has(\"thg_chestkey\")`.","type":["string","null"]},"maxDistinct":{"description":"Different things; `None`: no limit.","type":["integer","null"],"format":"uint32","minimum":0,"default":null},"maxStack":{"description":"Of one thing; `None`: `settings.inventory.defaultMaxStack`.","type":["integer","null"],"format":"uint32","minimum":0,"default":null},"startingThings":{"type":"array","items":{"$ref":"#/$defs/ThingQty"},"default":[]}},"required":["id","name","owner"]},"StorageOwner":{"description":"Who or where a storage belongs to.","anyOf":[{"description":"Travels with that character while it is in the party.","type":"object","properties":{"characterId":{"type":"string"}},"required":["characterId"]},{"description":"Reachable in these passages only.","type":"object","properties":{"passageIds":{"type":"array","items":{"type":"string"}}},"required":["passageIds"]}]},"Collection":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"icon":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"entryNoun":{"description":"\"creature\", \"clue\", \"achievement\"","type":"string"},"showLocked":{"description":"Undiscovered entries listed as \"???\".","type":"boolean"},"acrossPlaythroughs":{"description":"Kept in meta state (achievements).","type":"boolean"},"showOnPage":{"description":"Listed on the published game's page for people who have not played yet (L-89): every\nentry, or only the entries marked `onPage`. Absent: not on the page.","anyOf":[{"$ref":"#/$defs/PageShow"},{"type":"null"}]},"entries":{"type":"array","items":{"$ref":"#/$defs/Entry"},"default":[]}},"required":["id","name","entryNoun","showLocked","acrossPlaythroughs"]},"PageShow":{"description":"Which entries of a collection the game's page lists (L-89).","oneOf":[{"description":"Every entry.","type":"string","const":"all"},{"description":"Only the entries marked `onPage`.","type":"string","const":"chosen"}]},"Entry":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"image":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"icon":{"description":"A small picture beside the title in lists (greyed while locked).","anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"hint":{"description":"Shown instead of \"???\" while the entry is locked (\"Find all three keys\").","type":["string","null"]},"about":{"anyOf":[{"$ref":"#/$defs/About"},{"type":"null"}]},"sections":{"type":"array","items":{"$ref":"#/$defs/Section"},"default":[]},"words":{"description":"Words marked every time they appear in the story texts the engine shows (L-87).","type":"array","items":{"type":"string"}},"onPage":{"description":"Chosen for the game's page when the collection shows only chosen entries (L-89).","type":"boolean"}},"required":["id","title"]},"About":{"type":"object","properties":{"type":{"$ref":"#/$defs/AboutKind"},"id":{"type":"string"}},"required":["type","id"]},"AboutKind":{"type":"string","enum":["enemy","character","thing","passage"]},"Section":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":["string","null"]},"content":{"$ref":"#/$defs/SectionContent"},"revealWhen":{"description":"Context `visual`.","type":["string","null"]},"onRead":{"description":"Revealed when a marked word of the entry is read (L-87).","type":"boolean"}},"required":["id","content"]},"SectionContent":{"oneOf":[{"type":"object","properties":{"text":{"type":"string"},"type":{"type":"string","const":"text"}},"required":["type","text"]},{"type":"object","properties":{"facts":{"type":"array","items":{"type":"string"}},"type":{"type":"string","const":"facts"}},"required":["type","facts"]}]},"StatusEffect":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"icon":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"kind":{"$ref":"#/$defs/StatusKind"},"duration":{"$ref":"#/$defs/Duration"},"stacking":{"$ref":"#/$defs/Stacking"},"modifiers":{"type":"array","items":{"$ref":"#/$defs/Modifier"},"default":[]},"ticks":{"type":"array","items":{"$ref":"#/$defs/Tick"},"default":[]},"restriction":{"$ref":"#/$defs/Restriction"},"endsWhenHit":{"type":"boolean"},"endsAfterBattle":{"type":"boolean"},"lasts":{"description":"Wounds that last (L-97): kept after the battle until the next rest or until removed,\nwhatever `ends_after_battle` says (none: as `ends_after_battle` says).","anyOf":[{"$ref":"#/$defs/Lasts"},{"type":"null"}]},"sitsOut":{"description":"A character holding it at a battle's start sits the battle out (L-97).","type":"boolean"}},"required":["id","name","kind","duration","stacking","restriction","endsWhenHit","endsAfterBattle"]},"StatusKind":{"type":"string","enum":["helpful","harmful"]},"Duration":{"anyOf":[{"type":"object","properties":{"unit":{"$ref":"#/$defs/DurationUnit"},"count":{"type":"integer","format":"uint32","minimum":0}},"required":["unit","count"]},{"$ref":"#/$defs/UntilRemoved"}]},"DurationUnit":{"type":"string","enum":["turns","passages"]},"UntilRemoved":{"type":"string","enum":["until_removed"]},"Stacking":{"type":"string","enum":["refresh","extend","ignore"]},"Tick":{"type":"object","properties":{"when":{"$ref":"#/$defs/TickWhen"},"effects":{"type":"array","items":{"$ref":"#/$defs/Effect"},"default":[]}},"required":["when"]},"TickWhen":{"type":"string","enum":["turn_start","turn_end"]},"Restriction":{"type":"string","enum":["none","skip_turn","basic_attack_only","random_target"]},"Lasts":{"description":"How long a status lasts beyond its battle (L-97).","oneOf":[{"description":"Ends with the battle.","type":"string","const":"battle"},{"description":"Kept after the battle; the camp's sleep ends it.","type":"string","const":"until_rest"},{"description":"Kept until an effect removes it.","type":"string","const":"until_removed"}]},"Skill":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"icon":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"basic":{"description":"The basic attack; owned by Battles.","type":"boolean","default":false},"where":{"$ref":"#/$defs/Where"},"target":{"$ref":"#/$defs/TargetSpec"},"cost":{"type":"array","items":{"$ref":"#/$defs/Cost"},"default":[]},"cooldown":{"type":"integer","format":"uint32","minimum":0,"default":0},"power":{"type":"number","format":"double","default":0},"effects":{"type":"array","items":{"$ref":"#/$defs/Effect"},"default":[]},"ranks":{"type":"array","items":{"$ref":"#/$defs/SkillRankDef"},"default":[]},"look":{"description":"How using it looks and sounds (Fireball: cast, flames, boom).","anyOf":[{"$ref":"#/$defs/ActionLook"},{"type":"null"}]},"needsFull":{"description":"A gauge's value ID: usable only while that gauge is full, and empties it (a limit move).","type":["string","null"]},"time":{"description":"Planned turns (L-84): its cost in a fighter's time budget (none: 40; the basic attack 30).","type":["integer","null"],"format":"uint32","minimum":0},"follows":{"description":"Planned turns (L-84): combos, a bonus to its power when it comes right after a skill.","type":"array","items":{"$ref":"#/$defs/SkillCombo"}},"dice":{"description":"Skills paid with a die (L-105): in a dice battle, usable only with a die of the held throw\nthat meets the condition; with `spend` (the default) that die leaves the throw.","anyOf":[{"$ref":"#/$defs/SkillDice"},{"type":"null"}]}},"required":["id","name","where","target"]},"Cost":{"type":"object","properties":{"valueId":{"type":"string"},"amount":{"type":"number","format":"double"}},"required":["valueId","amount"]},"SkillRankDef":{"type":"object","properties":{"power":{"type":["number","null"],"format":"double"},"cost":{"type":["array","null"],"items":{"$ref":"#/$defs/Cost"}},"addEffects":{"type":["array","null"],"items":{"$ref":"#/$defs/Effect"}}}},"ActionLook":{"description":"How one action looks and sounds; every field optional, a missing one falls back (skill →\ndamage type → the battle look's `attack` or `heal`).","type":"object","properties":{"sound":{"description":"As the action starts (a swing, a spell's cast).","type":["string","null"]},"hitSound":{"description":"On each target hit.","type":["string","null"]},"painSound":{"description":"On a hit of `pain_from` damage or more, after the hit sound: the struck one's cry (P8-80).","type":["string","null"]},"painFrom":{"description":"The damage from which `pain_sound` plays (none: 6).","type":["integer","null"],"format":"uint32","minimum":0},"painMark":{"description":"On such a hit: a mark on the struck one's portrait, kept for the battle (none: none).","anyOf":[{"$ref":"#/$defs/PainMark"},{"type":"null"}]},"actor":{"description":"What the one acting does.","anyOf":[{"$ref":"#/$defs/ActorMove"},{"type":"null"}]},"animation":{"description":"A strip played over the target(s).","anyOf":[{"$ref":"#/$defs/BattleAnimation"},{"type":"null"}]},"target":{"description":"What the one hit does.","anyOf":[{"$ref":"#/$defs/TargetReaction"},{"type":"null"}]},"color":{"description":"`#rrggbb`: the flash's and the number's colour.","type":["string","null"]},"screen":{"description":"The whole battle screen.","anyOf":[{"$ref":"#/$defs/ScreenEffect"},{"type":"null"}]}}},"PainMark":{"description":"What a hard blow leaves on the struck one's portrait (P8-80).","oneOf":[{"type":"string","enum":["none"]},{"description":"A blood splash, up to three, kept for the battle.","type":"string","const":"blood"}]},"ActorMove":{"description":"What the one acting does; `step` walks toward the other side and back (L-66).","type":"string","enum":["none","lunge","jump","glow","step"]},"BattleAnimation":{"description":"An animation strip: one row of frames `frameWidth` pixels wide (the picture's height is the\nframe's), played at `fps`.","type":"object","properties":{"image":{"type":"string"},"frameWidth":{"type":"integer","format":"uint32","minimum":0},"frames":{"description":"Frame numbers in playing order, from 0.","type":"array","items":{"type":"integer","format":"uint32","minimum":0}},"fps":{"type":"integer","format":"uint32","minimum":0},"on":{"$ref":"#/$defs/AnimationPlace"}},"required":["image","frameWidth","frames","fps","on"]},"AnimationPlace":{"type":"string","enum":["each_target","side","screen"]},"TargetReaction":{"type":"string","enum":["none","shake","blink","flash","knockback"]},"ScreenEffect":{"type":"string","enum":["none","shake","flash"]},"SkillCombo":{"description":"A combo (L-84): played right after `skill_id`, the skill's power gains `bonus`.","type":"object","properties":{"skillId":{"type":"string"},"bonus":{"description":"Added to the skill's power; a battle formula with `self.*` (the one using it).","type":"string"},"ally":{"description":"Also after an ally's action: the action just before on the round's timeline, by anyone on\nthe same side (none: only the same fighter's chain).","type":["boolean","null"]}},"required":["skillId","bonus"]},"SkillDice":{"description":"Skills paid with a die (L-105): the die a skill needs (`min` to `max`, or `exact`) and whether\nit is used up (`spend`, none: yes). A skill marked `desperate` is paid by foes whenever they are\nbelow a third of their bar.","type":"object","properties":{"min":{"type":["integer","null"],"format":"uint32","minimum":0},"max":{"type":["integer","null"],"format":"uint32","minimum":0},"exact":{"type":["integer","null"],"format":"uint32","minimum":0},"spend":{"type":["boolean","null"]},"desperate":{"type":["boolean","null"]},"set":{"description":"Special throws (L-151): a set of dice instead of one, each condition met by a different\ndie in any order (1 · 1 · 2: `exact` 1, 1 and 2); `min`, `max` and `exact` then count for\nnothing.","type":["array","null"],"items":{"$ref":"#/$defs/DieCondition"}}}},"DieCondition":{"description":"One die of a special throw's set (L-151): `min` to `max`, or `exact`.","type":"object","properties":{"min":{"type":["integer","null"],"format":"uint32","minimum":0},"max":{"type":["integer","null"],"format":"uint32","minimum":0},"exact":{"type":["integer","null"],"format":"uint32","minimum":0}}},"KitHook":{"description":"An open way of a kit.","type":"object","properties":{"exitId":{"description":"The exit, in one of the kit's passages, that the creator connects.","type":"string"},"label":{"description":"What it is for (\"After asking around\").","type":"string"}},"required":["exitId","label"]},"KitHelp":{"description":"A part of a kit's help.","type":"object","properties":{"title":{"type":"string"},"text":{"type":"string"}},"required":["title","text"]}}}