kts.Tile – create a new Tile
tile = kts.Tile { type = <"", "home", "door", "chest" or "barrel">, -- For all tile types: access = <access table (see below)>, connectivity_check = <integer>, control = <control or function>, depth = <integer>, graphic = <graphic>, hit_points = <function or integer>, items = <see description below>, on_activate = <function>, on_approach = <function>, on_destroy = <function>, on_hit = <function>, on_walk_over = <function>, on_withdraw = <function>, stairs_down = <"special", "north", "south", "east", "west">, tutorial = <integer>, map_as = <"wall", "floor">, -- For type = "home": facing = <"north", "south", "east", "west">, special_exit = <boolean>, unsecured_colour = <integer>, -- For type = "door" or "chest": open = <boolean>, open_graphic = <graphic>, lock_chance = <number between 0.0 and 1.0>, lock_pick_only_chance = <number between 0.0 and 1.0>, keymax = <integer>, special_lock = <boolean>, on_open_or_close = <function>, on_unlock_fail = <function>, -- Additionally for type = "chest": facing = <"north", "south", "east", "west">, trap_chance = <number between 0.0 and 1.0>, traps = <function> }
where:
<access table> = { "flying" = <access type>, "missiles" = <access type>, "walking" = <access type> } <access type> = nil, "approach", "partial", "blocked", "clear"
All fields listed above also accept nil
as a valid value.
A "Tile" is an object representing the "terrain" within a particular square of the dungeon. A Tile might therefore represent a wall, a piece of floor, a treasure chest, etc. A given dungeon square can contain more than one Tile, for example a treasure chest tile might be overlaid on top of a floor tile.
The kts.Tile
function creates a new Tile. The function takes one parameter, a table, which contains various properties that the new Tile should have. These are as follows:
type
selects the overall type of the tile. This can be one of the following values: ""
(or nil
) selects a normal tile with no special properties. "home"
selects an entry/exit point tile. These tiles can be used by knights as a spawn point, used as dungeon exits (in "escape from the dungeon" quests), or secured by the Wand of Securing. "door"
or "chest"
select door or chest tiles respectively. Unlike other tile types, these tiles have two states: open and closed. They can also have traps set on them, and can be locked. Chests can additionally contain items. "barrel"
is a tile that may be "hiding" an item within it. When the tile is destroyed, the item is revealed. access
controls whether the tile can be passed through. "blocked"
means that the tile is blocked – nothing can pass through it. Used for walls. "clear"
means that the tile is open – creatures can enter the tile. Used for floors. "approach"
or "partial"
means that the tile can be approached, but not moved through. Used for closed doors and the like. "flying"
, "missiles"
and "walking"
. The access type can be set separately for each. For example, a treasure chest might have {"flying": "clear", "walking": "approach"}
, which means that knights (and other walking creatures) can approach the chest but not move through it, while vampire bats (and other flying creatures) can fly over it. "missiles"
access level refers to projectiles such as flying daggers and axes. Note that if "missiles"
is set to "approach"
(or "partial"
) this has a special meaning: the missile will have a fixed probability of passing through the tile, set by the missile_access_chance
property of the ItemType. (This is used for the closed gates, where a certain proportion of missiles will be blocked by the gate.) See also kts.ItemType. "clear"
at all levels. connectivity_check
determines whether the dungeon generator considers this tile as usually impassable by knights (-1), usually passable (1), or the dungeon generator should guess based on heuristics (0). See "Notes" below for a full explanation of what this is used for. control
may be set to a Control (see kts.Control) which becomes available if the knight is standing on or approaching the tile. For example, this is used by doors and chests, to make the "open/close door" control available. control
may also be set to a Lua function, in which case the function will be passed the current position of the tile, and it can then return a Control object (or nil). depth
is an integer which controls the order in which overlapping tiles are drawn. For example, this is set to a high value for floor tiles, and a lower value for chests, tables etc., to make sure that the chests/tables are drawn on top of the floor tile (and not the other way around). Note that depth values must be between –8 and +7 currently. graphic
is the Graphic object used for drawing the tile (see kts.Graphic). hit_points
is the number of hit points that the tile has. If nonzero, then the tile can be destroyed, once it suffers the given amount of damage. This can also be set to a function that returns a number (in this case the function would usually return a random number – and having it as a function means that the number will be "rerolled" for each individual instance of the tile in the dungeon, rather than "rolled" only once when the Tile is first created). items
controls how the dungeon generator places items on this tile. This can have several values: 0
means items may not be placed on this tile. "destroy"
has a special meaning: any items placed on this tile are automatically destroyed/lost. This is used for pits. items
is nil
or not specified, is to disallow items (equivalent to items=0
) if access at "walking" level is "clear"; or to allow items (equivalent to items=1
) otherwise. on_activate
is a Lua function that is called when the tile is "activated" (see kts.Activate). on_approach
is a Lua function that is called when the tile is approached by any creature. on_destroy
is a Lua function that is called when the tile is destroyed. on_hit
is a Lua function that is called when the tile is hit by any creature (e.g. a sword strike from a knight). on_walk_over
is a Lua function that is called when any creature walks onto the tile (note this is not triggered by flying creatures, only walking). on_withdraw
is a Lua function that is called when a creature moves back from approaching the tile. stairs_down
is used to indicate staircase tiles. If set to nil (or omitted) then this tile is not a staircase. If set to a direction (north, south, east or west), then the tile is a staircase and walking in the given direction is going "downstairs". If set to "special" then this tile represents the "top" of a staircase. tutorial
is an integer indicating which tutorial message (if any) is associated with seeing this tile. map_as
indicates whether the tile should be shown on the mini-map as either a "wall"
or a "floor"
. If omitted, the game will decide automatically, based on the access settings and whether or not the tile is destructible. facing
indicates the orientation of a home or chest tile. For home tiles, this must point "towards" the exit (i.e. out of the dungeon). For chests, this is the direction from the centre of the chest towards the "front" of the chest. (A chest cannot be opened from behind.) special_exit
(for homes) indicates that this is the "special" exit point (e.g. used for "guarded exit" quests). unsecured_colour
(for homes) is an RGB colour value (hex number between 000000 and FFFFFF). The graphic for a "home" tile is expected to include several pixels with colour value FF0000 (red). The game will re-colour all of these pixels in the knight's own house colours (if the home is secured) or in the unsecured_colour
if the home is unsecured. Usually unsecured_colour
would be set to 0 (black). open
(for doors or chests) indicates whether the door is initially open. open_graphic
(for doors or chests) is an alternative graphic to be used when the door or chest is open (the main graphic
is used when it is closed). lock_chance
(for doors/chests) is the probability that the door/chest will be locked at the start of the game. lock_pick_only_chance
(for doors/chests) is the probability that, if locked, the door/chest can only be opened by lockpicks, and not by any of the keys. keymax
(for doors/chests) is the highest allowed key number that will unlock this chest. (When a chest is to be locked, a random number between 1 and keymax
will be generated. If this turns out to be higher than the number of keys in the game, then the chest is unlocked instead.) Usually keymax
would be set to 3 as a Knights quest usually has up to 3 keys. special_lock
(for doors/chests) means that the door can be opened neither by keys nor lock picks; only switches will work. Used for doors that are involved in switch puzzles. on_open_or_close
(for doors/chests) is a Lua function that is called when the tile is opened or closed by any means. on_unlock_fail
(for doors/chests) is called when a knight fails to unlock the tile (because they do not have the right key, or because their attempt at using lockpicks failed). This is usually used to play a sound effect or show a "Locked" message. trap_chance
(for chests) is the probability that the tile will contain a trap, when "pretrapped chests" is active. traps
(for chests) is a Lua function that is called during dungeon generation, when a chest needs to be given a trap. The function receives two parameters: the position of the chest, and the chest's "facing" direction. It will usually just call either kts.SetPoisonTrap or kts.SetBladeTrap to create the trap. The new Tile (a Lua userdata object) will be returned.
There are several different errors that can be generated if any of the input parameters are incorrect.
(This section gives a detailed description of how the connectivity_check
setting works.)
(TODO: this should probably be moved to the kts.ConnectivityCheck page, when that is written.)
When a new game of Knights is started, a dungeon is randomly generated by stitching map segments together, and inserting random doors between segments. Items are then dropped into random locations. This might, in some cases, result in an "impossible" layout, for example, if there is a locked iron door, and the only key (or lock pick) that can open it, is on the inside of the locked room.
In order to avoid this situation, the dungeon generator runs a "connectivity check", which is essentially a flood fill, starting from each knight's entry point. The fill will pass through tiles that are considered "passable" by knights (such as floor tiles). Locked doors are considered passable only if the flood fill has reached an appropriate key (or lock picks). If this flood fill does not reach all keys (or lockpicks), then the dungeon is considered "impossible", and extra lockpicks are spawned at an appropriate location, to avoid the problem.
What has this got to do with Tile settings? Well, the dungeon generator decides whether a tile is passable by a knight, by considering the following:
These heuristics are usually correct, but sometimes need to be overridden. For example, the default Knights data files set "pit" tiles to have access = clear, but then kill the knight (in the on_walk_over
function) if any knight walks into the pit. The above heuristic would mark a pit as being "passable" (on the grounds that access is clear) but this would not be accurate. Therefore, pits set connectivity_check = -1
to make sure that the dungeon generator treats open pits the same as walls, for the purpose of the connectivity check.
The other case where an override is needed is in the "closed gate" tiles. Under the final bullet point above, these would be treated as passable, on the assumption that there is a switch somewhere that opens them, however, this is not always the case – some gates are not openable at all. Therefore, gates also have connectivity_check = -1
in the data files.
A simple floor tile:
floor = kts.Tile { access = { walking = "clear", flying = "clear", missiles = "clear" }, items = "floor", graphic = my_floor_graphic }
A treasure chest:
chest = kts.Tile { type = "chest", graphic = my_graphic, -- previously created by calling kts.Graphic open_graphic = my_open_graphic, facing = "north", depth = -4, items = "chest", access = { walking = "approach", flying = "clear", missiles = "clear" }, trap_chance = 0.5, traps = function(pos, dir) if kts.RandomChance(0.5) then kts.SetPoisonTrap(pos, poison_trap_item) else kts.SetBladeTrap(pos, blade_trap_item, bolt_item, dir) end end, lock_chance = 0.5, lock_pick_only_chance = 0.16667, keymax = 3, hit_points = function() return kts.RandomRange(1, 20) end, control = my_control, -- previously created by calling kts.Control -- Not shown here: -- functions on_open_or_close, on_unlock_fail, on_hit, -- which would typically play sound effects and/or show messages. }