openclonk/docs/sdk/playercontrols.xml

328 lines
14 KiB
XML

<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
<!DOCTYPE doc SYSTEM "../clonk.dtd">
<?xml-stylesheet type="text/xsl" href="../clonk.xsl"?>
<doc>
<title>Spielersteuerung</title>
<h id="Controls">Spielersteuerung</h>
<part>
<text>Ab OC erlaubt die Engine, Steuerungskommandos fuer Spieler komplett frei zu definieren. Eigene Tastaturkommandos koennen hinzugefuegt oder veraendert werden. Alle unterstuetzten Eingabegeraete wie Maus, Tastatur und Gamepads koennen frei belegt werden und Kommandos koennen aus beliebigen Tastenkombinationen oder Sequenzen bestehen.</text>
<h id="ControlFiles">PlayerControls.txt</h>
<text>Alle Steuerungsbefehle, die ein Spieler an das Spiel geben kann, werden in der Datei PlayerControls.txt definiert. Die Standardtasten sowie deren Standardbelegung fuer verschiedene Eingabegeraete befinden sich in der globalen Definitionsdatei in der System.c4g. Objektdefinitionen und Szenarien koennen weitere Tasten in ihrer lokalen System.c4g hinzufuegen oder die Parameter vorhandener Steuerkommandos ueberladen**.</text>
<text>Zusaetzliche Dateien PlayerControls.txt koennen in Sprachpaketen abgelegt werden, um die Standardbelegungen der Tasten bei verschiedenen, geladenen Sprachen an die Tastaturen des jeweiligen Landes anzupassen**.</text>
<part>
<h id="ControlDefs">Sektion [ControlDefs]</h>
<text>Definition der moeglichen Spielerkommandos. Nicht gueltig in Sprachpaketen. Dieser Sektion untergeordnet:
<text><table>
<caption id="ControlDef">Beliebig viele Sektionen [ControlDef]</caption>
<rowh>
<col>Wert</col>
<col>Datentyp</col>
<col>Beschreibung</col>
</rowh>
<row>
<col>Identifier</col>
<col>Zeichenfolge (Max. 96 Zeichen)</col>
<col>Intern benutzter Name zur Identifikation des Kommandos. Das Kommando wird unter diesem Namen in Standardbelegungen referenziert und im Script als CON_Name-Konstante vordefiniert. Der Name sollte folglich im Script gueltig sein, d.h. nur aus Buchstaben, Zahlen sowie _ bestehen. Insbesondere sollten keine Leerzeichen oder deutsche Umlaute verwendet werden. Zur Vermeidung von Konflikten gelten in szenarienlokalen sowie Objektpaketlokalen Definitionen dieselben Benennungsregeln wie zur Vergabe von Objekt-IDs.</col>
</row>
<row>
<col>GUIName</col>
<col>Zeichenfolge</col>
<col>Name, der dem Spieler im Steuerungskonfigurationsdialog sowie in den Steuerungstooltips angezeigt wird. Lokalisierte Zeichenketten koennen aus dem zugehoerigen StringTable refeenziert werden ($Name$).</col>
</row>
<row>
<col>GUIDesc</col>
<col>Zeichenfolge</col>
<col>Erlaeuternde Beschreibung, die dem Spieler im Steuerungskonfigurationsdialog angezeigt wird. Lokalisierte Zeichenketten koennen aus dem zugehoerigen StringTable refeenziert werden ($Name$).</col>
</row>
<row>
<col>Global</col>
<col>Boolean</col>
<col>Wenn wahr, ist dies eine globale, d.h. keinem Spieler zugeordnete Definition. Siehe <emlink href="playercontrols.xml#Globals">Globale Definitionen</emlink>.</col>
</row>
<row>
<col>Hold</col>
<col>Boolean</col>
<col>Wenn wahr, wird das Kommando als ein gehaltenes Kommando interpretiert. Ein solches Kommando speichert, ob die Steuerungstaste gedrueckt ist und generiert beim Loslassen ein zusaetzliches Scriptereignis. Siehe <emlink href="playercontrols.xml#Hold">Gehaltene Tasten</emlink>.</col>
</row>
<row>
<col>RepeatDelay</col>
<col>Integer</col>
<col>Nur gueltig wenn <em>Hold</em> wahr. Wenn groesser 0, generiert die Taste im gehaltenen Zustand im angegebenen Abstand (in Frames) weitere Scriptereignisse. Siehe <emlink href="playercontrols.xml#Repeat">Tastenwiederholungen</emlink>.</col>
</row>
<row>
<col>InitialRepeatDelay</col>
<col>Integer</col>
<col>Wenn angegeben, kann die Wartezeit fuer das erste Tastenwiederholungsereignis geaendert werden. Siehe <emlink href="playercontrols.xml#Repeat">Tastenwiederholungen</emlink>.</col>
</row>
<row>
<col>DefaultDisabled</col>
<col>Boolean</col>
<col>Wenn wahr, ist das Kommando im Normalfall deaktiviert und muss erst per Script aktiviert werden. Nuetzlich fuer Kommandos, die nur in sehr speziellen Situationen benoetigt werden. Siehe <emlink href="playercontrols.xml#Deactivate">Deaktivierte Kommandos</emlink>.</col>
</row>
<row>
<col>ExtraData</col>
<col>C4ID</col>
<col>Optionale ID, die an die Scriptfunktion uebergeben wird. Siehe <emlink href="playercontrols.xml#ExtraData">ExtraData</emlink>.</col>
</row>
<row>
<col>Action</col>
<col>Zeichenfolge</col>
<col>Auszufuehrende Aktion bei diesem Kommando. Moegliche Werte:
<text><table>
<rowh>
<col>Wert</col>
<col>Beschreibung</col>
</rowh>
<row>
<col>None</col>
<col>Keine Aktion.</col>
</row>
<row>
<col>Script (Standardwert)</col>
<col>Ausfuehrung des Scriptbefehls <em>PlayerControl</em>. Siehe <emlink href="playercontrols.xml#Script">Script-Callbacks</emlink>.</col>
</row>
<row>
<col>Menu</col>
<col>Oeffnen des Spielermenues (asynchrones Kommando).</col>
</row>
<row>
<col>MenuOK</col>
<col>Bestaetigen des ausgewaehlten Elementes im Spielermenue (asynchrones Kommando).</col>
</row>
<row>
<col>MenuCancel</col>
<col>Schliessen des Spielermenues (asynchrones Kommando).</col>
</row>
<row>
<col>MenuLeft / MenuUp / MenuRight / MenuDown</col>
<col>Navigation im Spielermenu (asynchrones Kommando).</col>
</row></table></text>
</col>
</row></table></text></text>
<h id="ControlSets">Sektion [ControlSets]</h>
<text>Definition von Standard-Steuerungsbelegungen.
<text><table>
<caption id="ControlSet">Beliebig viele Sektionen [ControlSet]</caption>
<rowh>
<col>Wert</col>
<col>Datentyp</col>
<col>Beschreibung</col>
</rowh>
<row>
<col>Name</col>
<col>Zeichenfolge</col>
<col>Interner Name zur Identifikation gleicher Steuerungsbelegungen. Die Namen der Standardbelegungen sind <em>Keyboard1</em>, <em>Keyboard1Classic</em>, <em>Keyboard2</em>, <em>Keyboard2Classic</em>, <em>Gamepad</em>. Ueber Platzhalter (*) koennen Tasten direkt in mehreren Belegungen definiert werden**.</col>
</row></table>
<text><table>
<caption id="ControlSet">Beliebig viele Sektionen [Assignment]</caption>
<rowh>
<col>Wert</col>
<col>Datentyp</col>
<col>Beschreibung</col>
</rowh>
<row>
<col>Key</col>
<col>Zeichenfolge</col>
<col>Taste(n) dieser Belegung oder Referenz auf eine andere Belegung. Siehe <emlink href="playercontrols.xml#Keys">Tastenbelegungen</emlink>.</col>
</row>
<row>
<col>ComboIsSequence</col>
<col>Boolean</col>
<col>Wenn wahr, werden mehrfache Tasten als Sequenz interpretiert. Das heisst, sie muessen nacheinander statt gleichzeitig gedrueckt werden. Siehe <emlink href="playercontrols.xml#Keys">Tastenbelegungen</emlink>.</col>
</row>
<row>
<col>Control</col>
<col>Zeichenfolge</col>
<col>Kommando, das mit dieser Belegung verknuepft wird. Der Name sollte dem <em>Identifier</em> eines in einer <emlink href="playercontrols.xml#ControlDef">[ControlDef]</emlink> definierten Kommandos entsprechen.</col>
</row>
<row>
<col>Priority</col>
<col>Integer</col>
<col>Prioritaet der Belegung. Nutzen mehrere Belegungen die gleichen Tasten, so wird zunaechst die Taste mit der hoeheren Prioritaet ausgefuehrt, bis ein Kommando als behandelt gilt.</col>
</row>
<row>
<col>TriggerMode</col>
<col>Bitmaske</col>
<col>Ausloesmodus dieser Belegung. Bitmaske aus folgenden Werten:
<text><table>
<rowh>
<col>Wert</col>
<col>Beschreibung</col>
</rowh>
<row>
<col>Default (Standardwert)</col>
<col>Keine besondere Aktion.</col>
</row>
<row>
<col>Hold</col>
<col>Die Taste versetzt das verlinkte Kommando in den gedrueckten Zustand, selbst wenn die Taste selbst nur angeschlagen wird. Nur gueltig, wenn das Kommando das <em>Hold</em>-Attribut gesetzt hat. Dieser Zustand bleibt erhalten, bis eine entsprechende Belegung mit Ausloesemodus <em>Release</em> gedrueckt wird. Siehe <emlink href="playercontrols.xml#Hold">Gehaltene Tasten</emlink>.</col>
</row>
<row>
<col>Release</col>
<col>Die Taste entfernt den gedrueckten Zustand. Eine Taste kann auch sowohl Hold als auch Release setzen, um zwischen den Zustaenden hin und her zu schalten. Siehe <emlink href="playercontrols.xml#Hold">Gehaltene Tasten</emlink>.</col>
</row>
<row>
<col>AlwaysUnhandled</col>
<col>Der Tastendruck wird immer an die Belegung mit der naechstniedrigen Prioritaet weitergereicht, unabhaengig davon, ob das vorherige Kommando erfolgreich ausgefuehrt wurde.</col>
</row>
<row>
<col>ToggleUnhandled</col>
<col>Der Tastendruck wird genau dann an die Belegung mit der naechstniedrigen Prioritaet weitergereicht, wenn das vorherige Kommando erfolgreich ausgefuehrt wurde. Hiermit lassen sich Makros definieren. **</col>
</row></table></text>
</col>
</row></table></text>
</text></text>
</part>
<h id="Script">Script-Callbacks</h>
<text>Die meisten Kommandos (abgesehen von asyrnchronen Kommandos im Spielermenue), rufen eine globale Scriptfunktion auf:</text>
<code>global func PlayerControl(int player, int control, C4ID control_extra, int x, int y, int strength, bool repeated, bool release)</code>
<text>Fuer eine Erlaeuterung der Parameter siehe <funclink>PlayerControl</funclink>. Die Funktion erhaelt unter anderem den aufrufenden Spieler in iPlr, sowie das ausgefuehrte Kommando in iControl.</text>
<text>Fuer ein einfaches Beispiel sei in der globalen <em>PlayerControls.txt</em> folgendes Kommando definiert:</text>
<code>[ControlDefs]
[ControlDef]
Identifier=Jump
GUIName=Jump
GUIDesc=Hoppin' around
Repeat=5
[ControlSets]
[ControlSet]
Name=Keyboard1
[Assignment]
Key=W
Control=Jump
Priority=50</code>
<text>Dies definiert eine Sprungtaste und die zugehoerige Standardbelegung auf der Tastatur fuer den ersten Spieler. Dazu folgendes Script zur Behandlung:</text>
<code>global func PlayerControl(int player, int control, C4ID control_extra, int x, int y, int strength, bool repeated, bool release)
{
// Welches Kommando wurde ausgeloest?
// Die Konstante CON_Jump wurde automatisch durch die Definition in PlayerControls.txt angelegt
if (control == CON_Jump &amp;&amp; !release)
{
// Sprungtaste gedrueckt. Der vom Spieler ausgewaehlte Clonk soll springen
var player_clonk = GetCursor(player);
if (player_clonk &amp;&amp; player_clonk->Jump())
{
// Das Kommando wurde erfolgreich abgearbeitet
return true;
}
}
// Unbekanntes Kommando
return false;
}</code>
<h id="ExtraData">ExtraData</h>
<text>Da nicht jede Objektdefinition die globale PlayerControl-Funktion ueberladen kann, gibt es das ExtraData-Feld zum Verteilen von Kommandos. Zum Beispiel fuer folgende Definition:</text>
<code>[ControlDefs]
[ControlDef]
Identifier=Dig
GUIName=Dig
GUIDesc=Going underground
ExtraData=SHVL</code>
<text>Dabei sei SHVL die ID eines Schaufelobjektes. Im globalen Script kann zum Beispiel folgende, allgemeine Behandlung fuer unbekannte Kommandos stehen:</text>
<code>global func PlayerControl(int player, int control, C4ID control_extra, int x, int y, int strength, bool repeated, bool release)
{
// Behandlung bekannter Befehle
// [...]
// Befehl mit eigener Behandlung
if (control_extra) return control_extra->PlayerControl(player, control, x, y, strength, repeat, release);
// Unbekanntes Kommando
return false;
}</code>
<text>Und im Script der Schaufel:</text>
<code>func PlayerControl(int player, int control, int x, int y, int strength, bool repeated, bool release)
{
// Behandlung bekannter Befehle
// Grabkommando direkt an die Schaufel
if (control == CON_Dig)
{
// Nur, wenn ein Clonk ausgewaehlt ist, der graben kann
var player_clonk = GetCursor(player);
if (player_clonk &amp;&amp; player_clonk->HasShovel())
{
return player_clonk->StartDig();
}
}
// Unbekanntes Kommando
return false;
}</code>
<h id="Hold">Gehaltene Tasten</h>
<text>Wird fuer ein Kommando das <em>Hold</em>-Flag gesetzt, so speichert die Engine den gegenwaertigen Tastenzustand fuer diese Taste. Solche Tasten haben einige Besonderheiten:</text>
<text><ul>
<li>Sie generieren auch beim Loslassen <funclink>PlayerControl</funclink>-Aufrufe mit gesetztem <em>Release</em>-Flag im Script.</li>
<li>Belegungen koennen mit den <em>Hold</em>/<em>Release</em>-Flags dauerhafte Tastendruecke emulieren.</li>
<li><emlink href="playercontrols.xml#Repeat">Tastenwiederholungen</emlink> werden erzeugt.</li>
<li>Der Haltezustand der Taste kann mit <funclink>GetPlayerControlState</funclink> im Script abgefragt werden.</li>
</ul></text>
<text>Bestes Beispiel hierfuer ist ein Richtungskommando:</text>
<code> [ControlDef]
Identifier=Left
GUIName=Left
GUIDesc=Walk left
Hold=1</code>
<text>Im Script wird die Richtung dann auf den Clonk uebertragen:</text>
<code>global func PlayerControl(int player, int control, C4ID control_extra, int x, int y, int strength, bool repeated, bool release)
{
if (control == CON_Left) return UpdateControlDir(player);
// ...
}
global func UpdateControlDir(int player)
{
// Clonk ausgewaehlt?
var player_clonk = GetCursor(player);
if (player_clonk)
{
// Clonkrichtung aktualisieren
var new_comdir = COMD_Stop;
if (GetPlayerControlState(player, CON_Left)) new_comdir = COMD_Left;
player_clonk->SetComDir(new_comdir);
// Kommando behandelt
return true;
}
// Kommando behandelt
return false;
}</code>
<text>Um klassisches Steuerungsverhalten zu erreichen, kann eine Tastenbelegung den <em>Hold</em>-Zustand emulieren:</text>
<code> [Assignment]
Key=A
Control=Left
TriggerMode=Hold
[Assignment]
Key=S
Control=Left
TriggerMode=Release | AlwaysUnhandled</code>
<h id="Globals">Globale Definitionen</h>
<text>...</text>
<h id="Repeat">Tastenwiederholungen</h>
<text>Hat ein Kommando ein <em>RepeatDelay</em> definiert, so werden wiederholte Kommandos beim Halten der Taste erzeugt. Zum Beispiel fuer ein Wurkommando:</text>
<code> [ControlDef]
Identifier=Throw
GUIName=Throw
GUIDesc=Get rid of your selected inventory
Hold=1
RepeatDelay=5
InitialRepeatDelay=35</code>
<text>Im Beispiel koennte man die Wurftaste nach einmal Druecken auch halten. Das Wurfkommando wuerde dann nach 35 Frames (ca. eine Sekunde) halten alle 5 Frames automatisch wiederholt.</text>
<text>Wiederholungen werden nur erzeugt, wenn das Kommando ebenfalls das <em>Hold</em>-Flag gesetzt hat.</text>
<h id="Deactivate">Deaktivierte Kommandos**</h>
<text>...</text>
<h id="Keys">Tastenbelegungen</h>
<text>...</text>
<h id="Priority">Prioritaeten</h>
<text>...</text>
</part>
<text><em>** - noch nicht implementiert</em></text>
<author>Sven2</author><date>Juni 2009</date>
</doc>