Yodesk.ksy
This is a machine-readable definition of the file format used by Yoda Stories. It can be used to generate a parser or inspect files online in the Kaitai Web IDE.
meta:
id: yodesk
application: "Star Wars: Yoda Stories"
file-extension: dta
license: CC0-1.0
ks-version: 0.9
endian: le
encoding: ASCII
doc: |
[Star Wars: Yoda Stories](https://en.wikipedia.org/wiki/Star_Wars:_Yoda_Stories) is a unique tile based game with procedurally
generated worlds.
This spec describes the file format used for all assets of the Windows
version of the game.
The file format follows the TLV (type-length-value) pattern to build a
central catalog containing the most important (and globally accessible)
assets of the game (e.g. puzzles, zones, tiles, etc.). The same pattern is
also found in some catalog entries to encode arrays of variable-length
structures.
With every new game, Yoda Stories generates a new world. This is done by
picking a random sample of puzzles from `PUZ2`. One of the chosen puzzles
will be the goal, which when solved wins the game.
Each puzzle provides an item when solved and some require one to be completed.
During world generation a global world map of 10x10 sectors is filled with
zones based on the selected puzzles.
To add variety and interactivity to each zone the game includes a simple
scripting engine. Zones can declare actions that when executed can for
example set, move or delete tiles, drop items or activate enemies.
seq:
- id: catalog
type: catalog_entry
repeat: until
repeat-until: _.type == "ENDF"
types:
catalog_entry:
seq:
- id: type
type: str
size: 4
- id: size
type: u4
if: type != "VERS" and type != "ZONE"
- id: content
type:
switch-on: type
cases:
'"VERS"': version
'"STUP"': startup_image
'"CHAR"': characters
'"CAUX"': character_auxiliaries
'"CHWP"': character_weapons
'"PUZ2"': puzzles
'"SNDS"': sounds
'"TILE"': tiles
'"TNAM"': tile_names
'"ZONE"': zones
'"TGEN"': tgen
'"ENDF"': endf
_: unknown_catalog_entry
unknown_catalog_entry:
seq:
- id: data
size: _parent.size
version:
seq:
- id: version
doc: Version of the file. This value is always set to 512.
type: u4
startup_image:
doc: |
A 288x288 bitmap to be shown while other assets are loaded and a new
world is generated.
seq:
- id: pixels
size: _parent.size
sounds:
doc: |
This section declares sounds used in the game. The actual audio data is
stored in wav files on the disk (in a directory named `sfx`) so this
section contains paths to each sound file.
Sounds can be referenced from the scripting language (see `play_sound`
instruction opcode below) and from weapon (see `character` structure).
Some sound ids (like the one when the hero is hit, or can't leave a
zone) are hard coded in the game.
seq:
- id: count
type: s2
- id: sounds
type: prefixed_strz
repeat: expr
repeat-expr: -count
tile_names:
seq:
- id: names
doc: |
List of tile ids and their corresponding names. These are shown in
the inventory or used in dialogs (see `speak_hero` and `speak_npc`
opcodes).
type: tile_name
repeat: until
repeat-until: _.tile_id == 0xFF_FF
tile_name:
seq:
- id: tile_id
type: u2
- id: name
type: strz
size: 0x18
if: tile_id != 0xFF_FF
tiles:
seq:
- id: tiles
type: tiles_entries
size: _parent.size
tiles_entries:
seq:
- id: tiles
type: tile
repeat: eos
tile:
seq:
- id: attributes
type: tile_attributes
size: 4
- id: pixels
size: 32 * 32
tile_attributes:
meta:
bit-endian: le
seq:
- id: has_transparency
type: b1
doc: |
Affects how tile image should be drawn. If set, the
value 0 in `pixels` is treated as transparent. Otherwise
it is drawn as black.
- id: is_floor
type: b1
doc: |
Tile is usually placed on the lowest layer of a zone
- id: is_object
type: b1
doc: |
Object, tile is usually placed on the middle layer of a zone
- id: is_draggable
type: b1
doc: |
If set and the tile is placed on the object layer it can be
dragged and pushed around by the hero.
- id: is_roof
type: b1
doc: |
Tile is usually placed on the top layer (roof)
- id: is_locator
type: b1
doc: |
Locator, tile is used in world map view overview
- id: is_weapon
type: b1
doc: |
Identifies tiles that are mapped to weapons
- id: is_item
type: b1
- id: is_character
type: b1
doc: |
Tile forms part of a character
- id: unused
type: b7
# Floor flags
- id: is_doorway
type: b1
doc: |
These tiles are doorways, monsters can't go
if: is_floor
# Locator flags
- id: unused1
type: b1
if: is_locator
- id: is_town
type: b1
doc: |
Marks the spaceport on the map
if: is_locator
- id: is_unsolved_puzzle
type: b1
doc: |
Marks a discovered, but unsolved puzzle on the map
if: is_locator
- id: is_solved_puzzle
type: b1
doc: |
Marks a solved puzzle on the map
if: is_locator
- id: is_unsolved_travel
type: b1
doc: |
Marks a place of travel on the map that has not been solved
if: is_locator
- id: is_solved_travel
type: b1
doc: |
Marks a solved place of travel on the map
if: is_locator
- id: is_unsolved_blockade_north
type: b1
doc: |
Marks a sector on the map that blocks access to northern zones
if: is_locator
- id: is_unsolved_blockade_south
type: b1
doc: |
Marks a sector on the map that blocks access to southern zones
if: is_locator
- id: is_unsolved_blockade_west
type: b1
doc: |
Marks a sector on the map that blocks access to western zones
if: is_locator
- id: is_unsolved_blockade_east
type: b1
doc: |
Marks a sector on the map that blocks access to eastern zones
if: is_locator
- id: is_solved_blockade_north
type: b1
doc: |
Marks a solved sector on the map that used to block access to
northern zones
if: is_locator
- id: is_solved_blockade_south
type: b1
doc: |
Marks a solved sector on the map that used to block access to
southern zones
if: is_locator
- id: is_solved_blockade_west
type: b1
doc: |
Marks a solved sector on the map that used to block access to
western zones
if: is_locator
- id: is_solved_blockade_east
type: b1
doc: |
Marks a solved sector on the map that used to block access to
eastern zones
if: is_locator
- id: is_unsolved_goal
type: b1
doc: |
The final puzzle of the world. Solving this wins the game
if: is_locator
- id: is_location_indicator
type: b1
doc: |
Overlay to mark the current position on the map
if: is_locator
# Item flags
- id: is_keycard
type: b1
if: is_item
- id: is_tool
type: b1
if: is_item
- id: is_part
type: b1
if: is_item
- id: is_valuable
type: b1
if: is_item
- id: is_map
type: b1
if: is_item
- id: unused2
type: b1
if: is_item
- id: is_edible
type: b1
if: is_item
# Weapon flags
- id: is_low_blaster
type: b1
doc: |
Item is a low intensity blaster (like the blaster pistol)
if: is_weapon
- id: is_high_blaster
type: b1
doc: |
Item is a high intensity blaster (like the blaster rifle)
if: is_weapon
- id: is_lightsaber
type: b1
if: is_weapon
- id: is_the_force
type: b1
if: is_weapon
# Character flags
- id: is_hero
type: b1
if: is_character
- id: is_enemy
type: b1
if: is_character
- id: is_npc
type: b1
if: is_character
action:
doc: |
Actions are the game's way to make static tile based maps more engaging
and interactive. Each action consists of zero or more conditions and
instructions, once all conditions are satisfied, all instructions are
executed in order.
To facilitate state, each zone has three 16-bit registers. These registers
are named `counter`, `shared-counter` and `random`. In addition to these
registers hidden tiles are sometimes used to mark state.
There are conditions and instructions to query and update these registers.
The `shared-counter` register is special in that it is shared between a
zone and it's rooms. Instruction `0xc` roll_dice can be used to set the
`random` register to a random value.
A naive implementation of the scripting engine could look like this:
```
for action in zone.actions:
all_conditions_satisfied = False
for condition in action.conditions:
all_conditions_satisfied = check(condition)
if !all_conditions_satisfied:
break
if !all_conditions_satisfied:
continue
for instruction in action.instructions:
execute(instruction)
```
See `condition_opcode` and `instruction_opcode` enums for a list of
available opcodes and their meanings.
seq:
- id: marker
contents: "IACT"
- id: size
type: u4
- id: num_conditions
type: u2
- id: conditions
type: condition
repeat: expr
repeat-expr: num_conditions
- id: num_instructions
type: u2
- id: instructions
type: instruction
repeat: expr
repeat-expr: num_instructions
condition:
seq:
- id: opcode
type: u2
enum: condition_opcode
- id: arguments
type: s2
repeat: expr
repeat-expr: 5
- id: len_text
type: u2
- id: text
type: str
size: len_text
doc: |
The `text_attribute` is never used, but seems to be included to
shared the type with instructions.
enums:
condition_opcode:
0x0:
id: zone_not_initialised
doc: Evaluates to true exactly once (used for initialisation)
0x1:
id: zone_entered
doc: Evaluates to true if hero just entered the zone
0x2:
id: bump
0x3:
id: placed_item_is
0x4:
id: standing_on
doc: |
Check if hero is at `args[0]`x`args[1]` and the floor tile is
`args[2]`
0x5:
id: counter_is
doc: Current zone's `counter` value is equal to `args[0]`
0x6:
id: random_is
doc: Current zone's `random` value is equal to `args[0]`
0x7:
id: random_is_greater_than
doc: Current zone's `random` value is greater than `args[0]`
0x8:
id: random_is_less_than
doc: Current zone's `random` value is less than `args[0]`
0x9:
id: enter_by_plane
0xa:
id: tile_at_is
doc: |
Check if tile at `args[0]`x`args[1]`x`args[2]` is equal to
`args[3]`
0xb:
id: monster_is_dead
doc: True if monster `args[0]` is dead.
0xc:
id: has_no_active_monsters
doc: undefined
0xd:
id: has_item
doc: |
True if inventory contains `args[0]`. If `args[0]` is `0xFFFF`
check if inventory contains the item provided by the current
zone's puzzle
0xe:
id: required_item_is
0xf:
id: ending_is
doc: True if `args[0]` is equal to current goal item id
0x10:
id: zone_is_solved
doc: True if the current zone is solved
0x11:
id: no_item_placed
doc: Returns true if the user did not place an item
0x12:
id: item_placed
doc: Returns true if the user placed an item
0x13:
id: health_is_less_than
doc: Hero's health is less than `args[0]`.
0x14:
id: health_is_greater_than
doc: Hero's health is greater than `args[0]`.
0x15: unused
0x16:
id: find_item_is
doc: True the item provided by current zone is `args[0]`
0x17:
id: placed_item_is_not
0x18:
id: hero_is_at
doc: True if hero's x/y position is `args_0`x`args_1`.
0x19:
id: shared_counter_is
doc: Current zone's `shared_counter` value is equal to `args[0]`
0x1a:
id: shared_counter_is_less_than
doc: Current zone's `shared_counter` value is less than `args[0]`
0x1b:
id: shared_counter_is_greater_than
doc: Current zone's `shared_counter` value is greater than `args[0]`
0x1c:
id: games_won_is
doc: Total games won is equal to `args[0]`
0x1d:
id: drops_quest_item_at
0x1e:
id: has_any_required_item
doc: |
Determines if inventory contains any of the required items needed
for current zone
0x1f:
id: counter_is_not
doc: Current zone's `counter` value is not equal to `args[0]`
0x20:
id: random_is_not
doc: Current zone's `random` value is not equal to `args[0]`
0x21:
id: shared_counter_is_not
doc: Current zone's `shared_counter` value is not equal to `args[0]`
0x22:
id: is_variable
doc: |
Check if variable identified by `args[0]`⊕`args[1]`⊕`args[2]` is
set to `args[3]`. Internally this is implemented as opcode 0x0a,
check if tile at `args[0]`x`args[1]`x`args[2]` is equal to
`args[3]`
0x23:
id: games_won_is_greater_than
doc: True, if total games won is greater than `args[0]`
instruction:
seq:
- id: opcode
type: u2
enum: instruction_opcode
- id: arguments
type: s2
repeat: expr
repeat-expr: 5
- id: len_text
type: u2
- id: text
type: str
size: len_text
enums:
instruction_opcode:
0x0:
id: place_tile
doc: |
Place tile `args[3]` at `args[0]`x`args[1]`x`args[2]`. To remove a
tile `args[3]` can be set to `0xFFFF`.
0x1:
id: remove_tile
doc: Remove tile at `args[0]`x`args[1]`x`args[2]`
0x2:
id: move_tile
doc: |
Move tile at `args[0]`x`args[0]`x`args[2]` to
`args[3]`x`args[4]`x`args[2]`. *Note that this can not be used to
move tiles between layers!*
0x3:
id: draw_tile
0x4:
id: speak_hero
doc: |
Show speech bubble next to hero. _Uses `text` attribute_.
Script execution is paused until the speech bubble is dismissed.
0x5:
id: speak_npc
doc: |
Show speech bubble at `args[0]`x`args[1]`. _Uses `text`
attribute_. The characters `¢` and `¥` are used as placeholders
for provided and required items of the current zone, respectively.
Script execution is paused until the speech bubble is dismissed.
0x6:
id: set_tile_needs_display
doc: Redraw tile at `args[0]`x`args[1]`
0x7:
id: set_rect_needs_display
doc: |
Redraw the part of the current scene, specified by a rectangle
positioned at `args[0]`x`args[1]` with width `args[2]` and height
`args[3]`.
0x8:
id: wait
doc: Pause script execution for one tick.
0x9:
id: redraw
doc: Redraw the whole scene immediately
0xa:
id: play_sound
doc: Play sound specified by `args[0]`
0xb:
id: stop_sound
doc: Stop playing sounds
0xc:
id: roll_dice
doc: |
Set current zone's `random` to a random value between 1 and
`args[0]`.
0xd:
id: set_counter
doc: Set current zone's `counter` value to a `args[0]`
0xe:
id: add_to_counter
doc: Add `args[0]` to current zone's `counter` value
0xf:
id: set_variable
doc: |
Set variable identified by `args[0]`⊕`args[1]`⊕`args[2]` to
`args[3]`. Internally this is implemented as opcode 0x00, setting
tile at `args[0]`x`args[1]`x`args[2]` to `args[3]`.
0x10:
id: hide_hero
doc: Hide hero
0x11:
id: show_hero
doc: Show hero
0x12:
id: move_hero_to
doc: |
Set hero's position to `args[0]`x`args[1]` ignoring impassable
tiles. Execute hotspot actions, redraw the current scene and move
camera if the hero is not hidden.
0x13:
id: move_hero_by
doc: |
Moves hero relative to the current location by `args[0]` in x and
`args[1]` in y direction.
0x14:
id: disable_action
doc: |
Disable current action, note that there's no way to activate the
action again.
0x15:
id: enable_hotspot
doc: Enable hotspot `args[0]` so it can be triggered.
0x16:
id: disable_hotspot
doc: Disable hotspot `args[0]` so it can't be triggered anymore.
0x17:
id: enable_monster
doc: Enable monster `args[0]`
0x18:
id: disable_monster
doc: Disable monster `args[0]`
0x19:
id: enable_all_monsters
doc: Enable all monsters
0x1a:
id: disable_all_monsters
doc: Disable all monsters
0x1b:
id: drop_item
doc: |
Drops item `args[0]` for pickup at `args[1]`x`args[2]`. If the
item is 0xFFFF, it drops the current sector's find item instead.
Script execution is paused until the item is picked up.
0x1c:
id: add_item
doc: Add tile with id `args[0]` to inventory
0x1d:
id: remove_item
doc: Remove one instance of item `args[0]` from the inventory
0x1e:
id: mark_as_solved
doc: |
Marks current sector solved for the overview map.
0x1f:
id: win_game
doc: Ends the current story by winning.
0x20:
id: lose_game
doc: Ends the current story by losing.
0x21:
id: change_zone
doc: |
Change current zone to `args[0]`. Hero will be placed at
`args[1]`x`args[2]` in the new zone.
0x22:
id: set_shared_counter
doc: Set current zone's `shared_counter` value to a `args[0]`
0x23:
id: add_to_shared_counter
doc: Add `args[0]` to current zone's `shared_counter` value
0x24:
id: set_random
doc: Set current zone's `random` value to a `args[0]`
0x25:
id: add_health
doc: |
Increase hero's health by `args[0]`. New health is capped at
hero's max health (0x300). Argument 0 can also be negative
subtract from hero's health.
monster:
doc: A monster is a enemy in a zone.
seq:
- id: character
type: u2
- id: x
type: u2
- id: y
type: u2
- id: loot
doc: |
References the item (loot - 1) that will be dropped if the monster
is killed. If set to `0xFFFF` the current zone's quest item will be
dropped.
type: u2
- id: drops_loot
doc: If this field is anything other than 0 the monster may drop an
item when killed.
type: u4
- id: waypoints
type: waypoint
repeat: expr
repeat-expr: 4
zone:
seq:
- id: planet
doc: |
Planet this zone can be placed on.
During world generation the goal puzzle dictates which planet is
chosen. Apart from `swamp` zones, only the zones with type `empty`
or the chosen type are loaded when a game is in progress.
type: u2
enum: planet
- id: size
type: u4
- id: index
type: u2
- id: marker
contents: "IZON"
- id: size2
type: u4
- id: width
doc: Width of the zone in tiles. Either 9 or 18.
type: u2
- id: height
doc: Height of the zone in tiles. Either 9 or 18.
type: u2
- id: type
enum: zone_type
type: u4
- id: shared_counter
doc: |
Scripting register shared between the zone and its rooms.
type: u2
valid: 0xFF_FF
- id: planet_again
doc: Repetition of the `planet` field
type: u2
- id: tile_ids
type: zone_spot
repeat: expr
repeat-expr: width * height
doc: |
`tile_ids` is made up of three interleaved tile layers ordered from
bottom (floor) to top (roof).
Tiles are often references via 3 coordinates (xyz), which
corresponds to an index into this array calculated as `n = y * width
* 3 + x * 3 = z`.
- id: num_hotspots
type: u2
- id: hotspots
type: hotspot
repeat: expr
repeat-expr: num_hotspots
- id: izax
type: zone_auxiliary
- id: izx2
type: zone_auxiliary_2
- id: izx3
type: zone_auxiliary_3
- id: izx4
type: zone_auxiliary_4
- id: num_actions
type: u2
- id: actions
type: action
repeat: expr
repeat-expr: num_actions
enums:
planet:
0: none
1: desert
2: snow
3: forest
5: swamp
zone_type:
0:
id: none
1:
id: empty
doc: |
Empty zones do not contain a puzzle to be solved and are used to
fill the space between between zones that are relevant for winning
the game.
2:
id: blockade_north
doc: |
This type of zone blocks access to sectors north of it until the
puzzle is solved.
3:
id: blockade_south
doc: |
This type of zone blocks access to sectors south of it until the
puzzle is solved.
4:
id: blockade_east
doc: |
This type of zone blocks access to sectors east of it until the
puzzle is solved.
5:
id: blockade_west
doc: |
This type of zone blocks access to sectors west of it until the
puzzle is solved.
6:
id: travel_start
doc: |
Starting point to travel to an island on the edge of the world.
`travel_start` and `travel_end` zones are connected through
hotspot of type `vehicle_to` and `vehicle_back`.
7:
id: travel_end
doc: |
Travel target that is only placed on an island at the edge of the
world map during world generation.
8:
id: room
doc: |
A zone that can not be placed on the world map directly. Instead
rooms are accessed via actions or hotspots of type `door_in`. They
usually contain at least one `door_out` hotspot to get back to the
other zone.
9:
id: load
doc: |
This type of zone is shown after the game has loaded all assets.
It should resemble the image from the catalog entry of type
`startup_image` for a smooth transition from loading to game play.
10:
id: goal
doc: |
Every world contains exactly one goal zone. Solving this zone wins
the game.
11:
id: town
doc: |
This is the entry zone where the hero arrives after leaving the
swamp planet. Each planet can only have one town zone.
13:
id: win
doc: |
Shown when a game is won. The score is rendered above the tiles at
coordinates 5x7 and 6x7.
14:
id: lose
doc: |
Shown when a game is lost.
15:
id: trade
doc: |
In order to solve this zone and gain a new item the hero has to
trade something in.
16:
id: use
doc: |
This type of zone can be solved by making applying a tool or using
a keycard.
17:
id: find
doc: |
This type of zone can be solved without using items.
18:
id: find_unique_weapon
doc: |
This zone provides the hero with a unique weapon and will be
placed closed to a town zone.
zone_spot:
seq:
- id: column
doc: from bottom to top, 0xFFFF indicates empty tiles
type: u2
repeat: expr
repeat-expr: 3
hotspot:
doc: |
In addition to actions some puzzles and events are triggered by
hotspots. These hotspots are triggered when the hero steps on them or
places an item at the location. Additionally, hotspots are used during
world generation to mark places where NPCs can spawn.
seq:
- id: type
type: u4
enum: hotspot_type
- id: x
type: u2
- id: y
type: u2
- id: enabled
doc: |
If disabled, hotspots can not be triggered. See instruction opcodes
called `enable_hotspot` and `disable_hotspot`.
type: u2
- id: argument
type: u2
enums:
hotspot_type:
0:
id: drop_quest_item
doc: |
Drops the item provided by the zone when solved. Can be set to a
specific item, or to `0xFFFF` to use the one from the currently
assigned puzzle.
1:
id: spawn_location
doc: |
Possible spawn location for one of the zone's NPCs.
2:
id: drop_unique_weapon
doc: |
Hotspot that drops the unique weapon found in zones of type
`find_unique_weapon`.
3:
id: vehicle_to
doc: |
Used in `travel_start` zones as a trigger to teleport to the
corresponding `travel_end` zone. The hotspot argument contains the
id of the zone to teleport to.
4:
id: vehicle_back
doc: |
Counter part to `vehicle_to` hotspots. This is used to determine
the hero's position on the zone after the `vehicle_to` hotspot has
been triggered and to teleport back to the zone on main land.
5:
id: drop_map
doc: |
Hotspot that drops the map (aka locator) tile. One `find` zone
with a hotspot of this type will be placed next to a town during
world generation.
6:
id: drop_item
doc: |
Hotspot that, when triggered drops the item specified in the
hotspot's argument. If the item is set to `0xFFFF` the zone's
quest item will be dropped.
7:
id: npc
doc: |
This seems to be a placeholder for a pre-assigned NPC.
8:
id: drop_weapon
doc: |
Drops a weapon (specified by the hotspot argument) when triggered.
9:
id: door_in
doc: |
When triggered this hotspot type move the hero to the zone
specified in the hotspot argument. The hero's location on the new
zone will be determined by a corresponding `door_out` hotspot in
the target zone.
10:
id: door_out
doc: |
Determines where the hero will be placed when the zone is entered
through a door. When triggered, this transports the player back to
the `door_in` hotspot they game from.
11: unused
12: lock
13:
id: teleporter
doc: |
Teleporter hotspots can be used to instantly teleport to other
(visited) teleporters on the map
14:
id: ship_to_planet
doc: |
Behaves similar to the `vehicle_to` hotspot type but travels
between the town and the swamp planet.
15:
id: ship_from_planet
doc: |
Behaves similar to the `vehicle_back` hotspot type but travels
between the town and the swamp planet.
zone_auxiliary:
seq:
- id: marker
contents: "IZAX"
- id: size
type: u4
- type: u2
- id: num_monsters
type: u2
- id: monsters
type: monster
repeat: expr
repeat-expr: num_monsters
- id: num_required_items
type: u2
- id: required_items
doc: List of items that can be used to solve the zone.
type: u2
repeat: expr
repeat-expr: num_required_items
- id: num_goal_items
type: u2
- id: goal_items
doc: |
Additional items that are needed to solve the zone. Only used if the
zone type is `goal`.
type: u2
repeat: expr
repeat-expr: num_goal_items
zone_auxiliary_2:
seq:
- id: marker
contents: "IZX2"
- id: size
type: u4
- id: num_provided_items
type: u2
- id: provided_items
doc: Items that can be gained when the zone is solved.
type: u2
repeat: expr
repeat-expr: num_provided_items
zone_auxiliary_3:
seq:
- id: marker
contents: "IZX3"
- id: size
type: u4
- id: num_npcs
type: u2
- id: npcs
doc: |
NPCs that can be placed in the zone to trade items with the hero.
type: u2
repeat: expr
repeat-expr: num_npcs
zone_auxiliary_4:
seq:
- id: marker
contents: "IZX4"
- id: size
type: u4
- type: u2
zones:
seq:
- id: num_zones
type: u2
- id: zones
type: zone
repeat: expr
repeat-expr: num_zones
puzzles:
seq:
- id: puzzles
type: puzzle
repeat: until
repeat-until: _.index == 0xFF_FF
puzzle:
seq:
- id: index
type: u2
- id: marker
if: index != 0xFF_FF
contents: "IPUZ"
- id: size
type: u4
if: index != 0xFF_FF
- id: type
type: u4
if: index != 0xFF_FF
- id: item1_class
type: u4
enum: puzzle_item_class
if: index != 0xFF_FF
- id: item2_class
type: u4
enum: puzzle_item_class
if: index != 0xFF_FF
- type: u2
if: index != 0xFF_FF
- id: strings
type: prefixed_str
repeat: expr
repeat-expr: 5
if: index != 0xFF_FF
- id: item_1
type: u2
if: index != 0xFF_FF
- id: item_2
type: u2
if: index != 0xFF_FF
enums:
puzzle_item_class:
0: keycard
1: tool
2: part
4: valuable
0xFFFF_FFFF: none
endf:
seq: []
tgen:
doc: |
The TGEN section is only present in non-english versions of the game. It's purpose or
internal structure is unknown.
seq:
- id: data
size: _parent.size
characters:
seq:
- id: characters
type: character
repeat: until
repeat-until: _.index == 0xFF_FF
character:
seq:
- id: index
type: u2
- id: marker
contents: "ICHA"
if: index != 0xFF_FF
- id: size
type: u4
if: index != 0xFF_FF
- id: name
type: strz
size: 16
if: index != 0xFF_FF
- id: type
type: u2
enum: character_type
if: index != 0xFF_FF
- id: movement_type
type: u2
enum: movement_type
if: index != 0xFF_FF
- id: probably_garbage_1
type: u2
if: index != 0xFF_FF
- id: probably_garbage_2
type: u4
if: index != 0xFF_FF
- id: frame_1
type: char_frame
if: index != 0xFF_FF
- id: frame_2
type: char_frame
if: index != 0xFF_FF
- id: frame_3
type: char_frame
if: index != 0xFF_FF
enums:
character_type:
1: hero
2: enemy
4: weapon
movement_type:
0: none
4: sit
9: wander
10: patrol
12: animation
char_frame:
seq:
- id: tiles
type: u2
repeat: expr
repeat-expr: 0x8
character_auxiliaries:
seq:
- id: auxiliaries
type: character_auxiliary
repeat: until
repeat-until: _.index == 0xFF_FF
character_auxiliary:
seq:
- id: index
type: u2
- id: damage
type: s2
if: index != 0xFF_FF
character_weapons:
seq:
- id: weapons
type: character_weapon
repeat: until
repeat-until: _.index == 0xFF_FF
character_weapon:
seq:
- id: index
type: u2
- id: reference
doc: |
If the character referenced by index is a monster, this is a
reference to their weapon, otherwise this is the index of the
weapon's sound
type: u2
if: index != 0xFF_FF
- id: health
type: u2
if: index != 0xFF_FF
# Utilities
prefixed_str:
seq:
- id: len_content
type: u2
- id: content
type: str
size: len_content
prefixed_strz:
seq:
- id: len_content
type: u2
- id: content
type: strz
size: len_content
waypoint:
seq:
- id: x
type: u4
- id: y
type: u4