in pretty much every thread that has anything to do with input i always mention the ability to add commands to list of available commands in the control options screen so that they can be bound to input devices. i bring it up a lot, but ive never really given it its own thread. so here it is. most game engines have a system for mapping input devices to specific commands (referenced by name string or index) so that mods that add functions can make those functions bindable in whatever control options interface the engine has. and the ability of the engine to let modders implement new commands is a real possibility thanks to lua and a greatly improved events system. but we need to expand the control options to make available custom commands in a manor familiar to the player, making the engine both more versatile and more user friendly.
also some mods do not make use of the whole set of commands the game has to offer, mods without shields may want to remove the shield binds from the list so as not to confuse the player. it is now very easy for modders to add new functions to the game and we need a way to use those functions without resorting to hard coded commands.
thats where input.tbl comes into play. it would allow the user to add, remove, or modify available controls to the lists of bindable commands in the control options, as well as to set mod default bindings. probably start an entry in the input table with something like this:
$command name: somename ;name of command
$set: ship ;which subset the command appears on (such as ship, weapon, targeting, misc, and maybe even the ability to define new lists provided the interface modifications + art is available)
if the command name already exists as a hard coded fsopen command (or a command defined in an alternate input.tbl, in case modular versions exist), then anything after command name would change the behavior of the command. for hardcoded commands, the available options would be less, for example theres no reason to change the command type, it would be bad to change a command like forward thrust to a toggle, or use an axis to control what would otherwise be a boolean command. for the default command set there would only be few reasons to even list them in the table. to remove them from the command list move them to another list, or to rename them. to move them to another list you would just change $set:, removing them may involve setting $set: to "none", or perhaps have a +remove: flag , to rename them would use another table option:
+rename: newnameofcommand ;name command will be changed too
perhaps you might want to make remove have its own flag:
+remove:
those cover what you may want to do with an existing command, but what if the command you want to add is not in the list, well then just add a new one:
$command name: lower landing gear
$set: ship
this would add a new command called "lower landing gear" to the list of ship controls. but before we can bind this to anything we need to decide what kind of command it is. most commands are boolean, some commands operate as toggles (key must be pressed and released to become true, and is set back to false when its handled), others are activated when the key/button is held down (true when down, false when not), some are mouse or joystick axes. and some axes may want to map the control to a specific range. for this we need a type. since landing gear would be a toggle we would do something like:
$type: toggle
this means that the key must be pressed and released to change the state. and that state may be read and the value reset in script or perhaps as a sexp. this is more of a shortcut for mod simplicity, where we dont want to deal with the hassle of latching a straight boolean so it can only be used till it goes back to false, for an event system implementation of the function this is very useful since you dont have the full functionality of scripting. but what if we need a command that only cares if the button is down:
$command: fire turret
$set: weapon
$type: pressed
button down, state = true, button up state = false and no reason to clear it. now it might be better to only include this type for boolean commands, and then have key pressed, key released, key down events associated with it. on the mod side having two types of booleans kinda makes things simpler, especially if youre not implementing the command through lua. this however is open to debate.
so we have covered boolean commands but what about axes. we actually have 2 kinds of axes, mouse and joystick. joystick values are usually represented internally as a 16 bit signed integer, but in most cases like for a bank axis it is mapped to a float into a range of -1 to 1. other axes, like the throttle are mapped to range of 0 to 1. mouse axes on the other hand are represented by an unsigned (16 bit?) integer, and is in the format of screen coordinates. the range of the mouse is usually handled by how far the mouse moves within a period of time, such as one frame. this value is normalized to one second and uses some sensitivity and curve calculation to map it to a range (-1 to 1 for steering the ship). thers another way to handle the mouse, distance from center. center screen position is subtracted from the pointers actual location. if your screen width is 1024 then youre mouse range is about -512 to 512, which after deadzone and sensitivity calculation can vary, but its probably best to normalize it somehow to -1 to 1. this kind of mouse usage would better be implemented at engine level. but for mice we will assume the value returned for it is mapped out to a min and max range, and this range can be remapped by the user. ideally the engine would handle all the sensitivity tweaks and abstract it to a specific range so even if the axis is a mouse axis, it can be handled in exactly the same way:
$command: absolute turret pitch ;think mechwarrior 2
$set: weapon
$type: axis
$min value: 0 ;the minimum
$max value: 1 ;and maximum range that the internal axis is mapped to
now of course if a command is new, or even if its pre-existing (conversions of other games, like tachyon for example, may want default input mappings that are similar to tachyon ), then you might want a default binding, which is either a key, joystick button, mouse axis, whatever. when a new pilot for a set mod is created then these defaults may be used in place of the standard ones. if input.tbl is unavailable then the hardcoded set are used. keys may be represented with:
$command: toggle s-foils
$set: weapon
$type: toggle
$defeat:
+device: keyboard ;interface type
+instance: 1 ;interface instance (in case more that one exist)
+key: s ;key value for string type command
;may also be numeric index for international keyboard compatibility
+control index: 83 ;do keyboards use ascii codes?
or if its a button
$default:
+device: mousebutton
+instance: 1
+control index: 1 ;button number, for integer type commands
or a joystick button
$default:
+device: joystick
+instance: 2 ;command on second joystick
+control index: 13 ;13th button
or for an axis
$default:
+device: joystick
+instance: 1
+control index: 2 (second axis)
note that on most of those with +control index:, context is important. if the default is for an axis type command then its the axis index, for boolean type commands its a button index. the reason a +button: or +axis: tag isnt used is to avoid modder confusion. keyboards would be the only exception where modders might not know (or be able to look up) the numeric code for a particular key. may also want to add modifiers:
+alt: y/n
+shift: y/n
+invert: y/n
i think this pretty much covers the structure of the input.tbl. commands that are modified get modified and commands that are created get created, and all the changes are visible from the control options screen, where they can be bound to an axis or button. might pay to do a basic implementation first to allow modification or removal of existing commands, and the setting of new mod specific defaults then expand it to a system for adding new commands. once the capability of new commands is added then a lua interface could be created. ba.Commands['command name'] would provide a list of states (or perhaps a command object which has get state member functions) for each command, maybe a get-command-state sexp could be added as well. would make a great addition to the engine.