Player controls

The engine allows to define control commands completely arbitrarily. Own keyboard commands can be added and modified. All supported input devices such as mouse, keyboard and gamepads can be mapped freely and commands can consist of any key combinations or sequences.

PlayerControls.txt

All control commands which a player can send to the game are defined in the file PlayerControls.txt. The standard keys as well as their standard mapping for various input devices are contained in the global definition file in the Systems.ocg folder. Object definitions and scenarios can add more keys or overload the parameters of existing commands in their local Systems.ocg folder.

Section [ControlDefs]

Definition of possible player commands. Subordinated to this section:
Any number of sections [ControlDef]
Value Data type Description
Identifier String (max. 96 chars) Internally used name for identification of the command. The command is referenced by that name in standard mappings and it is predefined in script as CON_Name. The name should therefore be a valid identifier in script, i.e. only consist of letters, numbers and _. Especially there should be no space characters or German umlauts. To avoid conflicts the same rules as for object IDs apply for definitions local to a certain scenario or object.
GUIName String Name which is shown to the player in the control configuration dialog and in control tooltips. Localized strings from the corresponding string table can be used ($Name$).
GUIDesc String Informative description which is displayed to the player in the control configuration dialog. Localized strings from the corresponding string table can be used ($Desc$).
Global Boolean If true this is a global definition, i.e. not assigned to a particular player. See Global definitions.
Hold Boolean If true this command is interpreted as a held command. Such a command remembers whether the control key is pressed and generates another scripting event when it is released. See Held keys.
RepeatDelay Integer Only valid if Hold is true. If greater than 0 then this key generates additional scripting events while pressed every that many number of frames. See Key repeats.
InitialRepeatDelay Integer If specified then the delay of the first key repeat event can be changed. See Key repeats.
DefaultDisabled Boolean If true then the command is deactivated in the normal case and needs to be activated by script first. This is useful for commands that are only required in special situations. See Deactivated commands.
ExtraData C4ID Optional ID that is passed to the script function. See ExtraData.
CoordinateSpace Game, Viewport For viewport the given coordinates are relative to the players top left corner of the window. Default ist Game.
SendCursorPos Boolean If true then the GUI mouse position at the time of triggering the command will be sent as a separate CON_CursorPos command. If the mouse is not activated then the cursor position in GUI coordinates is transmitted.
Action String
Action to be executed for this command. Possible values:
Value Description
None No action.
Script Execution of the script function PlayerControl. See Script callbacks. (Default value)
ZoomIn Zoom in one unit
ZoomOut Zoom out one unit
Menu Open the player menu (asynchronous command).
MenuOK Confirmation of the selected item in the player menu (asynchronous command).
MenuCancel Close the player menu (asynchronous command).
MenuLeft / MenuUp / MenuRight / MenuDown Navigation in the player menu (asynchronous command).
ObjectMenuOK / ObjectMenuSelect / ObjectMenuOKAll Confirmation of the selected item in a menu (synchronous command).
ObjectMenuCancel Close a menu (synchronous command).
ObjectMenuLeft / ObjectMenuUp / ObjectMenuRight / ObjectMenuDown Navigation in a menu (synchronous command).

Section [ControlSets]

Definition of standard control mappings.
Any number of sections [ControlSet]
Value Data type Description
Name String Internal name for identification of otherwise equal control mappings. By using placeholders (*) keys can directly be defined in multiple mappings.
GUIName String Name for the control assignment set which is shown to the player in the control configuration dialog.
Keyboard Boolean Whether this control assignment set uses the keyboard. Default 1.
Mouse Boolean Whether this control assignment set uses the mouse. Default 1.
Gamepad Boolean Whether this control assignment set uses the gamepad. Default 0.
Any number of sections [Assignment]
Value Data type Description
Key String Specifies the key(s) of this mapping or a reference to another mapping. See Key mappings.
ComboIsSequence Boolean If true then multiple keys are taken as a sequence, i.e. they need to be pressed one after the other instead of all at the same time. See Key mappings.
Control String Command that is combined with this mapping. The name should be equivalent to the Identifier of a command defined in a [ControlDef].
GUIName String Name which is shown to the player in the control configuration dialog and in control tooltips. Localized strings from the corresponding string table can be used ($Name$). If unset, GUIName of the control def is used. If set to "None", the control is not displayed in the user customization dialog even if the control def has a name set.
GUIDesc String Informative description which is displayed to the player in the control configuration dialog. Lokalisierte Zeichenketten koennen aus dem zugehoerigen StringTable refeenziert werden ($Name$). If unset, GUIDesc of the control def is used.
GUIGroup Integer Control assignments in the same group are displayed grouped together in the control assignment dialog. The group with the lowest number is displayed at the top. Default 0.
GUIDisabled Boolean Whether this control assignment can not be changed in the control assignment dialog. Default 0.
Priority Integer Priority of the mapping. If more than once mapping is using the same keys then the key with the highest priority is executed first until a command is treated as handled.
TriggerMode Bitmask
Trigger mode of this mapping. Bitmask based on the following values:
Value Description
Default value No particular action.
Hold The key changes the state of the command linked to to be held even if the key itself is pressed only shortly. Only valid if the Hold attribute is set for the command. This state remains until a corresponding mapping with trigger mode Release is being pressed. See Held keys.
Release The key removes the held state. A key can have both Hold and Release set to toggle between the two states. See Held keys.
AlwaysUnhandled The key press is always passed to the mapping with the next lowest priority, independent of whether the previous command was executed successfully or not.
ClearRecentKeys When the assignment is triggered, all recent keys are deleted and the trigger key is not added to the recent list. This means no future key combos can be triggered with any keys including and preceding the current.
OverrideAssignments Boolean The assignment overwrites all other assignments for the same control with the same press/release trigger mode.

