Custom commands and bindings

From Serious Sam Wiki
< Lua
Jump to: navigation, search


Overview

On the low level, SeriousEngine understands input from many different user input devices, such as keyboards, mice, or gamepads. However, on the high level, input from all of these devices is translated into player commands, according to defined key bindings. A player command is an event describing a player's action, and each has a unique descriptive name. For example, "plcmdFire" is the command which initiates firing from player's current weapon. Each command can have one or more key bindings which trigger it, and these bindings can be customized by the player as they like, through the in-game menu interface.

While a number of standard, basic player commands is predefined in native game code, it is possible to add as many new player commands as needed through scripts. To do this, a new script must be placed in project's content directory under "Scripts/CommandTable/", e.g.: "Content/SeriousSam3/Scripts/CommandTable/". This script should call the global function AddPlayerCommand() for each of the desired new commands.

Add a new command to player command table.
  • idCommand name of the command
  • strCommandDescription human-readable description of the command
void AddPlayerCommand(IDENT idCommand, CString strCommandDescription);

A newly created player command isn't particularly useful without at least one default key binding. To create a default key binding for a player command, there is a global function AddDefaultBinding(). This function should be called from a script placed in project's content directory under "Scripts/DefaultBindings/", e.g. "Content/SeriousSam3/Scripts/DefaultBindings/".

Add new default player command binding.
  • iVersion version of the binding (can be used to override code-defined default bindings by setting a higher version)
  • strDevice device for which the binding is created (one of: "Keyboard+Mouse", "GamepadX")
  • strControl device controls which are being mapped to the command
  • idCommand name of the command
void AddDefaultBinding(INDEX iVersion, CString strDevice, CString strControl, IDENT idCommand);

Important: these two global functions should only be called from special scripts placed in their respective directories, as described above. While it may be possible to call them from elsewhere, i.e. Editor's console, or world scripts, this is strongly discouraged.

Polling commands

All player commands can be polled from scripts using a set of three functions defined on the CPlayerPuppet class:

Get current command value.
  • idCommand name of the command
  • return fraction of current frame time during which command was pressed (0 to 1)
FLOAT GetCommandValue(IDENT idCommand);
Check if a command was pressed between two last polls.
  • idCommand name of the command
  • return true if pressed, false otherwise
BOOL IsCommandPressed(IDENT idCommand);
Check if a command was released between two last polls.
  • idCommand name of the command
  • return true if released, false otherwise
BOOL IsCommandReleased(IDENT idCommand);

Example

Imagine we're making a mod that adds a magic bubble ability to the player. If active, the magic bubble absorbs all damage and makes the player invulnerable. We'd like to be able to activate this ability by pressing the "G" key on the keyboard, and deactivate it by pressing "G" again.

We'll start by creating a new player command and its default key binding, using two special scripts placed in appropriate directories.

Command table script ("Content/SeriousSam3/Scripts/CommandTable/MyShieldMod.lua"):

AddPlayerCommand("plcmdShield", "Shield")

Key binding script ("Content/SeriousSam3/Scripts/DefaultBindings/MyShieldMod.lua"):

AddDefaultBinding(1, "Keyboard+Mouse", "G", "plcmdShield")

Now, we can create a custom world script which will be started on every world.

Custom world script ("Content/SeriousSam3/Scripts/CustomWorldScripts/MyShieldMod.lua"):

RunHandled(
  WaitForever,
  
  OnEvery(Event(worldInfo.PlayerBorn)),
  function(eePlayerBorn)
    -- player : CPlayerPuppetEntity
    local player = eePlayerBorn:GetBornPlayer()
    player:EnableReceiveDamageScriptEvent(true)
    local shieldActive = false
    
    RunHandled(
      function()
        Wait(Event(player.EntityDeleted))
      end,
      
      OnEvery(CustomEvent("OnStep")),
      -- eeOnStep : COnStepScriptEvent
      function(eeOnStep)
        if player:IsCommandPressed("plcmdShield") then
          shieldActive = not shieldActive
          if shieldActive then 
            print("shield on") 
          else 
            print("shield off") 
          end
        end
      end,       

      OnEvery(Event(player.ReceiveDamage)),
      -- eeDmg : CReceiveDamageScriptEvent
      function(eeDmg)
        local dmgAmount = eeDmg:GetDamageAmount()
        if shieldActive then
          dmgAmount = 0
        end
        eeDmg:SetDamageAmount(dmgAmount)
        eeDmg:HandleDamage()
      end
    )
    
  end
)
Personal tools