kts.LayoutDungeon

Name

kts.LayoutDungeon – generate the dungeon layout for a new game

Synopsis

kts.LayoutDungeon {
    layout = <layout table>,
    wall = <tile>,
    horiz_door = <tile>,
    vert_door = <tile>,
    segments = <segments>,
    special_segments = <segments>,
    entry_type = <string>,
    allow_rotate = <boolean>
}

Description

How dungeon layouts work

A dungeon layout consists of a grid of up to 3x3 "cells". Each cell is labelled either block, edge or special (the meaning of these terms will be discussed below). Also, each of the four borders of each cell can be considered either "open" or "closed".

Here are some example dungeon layouts:

Diagram showing four example dungeon layouts

In the above diagram, dotted lines indicate "open" borders between cells, and solid lines indicate "closed" borders.

(Note that a "Dungeon Type" in the Knights quest selection menu might correspond to more than one possible "dungeon layout" in the sense being discussed here. For example, there are three different "Ring" dungeon layouts, and five different "Long Snakes"; the above diagram shows only one of each.)

Dungeons are made by filling in each cell of the chosen layout with a different, randomly selected "segment". A segment is a pre-designed set of dungeon rooms. For example, this is a segment:

Example dungeon segment, showing several dungeon rooms

The standard Knights data files include over 200 different segments, allowing for plenty of variety in games, and users can also add more segments by editing the data files if they wish.

Here is an example of the "Long Snake" layout shown above being filled in with some segments, to make a dungeon:

Example Long Snake dungeon showing segment boundaries

Here, the segment boundaries have been highlighted in red. Observe how each of the seven cells in the "Long Snake" dungeon layout (see previous diagram) have now been filled in with a different, randomly chosen dungeon segment. Observe also the one-square-thick borders that have been added between the segments. In cases where there is a "closed" border (solid line on the dungeon layout diagram), the border squares are completely filled with solid walls, but on the "open" borders (dotted lines on the layout), there is a mix of solid walls and (randomly placed) wooden door tiles. This allows the knights to travel between the different dungeon segments. (In a Long Snake layout, the pattern of open and closed borders is designed such that the knights have to walk a long, winding path to get from one end of the dungeon to the other. In most other layouts, most of the borders are open, allowing the knights to traverse the dungeon more easily.)

We now explain what the different cell types (block, edge and special) mean. In many cases, the cell types don't actually make any difference, and the dungeon generator just fills each cell with a randomly chosen segment, regardless of the cell type. However, there are some circumstances in which the cell types matter, as follows:

An additional rule is that if a special cell is not filled with a "required" dungeon segment then it is removed from the layout entirely. This comes into play for the "Ring" dungeon type (which is the only dungeon type that uses the special cells currently). For example, in the "Ring" dungeon layout shown above, the centre cell is special. If the quest has at least one "required" segment (such as a guarded exit point), then this will appear in the centre of the ring, otherwise the centre of the ring will be left empty.

Representing dungeon layouts in Lua

In Lua, a dungeon layout is represented by a table, as in the following examples:

-- Tiny Dungeon
tiny_layout = {
    width = 1,
    height = 1,
    data = {
        { type="block" }
    }
}

-- Basic Dungeon
basic_layout = {
    width=2, 
    height=2, 
    data={
        { type="edge" }, { type="edge" },
        { type="edge" }, { type="edge" }
    }
}

-- Long Snake Dungeon
long_snake_layout = {
    width=3,
    height=3,
    data={
        { type="block" }, { type="edge",  exits="w"  }, { type="none"  },
        { type="block" }, { type="block", exits="we" }, { type="block" },
        { type="none"  }, { type="edge",  exits="e"  }, { type="block"
    }
}

-- Ring Dungeon
ring_layout = {
    width=3,
    height=3,
    data={
        {type="block"            }, {type="block"            }, {type="special"},
        {type="block", exits="ns"}, {type="block", exits="ns"}, {type="none"   },
        {type="block"            }, {type="block"            }, {type="none"   }
    }
}

The table contains fields width and height giving the size of the layout (in cells) and then a data field containing the cells themselves (in order, left to right then top to bottom). Each cell is itself represented by a table containing a type field, which must be set to one of the strings "block", "edge" or "special" (representing a cell of the corresponding type) or else "none" (representing a cell which is not actually part of the current layout). Each cell may also contain a field exits which is a string containing one or more of the letters "n", "e", "s" and/or "w" (for north, east, south and west) which determines the borders of the cell that are considered "open". The default (if exits is not specified) is for all borders to neighbouring cells to be considered open. Note that exits must be consistent, e.g. if one cell has an exit to the north, then the neighbouring cell just above must have an exit to the south (if this is not the case then an error message will be generated).

The kts.LayoutDungeon function

Calling the kts.LayoutDungeon function kicks off the dungeon generation process and places the map segments into the dungeon. The players' homes (dungeon entry points) are also assigned at this time.

Before this function is called, the dungeon should be completely empty, and also the kts.DUNGEON_ERROR variable should be nil. kts.WipeDungeon can be called beforehand, if necessary, to make sure that this is the case.

kts.LayoutDungeon takes exactly one parameter, which should be a table containing the following fields:

Return Value

None.

Errors

If the parameters to the function are invalid (for example, an incorrect dungeon layout table is given, or an invalid entry_type string is used), then a Lua error will be raised.

If the parameters are valid, but dungeon generation itself fails, no error is raised; instead, the variable kts.DUNGEON_ERROR is set to a string indicating the reason for the failure. (If dungeon generation is successful, kts.DUNGEON_ERROR will be left as nil.)

Notes

A full dungeon generation system will not only need to call kts.LayoutDungeon, but it will also need to call other functions such as kts.GenerateLocksAndTraps, kts.AddItem, kts.AddStuff, kts.AddMonsters and kts.ConnectivityCheck to populate the dungeon with items and monsters, and ensure that all rooms are accessible to players.

Also, calling the dungeon generator multiple times is sometimes necessary, as there might be cases where dungeon generation fails (just due to random chance) but retrying it succeeds. If dungeon generation fails more than, say, 25 times in a row, then it is likely that the current layout is simply not big enough to fit in everything needed for the current quest, and in that case, starting over with a larger dungeon layout is recommended.

This is all taken care of by the standard Knights Lua files; the code can be found in dungeon_setup.lua. (In particular, the function generate_dungeon in that file is the starting point for dungeon generation.)

Examples

The standard dungeon layouts ("Tiny", "Basic", "Big", "Huge", "Snake", "Ring" and so on) can be found in dungeon_layouts.lua. Note that the actual dungeon layout table is returned by the function marked func in each case (the rest of the structure in that file is internally used by the Lua code, and is not part of the data that is passed to kts.LayoutDungeon). Also note that for many of the dungeon types, there is not just one dungeon layout, but several, which are selected from at random when a game with that dungeon type is played. For example, there are three possible "Huge" dungeon layouts, one of which is selected at random whenever a quest with a "Huge" dungeon is played.

See Also

kts.AddItem

kts.AddStuff

kts.AddMonsters

kts.ConnectivityCheck

kts.GenerateLocksAndTraps

kts.LoadSegments

kts.SetReflect

kts.SetRespawnType

kts.SetRotate

kts.Tile