Moving controls to script...

stable-5.2
Sven Eberhardt 2009-05-26 02:10:38 -04:00
parent ff15ca7441
commit ce6d73b92a
13 changed files with 755 additions and 127 deletions

View File

@ -118,6 +118,7 @@
#define C4CFN_Teams "Teams.txt"
#define C4CFN_Parameters "Parameters.txt"
#define C4CFN_RoundResults "RoundResults.txt"
#define C4CFN_PlayerControls "PlayerControls.txt"
#define C4CFN_MapFolderData "FolderMap.txt"
#define C4CFN_MapFolderBG "FolderMap"

View File

@ -173,6 +173,37 @@ public:
DECLARE_C4CONTROL_VIRTUALS
};
class C4ControlPlayerControl2 : public C4ControlPacket // sync
{
public:
C4ControlPlayerControl2() : iPlr(-1), fRelease(false) {}
C4ControlPlayerControl2(int32_t iPlr, bool fRelease, const C4KeyEventData &rExtraData)
: iPlr(iPlr), fRelease(fRelease), ExtraData(rExtraData) { }
struct ControlItem
{
int32_t iControl;
int32_t iTriggerMode;
ControlItem() : iControl(-1), iTriggerMode(0) {}
ControlItem(int32_t iControl, int32_t iTriggerMode) : iControl(iControl), iTriggerMode(iTriggerMode) {}
void CompileFunc(StdCompiler *pComp);
bool operator ==(const struct ControlItem &cmp) const { return iControl==cmp.iControl && iTriggerMode == cmp.iTriggerMode; }
};
typedef std::vector<ControlItem> ControlItemVec;
protected:
int32_t iPlr;
bool fRelease;
C4KeyEventData ExtraData;
ControlItemVec ControlItems;
public:
DECLARE_C4CONTROL_VIRTUALS
void AddControl(int32_t iControl, int32_t iTriggerMode)
{ ControlItems.push_back(ControlItem(iControl, iTriggerMode)); }
const ControlItemVec &GetControlItems() const { return ControlItems; }
bool IsReleaseControl() const { return fRelease; }
const C4KeyEventData &GetExtraData() const { return ExtraData; }
};
class C4ControlPlayerCommand : public C4ControlPacket // sync
{
public:

View File

@ -58,9 +58,10 @@
#include <C4Network2Reference.h>
#include <C4VideoPlayback.h>
#include <C4RoundResults.h>
#include <C4PlayerControl.h>
class C4Game
{
{
private:
// used as StdCompiler-parameter
struct CompileSettings
@ -81,13 +82,13 @@ class C4Game
C4KeySetCtrl(int32_t iKeySet, int32_t iCtrl) : iKeySet(iKeySet), iCtrl(iCtrl) {}
};
public:
C4Game();
public:
C4Game();
~C4Game();
public:
C4DefList Defs;
C4TextureMap TextureMap;
C4RankSystem Rank;
C4DefList Defs;
C4TextureMap TextureMap;
C4RankSystem Rank;
C4GraphicsSystem GraphicsSystem;
C4MessageInput MessageInput;
C4GraphicsResource GraphicsResource;
@ -100,13 +101,13 @@ class C4Game
C4RoundResults RoundResults;
C4GameMessageList Messages;
C4MouseControl MouseControl;
C4Weather Weather;
C4Weather Weather;
C4MaterialMap Material;
C4GameObjects Objects;
C4ObjectList BackObjects; // objects in background (C4D_Background)
C4ObjectList ForeObjects; // objects in foreground (C4D_Foreground)
C4Landscape Landscape;
C4Scenario C4S;
C4Landscape Landscape;
C4Scenario C4S;
C4ComponentHost Info;
C4ComponentHost Title;
C4ComponentHost Names;
@ -114,7 +115,7 @@ class C4Game
C4AulScriptEngine ScriptEngine;
C4GameScriptHost Script;
C4LangStringTable MainSysLangStringTable, ScenarioLangStringTable, ScenarioSysLangStringTable;
C4MassMoverSet MassMover;
C4MassMoverSet MassMover;
C4PXSSystem PXS;
C4ParticleSystem Particles;
C4PlayerList Players;
@ -124,13 +125,15 @@ class C4Game
C4PathFinder PathFinder;
C4TransferZones TransferZones;
C4Group ScenarioFile;
C4Group ScenarioFile;
C4GroupSet GroupSet;
C4Group *pParentGroup;
C4Extra Extra;
C4GUIScreen *pGUI;
C4ScenarioSection *pScenarioSections, *pCurrentScenarioSection;
C4Effect *pGlobalEffects;
C4PlayerControlDefs PlayerControlDefs;
C4PlayerControlAssignmentSets PlayerControlAssignmentSets;
#ifndef USE_CONSOLE
// We don't need fonts when we don't have graphics
C4FontLoader FontLoader;
@ -142,8 +145,8 @@ class C4Game
class C4FileMonitor *pFileMonitor;
class C4GameSec1Timer *pSec1Timer;
char CurrentScenarioSection[C4MaxName+1];
char ScenarioFilename[_MAX_PATH+1];
char CurrentScenarioSection[C4MaxName+1];
char ScenarioFilename[_MAX_PATH+1];
StdCopyStrBuf ScenarioTitle;
char PlayerFilenames[20*_MAX_PATH+1];
char DefinitionFilenames[20*_MAX_PATH+1];
@ -152,13 +155,13 @@ class C4Game
int32_t StartupPlayerCount;
int32_t FPS,cFPS;
int32_t HaltCount;
bool GameOver;
bool Evaluated;
bool GameOver;
bool Evaluated;
bool GameOverDlgShown;
bool fScriptCreatedObjects;
bool fLobby;
int32_t iLobbyTimeout;
bool fObserve;
bool fObserve;
bool fReferenceDefinitionOverride;
bool NetworkActive;
bool Record;
@ -192,27 +195,27 @@ class C4Game
// next mission to be played after this one
StdCopyStrBuf NextMission, NextMissionText, NextMissionDesc;
public:
// Init and execution
public:
// Init and execution
void Default();
void Clear();
void Abort(bool fApproved = false); // hard-quit on Esc+Y (/J/O)
void Evaluate();
void Evaluate();
void ShowGameOverDlg();
bool DoKeyboardInput(C4KeyCode vk_code, C4KeyEventType eEventType, bool fAlt, bool fCtrl, bool fShift, bool fRepeated, class C4GUI::Dialog *pForDialog=NULL, bool fPlrCtrlOnly=false);
void DrawCursors(C4TargetFacet &cgo, int32_t iPlayer);
bool LocalControlKey(C4KeyCodeEx key, C4KeySetCtrl Ctrl);
bool LocalControlKeyUp(C4KeyCodeEx key, C4KeySetCtrl Ctrl);
void LocalPlayerControl(int32_t iPlayer, int32_t iCom);
void FixRandom(int32_t iSeed);
void LocalPlayerControl(int32_t iPlayer, int32_t iCom);
void FixRandom(int32_t iSeed);
bool Init();
bool PreInit();
void ParseCommandLine(const char *szCmdLine);
BOOL Execute();
class C4Player *JoinPlayer(const char *szFilename, int32_t iAtClient, const char *szAtClientName, C4PlayerInfo *pInfo);
BOOL DoGameOver();
void ParseCommandLine(const char *szCmdLine);
BOOL Execute();
class C4Player *JoinPlayer(const char *szFilename, int32_t iAtClient, const char *szAtClientName, C4PlayerInfo *pInfo);
BOOL DoGameOver();
bool CanQuickSave();
BOOL QuickSave(const char *strFilename, const char *strTitle, bool fForceSave=false);
BOOL QuickSave(const char *strFilename, const char *strTitle, bool fForceSave=false);
void SetInitProgress(float fToProgress);
void OnResolutionChanged(unsigned int iXRes, unsigned int iYRes); // update anything that's dependant on screen resolution
void InitFullscreenComponents(bool fRunning);
@ -223,58 +226,58 @@ class C4Game
bool Unpause();
bool IsPaused();
// Network
void Synchronize(BOOL fSavePlayerFiles);
void SyncClearance();
void Synchronize(BOOL fSavePlayerFiles);
void SyncClearance();
BOOL ReSync();
void SyncCheckFiles(); // check if files are in sync
// Editing
// Editing
BOOL DropFile(const char *szFilename, float iX, float iY);
BOOL CreateViewport(int32_t iPlayer, bool fSilent=false);
BOOL DropDef(C4ID id, float iX, float iY);
BOOL LoadDef(const char *szFilename);
BOOL ReloadFile(const char *szPath);
BOOL ReloadDef(C4ID id);
BOOL DropDef(C4ID id, float iX, float iY);
BOOL LoadDef(const char *szFilename);
BOOL ReloadFile(const char *szPath);
BOOL ReloadDef(C4ID id);
BOOL ReloadParticle(const char *szName);
// Object functions
void ClearPointers(C4Object *cobj);
C4Object *CreateObject(C4ID type, C4Object *pCreator, int32_t owner=NO_OWNER,
int32_t x=50, int32_t y=50, int32_t r=0,
FIXED xdir=Fix0, FIXED ydir=Fix0, FIXED rdir=Fix0, int32_t iController=NO_OWNER);
C4Object *CreateObjectConstruction(C4ID type,
C4Object *pCreator,
int32_t owner,
int32_t ctx=0, int32_t bty=0,
int32_t con=1, BOOL terrain=FALSE);
C4Object *CreateInfoObject(C4ObjectInfo *cinf, int32_t owner,
int32_t tx=50, int32_t ty=50);
void BlastObjects(int32_t tx, int32_t ty, int32_t level, C4Object *inobj, int32_t iCausedBy, C4Object *pByObj);
// Object functions
void ClearPointers(C4Object *cobj);
C4Object *CreateObject(C4ID type, C4Object *pCreator, int32_t owner=NO_OWNER,
int32_t x=50, int32_t y=50, int32_t r=0,
FIXED xdir=Fix0, FIXED ydir=Fix0, FIXED rdir=Fix0, int32_t iController=NO_OWNER);
C4Object *CreateObjectConstruction(C4ID type,
C4Object *pCreator,
int32_t owner,
int32_t ctx=0, int32_t bty=0,
int32_t con=1, BOOL terrain=FALSE);
C4Object *CreateInfoObject(C4ObjectInfo *cinf, int32_t owner,
int32_t tx=50, int32_t ty=50);
void BlastObjects(int32_t tx, int32_t ty, int32_t level, C4Object *inobj, int32_t iCausedBy, C4Object *pByObj);
void ShakeObjects(int32_t tx, int32_t ry, int32_t range);
C4Object *OverlapObject(int32_t tx, int32_t ty, int32_t wdt, int32_t hgt,
int32_t category);
C4Object *FindObject(C4ID id,
int32_t iX=0, int32_t iY=0, int32_t iWdt=0, int32_t iHgt=0,
DWORD ocf=OCF_All,
const char *szAction=NULL, C4Object *pActionTarget=NULL,
C4Object *pExclude=NULL,
C4Object *pContainer=NULL,
int32_t iOwner=ANY_OWNER,
C4Object *pFindNext=NULL);
C4Object *OverlapObject(int32_t tx, int32_t ty, int32_t wdt, int32_t hgt,
int32_t category);
C4Object *FindObject(C4ID id,
int32_t iX=0, int32_t iY=0, int32_t iWdt=0, int32_t iHgt=0,
DWORD ocf=OCF_All,
const char *szAction=NULL, C4Object *pActionTarget=NULL,
C4Object *pExclude=NULL,
C4Object *pContainer=NULL,
int32_t iOwner=ANY_OWNER,
C4Object *pFindNext=NULL);
C4Object *FindVisObject( // find object in view at pos, regarding parallaxity and visibility (but not distance)
float tx, float ty, int32_t iPlr, const C4Facet &fctViewport,
float iX=0, float iY=0, float iWdt=0, float iHgt=0,
DWORD ocf=OCF_All,
C4Object *pExclude=NULL,
int32_t iOwner=ANY_OWNER,
C4Object *pFindNext=NULL);
int32_t ObjectCount(C4ID id,
int32_t x=0, int32_t y=0, int32_t wdt=0, int32_t hgt=0,
DWORD ocf=OCF_All,
const char *szAction=NULL, C4Object *pActionTarget=NULL,
C4Object *pExclude=NULL,
C4Object *pContainer=NULL,
int32_t iOwner=ANY_OWNER);
C4Object *FindBase(int32_t iPlayer, int32_t iIndex);
C4Object *FindFriendlyBase(int32_t iPlayer, int32_t iIndex);
float tx, float ty, int32_t iPlr, const C4Facet &fctViewport,
float iX=0, float iY=0, float iWdt=0, float iHgt=0,
DWORD ocf=OCF_All,
C4Object *pExclude=NULL,
int32_t iOwner=ANY_OWNER,
C4Object *pFindNext=NULL);
int32_t ObjectCount(C4ID id,
int32_t x=0, int32_t y=0, int32_t wdt=0, int32_t hgt=0,
DWORD ocf=OCF_All,
const char *szAction=NULL, C4Object *pActionTarget=NULL,
C4Object *pExclude=NULL,
C4Object *pContainer=NULL,
int32_t iOwner=ANY_OWNER);
C4Object *FindBase(int32_t iPlayer, int32_t iIndex);
C4Object *FindFriendlyBase(int32_t iPlayer, int32_t iIndex);
C4Object *FindObjectByCommand(int32_t iCommand, C4Object *pTarget=NULL, C4Value iTx=C4VNull, int32_t iTy=0, C4Object *pTarget2=NULL, C4Object *pFindNext=NULL);
void CastObjects(C4ID id, C4Object *pCreator, int32_t num, int32_t level, int32_t tx, int32_t ty, int32_t iOwner=NO_OWNER, int32_t iController=NO_OWNER);
void BlastCastObjects(C4ID id, C4Object *pCreator, int32_t num, int32_t tx, int32_t ty, int32_t iController=NO_OWNER);
@ -282,14 +285,16 @@ class C4Game
C4Object *PlaceAnimal(C4ID idAnimal);
BOOL LoadScenarioSection(const char *szSection, DWORD dwFlags);
BOOL SaveDesc(C4Group &hGroup, BOOL fSaveGame=FALSE, BOOL fReference=FALSE, BOOL fLobby=FALSE, BOOL fUnregistered=FALSE, BOOL fRecord=FALSE);
BOOL SaveDesc(C4Group &hGroup, BOOL fSaveGame=FALSE, BOOL fReference=FALSE, BOOL fLobby=FALSE, BOOL fUnregistered=FALSE, BOOL fRecord=FALSE);
bool DrawTextSpecImage(C4FacetSurface &fctTarget, const char *szSpec, uint32_t dwClr=0xff);
bool SpeedUp();
bool SlowDown();
bool InitKeyboard(); // register main keyboard input functions
void UpdateLanguage();
bool InitPlayerControlSettings();
protected:
protected:
bool InitSystem();
void InitInEarth();
void InitVegetation();

View File

@ -202,6 +202,7 @@
#include "C4PathFinder.h"
#include "C4Physics.h"
#include "C4Player.h"
#include "C4PlayerControl.h"
#include "C4PlayerInfo.h"
#include "C4PlayerInfoListBox.h"
#include "C4PlayerList.h"

View File

@ -167,7 +167,17 @@ struct C4KeyCodeEx
C4KeyCodeEx(C4KeyCode Key = KEY_Default, C4KeyShiftState Shift = KEYS_None, bool fIsRepeated = false)
: Key(Key), dwShift(Shift), fRepeated(fIsRepeated) {}
bool IsRepeated() { return fRepeated; }
bool IsRepeated() const { return fRepeated; }
};
// extra data associated with a key event
struct C4KeyEventData
{
int32_t iStrength; // pressure between 0 and 100 (100 for nomal keypress)
int32_t x,y; // position for mouse event
C4KeyEventData() : iStrength(0), x(0), y(0) {}
void CompileFunc(StdCompiler *pComp);
bool operator ==(const struct C4KeyEventData &cmp) const;
};
// callback interface
@ -392,6 +402,7 @@ class C4KeyboardInput
// mapping of all keys by code and name
KeyCodeMap KeysByCode;
KeyNameMap KeysByName;
C4KeyEventData LastKeyExtraData;
public:
static bool IsValid; // global var to fix any deinitialization orders of key map and static keys
@ -417,6 +428,7 @@ class C4KeyboardInput
C4CustomKey *GetKeyByName(const char *szKeyName);
StdStrBuf GetKeyCodeNameByKeyName(const char *szKeyName, bool fShort = false, int32_t iIndex = 0);
const C4KeyEventData &GetLastKeyExtraData() const { return LastKeyExtraData; }
};
// keyboardinput-initializer-helper

