From f6fadb300db00e4e47ee3c6cc83f664142d78b55 Mon Sep 17 00:00:00 2001 From: Sven Eberhardt Date: Tue, 9 Jun 2009 19:29:16 -0400 Subject: [PATCH] Moving controls to script... --- docs/sdk/playercontrols.xml | 90 ++++++++++++++++++++++++---- engine/inc/C4PlayerControl.h | 6 +- engine/inc/C4Script.h | 4 +- engine/src/C4Game.cpp | 3 + engine/src/C4PlayerControl.cpp | 21 ++++++- planet/System.c4g/PlayerControl.c | 13 ++++ planet/System.c4g/PlayerControls.txt | 60 +++++++++++++++++++ 7 files changed, 179 insertions(+), 18 deletions(-) create mode 100644 planet/System.c4g/PlayerControl.c create mode 100644 planet/System.c4g/PlayerControls.txt diff --git a/docs/sdk/playercontrols.xml b/docs/sdk/playercontrols.xml index 6ffdd37f9..58b06fa1a 100644 --- a/docs/sdk/playercontrols.xml +++ b/docs/sdk/playercontrols.xml @@ -80,7 +80,7 @@ Script (Standardwert) - Ausfuehrung des Scriptbefehls PlayerControl bzw. PlayerControlReleased. Siehe Script-Callbacks. + Ausfuehrung des Scriptbefehls PlayerControl bzw. PlayerControlRelease. Siehe Script-Callbacks. Menu @@ -113,7 +113,7 @@ Name Zeichenfolge - Interner Name zur Identifikation gleicher Steuerungsbelegungen. Die Namen der Standardbelegungen sind Keyboard1, Keyboard1Classic, Keyboard2, Keyboard2Classic, Gamepad + Interner Name zur Identifikation gleicher Steuerungsbelegungen. Die Namen der Standardbelegungen sind Keyboard1, Keyboard1Classic, Keyboard2, Keyboard2Classic, Gamepad. Ueber Platzhalter (*) koennen Tasten direkt in mehreren Belegungen definiert werden**. @@ -128,6 +128,11 @@ ZeichenfolgeTaste(n) dieser Belegung oder Referenz auf eine andere Belegung. Siehe Tastenbelegungen. + + ComboIsSequence + Boolean + Wenn wahr, werden mehrfache Tasten als Sequenz interpretiert. Das heisst, sie muessen nacheinander statt gleichzeitig gedrueckt werden. Siehe Tastenbelegungen. + ControlZeichenfolge @@ -193,8 +198,7 @@ [Assignment] Key=W Control=Jump - Priority=50 - + Priority=50Dies definiert eine Sprungtaste und die zugehoerige Standardbelegung auf der Tastatur fuer den ersten Spieler. Dazu folgendes Script zur Behandlung: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; -} - +}ExtraDataDa nicht jede Objektdefinition die globale PlayerControl-Funktion ueberladen kann, gibt es das ExtraData-Feld zum Verteilen von Kommandos. Zum Beispiel fuer folgende Definition: @@ -232,8 +235,7 @@ if (control_extra) return control_extra->PlayerControl(player, control, x, y, strength, repeat); // Unbekanntes Kommando return false; -} - +}Und im Script der Schaufel:func PlayerControl(int player, int control, int x, int y, int strength, bool repeated) { @@ -250,15 +252,81 @@ } // Unbekanntes Kommando return false; -} - +}Gehaltene Tasten +Wird fuer ein Kommando das Hold-Flag gesetzt, so speichert die Engine den gegenwaertigen Tastenzustand fuer diese Taste. Solche Tasten haben einige Besonderheiten: +
    +
  • Sie generieren beim Loslassen PlayerControlRelease-Aufrufe im Script.
  • +
  • Belegungen koennen mit den Hold/Release-Flags dauerhafte Tastendruecke emulieren.
  • +
  • Tastenwiederholungen werden erzeugt.
  • +
  • Der Haltezustand der Taste kann mit GetPlayerControlState im Script abgefragt werden.
  • +
+Bestes Beispiel hierfuer ist ein Richtungskommando: + [ControlDef] + Identifier=Left + GUIName=Left + GUIDesc=Walk left + Hold=1 +Im Script wird die Richtung dann auf den Clonk uebertragen: +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; +} +Um klassisches Steuerungsverhalten zu erreichen, kann eine Tastenbelegung den Hold-Zustand emulieren: + [Assignment] + Key=A + Control=Left + TriggerMode=Hold + + [Assignment] + Key=S + Control=Left + TriggerMode=Release | AlwaysUnhandled + Globale Definitionen +...Tastenwiederholungen -Deaktivierte Kommandos +Hat ein Kommando ein RepeatDelay definiert, so werden wiederholte Kommandos beim Halten der Taste erzeugt. Zum Beispiel fuer ein Wurkommando: + [ControlDef] + Identifier=Throw + GUIName=Throw + GUIDesc=Get rid of your selected inventory + Hold=1 + RepeatDelay=5 + InitialRepeatDelay=35 +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. +Wiederholungen werden nur erzeugt, wenn das Kommando ebenfalls das Hold-Flag gesetzt hat. +Deaktivierte Kommandos** +...Tastenbelegungen +...Prioritaeten +...** - noch nicht implementiertSven2Juni 2009 diff --git a/engine/inc/C4PlayerControl.h b/engine/inc/C4PlayerControl.h index be7e712f0..7daf70cb0 100644 --- a/engine/inc/C4PlayerControl.h +++ b/engine/inc/C4PlayerControl.h @@ -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 KeyBindingList; + typedef std::list KeyBindingList; KeyBindingList KeyBindings; // keys registered into Game.KeyboardInput C4PlayerControlRecentKeyList RecentKeys; // keys pressed recently; for combinations C4PlayerControlRecentKeyList DownKeys; // keys currently held down diff --git a/engine/inc/C4Script.h b/engine/inc/C4Script.h index 74f11ba27..17127f7b5 100644 --- a/engine/inc/C4Script.h +++ b/engine/inc/C4Script.h @@ -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 diff --git a/engine/src/C4Game.cpp b/engine/src/C4Game.cpp index 663866b73..931097406 100644 --- a/engine/src/C4Game.cpp +++ b/engine/src/C4Game.cpp @@ -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); diff --git a/engine/src/C4PlayerControl.cpp b/engine/src/C4PlayerControl.cpp index f2eeae6a1..d6b2aa3ec 100644 --- a/engine/src/C4PlayerControl.cpp +++ b/engine/src/C4PlayerControl.cpp @@ -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 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(*this, &C4PlayerControl::ProcessKeyDown, fHoldKey ? &C4PlayerControl::ProcessKeyUp : NULL), C4CustomKey::PRIO_PlrControl)); diff --git a/planet/System.c4g/PlayerControl.c b/planet/System.c4g/PlayerControl.c new file mode 100644 index 000000000..083124dce --- /dev/null +++ b/planet/System.c4g/PlayerControl.c @@ -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; +} \ No newline at end of file diff --git a/planet/System.c4g/PlayerControls.txt b/planet/System.c4g/PlayerControls.txt new file mode 100644 index 000000000..583b29156 --- /dev/null +++ b/planet/System.c4g/PlayerControls.txt @@ -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