Moving controls to script...

stable-5.2
Sven Eberhardt 2009-06-09 19:29:16 -04:00
parent 22d689d560
commit f6fadb300d
7 changed files with 179 additions and 18 deletions

View File

@ -80,7 +80,7 @@
</row>
<row>
<col>Script (Standardwert)</col>
<col>Ausfuehrung des Scriptbefehls <em>PlayerControl</em> bzw. <em>PlayerControlReleased</em>. Siehe <emlink href="playercontrols.xml#Script">Script-Callbacks</emlink>.</col>
<col>Ausfuehrung des Scriptbefehls <em>PlayerControl</em> bzw. <em>PlayerControlRelease</em>. Siehe <emlink href="playercontrols.xml#Script">Script-Callbacks</emlink>.</col>
</row>
<row>
<col>Menu</col>
@ -113,7 +113,7 @@
<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></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>
@ -128,6 +128,11 @@
<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>
@ -193,8 +198,7 @@
[Assignment]
Key=W
Control=Jump
Priority=50
</code>
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)
{
@ -212,8 +216,7 @@
}
// Unbekanntes Kommando
return false;
}
</code>
}</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>
@ -232,8 +235,7 @@
if (control_extra) return control_extra->PlayerControl(player, control, x, y, strength, repeat);
// Unbekanntes Kommando
return false;
}
</code>
}</code>
<text>Und im Script der Schaufel:</text>
<code>func PlayerControl(int player, int control, int x, int y, int strength, bool repeated)
{
@ -250,15 +252,81 @@
}
// Unbekanntes Kommando
return false;
}
</code>
}</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 beim Loslassen <funclink>PlayerControlRelease</funclink>-Aufrufe 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)
{
if (control == CON_Left) return UpdateControlDir(player);
// ...
}
global func PlayerControlRelease(int player, int control, C4ID control_extra, int x, int y)
{
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>
<h id="Deactivate">Deaktivierte Kommandos</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>

View File

@ -99,6 +99,8 @@ class C4PlayerControlDefs
void CompileFunc(StdCompiler *pComp);
void MergeFrom(const C4PlayerControlDefs &Src); // copy all defs from source file; overwrite defs of same name if found
void FinalInit(); // after all defs have been loaded: register script constants
const C4PlayerControlDef *GetControlByIndex(int32_t idx) const;
int32_t GetControlIndexByIdentifier(const char *szIdentifier) const; // return CON_None for not found
int32_t GetCount() const { return Defs.size(); }
@ -167,7 +169,7 @@ class C4PlayerControlAssignment
bool IsComboMatched(const C4PlayerControlRecentKeyList &DownKeys, const C4PlayerControlRecentKeyList &RecentKeys) const; // check if combo is currently fulfilled (assuming TriggerKey is already matched)
bool operator ==(const C4PlayerControlAssignment &cmp) const; // doesn't compare resolved TriggerKey/iControl
bool operator <(const C4PlayerControlAssignment &cmp) const { return iPriority < cmp.iPriority; }
bool operator <(const C4PlayerControlAssignment &cmp) const { return iPriority > cmp.iPriority; } // assignments are processed in DESCENDING priority!
const char *GetControlName() const { return sControlName.getData(); }
int32_t GetControl() const { return iControl; }
bool IsRefsResolved() const { return fRefsResolved; }
@ -256,7 +258,7 @@ class C4PlayerControl
// async values
C4PlayerControlAssignmentSet *pControlSet; // the control set used by this player - may be NULL if the player cannot be controlled!
typedef std::list<C4CustomKey *> KeyBindingList;
typedef std::list<C4KeyBinding *> KeyBindingList;
KeyBindingList KeyBindings; // keys registered into Game.KeyboardInput
C4PlayerControlRecentKeyList RecentKeys; // keys pressed recently; for combinations
C4PlayerControlRecentKeyList DownKeys; // keys currently held down

View File

@ -150,8 +150,8 @@ void InitFunctionMap(C4AulScriptEngine *pEngine); // add functions to engine
#define PSF_OnHostilityChange "~OnHostilityChange" // int iPlr1, int iPlr2, bool fNewHostility, bool fOldHostility
#define PSF_OnTeamSwitch "~OnTeamSwitch" // int iPlr1, int idNewTeam, int idOldTeam
#define PSF_OnOwnerRemoved "~OnOwnerRemoved"
#define PSF_PlayerControl "~PlayerControl" // int iControl, C4ID idControlExtraData, int x, int y, int iStrength, bool fRepeated
#define PSF_PlayerControlRelease "~PlayerControlRelease" // int iControl, C4ID idControlExtraData, int x, int y
#define PSF_PlayerControl "PlayerControl" // int iPlr, int iControl, C4ID idControlExtraData, int x, int y, int iStrength, bool fRepeated
#define PSF_PlayerControlRelease "PlayerControlRelease" // int iPlr, int iControl, C4ID idControlExtraData, int x, int y
// Fx%s is automatically prefixed
#define PSFS_FxAdd "Add" // C4Object *pTarget, int iEffectNumber, C4String *szNewEffect, int iNewTimer, C4Value vNewEffectVar1, C4Value vNewEffectVar2, C4Value vNewEffectVar3, C4Value vNewEffectVar4

View File

@ -2273,6 +2273,9 @@ BOOL C4Game::InitGame(C4Group &hGroup, bool fLoadSection, bool fLoadSky)
{ LogFatal(LoadResStr("IDS_PRC_FAIL")); return FALSE; }
SetInitProgress(56);
// Final init for loaded player commands. Before linking scripts, so CON_* constants are registered
PlayerControlDefs.FinalInit();
// Link scripts
if (!LinkScriptEngine()) return FALSE;
SetInitProgress(57);

View File

@ -122,6 +122,20 @@ int32_t C4PlayerControlDefs::GetControlIndexByIdentifier(const char *szIdentifie
return CON_None;
}
void C4PlayerControlDefs::FinalInit()
{
// Assume all defs have been loaded
// Register scritp constants
for (DefVecImpl::const_iterator i = Defs.begin(); i != Defs.end(); ++i)
{
const char *szIdtf = (*i).GetIdentifier();
if (szIdtf && *szIdtf && !SEqual(szIdtf, "None"))
{
Game.ScriptEngine.RegisterGlobalConstant(FormatString("CON_%s", szIdtf).getData(), C4VInt(i-Defs.begin()));
}
}
}
/* C4PlayerControlAssignment */
@ -150,6 +164,7 @@ void C4PlayerControlAssignment::CompileFunc(StdCompiler *pComp)
{
if (!pComp->Name("Assignment")) { pComp->NameEnd(); pComp->excNotFound("Assignment"); }
pComp->Value(mkNamingAdapt(mkSTLContainerAdapt(KeyCombo), "Key", KeyComboVec()));
pComp->Value(mkNamingAdapt(fComboIsSequence, "ComboIsSequence", false));
pComp->Value(mkNamingAdapt(mkParAdapt(sControlName, StdCompiler::RCT_Idtf), "Control", "None"));
pComp->Value(mkNamingAdapt(iPriority, "Priority", 0));
const StdBitfieldEntry<int32_t> TriggerModeNames[] = {
@ -749,7 +764,7 @@ bool C4PlayerControl::ExecuteControlScript(int32_t iControl, C4ID idControlExtra
// control down
C4AulFunc *pFunc = Game.ScriptEngine.GetFirstFunc(PSF_PlayerControl);
if (!pFunc) return false;
C4AulParSet Pars(C4VInt(iControl), C4VID(idControlExtraData), C4VInt(rKeyExtraData.x), C4VInt(rKeyExtraData.y), C4VInt(rKeyExtraData.iStrength), C4VBool(fRepeated));
C4AulParSet Pars(C4VInt(iPlr), C4VInt(iControl), C4VID(idControlExtraData), C4VInt(rKeyExtraData.x), C4VInt(rKeyExtraData.y), C4VInt(rKeyExtraData.iStrength), C4VBool(fRepeated));
return !!pFunc->Exec(NULL, &Pars);
}
else
@ -757,7 +772,7 @@ bool C4PlayerControl::ExecuteControlScript(int32_t iControl, C4ID idControlExtra
// control up
C4AulFunc *pFunc = Game.ScriptEngine.GetFirstFunc(PSF_PlayerControlRelease);
if (!pFunc) return false;
C4AulParSet Pars(C4VInt(iControl), C4VID(idControlExtraData), C4VInt(rKeyExtraData.x), C4VInt(rKeyExtraData.y));
C4AulParSet Pars(C4VInt(iPlr), C4VInt(iControl), C4VID(idControlExtraData), C4VInt(rKeyExtraData.x), C4VInt(rKeyExtraData.y));
return !!pFunc->Exec(NULL, &Pars);
}
}
@ -835,7 +850,7 @@ void C4PlayerControl::RegisterKeyset(int32_t iPlr, C4PlayerControlAssignmentSet
void C4PlayerControl::AddKeyBinding(const C4KeyCodeEx &key, bool fHoldKey, int32_t idx)
{
KeyBindings.push_back(new C4CustomKey(
KeyBindings.push_back(new C4KeyBinding(
key, FormatString("PlrKey%02d", idx).getData(), KEYSCOPE_Control,
new C4KeyCBPassKey<C4PlayerControl>(*this, &C4PlayerControl::ProcessKeyDown, fHoldKey ? &C4PlayerControl::ProcessKeyUp : NULL),
C4CustomKey::PRIO_PlrControl));

View File

@ -0,0 +1,13 @@
#strict 2
global func PlayerControl(int plr, int ctrl, id spec_id, int x, int y, int strength, bool repeat)
{
Log("%d, %d, %i, %d, %d, %d, %v", plr, ctrl, spec_id, x,y,strength, repeat);
return true;
}
global func PlayerControlRelease(int plr, int ctrl, id spec_id, int x, int y)
{
Log("re %d, %d, %i, %d, %d", plr, ctrl, spec_id, x,y);
return true;
}

View File

@ -0,0 +1,60 @@
[ControlDefs]
[ControlDef]
Identifier=Left
GUIName=Left
GUIDesc=Walk left
Hold=1
RepeatDelay=5
InitialRepeatDelay=35
[ControlDef]
Identifier=Throw
GUIName=Throw
GUIDesc=Get rid of your selected inventory
Hold=1
RepeatDelay=5
InitialRepeatDelay=35
[ControlDef]
Identifier=Dig
GUIName=Dig
GUIDesc=Delve through the earth
[ControlDef]
Identifier=Test
GUIName=Test
GUIDesc=Test key
[ControlSets]
[ControlSet]
Name=Keyboard2Classic
[Assignment]
Key=Q
Control=Throw
Priority=50
[Assignment]
Key=E
Control=Dig
Priority=50
[Assignment]
Key=A
Control=Left
TriggerMode=Hold
[Assignment]
Key=S
Control=Left
TriggerMode=Release | AlwaysUnhandled
[Assignment]
Key=Throw,Throw,Dig
ComboIsSequence=1
Control=Test
Priority=60