View File

@ -159,6 +159,7 @@ enum C4PacketType
CID_PlrControl = CID_First | 0x21,
CID_PlrCommand = CID_First | 0x22,
CID_Message = CID_First | 0x23,
CID_PlrControl2 = CID_First | 0x24,
CID_EMMoveObj = CID_First | 0x30,
CID_EMDrawTool = CID_First | 0x31,

View File

@ -30,12 +30,25 @@ class C4PlayerControlDef
StdCopyStrBuf sIdentifier; // name as seen in script and config
StdCopyStrBuf sGUIName; // name as displayed to player
StdCopyStrBuf sGUIDesc; // key description displayed to player in config dialog
bool fGlobal; // if true, control can be bound to the global player only
bool fIsHoldKey; // if true, the control can be in down and up state
int32_t iRepeat; // if >0, the key will generate successive events when held down
int32_t iRepeatDelay; // if >0, the key will generate successive events when held down
int32_t iInitialRepeatDelay; // delay after which KeyRepeat will be enabled
bool fDefaultDisabled; // if true, the control is disabled by default and needs to be enabled by script
C4ID idControlExtraData; // extra data to be passed to script function
public:
enum Actions //action to be performed when control is triggered
{
CDA_None=0, // do nothing
CDA_Script, // default: Script callback
CDA_Menu, // open player menu (async)
CDA_MenuOK, CDA_MenuCancel, CDA_MenuLeft, CDA_MenuUp, CDA_MenuRight, CDA_MenuDown, // player menu controls (async)
};
private:
Actions eAction;
public:
C4PlayerControlDef() : fIsHoldKey(false), fDefaultDisabled(false) {}
C4PlayerControlDef() : fIsHoldKey(false), fDefaultDisabled(false), eAction(CDA_Script), fGlobal(false), idControlExtraData(C4ID_None) {}
~C4PlayerControlDef() {};
void CompileFunc(StdCompiler *pComp);
@ -43,9 +56,18 @@ class C4PlayerControlDef
const char *GetIdentifier() const { return sIdentifier.getData(); }
const char *GetGUIName() const { return sGUIName.getData(); }
const char *GetGUIDesc() const { return sGUIDesc.getData(); }
Actions GetAction() const { return eAction; }
bool IsHoldKey() const { return fIsHoldKey; }
C4ID GetExtraData() const { return idControlExtraData; }
bool IsGlobal() const { return fGlobal; }
//C4PlayerControlDef &operator =(const C4PlayerControlDef &src);
bool operator ==(const C4PlayerControlDef &cmp) const;
bool Execute(bool fUp, const C4KeyEventData &rKeyExtraData); // key was triggered - execute and return if handled
bool IsAsync() const { return eAction != CDA_None && eAction != CDA_Script; } // true if to be executed directly when triggered
bool IsSync() const { return eAction == CDA_Script; } // true if to be executed via control queue
bool IsValid() const { return eAction != CDA_None; }
};
// CON_* constants are indices into the C4PlayerControlDefs list
@ -59,11 +81,17 @@ class C4PlayerControlDefs
DefVecImpl Defs;
public:
C4PlayerControlDefs() {}
~C4PlayerControlDefs() {}
void Clear();
void CompileFunc(StdCompiler *pComp);
void MergeFrom(const C4PlayerControlDefs &Src); // copy all defs from source file; overwrite defs of same name if found
C4PlayerControlDef *GetControlByIndex(int32_t idx);
int32_t GetControlIndexByIdentifier(const char *szIdentifier) const; // return CON_None for not found
bool operator ==(const C4PlayerControlDefs &cmp) const { return Defs == cmp.Defs; }
};
// a key/mouse/gamepad assignment to a PlayerControlDef
@ -89,47 +117,73 @@ class C4PlayerControlAssignment
StdCopyStrBuf sControlName; // name of the control to be executed on this key
int32_t iControl; // the control to be executed on this key, i.e. the resolved sControlName
bool fAlwaysUnhandled; // if true, the key will not block handling of other keys even if it got handled
int32_t iPriority; // higher priority assignments get handled first
public:
// action to be performed on the control upon this key
enum TriggerModes
{
CTM_Default=0, // standard behaviour: The control will be triggered
CTM_Hold, // the control will be put into "down"-mode
CTM_Release, // the hold mode of the control will be released
} eTriggerMode;
CTM_Default=0, // standard behaviour: The control will be triggered
CTM_Hold= 1<<0, // the control will be put into "down"-mode
CTM_Release= 1<<1, // the hold mode of the control will be released
CTM_AlwaysUnhandled= 1<<2, // the key will not block handling of other keys even if it got handled
};
private:
int32_t iTriggerMode;
bool fRefsResolved; // set to true after sControlName and sKeyNames have been resolved to runtime values
public:
C4PlayerControlAssignment() : TriggerKey(), iControl(CON_None), fAlwaysUnhandled(false), eTriggerMode(CTM_Default) {}
~C4PlayerControlAssignment();
C4PlayerControlAssignment() : TriggerKey(), iControl(CON_None), iTriggerMode(CTM_Default), iPriority(0), fRefsResolved(false) {}
~C4PlayerControlAssignment() {}
void CompileFunc(StdCompiler *pComp);
void ResolveRefs(C4PlayerControlDefs *pControlDefs); // resolve references between assignments
bool ResolveRefs(class C4PlayerControlAssignmentSet *pParentSet, C4PlayerControlDefs *pControlDefs); // resolve references between assignments
bool operator ==(const C4PlayerControlAssignment &cmp) const; // doesn't compare resolved TriggerKey/iControl
bool operator <(const C4PlayerControlAssignment &cmp) const { return iPriority < cmp.iPriority; }
const char *GetControlName() const { return sControlName.getData(); }
int32_t GetControl() const { return iControl; }
bool IsRefsResolved() const { return fRefsResolved; }
bool IsAlwaysUnhandled() const { return iTriggerMode & CTM_AlwaysUnhandled; }
int32_t GetTriggerMode() const { return iTriggerMode; }
};
typedef std::vector<C4PlayerControlAssignment> C4PlayerControlAssignmentVec;
struct C4PlayerControlRecentKey
{
C4KeyCodeEx Key;
int32_t iFrame;
C4PlayerControlRecentKey(const C4KeyCodeEx &Key, int32_t iFrame) : Key(Key), iFrame(iFrame) {}
bool operator ==(const C4PlayerControlRecentKey &cmp) { return Key==cmp.Key; } // comparison op for finding items in lists: Search for the key only
};
typedef std::list<C4PlayerControlRecentKey> C4PlayerControlRecentKeyList;
// a set of key/mouse/gamepad assignments to all controls
class C4PlayerControlAssignmentSet
{
private:
StdCopyStrBuf sName;
typedef std::vector<C4PlayerControlAssignment> AssignmentsVec;
AssignmentsVec Assignments;
C4PlayerControlAssignmentVec Assignments;
public:
C4PlayerControlAssignmentSet() {}
~C4PlayerControlAssignmentSet() {}
void CompileFunc(StdCompiler *pComp);
void ResolveRefs(C4PlayerControlDefs *pControlDefs); // resolve references between assignments
bool ResolveRefs(C4PlayerControlDefs *pControlDefs); // resolve references between assignments
void MergeFrom(const C4PlayerControlAssignmentSet &Src, bool fLowPrio); // take over all assignments defined in Src
const char *GetName() const { return sName.getData(); }
C4PlayerControlAssignment *GetAssignmentByControlName(const char *szControlName) const;
C4PlayerControlAssignment *GetAssignmentByControlName(const char *szControlName);
void GetAssignmentsByKey(const C4KeyCodeEx &key, bool fHoldKeysOnly, C4PlayerControlAssignmentVec *pOutVec, const C4PlayerControlRecentKeyList &DownKeys, const C4PlayerControlRecentKeyList &RecentKeys); // match only by TriggerKey (last key of Combo) if fHoldKeysOnly
bool operator ==(const C4PlayerControlAssignmentSet &cmp) const;
};
// list of C4PlayerControlAssignmentSet
@ -137,26 +191,34 @@ class C4PlayerControlAssignmentSets
{
private:
typedef std::list<C4PlayerControlAssignmentSet> AssignmentSetList;
AssignmentSetList Sets;
public:
C4PlayerControlAssignmentSets() {}
~C4PlayerControlAssignmentSets() {}
void Clear();
void CompileFunc(StdCompiler *pComp);
bool ResolveRefs(C4PlayerControlDefs *pControlDefs); // resolve references between assignments
void MergeFrom(const C4PlayerControlAssignmentSets &Src, bool fLowPrio); // take over all assignments in known sets and new sets defined in Src
C4PlayerControlAssignmentSet *GetSetByName(const char *szName);
};
// contents of one PlayerControls.txt file
class C4PlayerControlFile
{
private:
C4PlayerControlDef ControlDefs;
C4PlayerControlDefs ControlDefs;
C4PlayerControlAssignmentSets AssignmentSets;
public:
bool Load(C4Group &hGroup, const char *szFilename);
void Clear();
void CompileFunc(StdCompiler *pComp);
bool Load(C4Group &hGroup, const char *szFilename, C4LangStringTable *pLang);
bool Save(C4Group &hGroup, const char *szFilename);
const C4PlayerControlDef &GetControlDefs() const { return ControlDefs; }
const C4PlayerControlDefs &GetControlDefs() const { return ControlDefs; }
const C4PlayerControlAssignmentSets &GetAssignmentSets() const { return AssignmentSets; }
};
@ -164,40 +226,69 @@ class C4PlayerControlFile
class C4PlayerControl
{
private:
struct RecentKey
{
C4KeyCodeEx Key;
int32_t iFrame;
};
// shortcut
C4PlayerControlDefs &ControlDefs;
C4PlayerControlDefs &ControlDefs; // shortcut
// owner
int32_t iPlr;
// async values
C4PlayerControlAssignmentSet *pControlSet; // the control set used by this player
std::list<C4KeyBinding *> KeyBindings; // keys registered into Game.KeyboardInput
std::list<RecentKey> RecentKeys; // keys pressed recently; for combinations
std::vector<C4KeyCodeEx> DownKeys; // keys currently held down
C4PlayerControlRecentKeyList RecentKeys; // keys pressed recently; for combinations
C4PlayerControlRecentKeyList DownKeys; // keys currently held down
// sync values
struct
struct CSync
{
std::vector<int32_t> ControlDownStates; // indexed by C4PlayerControlID: Down-state of a control. 0=up, 100=down; values inbetween e.g. for gamepad sticks
std::vector<int32_t> ControlDisableStates; // indexed by C4PlayerControlID: Disable-states of controls. >0 is disabled.
struct ControlDownState
{
C4KeyEventData DownState; // control is down if DownState.iStrength>0
int32_t iDownFrame; // frame when control was pressed
bool fDownByUser; // if true, the key is actually pressed. Otherwise, it's triggered as down by another key
ControlDownState(const C4KeyEventData &rDownState, int32_t iDownFrame, bool fDownByUser)
: DownState(rDownState), iDownFrame(iDownFrame), fDownByUser(fDownByUser) {}
};
typedef std::vector<int32_t> DownStateVec;
DownStateVec ControlDownStates; // indexed by C4PlayerControlID: Down-state of a control. 0=up, 100=down; values inbetween e.g. for gamepad sticks
typedef std::vector<int32_t> DisableStateVec;
DisableStateVec ControlDisableStates; // indexed by C4PlayerControlID: Disable-states of controls. >0 is disabled.
const ControlDownState *GetControlDownState(int32_t iControl) const;
int32_t GetControlDisabled(int32_t iControl) const;
bool IsControlDisabled(int32_t iControl) const { return GetControlDisabled(iControl)>0; }
void SetControlDownState(int32_t iControl, const C4KeyEventData &rDownState, int32_t iDownFrame, bool fDownByUser);
void SetControlDisabled(int32_t iControl, int32_t iVal);
void CompileFunc(StdCompiler *pComp);
bool operator ==(const CSync &cmp) const;
} Sync;
// callbacks from Game.KeyboardInput
bool ProcessKeyPress(C4KeyCodeEx key, int32_t iKeyIndex);
bool ProcessKeyDown(C4KeyCodeEx key, int32_t iKeyIndex);
bool ProcessKeyUp(C4KeyCodeEx key, int32_t iKeyIndex);
bool ProcessKeyEvent(const C4KeyCodeEx &key, bool fUp, const C4KeyEventData &rKeyExtraData);
bool ProcessKeyDown(const C4KeyCodeEx &key);
bool ProcessKeyUp(const C4KeyCodeEx &key);
// execute single control. return if handled.
bool ExecuteControl(int32_t iControl, bool fUp, const C4KeyEventData &rKeyExtraData, int32_t iTriggerMode, bool fRepeated);
bool ExecuteControlAction(int32_t iControl, C4PlayerControlDef::Actions eAction, C4ID idControlExtraData, bool fUp, const C4KeyEventData &rKeyExtraData, bool fRepeated);
bool ExecuteControlScript(int32_t iControl, C4ID idControlExtraData, bool fUp, const C4KeyEventData &rKeyExtraData, bool fRepeated);
// sync execution: Do keyrepeat, etc.
void Execute();
public:
C4PlayerControl();
~C4PlayerControl() { Clear(); }
void Clear();
void RegisterKeyset(C4PlayerControlAssignmentSet *pKeyset); // register all keys into Game.KeyboardInput creating KeyBindings
void CompileFunc(StdCompiler *pComp);
void RegisterKeyset(int32_t iPlr, C4PlayerControlAssignmentSet *pKeyset); // register all keys into Game.KeyboardInput creating KeyBindings
bool IsGlobal() const { return iPlr==-1; }
// callback from control queue
void ExecuteControlPacket(const class C4ControlPlayerControl2 *pCtrl);
};