Script callbacks

To initialize the player control the script function InitializePlayerControl is called for each player. This call might be delayed by a few frames with respect to InitializePlayer since the initialization of the control needs to be transmitted in the network. When continuing savegames InitalizePlayerControl will be called again. The chosen control might be different from the original one. The same can happen if a player chooses to change its controls during the game.
global func InitializePlayerControl(int player, string control_name, bool has_keyboard, bool has_mouse, bool has_gamepad)
{
  // Here one has the possibility to create special control elements like a gamepad crosshair
  // or destroy it because the controls have changed from gamepad to another control
  return true;
}
most commands (except for asynchronous commands in the player menu) call a global script function:
global func PlayerControl(int player, int control, C4ID control_extra, int x, int y, int strength, bool repeated, int state)
For an explanation of the parameters see PlayerControl. Amongst others, the function receives the calling player in player as well as the command to be executed in control.
As a simple example let's assume that in the global PlayerControls.txt the following command has been defined:
[ControlDefs]
  [ControlDef]
  Identifier=Jump
  GUIName=Jump
  GUIDesc=Hoppin' around
  Repeat=5

[ControlSets]

  [ControlSet]
  Name=Keyboard1
  
    [Assignment]
    Key=W
    Control=Jump
    Priority=50
This defines a Jump key and the corresponding standard mapping on the keyboard for the first player. The following script is used to handle the control:
global func PlayerControl(int player, int control, C4ID control_extra, int x, int y, int strength, bool repeated, int state)
{
  // Which command has been issued?
  // The constant CON_Jump has been declared automatically through the definition in PlayerControls.txt
  if (control == CON_Jump && state == CONS_Down)
  {
    // pressed the jump button. The clonk selected by the player shall jump
    var player_clonk = GetCursor(player);
    if (player_clonk && player_clonk->Jump())
    {
      // The command has been processed successfully
      return true;
    }
  }
  // Unbekanntes Kommando
  return false;
}

ExtraData

Since not every object definition is able to overload the global PlayerControl function the ExtraData field can be used to distribute commands. As an example consider the following definition:
[ControlDefs]
  [ControlDef]
  Identifier=Dig
  GUIName=Dig
  GUIDesc=Going underground
  ExtraData=Shovel
Let shovel be the ID of a shovel object. In the global script there could be the following, generic handling for unknown commands, for example:
global func PlayerControl(int player, int control, C4ID control_extra, int x, int y, int strength, bool repeated, int state)
{
  // Handling of known controls
  // [...]
  // control with own handling
  if (control_extra) return control_extra->PlayerControl(player, control, x, y, strength, repeat, state);
  // unkown control
  return false;
}
And in the script of the shovel:
func PlayerControl(int player, int control, int x, int y, int strength, bool repeated, int state)
{
  // Handling of known controls
  // Control dig directly in the shovel
  if (control == CON_Dig)
  {
    // Only if a clonk is selected that can dig
    var player_clonk = GetCursor(player);
    if (player_clonk && player_clonk->HasShovel())
    {
      return player_clonk->StartDig();
    }
  }
  // Unkown control
  return false;
}

Held keys

If the Hold flag is set for a command then the engines saves the current key state for that key. These kind of keys have a few specialties:
A good example for this functionality is a directional command:
  [ControlDef]
  Identifier=Left
  GUIName=Left
  GUIDesc=Walk left
  Hold=1
In the script the direction is transferred to the Clonk:
global func PlayerControl(int player, int control, C4ID control_extra, int x, int y, int strength, bool repeated, int state)
{
  if (control == CON_Left) return UpdateControlDir(player);
  // ...
}

global func UpdateControlDir(int player)
{
  // Clonk is selected?
  var player_clonk = GetCursor(player);
  if (player_clonk)
  {
    // update control dir
    var new_comdir = COMD_Stop;
    if (GetPlayerControlState(player, CON_Left)) new_comdir = COMD_Left;
    player_clonk->SetComDir(new_comdir);
    // control handled
    return true;
  }
  // control handled
  return false;
}
To achieve the behaviour of classic controls a mapping can emulate the Hold state:
    [Assignment]
    Key=A
    Control=Left
    TriggerMode=Hold

    [Assignment]
    Key=S
    Control=Left
    TriggerMode=Release | AlwaysUnhandled

Global definitions

...

Key repeats

If a command has RepeatDelay defined then repeated commands are generated while the key is pressed. For example for a throwing command:
  [ControlDef]
  Identifier=Throw
  GUIName=Throw
  GUIDesc=Get rid of your selected inventory
  Hold=1
  RepeatDelay=5
  InitialRepeatDelay=35
In the example one could keep the key pressed after having it pressed for the first time. The Throw command then would be sent every 5 seconds automatically after an initial delay of 35 frames (about one second).
Repeats are only generated when the command also has the Hold flag set.

Deactivated commands**

...

Keyboard shortcuts

...

Priorities

...
Sven2, 2009-06