kts.MENU

Name

kts.MENU – defines the Dungeon Environment Customization Menu

Synopsis

kts.MENU = {
    text = "Menu Title",   -- e.g. "QUEST SELECTION"

    initialize_func = function(S) ... end,
    on_select = function(S) ... end,
    describe_quest_func = function(S) ... return "quest description" end,
    prepare_game_func = function(S) ... end,
    start_game_func = function(S) ... end,

    items = <list of menu_items>
}

menu_item = {
    id = "id_string",
    text = "Menu Item Text",

    type = <"numeric" or "dropdown">,   -- default is "dropdown"

    digits = <number>,
    suffix = "string",

    choices = <list of menu_choices>,
    choice_min = <number>,
    choice_max = <number>,
    show = function(id) ... return <string or number> end,

    on_select = function(S) ... end,
    constrain = function(S) ... end,
    features = function(S) ... end,
    randomize = function(S) ... return <menu choice id> end
}

-- note: a menu_item can also be the string "spacer"

menu_choice = {
    id = "id_string",
    text = "Menu Choice Text",
    
    min_players = <number>,
    max_players = <number>,
    min_teams = <number>,
    max_teams = <number>,
    
    on_select = function(S) ... end,
    constrain = function(S) ... end,
    features = function(S) ... end
}

Description

Concepts

The Knights "Quest Selection" menu is a key part of the game, allowing users to customize both quest objectives and dungeon properties before play begins.

This is what the menu UI looks like in-game:

Quest Selection menu

The dropdowns and text entry fields in the UI are referred to as menu items. Each menu item has an "id" (the string used to refer to the item internally) as well as its "text" (the actual name of the menu item as shown to the user). For example, the second menu item from the top, in the above screenshot, has id "mission" and text "Mission Type", and the sixth one from the top has id "num_gems" and text "Number of Gems".

For each menu item, the different options that can be selected are referred to as menu choices. Each menu choice also has both an internal "id" and some external "text"; but this time, the ids are allowed to be booleans or numbers as well as just strings. For example, for the "Mission Type" menu item, the different choices have ids like "escape", "retrieve_book" and so on, with corresponding texts of "Escape from the Dungeon", "Retrieve Book and Escape", and so on. For "Number of Gems", the menu choice ids are just the numbers from 0 to 6, with the texts being strings like "1" or "3" (or the string "None" if the number of gems is zero).

"S" table

While on the menu screen, the currently selected menu choices are held in a Lua table called "S" (for "State" or "Settings"). The keys in this table are the menu item ids and the values are the selected menu choice ids. For example, in a Quest for Gems we might have S.mission = "escape", S.num_gems = 4, S.gems_needed = 3, S.dungeon = "basic", and so on.

The "S" table also contains fields num_players and num_teams giving the current number of players and teams in the game, in case this information is needed by the Lua code at any point.

Finally, "S" also contains some special fields named Is, IsNot, IsAtLeast and IsAtMost; these contain functions which can be used in the menu constraints system. This will be explained further below.

kts.MENU table

The set of available menu items, and corresponding menu choices, together with some other settings, are all defined in a Lua table named kts.MENU. This is set up by the standard Lua files provided with the game (see menus.lua) and mods are free to modify this table as they see fit. The following fields can be set in the kts.MENU table:

Menu Item tables

The menu item tables can have the following fields:

Menu Choice tables

The menu choice tables (used in the choices field of a menu item) can have the following fields:

Constraints

"Constraints" refer to any kind of restrictions on the available menu settings. For example, "Gems Needed" can never be set higher than "Number of Gems". As another example, if "Mission Type" is "Retrieve Book and Escape", then "Exit Point" cannot be "No Escape", and "Type of Book" cannot be "No Book in the Dungeon".

To allow setting up these constraints, a constrain Lua function can be attached to any menu item or menu choice. If the function is attached to a menu item, then the constraints it defines are always active, and if it is attached to a menu choice, then the constraints are only active when that menu choice is selected.

The constraint function is passed the "S" table and it should call one or more of the special functions S.Is, S.IsNot, S.IsAtLeast and S.IsAtMost. These do the following:

The game will try to ensure that any specified constraints are satisfied at all times. For example, options that would violate a constraint will simply not be shown as part of the relevant dropdown(s), and will not be selectable. If the menu ever does get into a state where the constraints are not met, then the game will try to put it back into a valid state again (by changing menu settings as required). This might not always succeed (see "Bugs" below), but as long as the constraints are not too complex (or indeed impossible, e.g. asking for the same menu item to be both less than 1 and greater than 1 at the same time), it should work well enough.

See "Examples" below for some examples of things that can be done using the constraint system.

Bugs

The constraint solver is not perfect; if the constraints are extremely complicated, then the solver might "fail" and leave the menu in an invalid state. Also, if the constraints are actually impossible to solve, then no error message will be reported; instead the menu will just be left in some inconsistent state.

Examples

General Examples

The best way to understand the menu system is probably to study menus.lua which is where the standard kts.MENU is defined. See also the related files preset_quests.lua and quest_description.lua. Finally, if you want to see how the various menu settings get converted into actual gameplay features, take a look at dungeon_setup.lua, as well as the logic in the features functions and in start_game_func (the latter just calls through to start_game in dungeon_setup.lua).

Constraints System Examples

As promised above, here are some examples of how the "constraints" system can be used to achieve various effects:

-- This ensures that "Retrieve Book and Escape" quests always contain
-- both a book and an exit point.
-- It is added to the "retrieve_book" choice of the "mission" menu item.
constrain = function(S)
    S.IsNot("exit", "none")   -- must have exit
    S.IsNot("book", "none")   -- must have book
end

-- This ensures that "Destroy Book with Wand" quests contain a book
-- and a wand, but no exit point.
-- It is added to the "destroy_book" choice of the "mission" menu item.
constrain = function(S)
    S.IsNot("exit", "none")
    S.Is("book", "none")
    S.IsAtLeast("num_wands", 1)
end

-- This ensures that Gems Needed is no more than Number of Gems.
-- It is added to the "num_gems" menu item (although it could
-- equally well have been added to "gems_needed", or indeed any
-- other menu item, although attaching constraints to the menu
-- items that they most relate to is generally the best idea).
constrain = function(S)
    S.IsAtMost("gems_needed", S.num_gems)
end

-- This forces the "Type of Wand" to be "None" when 0 wands are
-- selected, or anything other than "None" when a non-zero number
-- of wands is selected. It is added to the "num_wands" menu item.
constrain = function(S)
    if S.num_wands == 0 then
        S.Is("wand", "none")
    else
        S.IsNot("wand", "none")
    end
end

See Also

TODO