View File

@ -150,6 +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
// 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

@ -376,6 +376,45 @@ void C4ControlPlayerControl::CompileFunc(StdCompiler *pComp)
C4ControlPacket::CompileFunc(pComp);
}
// *** C4ControlPlayerControl2
void C4ControlPlayerControl2::Execute() const
{
C4PlayerControl *pTargetCtrl = NULL;
if (iPlr == -1)
{
// neutral control packet: Execute in global control
}
else
{
// player-based control: Execute on control owned by player
C4Player *pPlr=Game.Players.Get(iPlr);
if (pPlr)
{
//pPlr->CountControl(C4Player::PCID_DirectCom, iCom*10000+iData);
}
}
if (pTargetCtrl) pTargetCtrl->ExecuteControlPacket(this);
}
void C4ControlPlayerControl2::ControlItem::CompileFunc(StdCompiler *pComp)
{
pComp->Value(iControl);
pComp->Seperator();
pComp->Value(iTriggerMode);
}
void C4ControlPlayerControl2::CompileFunc(StdCompiler *pComp)
{
pComp->Value(mkNamingAdapt(mkIntPackAdapt(iPlr), "Player", -1));
pComp->Value(mkNamingAdapt(fRelease, "Release", false));
pComp->Value(mkNamingAdapt(ExtraData, "ExtraData", C4KeyEventData()));
pComp->Value(mkNamingAdapt(mkSTLContainerAdapt(ControlItems), "Controls", ControlItemVec()));
C4ControlPacket::CompileFunc(pComp);
}
// *** C4ControlPlayerCommand
C4ControlPlayerCommand::C4ControlPlayerCommand(int32_t iPlr, int32_t iCmd, int32_t iX, int32_t iY,

View File

@ -50,6 +50,7 @@
#include <C4ObjectMenu.h>
#include <C4GameLobby.h>
#include <C4ChatDlg.h>
#include <C4PlayerControl.h>
#endif
#include <StdFile.h>
@ -572,6 +573,8 @@ void C4Game::Clear()
KeyboardInput.Clear();
SetMusicLevel(100);
PlayList.Clear();
PlayerControlAssignmentSets.Clear();
PlayerControlDefs.Clear();
// global fullscreen class is not cleared, because it holds the carrier window
// but the menu must be cleared (maybe move Fullscreen.Menu somewhere else?)
@ -2443,9 +2446,6 @@ BOOL C4Game::InitScriptEngine()
{ LogFatal(LoadResStr("IDS_ERR_INVALIDSYSGRP")); return FALSE; }
C4Group &File = Application.SystemGroup;
// Load string table
MainSysLangStringTable.LoadEx("StringTbl", File, C4CFN_ScriptStringTbl, Config.General.LanguageEx);
// get scripts
char fn[_MAX_FNAME+1] = { 0 };
File.ResetSearch();
@ -3238,12 +3238,34 @@ bool C4Game::InitSystem()
// init keyboard input (default keys, plus overloads)
if (!InitKeyboard())
{ LogFatal(LoadResStr("IDS_ERR_NOKEYBOARD")); return false; }
// Load string table
UpdateLanguage();
// Player keyboard input: Key definitions and default sets
if (!InitPlayerControlSettings()) return false;
// Rank system
Rank.Init(Config.GetSubkeyPath("ClonkRanks"), LoadResStr("IDS_GAME_DEFRANKS"), 1000);
// done, success
return true;
}
void C4Game::UpdateLanguage()
{
// Reload System.c4g string table
MainSysLangStringTable.LoadEx("StringTbl", Application.SystemGroup, C4CFN_ScriptStringTbl, Config.General.LanguageEx);
}
bool C4Game::InitPlayerControlSettings()
{
C4PlayerControlFile PlayerControlFile;
if (!PlayerControlFile.Load(Application.SystemGroup, C4CFN_PlayerControls, &MainSysLangStringTable)) { LogFatal("[!]Error loading player controls"); return false; }
PlayerControlDefs = PlayerControlFile.GetControlDefs();
PlayerControlAssignmentSets = PlayerControlFile.GetAssignmentSets();
PlayerControlAssignmentSets.ResolveRefs(&PlayerControlDefs);
// And overwrites from config
//PlayerControlAssignmentSets.MergeFrom(Config.Controls.Assignments);
return true;
}
C4Player *C4Game::JoinPlayer(const char *szFilename, int32_t iAtClient, const char *szAtClientName, C4PlayerInfo *pInfo)
{
assert(pInfo);

View File

@ -494,6 +494,21 @@ void C4KeyCodeEx::CompileFunc(StdCompiler *pComp, StdStrBuf *pOutBufIfUndefined)
}
}
void C4KeyEventData::CompileFunc(StdCompiler *pComp)
{
pComp->Value(iStrength);
pComp->Seperator();
pComp->Value(x);
pComp->Seperator();
pComp->Value(y);
}
bool C4KeyEventData::operator ==(const struct C4KeyEventData &cmp) const
{
return iStrength == cmp.iStrength
&& x == cmp.x && y == cmp.y;
}
/* ----------------- C4CustomKey------------------ */
C4CustomKey::C4CustomKey(C4KeyCodeEx DefCode, const char *szName, C4KeyScope Scope, C4KeyboardCallbackInterface *pCallback, unsigned int uiPriority)
@ -640,6 +655,7 @@ bool C4KeyboardInput::IsValid = false;
void C4KeyboardInput::Clear()
{
LastKeyExtraData = C4KeyEventData();
// release all keys - name map is guarantueed to contain them all
for (KeyNameMap::const_iterator i = KeysByName.begin(); i != KeysByName.end(); ++i)
i->second->Deref();

View File

@ -24,13 +24,28 @@
void C4PlayerControlDef::CompileFunc(StdCompiler *pComp)
{
if (!pComp->Name("ControlDef")) pComp->excNotFound("ControlDef");
if (!pComp->Name("ControlDef")) { pComp->NameEnd(); pComp->excNotFound("ControlDef"); }
pComp->Value(mkNamingAdapt(mkParAdapt(sIdentifier, StdCompiler::RCT_Idtf), "Identifier", "None"));
pComp->Value(mkNamingAdapt(mkParAdapt(sGUIName, StdCompiler::RCT_All), "GUIName", "undefined"));
pComp->Value(mkNamingAdapt(mkParAdapt(sGUIDesc, StdCompiler::RCT_All), "GUIDesc", ""));
pComp->Value(mkNamingAdapt(fIsHoldKey, "IsHoldKey", false));
pComp->Value(mkNamingAdapt(iRepeat, "Repeat", 0));
pComp->Value(mkNamingAdapt(fGlobal, "Global", false));
pComp->Value(mkNamingAdapt(fIsHoldKey, "Hold", false));
pComp->Value(mkNamingAdapt(iRepeatDelay, "RepeatDelay", 0));
pComp->Value(mkNamingAdapt(iInitialRepeatDelay, "InitialRepeatDelay", 0));
pComp->Value(mkNamingAdapt(fDefaultDisabled, "DefaultDisabled", false));
pComp->Value(mkNamingAdapt(mkC4IDAdapt(idControlExtraData), "ExtraData", C4ID_None));
const StdEnumEntry<Actions> ActionNames[] = {
{ "None", CDA_None },
{ "Script", CDA_Script },
{ "Menu", CDA_Menu },
{ "MenuOK", CDA_MenuOK },
{ "MenuCancel", CDA_MenuCancel },
{ "MenuLeft", CDA_MenuLeft },
{ "MenuUp", CDA_MenuUp },
{ "MenuRight", CDA_MenuRight },
{ "MenuDown", CDA_MenuDown },
{ NULL, CDA_None } };
pComp->Value(mkNamingAdapt(mkEnumAdapt<Actions, int32_t>(eAction, ActionNames), "Action", CDA_Script));
pComp->NameEnd();
}
@ -39,14 +54,23 @@ bool C4PlayerControlDef::operator ==(const C4PlayerControlDef &cmp) const
return sIdentifier == cmp.sIdentifier
&& sGUIName == cmp.sGUIName
&& sGUIDesc == cmp.sGUIDesc
&& fGlobal == cmp.fGlobal
&& fIsHoldKey == cmp.fIsHoldKey
&& iRepeat == cmp.iRepeat
&& fDefaultDisabled == cmp.fDefaultDisabled;
&& iRepeatDelay == cmp.iRepeatDelay
&& iInitialRepeatDelay == cmp.iInitialRepeatDelay
&& fDefaultDisabled == cmp.fDefaultDisabled
&& idControlExtraData == cmp.idControlExtraData
&& eAction == cmp.eAction;
}
/* C4PlayerControlDefs */
void C4PlayerControlDefs::Clear()
{
Defs.clear();
}
void C4PlayerControlDefs::CompileFunc(StdCompiler *pComp)
{
pComp->Value(mkNamingAdapt(mkSTLContainerAdapt(Defs, StdCompiler::SEP_NONE), "ControlDefs", DefVecImpl()));
@ -113,17 +137,68 @@ void C4PlayerControlAssignment::KeyComboItem::CompileFunc(StdCompiler *pComp)
void C4PlayerControlAssignment::CompileFunc(StdCompiler *pComp)
{
if (!pComp->Name("ControlAssignment")) pComp->excNotFound("ControlAssignment");
if (!pComp->Name("Assignment")) { pComp->NameEnd(); pComp->excNotFound("Assignment"); }
pComp->Value(mkNamingAdapt(mkSTLContainerAdapt(KeyCombo), "Key", KeyComboVec()));
pComp->Value(mkNamingAdapt(mkParAdapt(sControlName, StdCompiler::RCT_Idtf), "Control", "None"));
pComp->Value(mkNamingAdapt(fAlwaysUnhandled, "AlwaysUnhandled", false));
const StdEnumEntry<TriggerModes> TriggerModeNames[] = {
pComp->Value(mkNamingAdapt(iPriority, "Priority", 0));
const StdBitfieldEntry<int32_t> TriggerModeNames[] = {
{ "Default", CTM_Default },
{ "Hold", CTM_Hold },
{ "Release", CTM_Release },
{ NULL, CTM_Default } };
pComp->Value(mkNamingAdapt(mkEnumAdapt<TriggerModes, int32_t>(eTriggerMode, TriggerModeNames), "TriggerMode", CTM_Default));
{ "AlwaysUnhandled", CTM_AlwaysUnhandled },
{ NULL, 0 } };
pComp->Value(mkNamingAdapt(mkBitfieldAdapt< int32_t>(iTriggerMode, TriggerModeNames), "TriggerMode", CTM_Default));
pComp->NameEnd();
// newly loaded structures are not resolved
if (pComp->isCompiler()) fRefsResolved = false;
}
bool C4PlayerControlAssignment::ResolveRefs(C4PlayerControlAssignmentSet *pParentSet, C4PlayerControlDefs *pControlDefs)
{
// avoid circular chains
static C4PlayerControlAssignment *pCircularDetect = NULL;
if (!pCircularDetect) pCircularDetect = this; else if (pCircularDetect == this)
{
LogFatal(FormatString("Circular reference chain detected in player control assignments of set %s in assignment for key %s!", pParentSet->GetName(), GetControlName()).getData());
return false;
}
// resolve control name
iControl = pControlDefs->GetControlIndexByIdentifier(sControlName.getData());
// resolve keys
KeyComboVec NewCombo;
for (KeyComboVec::iterator i = KeyCombo.begin(); i != KeyCombo.end(); ++i)
{
KeyComboItem &rKeyComboItem = *i;
if (rKeyComboItem.Key == KEY_Default && rKeyComboItem.sKeyName.getLength())
{
// this is a key reference - find it
C4PlayerControlAssignment *pRefAssignment = pParentSet->GetAssignmentByControlName(rKeyComboItem.sKeyName.getData());
if (pRefAssignment)
{
// resolve itself if necessary
if (!pRefAssignment->IsRefsResolved()) if (!pRefAssignment->ResolveRefs(pParentSet, pControlDefs)) return false;
// insert all keys of that combo into own combo
NewCombo.insert(NewCombo.end(), pRefAssignment->KeyCombo.begin(), pRefAssignment->KeyCombo.end());
}
else
{
// undefined reference? Not fatal, but inform user
LogF("WARNING: Control %s of set %s contains reference to unassigned control %s.", GetControlName(), pParentSet->GetName(), rKeyComboItem.sKeyName.getData());
NewCombo.clear();
}
}
else
{
NewCombo.push_back(rKeyComboItem);
}
}
KeyCombo = NewCombo;
// the trigger key is always last of the chain
if (KeyCombo.size()) TriggerKey = KeyCombo.back().Key; else TriggerKey = C4KeyCodeEx();
// done
fRefsResolved = true;
if (pCircularDetect == this) pCircularDetect = NULL;
return true;
}
bool C4PlayerControlAssignment::operator ==(const C4PlayerControlAssignment &cmp) const
@ -131,8 +206,8 @@ bool C4PlayerControlAssignment::operator ==(const C4PlayerControlAssignment &cmp
// doesn't compare resolved TriggerKey/iControl
return KeyCombo == cmp.KeyCombo
&& sControlName == cmp.sControlName
&& fAlwaysUnhandled == cmp.fAlwaysUnhandled
&& eTriggerMode == cmp.eTriggerMode;
&& iTriggerMode == cmp.iTriggerMode
&& iPriority == cmp.iPriority;
}
@ -140,16 +215,16 @@ bool C4PlayerControlAssignment::operator ==(const C4PlayerControlAssignment &cmp
void C4PlayerControlAssignmentSet::CompileFunc(StdCompiler *pComp)
{
if (!pComp->Name("ControlAssignmentSet")) pComp->excNotFound("ControlAssignmentSet");
if (!pComp->Name("ControlSet")) { pComp->NameEnd(); pComp->excNotFound("ControlSet"); }
pComp->Value(mkNamingAdapt(mkParAdapt(sName, StdCompiler::RCT_Idtf), "Name", "None"));
pComp->Value(mkNamingAdapt(mkSTLContainerAdapt(Assignments, StdCompiler::SEP_NONE), "Key", AssignmentsVec()));
pComp->Value(mkSTLContainerAdapt(Assignments, StdCompiler::SEP_NONE));
pComp->NameEnd();
}
void C4PlayerControlAssignmentSet::MergeFrom(const C4PlayerControlAssignmentSet &Src, bool fLowPrio)
{
// take over all assignments defined in Src
for (AssignmentsVec::const_iterator i = Src.Assignments.begin(); i != Src.Assignments.end(); ++i)
for (C4PlayerControlAssignmentVec::const_iterator i = Src.Assignments.begin(); i != Src.Assignments.end(); ++i)
{
const C4PlayerControlAssignment &SrcAssignment = *i;
// overwrite if def of same name existed if it's not low priority anyway
@ -166,14 +241,345 @@ void C4PlayerControlAssignmentSet::MergeFrom(const C4PlayerControlAssignmentSet
}
}
C4PlayerControlAssignment *C4PlayerControlAssignmentSet::GetAssignmentByControlName(const char *szControlName) const
bool C4PlayerControlAssignmentSet::ResolveRefs(C4PlayerControlDefs *pDefs)
{
for (AssignmentsVec::const_iterator i = Assignments.begin(); i != Assignments.end(); ++i)
// resolve in order; ignore already resolved because they might have been resolved by cross reference
for (C4PlayerControlAssignmentVec::iterator i = Assignments.begin(); i != Assignments.end(); ++i)
if (!(*i).IsRefsResolved())
if (!(*i).ResolveRefs(this, pDefs))
return false;
// now sort assignments by priority
std::sort(Assignments.begin(), Assignments.end());
return true;
}
C4PlayerControlAssignment *C4PlayerControlAssignmentSet::GetAssignmentByControlName(const char *szControlName)
{
for (C4PlayerControlAssignmentVec::iterator i = Assignments.begin(); i != Assignments.end(); ++i)
if (SEqual((*i).GetControlName(), szControlName))
return &*i;
return NULL;
}
bool C4PlayerControlAssignmentSet::operator ==(const C4PlayerControlAssignmentSet &cmp) const
{
return Assignments == cmp.Assignments
&& sName == cmp.sName;
}
/* C4PlayerControlAssignmentSets */
void C4PlayerControlAssignmentSets::Clear()
{
Sets.clear();
}
void C4PlayerControlAssignmentSets::CompileFunc(StdCompiler *pComp)
{
pComp->Value(mkNamingAdapt(mkSTLContainerAdapt(Sets, StdCompiler::SEP_NONE), "ControlSets", AssignmentSetList()));
}
void C4PlayerControlAssignmentSets::MergeFrom(const C4PlayerControlAssignmentSets &Src, bool fLowPrio)
{
// take over all assignments in known sets and new sets defined in Src
for (AssignmentSetList::const_iterator i = Src.Sets.begin(); i != Src.Sets.end(); ++i)
{
const C4PlayerControlAssignmentSet &SrcSet = *i;
// overwrite if def of same name existed if it's not low priority anyway
C4PlayerControlAssignmentSet *pPrevSet = GetSetByName(SrcSet.GetName());
if (pPrevSet)
{
pPrevSet->MergeFrom(SrcSet, fLowPrio);
}
else
{
// new def: Append a copy
Sets.push_back(SrcSet);
}
}
}
bool C4PlayerControlAssignmentSets::ResolveRefs(C4PlayerControlDefs *pDefs)
{
for (AssignmentSetList::iterator i = Sets.begin(); i != Sets.end(); ++i)
if (!(*i).ResolveRefs(pDefs)) return false;
return true;
}
C4PlayerControlAssignmentSet *C4PlayerControlAssignmentSets::GetSetByName(const char *szName)
{
for (AssignmentSetList::iterator i = Sets.begin(); i != Sets.end(); ++i)
if (SEqual((*i).GetName(), szName))
return &*i;
return NULL;
}
/* C4PlayerControlFile */
void C4PlayerControlFile::CompileFunc(StdCompiler *pComp)
{
pComp->Value(ControlDefs);
pComp->Value(AssignmentSets);
}
bool C4PlayerControlFile::Load(C4Group &hGroup, const char *szFilename, C4LangStringTable *pLang)
{
// clear previous
Clear();
// load and prepare file contents
StdStrBuf Buf;
if (!hGroup.LoadEntryString(szFilename, Buf)) return false;
if (pLang) pLang->ReplaceStrings(Buf);
// parse it!
if (!CompileFromBuf_LogWarn<StdCompilerINIRead>(*this, Buf, szFilename)) return false;
return true;
}
bool C4PlayerControlFile::Save(C4Group &hGroup, const char *szFilename)
{
// decompile to buffer and save buffer to group
StdStrBuf Buf;
if (!DecompileToBuf_Log<StdCompilerINIWrite>(*this, &Buf, szFilename)) return false;
hGroup.Add(szFilename, Buf, false, true);
return true;
}
void C4PlayerControlFile::Clear()
{
ControlDefs.Clear();
AssignmentSets.Clear();
}
/* C4PlayerControl */
void C4PlayerControl::CSync::CompileFunc(StdCompiler *pComp)
{
pComp->Value(mkNamingAdapt(mkSTLContainerAdapt(ControlDownStates), "Down", DownStateVec()));
pComp->Value(mkNamingAdapt(mkSTLContainerAdapt(ControlDisableStates), "Disabled", DisableStateVec()));
}
bool C4PlayerControl::CSync::operator ==(const CSync &cmp) const
{
return ControlDownStates == cmp.ControlDownStates
&& ControlDisableStates == cmp.ControlDisableStates;
}
void C4PlayerControl::CompileFunc(StdCompiler *pComp)
{
// compile sync values only
pComp->Value(mkNamingAdapt(Sync, "PlayerControl", CSync()));
}
bool C4PlayerControl::ProcessKeyEvent(const C4KeyCodeEx &key, bool fUp, const C4KeyEventData &rKeyExtraData)
{
// collect all matching keys
C4PlayerControlAssignmentVec Matches;
pControlSet->GetAssignmentsByKey(key, fUp, &Matches, DownKeys, RecentKeys);
// process async controls
C4ControlPlayerControl2 *pControlPacket = NULL;
for (C4PlayerControlAssignmentVec::const_iterator i = Matches.begin(); i != Matches.end(); ++i)
{
const C4PlayerControlAssignment &rAssignment = *i;
int32_t iControlIndex = rAssignment.GetControl();
C4PlayerControlDef *pControlDef = ControlDefs.GetControlByIndex(iControlIndex);
if (pControlDef && pControlDef->IsValid() && (!fUp || pControlDef->IsHoldKey()))
{
if (pControlDef->IsAsync() && !pControlPacket)
{
if (ExecuteControl(iControlIndex, fUp, rKeyExtraData, rAssignment.GetTriggerMode(), key.IsRepeated()))
return true;
}
else
{
// sync control
// ignore key repeats, because we do our own key repeat for sync controls
if (key.IsRepeated()) return false;
// sync control has higher priority - no more async execution then
// build a control packet and add control data instead. even for async controls later in chain, as they may be blocked by a sync handler
if (!pControlPacket) pControlPacket = new C4ControlPlayerControl2(iPlr, fUp, rKeyExtraData);
pControlPacket->AddControl(iControlIndex, rAssignment.GetTriggerMode());
break;
}
}
}
// push sync control to input
if (pControlPacket) Game.Input.Add(CID_PlrControl2, pControlPacket);
}
bool C4PlayerControl::ProcessKeyDown(const C4KeyCodeEx &key)
{
// add key to local "down" list if it's not already in there
if (std::find(DownKeys.begin(), DownKeys.end(), C4PlayerControlRecentKey(key,0)) == DownKeys.end()) DownKeys.push_back(C4PlayerControlRecentKey(key,Game.FrameCounter));
// process!
bool fResult = ProcessKeyEvent(key, false, Game.KeyboardInput.GetLastKeyExtraData());
// add to recent list unless repeated
if (!key.IsRepeated()) RecentKeys.push_back(C4PlayerControlRecentKey(key,Game.FrameCounter));
return fResult;
}
bool C4PlayerControl::ProcessKeyUp(const C4KeyCodeEx &key)
{
// remove key from "down" list
C4PlayerControlRecentKeyList::iterator i = find(DownKeys.begin(), DownKeys.end(), C4PlayerControlRecentKey(key,0));
if (i != DownKeys.end()) DownKeys.erase(i);
// process!
return ProcessKeyEvent(key, true, Game.KeyboardInput.GetLastKeyExtraData());
}
void C4PlayerControl::ExecuteControlPacket(const class C4ControlPlayerControl2 *pCtrl)
{
// callback from control queue. Execute controls in packet until one of them gets processed
// assume async packets always as not processed to ensure sync safety (usually, sync commands should better not ovberride async commands anyway)
for (C4ControlPlayerControl2::ControlItemVec::const_iterator i = pCtrl->GetControlItems().begin(); i != pCtrl->GetControlItems().end(); ++i)
{
const C4ControlPlayerControl2::ControlItem &rItem = *i;
C4PlayerControlDef *pCtrlDef = ControlDefs.GetControlByIndex(rItem.iControl);
if (pCtrlDef)
{
if (ExecuteControl(rItem.iControl, pCtrl->IsReleaseControl(), pCtrl->GetExtraData(), rItem.iTriggerMode, false))
if (pCtrlDef->IsSync())
break;
}
}
}
bool C4PlayerControl::ExecuteControl(int32_t iControl, bool fUp, const C4KeyEventData &rKeyExtraData, int32_t iTriggerMode, bool fRepeated)
{
// execute single control. return if handled
C4PlayerControlDef *pControlDef = ControlDefs.GetControlByIndex(iControl);
if (!pControlDef || Sync.IsControlDisabled(iControl)) return false;
C4PlayerControlDef::Actions eAction = pControlDef->GetAction();
C4KeyEventData KeyExtraData(rKeyExtraData);
// global controls only in global context
if (IsGlobal() != pControlDef->IsGlobal()) return false;
// hold-actions only work on script controls with the hold flag
if (iTriggerMode & (C4PlayerControlAssignment::CTM_Hold | C4PlayerControlAssignment::CTM_Release))
{
if (eAction != C4PlayerControlDef::CDA_Script) return false;
if (!pControlDef->IsHoldKey()) return false;
if (fUp) return false; // hold triggers have no "up"-event
// perform hold/release
const CSync::ControlDownState *pCtrlDownState = Sync.GetControlDownState(iControl);
if (!pCtrlDownState) return false;
bool fWasDown = (pCtrlDownState->DownState.iStrength > 0);
if (fWasDown)
{
// control is currently down: release?
if (iTriggerMode & C4PlayerControlAssignment::CTM_Release)
{
KeyExtraData.iStrength = 0;
Sync.SetControlDownState(iControl, KeyExtraData, Game.FrameCounter, false);
// now process as a regular "Up" event
fUp = true;
fRepeated = false;
}
else //if (iTriggerMode & C4PlayerControlAssignment::CTM_Hold) - must be true
{
// control is down but trigger key is pressed again: Refresh down state
Sync.SetControlDownState(iControl, KeyExtraData, Game.FrameCounter, false);
// now process as a regular, repeated "down" event
fRepeated = true;
}
}
else
{
// control is currently up. Put into hold-down-state if this is a hold key
if (iTriggerMode & C4PlayerControlAssignment::CTM_Hold)
{
Sync.SetControlDownState(iControl, KeyExtraData, Game.FrameCounter, false);
// now process as a regular "down" event
fRepeated = false;
}
else
{
//. Ignore if it's only a release key
return false;
}
}
}
else if (fUp)
{
// regular ControlUp: Only valid if that control was down
const CSync::ControlDownState *pCtrlDownState = Sync.GetControlDownState(iControl);
if (!pCtrlDownState) return false;
bool fWasDown = (pCtrlDownState->DownState.iStrength > 0);
if (!fWasDown) return false;
}
// perform action for this control
bool fHandled = ExecuteControlAction(iControl, eAction, pControlDef->GetExtraData(), fUp, KeyExtraData, fRepeated);
// return if handled, unless control is defined as always unhandled
return fHandled && !(iTriggerMode & C4PlayerControlAssignment::CTM_AlwaysUnhandled);
}
bool C4PlayerControl::ExecuteControlAction(int32_t iControl, C4PlayerControlDef::Actions eAction, C4ID idControlExtraData, bool fUp, const C4KeyEventData &rKeyExtraData, bool fRepeated)
{
// get affected player
C4Player *pPlr = NULL;
if (iPlr > -1)
{
pPlr = Game.Players.Get(iPlr);
if (!pPlr) return false;
}
// exec action (on player)
switch (eAction)
{
// scripted player control
case C4PlayerControlDef::CDA_Script:
return ExecuteControlScript(iControl, idControlExtraData, fUp, rKeyExtraData, fRepeated);
// menu controls
case C4PlayerControlDef::CDA_Menu: if (!pPlr || fUp) return false; if (pPlr->Menu.IsActive()) pPlr->Menu.Close(false); else pPlr->ActivateMenuMain(); return true; // toggle
case C4PlayerControlDef::CDA_MenuOK: if (!pPlr || !pPlr->Menu.IsActive() || fUp) return false; pPlr->Menu.Control(COM_MenuEnter,0); return true; // ok on item
case C4PlayerControlDef::CDA_MenuCancel: if (!pPlr || !pPlr->Menu.IsActive() || fUp) return false; pPlr->Menu.Control(COM_MenuClose,0); return true; // close menu
case C4PlayerControlDef::CDA_MenuLeft: if (!pPlr || !pPlr->Menu.IsActive() || fUp) return false; pPlr->Menu.Control(COM_MenuLeft ,0); return true; // navigate
case C4PlayerControlDef::CDA_MenuUp: if (!pPlr || !pPlr->Menu.IsActive() || fUp) return false; pPlr->Menu.Control(COM_MenuUp ,0); return true; // navigate
case C4PlayerControlDef::CDA_MenuRight: if (!pPlr || !pPlr->Menu.IsActive() || fUp) return false; pPlr->Menu.Control(COM_MenuRight,0); return true; // navigate
case C4PlayerControlDef::CDA_MenuDown: if (!pPlr || !pPlr->Menu.IsActive() || fUp) return false; pPlr->Menu.Control(COM_MenuDown ,0); return true; // navigate
//unknown action
default: return false;
}
}
bool C4PlayerControl::ExecuteControlScript(int32_t iControl, C4ID idControlExtraData, bool fUp, const C4KeyEventData &rKeyExtraData, bool fRepeated)
{
if (!fUp)
{
// 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));
return !!pFunc->Exec(NULL, &Pars);
}
else
{
// 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));
return !!pFunc->Exec(NULL, &Pars);
}
}
void C4PlayerControl::Execute()
{
// sync execution: Do keyrepeat, etc.
}
C4PlayerControl::C4PlayerControl() : ControlDefs(Game.PlayerControlDefs), iPlr(-1), pControlSet(NULL)
{
}
void C4PlayerControl::Clear()
{
}
void C4PlayerControl::RegisterKeyset(int32_t iPlr, C4PlayerControlAssignmentSet *pKeyset)
{
// register all keys into Game.KeyboardInput creating KeyBindings
}

View File

@ -1340,6 +1340,7 @@ bool C4StartupOptionsDlg::OnLangComboSelChange(C4GUI::ComboBox *pForCombo, int32
Config.General.Language[2] = '\0';
UpdateLanguage();
Languages.LoadLanguage(Config.General.LanguageEx);
Game.UpdateLanguage();
// recreate everything to reflect language changes
RecreateDialog(true);
return true;