Skip to content
Nill edited this page Jun 29, 2021 · 4 revisions

In SKX, rooms are the fundamental unit of game design, each room being a "level" in the game.

Room Lookup

The data for a given room is loaded based on the room number, and the story the player is currently playing.

When the game loads the data for a room the work directory is checked for the presence of a file named room_xxs.json where xx is the hexadecimal room number and the s is the story ID (e.g. c, p, ...)

If this file is found, it is used, otherwise the internal Bundle is checked for the room. If the room is not found (which does not occur during normal gameplay), the engine will load a blank room (of the default size with a blank layout).

Dimensions

A standard SKX room is 17x14 cells, with the leftmost and rightmost columns being used for the solid bounding blocks, the top row being used for a solid ceiling (usually hidden behind the HUD), and the bottom row also solid blocks.

Custom dimensions can be used, however rooms other than 17x14 will need to define their own borders; standard size rooms can also define their own borders by turning the UseDefaultBorders property off. If UseDefaultBorders is true, and the room is 17x14, then the first and last rows and columns are automatically replaced by the engine.

Warning: Large room support is provided for specific scenarios and story arc progression. SKX always renders the entire room to a buffer internally regardless of size and/or Dana's position, so the theoretical size of rooms is limited by the ability for the game to create this off-screen buffer. It is not recommended to create areas larger than 1000 cells^2 (e.g. 100x100, 200x500, ...) as a single room.

Wrapping

By default, game objects (including Dana) will wrap around to the other side automatically if they leave the valid dimensions of the room.

Exceptions are some classes of enemies which will disappear off bottom of the level without wrapping, and enemy projectiles which do not wrap.

Unlike the NES version (which indexed into arbitrary data), out-of-bounds accesses to the cell grid (e.g. Dana trying to create a block off the side of the level) are wrapped appropriately.

Background

The background is a tilemap used to construct the background visual layer of the level. It holes one Tile per cell, up to the cell dimensions of the world/room.

Super Foreground

Similar to the background, the super foreground is a tilemap that, if present, is used to construct the super foreground layer which appears in front of all objects and terrain. The super foreground is optional for a layout.

Cell Grid

The cell grid (aka foreground) of the room contains an array of Cell values the correspond to the world-size grid of blocks in the level. Cell.Empty is empty space, with other values being terrain (blocks), items, keys, doors, decorations, and other items that are placed in the cell grid.

Each cell in the grid has two components that are ORed together:

  • Contents (low word) -- Either Empty or the contents of the space
  • Modifier (high word) -- Normal, Covered, Cracked, Hidden, xor Frozen

Cell.Frozen + Cell.MightyCoin = Cell.Frozen | Cell.MightyCoin

One peculiarity worth noting, which is a hold over from the original NES logic, is that breakable (dirt) blocks with nothing inside are use Cell.Dirt as their value (with no modifier), rather than, for example Cell.Covered | Cell.Empty. Likewise an empty frozen block is usually stored as Cell.FrozenBlock and not Cell.Frozen | Cell.Empty.

There are also certain conditions under which specific items will be removed from the cell grid automatically upon a room loading:

  1. Items flagged as FirstTry (see reference) are only present during Dana's first attempt at the level. On subsequent attempts (after a death), the items are removed.
  2. Keys that Dana already holds in his inventory will not be placed
  3. Persistent items (such as Seals) that Dana has already collected will not be placed
  4. Doors that Dana already has opened will be opened as part of the level start sequence.
  5. Spells may execute immediately upon level load which modify the layout before it is visible to the player.

Other Properties

Room Number

Every room has a hexadecimal room number unique to the story it is a part of. In most rooms the room number is well-known and visible on the title card, however some bonus, hidden, and finale rooms instead use room names which are shown instead.

By default new game sessions begin on room 1. The next room loaded is determined by the various "Next Room" properties of the current room.

Room Name

If a room name is provided, it is used instead of the room number. If the room name is omitted, ROOM xxx is used as the room name, where xxx is the room's number in hexadecimal format.

Shrine

As in the original NES game, each room is part of a "Shrine" which is displayed on the title screen and in load game menus. The shrine is stored as an integer from 0 to 0x28. The Classic story uses shrine 0x3D (Solomon) for any value over 0xA (Pieces), while other story types can use any shrine ID.

Next Room Normal Exit

Defines the room number Dana travels to when he exits the room normally.

Next Room Secret Exit

Defines the room number Dana travels to when he exits the room using a secret exit (see Doors).

Next Room Gold Wing Exit

Defines the room number Dana travels to when he exits the room using a gold wing (see Doors).

Initial Life Override

A layout can define the initial life that Dana/Adam start the level with; if not provided, the default is the standard 10,000 life.

Music

Determines which song is used for the room.

ID Song
0 Normal level (NES)
1 Hidden level (NES)
2 Easter egg
3 Puzzle/Bonus
4 Techno

Audio Effect

Determines which dynamic audio effect is in use in the room.

| ID | Name | Special Sauce |--|--|--|--|--|--|--|--|--|--|--|--|--|--|--|--|--|--| | 0 | Normal | LF0=Life, LP1=Life*2-1, LF1=Life*-1.5 | 1 | Special Room A | F0=dana.x, F1=dana.y, F2=0.75, LF0=Life*-1, LF1=Life*-1.5, LP1=Life*2-1, LF2=Life*-1.5 | 2 | Special Room B | F0=Life F1=-Life F2=0.75 LF0=Life*-1.5 LF1=Life*-1.5 LP1=1-Life*2 LF2=1-Life*-2 | 3 | Special Room C | F0=-Life F1=Life F2=0.75 LF0=Life*-1.5 LF1=Life*-1.5 LP1=1-Life*2 LF2=1-Life*-2 | 4 | Special Hidden | | 5 | Full Volume | No processing

Clone this wiki locally