Moving controls to script...

stable-5.2
Sven Eberhardt 2009-05-27 20:14:54 -04:00
parent ce6d73b92a
commit 2d5ad9fca1
28 changed files with 424 additions and 910 deletions

View File

@ -163,22 +163,11 @@ public:
class C4ControlPlayerControl : public C4ControlPacket // sync
{
public:
C4ControlPlayerControl()
: iPlr(-1), iCom(-1), iData(-1) { }
C4ControlPlayerControl(int32_t iPlr, int32_t iCom, int32_t iData)
: iPlr(iPlr), iCom(iCom), iData(iData) { }
protected:
int32_t iPlr, iCom, iData;
public:
DECLARE_C4CONTROL_VIRTUALS
};
class C4ControlPlayerControl2 : public C4ControlPacket // sync
{
public:
C4ControlPlayerControl2() : iPlr(-1), fRelease(false) {}
C4ControlPlayerControl2(int32_t iPlr, bool fRelease, const C4KeyEventData &rExtraData)
C4ControlPlayerControl() : iPlr(-1), fRelease(false) {}
C4ControlPlayerControl(int32_t iPlr, bool fRelease, const C4KeyEventData &rExtraData)
: iPlr(iPlr), fRelease(fRelease), ExtraData(rExtraData) { }
C4ControlPlayerControl(int32_t iPlr, int32_t iControl, int32_t iExtraData) // old-style menu com emulation
: iPlr(iPlr), fRelease(false), ExtraData(iExtraData,0,0) { AddControl(iControl,0); }
struct ControlItem
{

View File

@ -204,9 +204,6 @@ class C4Game
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);
bool Init();
bool PreInit();

View File

@ -1163,7 +1163,7 @@ namespace C4GUI {
private:
enum CursorOperation { COP_BACK, COP_DELETE, COP_LEFT, COP_RIGHT, COP_HOME, COP_END, };
bool KeyCursorOp(C4KeyCodeEx key, CursorOperation op);
bool KeyCursorOp(const C4KeyCodeEx &key, CursorOperation op);
bool KeyEnter();
bool KeyCopy() { Copy(); return true; }
bool KeyPaste() { Paste(); return true; }
@ -1671,7 +1671,7 @@ namespace C4GUI {
bool KeyBack();
bool KeyAbort();
bool KeyConfirm();
bool KeyHotkey(C4KeyCodeEx key);
bool KeyHotkey(const C4KeyCodeEx &key);
private:
static int32_t iGlobalMenuIndex;
@ -2005,7 +2005,7 @@ namespace C4GUI {
virtual void MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam); // input: mouse. forwards to child controls
private:
bool KeyHotkey(C4KeyCodeEx key);
bool KeyHotkey(const C4KeyCodeEx &key);
bool KeyFocusDefault();
public:
@ -2329,7 +2329,7 @@ namespace C4GUI {
{
private:
typedef C4KeyCBPassKey<TargetClass> Base;
typedef bool(TargetClass::*CallbackFunc)(C4KeyCodeEx key);
typedef bool(TargetClass::*CallbackFunc)(const C4KeyCodeEx &key);
public:
DlgKeyCBPassKey(TargetClass &rTarget, CallbackFunc pFuncDown, CallbackFunc pFuncUp=NULL, CallbackFunc pFuncPressed=NULL)
: Base(rTarget, pFuncDown, pFuncUp, pFuncPressed) {}
@ -2366,7 +2366,7 @@ namespace C4GUI {
{
private:
typedef C4KeyCBExPassKey<TargetClass, ParameterType> Base;
typedef bool(TargetClass::*CallbackFunc)(C4KeyCodeEx key, ParameterType par);
typedef bool(TargetClass::*CallbackFunc)(const C4KeyCodeEx &key, ParameterType par);
public:
ControlKeyCBExPassKey(TargetClass &rTarget, const ParameterType &rPar, CallbackFunc pFuncDown, CallbackFunc pFuncUp=NULL, CallbackFunc pFuncPressed=NULL)
: Base(rTarget, rPar, pFuncDown, pFuncUp, pFuncPressed) {}

View File

@ -176,6 +176,7 @@ 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) {}
C4KeyEventData(int32_t iStrength, int32_t x, int32_t y) : iStrength(iStrength), x(x), y(y) {}
void CompileFunc(StdCompiler *pComp);
bool operator ==(const struct C4KeyEventData &cmp) const;
};
@ -189,7 +190,7 @@ class C4KeyboardCallbackInterface
class C4CustomKey *pOriginalKey;
public:
virtual bool OnKeyEvent(C4KeyCodeEx key, C4KeyEventType eEv) = 0; // return true if processed
virtual bool OnKeyEvent(const C4KeyCodeEx &key, C4KeyEventType eEv) = 0; // return true if processed
friend class C4KeyboardMapping;
@ -214,7 +215,7 @@ template <class TargetClass> class C4KeyCB : public C4KeyboardCallbackInterface
CallbackFunc pFuncDown, pFuncUp, pFuncPressed;
protected:
virtual bool OnKeyEvent(C4KeyCodeEx key, C4KeyEventType eEv)
virtual bool OnKeyEvent(const C4KeyCodeEx &key, C4KeyEventType eEv)
{
if (!CheckCondition()) return false;
switch (eEv)
@ -237,14 +238,14 @@ template <class TargetClass> class C4KeyCB : public C4KeyboardCallbackInterface
template <class TargetClass> class C4KeyCBPassKey : public C4KeyboardCallbackInterface
{
public:
typedef bool(TargetClass::*CallbackFunc)(C4KeyCodeEx key);
typedef bool(TargetClass::*CallbackFunc)(const C4KeyCodeEx &key);
protected:
TargetClass &rTarget;
CallbackFunc pFuncDown, pFuncUp, pFuncPressed;
protected:
virtual bool OnKeyEvent(C4KeyCodeEx key, C4KeyEventType eEv)
virtual bool OnKeyEvent(const C4KeyCodeEx &key, C4KeyEventType eEv)
{
if (!CheckCondition()) return false;
switch (eEv)
@ -275,7 +276,7 @@ template <class TargetClass, class ParameterType> class C4KeyCBEx : public C4Key
ParameterType par;
protected:
virtual bool OnKeyEvent(C4KeyCodeEx key, C4KeyEventType eEv)
virtual bool OnKeyEvent(const C4KeyCodeEx &key, C4KeyEventType eEv)
{
if (!CheckCondition()) return false;
switch (eEv)
@ -297,7 +298,7 @@ template <class TargetClass, class ParameterType> class C4KeyCBEx : public C4Key
template <class TargetClass, class ParameterType> class C4KeyCBExPassKey : public C4KeyboardCallbackInterface
{
public:
typedef bool(TargetClass::*CallbackFunc)(C4KeyCodeEx key, ParameterType par);
typedef bool(TargetClass::*CallbackFunc)(const C4KeyCodeEx &key, ParameterType par);
protected:
TargetClass &rTarget;
@ -305,7 +306,7 @@ template <class TargetClass, class ParameterType> class C4KeyCBExPassKey : publi
ParameterType par;
protected:
virtual bool OnKeyEvent(C4KeyCodeEx key, C4KeyEventType eEv)
virtual bool OnKeyEvent(const C4KeyCodeEx &key, C4KeyEventType eEv)
{
if (!CheckCondition()) return false;
switch (eEv)
@ -356,9 +357,9 @@ class C4CustomKey
int iRef;
public:
C4CustomKey(C4KeyCodeEx DefCode, const char *szName, C4KeyScope Scope, C4KeyboardCallbackInterface *pCallback, unsigned int uiPriority = PRIO_Base); // ctor for default key
C4CustomKey(const C4KeyCodeEx &DefCode, const char *szName, C4KeyScope Scope, C4KeyboardCallbackInterface *pCallback, unsigned int uiPriority = PRIO_Base); // ctor for default key
C4CustomKey(const CodeList &rDefCodes, const char *szName, C4KeyScope Scope, C4KeyboardCallbackInterface *pCallback, unsigned int uiPriority = PRIO_Base); // ctor for default key with multiple possible keys assigned
C4CustomKey(C4KeyCodeEx Code, const StdStrBuf &rName); // ctor for single custom key override
C4CustomKey(const C4KeyCodeEx &Code, const StdStrBuf &rName); // ctor for single custom key override
C4CustomKey(const C4CustomKey &rCpy, bool fCopyCallbacks);
virtual ~C4CustomKey(); // dtor
@ -382,7 +383,7 @@ class C4CustomKey
class C4KeyBinding : protected C4CustomKey
{
public:
C4KeyBinding(C4KeyCodeEx DefCode, const char *szName, C4KeyScope Scope, C4KeyboardCallbackInterface *pCallback, unsigned int uiPriority = PRIO_Base); // ctor for default key
C4KeyBinding(const C4KeyCodeEx &DefCode, const char *szName, C4KeyScope Scope, C4KeyboardCallbackInterface *pCallback, unsigned int uiPriority = PRIO_Base); // ctor for default key
C4KeyBinding(const CodeList &rDefCodes, const char *szName, C4KeyScope Scope, C4KeyboardCallbackInterface *pCallback, unsigned int uiPriority = PRIO_Base); // ctor for default key
~C4KeyBinding();
};

View File

@ -46,10 +46,10 @@ class C4ChatInputDialog : public C4GUI::InputDialog
private:
bool KeyHistoryUpDown(bool fUp);
bool KeyCompleteNick(); // complete nick at cursor pos of edit
bool KeyPlrControl(C4KeyCodeEx key);
bool KeyGamepadControlDown(C4KeyCodeEx key);
bool KeyGamepadControlUp(C4KeyCodeEx key);
bool KeyGamepadControlPressed(C4KeyCodeEx key);
bool KeyPlrControl(const C4KeyCodeEx &key);
bool KeyGamepadControlDown(const C4KeyCodeEx &key);
bool KeyGamepadControlUp(const C4KeyCodeEx &key);
bool KeyGamepadControlPressed(const C4KeyCodeEx &key);
bool KeyBackspaceClose(); // close if chat text box is empty (on backspace)
protected:

View File

@ -220,7 +220,6 @@ class C4Object
C4Object *ComposeContents(C4ID id);
BOOL MenuCommand(const char *szCommand);
BOOL CallControl(C4Player *pPlr, BYTE byCom, C4AulParSet *pPars = 0);
C4Value Call(const char *szFunctionCall, C4AulParSet *pPars = 0, bool fPassError = false);
@ -338,9 +337,6 @@ class C4Object
const char *GetName();
void SetName (const char *NewName = 0);
int32_t GetValue(C4Object *pInBase, int32_t iForPlayer);
void DirectCom(BYTE byCom, int32_t iData);
void AutoStopDirectCom(BYTE byCom, int32_t iData);
void AutoStopUpdateComDir();
BOOL BuyEnergy();
void AutoSellContents();
BOOL SetOwner(int32_t iOwner);

View File

@ -24,6 +24,7 @@
#include <C4ObjectInfoList.h>
#include <C4InfoCore.h>
#include <C4ObjectList.h>
#include <C4PlayerControl.h>
const int32_t C4PVM_Cursor = 0,
C4PVM_Target = 1,
@ -70,7 +71,7 @@ class C4Player: public C4PlayerInfoCore
int32_t Team; // team ID - may be 0 for no teams
int32_t Color; // OldGfx color index
uint32_t ColorDw; // color as DWord for newgfx
int32_t Control;
int32_t ControlSet;
int32_t MouseControl;
int32_t Position;
int32_t PlrStartIndex;
@ -112,13 +113,10 @@ class C4Player: public C4PlayerInfoCore
C4IDList Knowledge;
C4IDList Magic;
// Control
C4PlayerControl Control;
C4Object *Cursor, *ViewCursor;
int32_t SelectCount;
int32_t SelectFlash,CursorFlash;
int32_t LastCom;
int32_t LastComDelay;
int32_t LastComDownDouble;
int32_t PressedComs;
int32_t CursorSelection,CursorToggled;
class C4GamePadOpener *pGamepad;
// Message
@ -169,9 +167,6 @@ class C4Player: public C4PlayerInfoCore
void CursorToggle();
void SelectAllCrew();
void UpdateSelectionToggleStatus();
void DirectCom(BYTE byCom, int32_t iData);
void InCom(BYTE byCom, int32_t iData);
BOOL ObjectCom(BYTE byCom, int32_t iData);
BOOL ObjectCommand(int32_t iCommand, C4Object *pTarget, int32_t iTx, int32_t iTy, C4Object *pTarget2=NULL, int32_t iData=0, int32_t iAddMode=C4P_Command_Set);
void ObjectCommand2Obj(C4Object *cObj, int32_t iCommand, C4Object *pTarget, int32_t iX, int32_t iY, C4Object *pTarget2, int32_t iData, int32_t iMode);
BOOL DoPoints(int32_t iChange);

View File

@ -60,6 +60,8 @@ class C4PlayerControlDef
bool IsHoldKey() const { return fIsHoldKey; }
C4ID GetExtraData() const { return idControlExtraData; }
bool IsGlobal() const { return fGlobal; }
int32_t GetRepeatDelay() const { return iRepeatDelay; }
int32_t GetInitialRepeatDelay() const { return iInitialRepeatDelay; }
//C4PlayerControlDef &operator =(const C4PlayerControlDef &src);
bool operator ==(const C4PlayerControlDef &cmp) const;
@ -80,6 +82,15 @@ class C4PlayerControlDefs
typedef std::vector<C4PlayerControlDef> DefVecImpl;
DefVecImpl Defs;
public:
struct CInternalCons
{
int32_t CON_MenuSelect, CON_MenuEnterAll, CON_MenuEnter, CON_MenuClose;
CInternalCons() : CON_MenuSelect(CON_None), CON_MenuEnterAll(CON_None), CON_MenuEnter(CON_None), CON_MenuClose(CON_None) {}
} InternalCons;
void UpdateInternalCons();
public:
C4PlayerControlDefs() {}
~C4PlayerControlDefs() {}
@ -88,12 +99,25 @@ class C4PlayerControlDefs
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);
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(); }
bool operator ==(const C4PlayerControlDefs &cmp) const { return Defs == cmp.Defs; }
};
struct C4PlayerControlRecentKey
{
C4KeyCodeEx Key;
DWORD tTime;
C4PlayerControlRecentKey(const C4KeyCodeEx &Key, DWORD tTime) : Key(Key), tTime(tTime) {}
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;
typedef std::vector<C4KeyCodeEx> C4KeyCodeExVec;
// a key/mouse/gamepad assignment to a PlayerControlDef
class C4PlayerControlAssignment
{
@ -140,6 +164,7 @@ class C4PlayerControlAssignment
void CompileFunc(StdCompiler *pComp);
bool ResolveRefs(class C4PlayerControlAssignmentSet *pParentSet, C4PlayerControlDefs *pControlDefs); // resolve references between assignments
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; }
@ -148,19 +173,13 @@ class C4PlayerControlAssignment
bool IsRefsResolved() const { return fRefsResolved; }
bool IsAlwaysUnhandled() const { return iTriggerMode & CTM_AlwaysUnhandled; }
int32_t GetTriggerMode() const { return iTriggerMode; }
const C4KeyCodeEx &GetTriggerKey() const { return TriggerKey; }
bool HasCombo() const { return KeyCombo.size()>1; }
};
typedef std::vector<C4PlayerControlAssignment> C4PlayerControlAssignmentVec;
typedef std::vector<const C4PlayerControlAssignment *> C4PlayerControlAssignmentPVec;
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
@ -181,7 +200,8 @@ class C4PlayerControlAssignmentSet
const char *GetName() const { return sName.getData(); }
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
void GetAssignmentsByKey(const C4PlayerControlDefs &rDefs, const C4KeyCodeEx &key, bool fHoldKeysOnly, C4PlayerControlAssignmentPVec *pOutVec, const C4PlayerControlRecentKeyList &DownKeys, const C4PlayerControlRecentKeyList &RecentKeys) const; // match only by TriggerKey (last key of Combo) if fHoldKeysOnly
void GetTriggerKeys(const C4PlayerControlDefs &rDefs, C4KeyCodeExVec *pRegularKeys, C4KeyCodeExVec *pHoldKeys) const; // put all trigger keys of keyset into output vectors
bool operator ==(const C4PlayerControlAssignmentSet &cmp) const;
};
@ -225,6 +245,9 @@ class C4PlayerControlFile
// runtime information about a player's control
class C4PlayerControl
{
public:
enum { MaxRecentKeyLookback = 3000, MaxSequenceKeyDelay = 800 }; // milliseconds: Time to press key combos
private:
C4PlayerControlDefs &ControlDefs; // shortcut
@ -232,8 +255,9 @@ class C4PlayerControl
int32_t iPlr;
// async values
C4PlayerControlAssignmentSet *pControlSet; // the control set used by this player
std::list<C4KeyBinding *> KeyBindings; // keys registered into Game.KeyboardInput
C4PlayerControlAssignmentSet *pControlSet; // the control set used by this player - may be NULL if the player cannot be controlled!
typedef std::list<C4CustomKey *> KeyBindingList;
KeyBindingList KeyBindings; // keys registered into Game.KeyboardInput
C4PlayerControlRecentKeyList RecentKeys; // keys pressed recently; for combinations
C4PlayerControlRecentKeyList DownKeys; // keys currently held down
@ -247,8 +271,13 @@ class C4PlayerControl
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) {}
bool IsDown() const { return DownState.iStrength>0; }
ControlDownState() : DownState(), iDownFrame(0), fDownByUser(false) {}
void CompileFunc(StdCompiler *pComp);
bool operator ==(const ControlDownState &cmp) const;
};
typedef std::vector<int32_t> DownStateVec;
typedef std::vector<ControlDownState> 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.
@ -259,6 +288,7 @@ class C4PlayerControl
void SetControlDownState(int32_t iControl, const C4KeyEventData &rDownState, int32_t iDownFrame, bool fDownByUser);
void SetControlDisabled(int32_t iControl, int32_t iVal);
void Clear();
void CompileFunc(StdCompiler *pComp);
bool operator ==(const CSync &cmp) const;
} Sync;
@ -273,8 +303,8 @@ class C4PlayerControl
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();
// init
void AddKeyBinding(const C4KeyCodeEx &key, bool fHoldKey, int32_t idx);
public:
C4PlayerControl();
@ -288,7 +318,10 @@ class C4PlayerControl
bool IsGlobal() const { return iPlr==-1; }
// callback from control queue
void ExecuteControlPacket(const class C4ControlPlayerControl2 *pCtrl);
void ExecuteControlPacket(const class C4ControlPlayerControl *pCtrl);
// sync execution: Do keyrepeat, etc.
void Execute();
};

View File

@ -171,7 +171,7 @@ class C4StartupOptionsDlg : public C4StartupDlg
int32_t iCtrlSet;
protected:
bool KeyDown(C4KeyCodeEx key);
bool KeyDown(const C4KeyCodeEx &key);
public:
KeySelDialog(int32_t iKeyID, int32_t iCtrlSet, bool fGamepad);
virtual ~KeySelDialog();

View File

@ -355,31 +355,10 @@ void C4ControlPlayerSelect::CompileFunc(StdCompiler *pComp)
C4ControlPacket::CompileFunc(pComp);
}
// *** C4ControlPlayerControl
void C4ControlPlayerControl::Execute() const
{
C4Player *pPlr=Game.Players.Get(iPlr);
if(pPlr)
{
if (!Inside<int>(iCom, COM_ReleaseFirst, COM_ReleaseLast))
pPlr->CountControl(C4Player::PCID_DirectCom, iCom*10000+iData);
pPlr->InCom(iCom, iData);
}
}
void C4ControlPlayerControl::CompileFunc(StdCompiler *pComp)
{
pComp->Value(mkNamingAdapt(mkIntPackAdapt(iPlr), "Player", -1));
pComp->Value(mkNamingAdapt(mkIntPackAdapt(iCom), "Com", 0));
pComp->Value(mkNamingAdapt(mkIntPackAdapt(iData), "Data", 0));
C4ControlPacket::CompileFunc(pComp);
}
// *** C4ControlPlayerControl2
void C4ControlPlayerControl2::Execute() const
{
C4PlayerControl *pTargetCtrl = NULL;
if (iPlr == -1)
@ -392,20 +371,20 @@ void C4ControlPlayerControl2::Execute() const
C4Player *pPlr=Game.Players.Get(iPlr);
if (pPlr)
{
//pPlr->CountControl(C4Player::PCID_DirectCom, iCom*10000+iData);
pTargetCtrl = &(pPlr->Control);
}
}
if (pTargetCtrl) pTargetCtrl->ExecuteControlPacket(this);
}
void C4ControlPlayerControl2::ControlItem::CompileFunc(StdCompiler *pComp)
void C4ControlPlayerControl::ControlItem::CompileFunc(StdCompiler *pComp)
{
pComp->Value(iControl);
pComp->Seperator();
pComp->Value(iTriggerMode);
}
void C4ControlPlayerControl2::CompileFunc(StdCompiler *pComp)
void C4ControlPlayerControl::CompileFunc(StdCompiler *pComp)
{
pComp->Value(mkNamingAdapt(mkIntPackAdapt(iPlr), "Player", -1));
pComp->Value(mkNamingAdapt(fRelease, "Release", false));

View File

@ -3161,37 +3161,6 @@ bool C4Game::InitKeyboard()
KeyboardInput.RegisterKey(new C4CustomKey(C4KeyCodeEx(KEY_Default ), "NetAllowJoinToggle", KEYSCOPE_Generic, new C4KeyCB <C4Network2> (Network, &C4Network2::ToggleAllowJoin)));
KeyboardInput.RegisterKey(new C4CustomKey(C4KeyCodeEx(KEY_Default ), "NetStatsToggle", KEYSCOPE_Generic, new C4KeyCB <C4GraphicsSystem>(GraphicsSystem, &C4GraphicsSystem::ToggleShowNetStatus)));
// Map player keyboard controls
int32_t iKdbSet,iCtrl;
StdStrBuf sPlrCtrlName;
for (iKdbSet=C4P_Control_Keyboard1; iKdbSet<=C4P_Control_Keyboard4; iKdbSet++)
for (iCtrl=0; iCtrl<C4MaxKey; iCtrl++)
{
sPlrCtrlName.Format("Kbd%dKey%d", iKdbSet-C4P_Control_Keyboard1+1, iCtrl+1);
KeyboardInput.RegisterKey(new C4CustomKey(
C4KeyCodeEx(Config.Controls.Keyboard[iKdbSet][iCtrl]),
sPlrCtrlName.getData(), KEYSCOPE_Control,
new C4KeyCBExPassKey<C4Game, C4KeySetCtrl>(*this, C4KeySetCtrl(iKdbSet, iCtrl), &C4Game::LocalControlKey, &C4Game::LocalControlKeyUp),
C4CustomKey::PRIO_PlrControl));
}
// Map player gamepad controls
int32_t iGamepad;
for (iGamepad=C4P_Control_GamePad1; iGamepad<=C4P_Control_GamePad1+C4ConfigMaxGamepads; iGamepad++)
{
C4ConfigGamepad &cfg = Config.Gamepads[iGamepad-C4P_Control_GamePad1];
for (iCtrl=0; iCtrl<C4MaxKey; iCtrl++)
{
if (cfg.Button[iCtrl] == -1) continue;
sPlrCtrlName.Format("Joy%dBtn%d", iGamepad-C4P_Control_GamePad1+1, iCtrl+1);
KeyboardInput.RegisterKey(new C4CustomKey(
C4KeyCodeEx(cfg.Button[iCtrl]),
sPlrCtrlName.getData(), KEYSCOPE_Control,
new C4KeyCBExPassKey<C4Game, C4KeySetCtrl>(*this, C4KeySetCtrl(iGamepad, iCtrl), &C4Game::LocalControlKey, &C4Game::LocalControlKeyUp),
C4CustomKey::PRIO_PlrControl));
}
}
// load any custom keysboard overloads
KeyboardInput.LoadCustomConfig();
@ -3297,71 +3266,6 @@ void C4Game::FixRandom(int32_t iSeed)
Randomize3();
}
bool C4Game::LocalControlKey(C4KeyCodeEx key, C4KeySetCtrl Ctrl)
{
// keyboard callback: Perform local player control
C4Player *pPlr;
if (pPlr = Players.GetLocalByKbdSet(Ctrl.iKeySet))
{
// Swallow a event generated from Keyrepeat for AutoStopControl
if (pPlr->PrefControlStyle)
{
if (key.IsRepeated())
return true;
}
LocalPlayerControl(pPlr->Number,Control2Com(Ctrl.iCtrl, false));
return true;
}
// not processed - must return false here, so unused keyboard control sets do not block used ones
return false;
}
bool C4Game::LocalControlKeyUp(C4KeyCodeEx key, C4KeySetCtrl Ctrl)
{
// Direct callback for released key in AutoStopControl-mode (ignore repeated)
if (key.IsRepeated())
return true;
C4Player *pPlr;
if ((pPlr = Players.GetLocalByKbdSet(Ctrl.iKeySet)) && pPlr->PrefControlStyle)
{
int iCom = Control2Com(Ctrl.iCtrl, true);
if (iCom != COM_None) LocalPlayerControl(pPlr->Number, iCom);
return true;
}
// not processed - must return false here, so unused keyboard control sets do not block used ones
return false;
}
void C4Game::LocalPlayerControl(int32_t iPlayer, int32_t iCom)
{
C4Player *pPlr = Players.Get(iPlayer); if (!pPlr) return;
int32_t iData=0;
// Menu button com
if (iCom==COM_PlayerMenu)
{
// Player menu open: close
if (pPlr->Menu.IsActive())
pPlr->Menu.Close(false);
// Menu closed: open main menu
else
pPlr->ActivateMenuMain();
return;
}
// Local player menu active: convert menu com and control local
if (pPlr->Menu.ConvertCom(iCom,iData,true))
{
pPlr->Menu.Control(iCom,iData);
return;
}
// Pre-queue asynchronous menu conversions
if (pPlr->Cursor && pPlr->Cursor->Menu)
pPlr->Cursor->Menu->ConvertCom(iCom,iData,true);
// Not for eliminated (checked again in DirectCom, but make sure no control is generated for eliminated players!)
if (pPlr->Eliminated) return;
// Player control: add to control queue
Input.Add(CID_PlrControl, new C4ControlPlayerControl(iPlayer,iCom,iData));
}
BOOL C4Game::DefinitionFilenamesFromSaveGame()
{
const char *pSource;

View File

@ -515,7 +515,7 @@ void C4GraphicsSystem::SortViewportsByPlayerControl()
pPlr1 = Game.Players.Get(pView->Player);
pPlr2 = Game.Players.Get(pNext->Player);
// Swap order
if (pPlr1 && pPlr2 && ( LayoutOrder(pPlr1->Control) > LayoutOrder(pPlr2->Control) ))
if (pPlr1 && pPlr2 && ( LayoutOrder(pPlr1->ControlSet) > LayoutOrder(pPlr2->ControlSet) ))
{
if (pPrev) pPrev->Next = pNext; else FirstViewport = pNext;
pView->Next = pNext->Next;

View File

@ -593,7 +593,7 @@ BOOL Dialog::CharIn(const char * c)
return FALSE;
}
bool Dialog::KeyHotkey(C4KeyCodeEx key)
bool Dialog::KeyHotkey(const C4KeyCodeEx &key)
{
WORD wKey = WORD(key.Key);
// do hotkey procs for standard alphanumerics only

View File

@ -396,7 +396,7 @@ bool Edit::KeyEnter()
return true;
}
bool Edit::KeyCursorOp(C4KeyCodeEx key, CursorOperation op)
bool Edit::KeyCursorOp(const C4KeyCodeEx &key, CursorOperation op)
{
bool fShift = !!(key.dwShift & KEYS_Shift);
bool fCtrl = !!(key.dwShift & KEYS_Control);

View File

@ -296,7 +296,8 @@ bool ContextMenu::KeyConfirm()
DoOK();
return true;
}
bool ContextMenu::KeyHotkey(C4KeyCodeEx key)
bool ContextMenu::KeyHotkey(const C4KeyCodeEx &key)
{
// not if focus is in submenu
if (pSubmenu) return false;

View File

@ -511,7 +511,7 @@ bool C4KeyEventData::operator ==(const struct C4KeyEventData &cmp) const
/* ----------------- C4CustomKey------------------ */
C4CustomKey::C4CustomKey(C4KeyCodeEx DefCode, const char *szName, C4KeyScope Scope, C4KeyboardCallbackInterface *pCallback, unsigned int uiPriority)
C4CustomKey::C4CustomKey(const C4KeyCodeEx &DefCode, const char *szName, C4KeyScope Scope, C4KeyboardCallbackInterface *pCallback, unsigned int uiPriority)
: Scope(Scope), Name(), uiPriority(uiPriority), iRef(0)
{
// generate code
@ -539,7 +539,7 @@ C4CustomKey::C4CustomKey(const CodeList &rDefCodes, const char *szName, C4KeySco
}
}
C4CustomKey::C4CustomKey(C4KeyCodeEx Code, const StdStrBuf &rName)
C4CustomKey::C4CustomKey(const C4KeyCodeEx &Code, const StdStrBuf &rName)
: Codes(), DefaultCodes(), Scope(KEYSCOPE_None), Name(), uiPriority(PRIO_None), iRef(0)
{
// ctor for custom key override
@ -620,7 +620,7 @@ bool C4CustomKey::Execute(C4KeyEventType eEv, C4KeyCodeEx key)
/* ----------------- C4KeyBinding ------------------ */
C4KeyBinding::C4KeyBinding(C4KeyCodeEx DefCode, const char *szName, C4KeyScope Scope, C4KeyboardCallbackInterface *pCallback, unsigned int uiPriority)
C4KeyBinding::C4KeyBinding(const C4KeyCodeEx &DefCode, const char *szName, C4KeyScope Scope, C4KeyboardCallbackInterface *pCallback, unsigned int uiPriority)
: C4CustomKey(DefCode, szName, Scope, pCallback, uiPriority)
{
// self holds a ref
@ -764,6 +764,9 @@ void C4KeyboardInput::UnregisterKeyBinding(C4CustomKey *pUnregKey)
bool C4KeyboardInput::DoInput(const C4KeyCodeEx &InKey, C4KeyEventType InEvent, DWORD InScope)
{
// store last-key-info
LastKeyExtraData.iStrength = (InEvent != KEYEV_Up) * 100;
LastKeyExtraData.x = LastKeyExtraData.y = 0;
// check all key events generated by this key: First the keycode itself, then any more generic key events like KEY_Any
const int32_t iKeyRangeMax = 5;
int32_t iKeyRangeCnt=0, j;

View File

@ -177,7 +177,7 @@ bool C4ChatInputDialog::KeyHistoryUpDown(bool fUp)
return true;
}
bool C4ChatInputDialog::KeyPlrControl(C4KeyCodeEx key)
bool C4ChatInputDialog::KeyPlrControl(const C4KeyCodeEx &key)
{
// Control pressed while doing this key: Reroute this key as a player-control
Game.DoKeyboardInput(WORD(key.Key), KEYEV_Down, !!(key.dwShift & KEYS_Alt), false, !!(key.dwShift & KEYS_Shift), key.IsRepeated(), NULL, true);
@ -185,7 +185,7 @@ bool C4ChatInputDialog::KeyPlrControl(C4KeyCodeEx key)
return true;
}
bool C4ChatInputDialog::KeyGamepadControlDown(C4KeyCodeEx key)
bool C4ChatInputDialog::KeyGamepadControlDown(const C4KeyCodeEx &key)
{
// filter gamepad control
if (!Key_IsGamepad(key.Key)) return false;
@ -194,7 +194,7 @@ bool C4ChatInputDialog::KeyGamepadControlDown(C4KeyCodeEx key)
return true;
}
bool C4ChatInputDialog::KeyGamepadControlUp(C4KeyCodeEx key)
bool C4ChatInputDialog::KeyGamepadControlUp(const C4KeyCodeEx &key)
{
// filter gamepad control
if (!Key_IsGamepad(key.Key)) return false;
@ -203,7 +203,7 @@ bool C4ChatInputDialog::KeyGamepadControlUp(C4KeyCodeEx key)
return true;
}
bool C4ChatInputDialog::KeyGamepadControlPressed(C4KeyCodeEx key)
bool C4ChatInputDialog::KeyGamepadControlPressed(const C4KeyCodeEx &key)
{
// filter gamepad control
if (!Key_IsGamepad(key.Key)) return false;

View File

@ -1064,8 +1064,9 @@ void C4MouseControl::Wheel(DWORD dwFlags)
// Ctrl + Wheel: pass to player control (might be used for inventory or such)
else
{
if(iDelta > 0) Game.LocalPlayerControl(Player, COM_WheelUp);
if(iDelta < 0) Game.LocalPlayerControl(Player, COM_WheelDown);
// 2do
//if(iDelta > 0) Game.LocalPlayerControl(Player, COM_WheelUp);
//if(iDelta < 0) Game.LocalPlayerControl(Player, COM_WheelDown);
}
}

View File

@ -3181,499 +3181,6 @@ void C4Object::Clear()
while (FirstRef) FirstRef->Set(0);
}
BOOL C4Object::ContainedControl(BYTE byCom)
{
// Check
if (!Contained) return FALSE;
// Check if object is about to exit; if so, return
// dunno, maybe I should check all the commands, not just the first one?
if ((byCom == COM_Left || byCom == COM_Right) && Command)
if (Command->Command == C4CMD_Exit)
// hack: in structures only; not in vehicles
// they might have a pending Exit-command due to a down-control
if (Contained->Category & C4D_Structure)
return FALSE; // or TRUE? Currently it doesn't matter.
// get script function if defined
C4AulFunc* sf = Contained->Def->Script.GetSFunc(FormatString(PSF_ContainedControl,ComName(byCom)).getData());
// in old versions, do hardcoded actions first (until gwe3)
// new objects may overload them
C4Def *pCDef = Contained->Def;
bool fCallSfEarly = CompareVersion(pCDef->rC4XVer[0],pCDef->rC4XVer[1],pCDef->rC4XVer[2],pCDef->rC4XVer[3],4,9,1,3) >= 0;
bool result = false;
C4Player * pPlr = Game.Players.Get(Controller);
if(fCallSfEarly)
{
if (sf && !!sf->Exec(Contained, &C4AulParSet(C4VObj(this)))) result = true;
// AutoStopControl: Also notify container about controlupdate
// Note Contained may be nulled now due to ContainedControl call
if(Contained && !(byCom & (COM_Single | COM_Double)) && pPlr->PrefControlStyle)
{
int32_t PressedComs = pPlr->PressedComs;
C4AulParSet set(C4VObj(this),
C4VInt(Coms2ComDir(PressedComs)),
C4VBool(!!(PressedComs & (1 << COM_Dig))),
C4VBool(!!(PressedComs & (1 << COM_Throw))));
Contained->Call(PSF_ContainedControlUpdate, &set);
}
}
if(result) return true;
// hardcoded actions
switch (byCom)
{
case COM_Down:
PlayerObjectCommand(Owner,C4CMD_Exit);
break;
case COM_Throw:
PlayerObjectCommand(Owner,C4CMD_Throw);
break;
case COM_Up:
if (ValidPlr(Contained->Base))
if (!Hostile(Owner,Contained->Base))
if (Game.C4S.Game.Realism.BaseFunctionality & BASEFUNC_Buy)
ActivateMenu(C4MN_Buy);
break;
case COM_Dig:
if (ValidPlr(Contained->Base))
if (!Hostile(Owner,Contained->Base))
if (Game.C4S.Game.Realism.BaseFunctionality & BASEFUNC_Sell)
ActivateMenu(C4MN_Sell);
break;
}
// Call container script if defined for old versions
if (!fCallSfEarly)
{
if(sf) sf->Exec(Contained, &C4AulParSet(C4VObj(this)));
if(Contained && !(byCom & (COM_Single | COM_Double)) && pPlr->PrefControlStyle)
{
int32_t PressedComs = pPlr->PressedComs;
C4AulParSet set(C4VObj(this),
C4VInt(Coms2ComDir(PressedComs)),
C4VBool(!!(PressedComs & (1 << COM_Dig))),
C4VBool(!!(PressedComs & (1 << COM_Throw))));
Contained->Call(PSF_ContainedControlUpdate, &set);
}
}
// Take/Take2
if(!sf || fCallSfEarly) switch (byCom)
{
case COM_Left:
PlayerObjectCommand(Owner,C4CMD_Take);
break;
case COM_Right:
PlayerObjectCommand(Owner,C4CMD_Take2);
break;
}
// Success
return TRUE;
}
BOOL C4Object::CallControl(C4Player *pPlr, BYTE byCom, C4AulParSet *pPars)
{
assert(pPlr);
bool result = !!Call(FormatString(PSF_Control,ComName(byCom)).getData(),pPars);
// Call ControlUpdate when using Jump'n'Run control
if(pPlr->PrefControlStyle)
{
int32_t PressedComs = pPlr->PressedComs;
C4AulParSet set(pPars ? pPars->Par[0] : C4VObj(this),
C4VInt(Coms2ComDir(PressedComs)),
C4VBool(!!(PressedComs & (1 << COM_Dig))),
C4VBool(!!(PressedComs & (1 << COM_Throw))),
C4VBool(!!(PressedComs & (1 << COM_Special))),
C4VBool(!!(PressedComs & (1 << COM_Special2))));
Call(PSF_ControlUpdate, &set);
}
return result;
}
void C4Object::DirectCom(BYTE byCom, int32_t iData) // By player ObjectCom
{
#ifdef DEBUGREC_OBJCOM
C4RCObjectCom rc = { byCom, iData, Number };
AddDbgRec(RCT_ObjCom, &rc, sizeof(C4RCObjectCom));
#endif
// COM_Special and COM_Contents specifically bypass the menu and always go to the object
bool fBypassMenu = ((byCom == COM_Special) || (byCom == COM_Contents));
// Menu control
if (!fBypassMenu)
if (Menu && Menu->Control(byCom,iData)) return;
// Ignore any menu com leftover in control queue from closed menu
if (Inside(byCom,COM_MenuNavigation1,COM_MenuNavigation2)) return;
// Wether this is a KeyRelease-event
bool IsRelease = Inside(byCom, COM_ReleaseFirst, COM_ReleaseLast);
// Decrease NoCollectDelay
if (!(byCom & COM_Single) && !(byCom & COM_Double) && !IsRelease)
if (NoCollectDelay>0)
NoCollectDelay--;
// COM_Contents contents shift (data is target number (not ID!))
// contents shift must always be done to container object, which is not necessarily this
if (byCom==COM_Contents)
{
C4Object *pTarget = Game.Objects.SafeObjectPointer(iData);
if (pTarget && pTarget->Contained)
pTarget->Contained->DirectComContents(pTarget, true);
return;
}
// Contained control (except specials - hey, doesn't catch singles or doubles)
if (Contained)
if (byCom!=COM_Special && byCom!=COM_Special2 && byCom!=COM_WheelUp && byCom!=COM_WheelDown)
{ ContainedControl(byCom); return; }
// Regular DirectCom clears commands
if (!(byCom & COM_Single) && !(byCom & COM_Double) && !IsRelease)
ClearCommands();
// Object script override
C4Player *pController;
if (pController = Game.Players.Get(Controller))
if (CallControl(pController, byCom))
return;
// direct wheel control
if (byCom==COM_WheelUp || byCom==COM_WheelDown)
// scroll contents
{ ShiftContents(byCom==COM_WheelUp, TRUE); return; }
// The Player updates Controller before calling this, so trust Players.Get will return it
if (pController && pController->PrefControlStyle)
{
AutoStopDirectCom(byCom, iData);
return;
}
// Control by procedure
switch (GetProcedure())
{
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
case DFA_WALK:
switch (byCom)
{
case COM_Left: ObjectComMovement(this,COMD_Left); break;
case COM_Right: ObjectComMovement(this,COMD_Right); break;
case COM_Down: ObjectComMovement(this,COMD_Stop); break;
case COM_Up: ObjectComUp(this); break;
case COM_Down_D: ObjectComDownDouble(this); break;
case COM_Dig_S:
if (ObjectComDig(this))
{
Action.ComDir = (Action.Dir==DIR_Right) ? COMD_DownRight : COMD_DownLeft;
}
break;
case COM_Dig_D: ObjectComDigDouble(this); break;
case COM_Throw: PlayerObjectCommand(Owner,C4CMD_Throw); break;
}
break;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
case DFA_FLIGHT: case DFA_KNEEL: case DFA_THROW:
switch (byCom)
{
case COM_Left: ObjectComMovement(this,COMD_Left); break;
case COM_Right: ObjectComMovement(this,COMD_Right); break;
case COM_Down: ObjectComMovement(this,COMD_Stop); break;
case COM_Throw: PlayerObjectCommand(Owner,C4CMD_Throw); break;
}
break;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
case DFA_SCALE:
switch (byCom)
{
case COM_Left:
if (Action.Dir==DIR_Left) ObjectComMovement(this,COMD_Stop);
else { ObjectComMovement(this,COMD_Left); ObjectComLetGo(this,-1); }
break;
case COM_Right:
if (Action.Dir==DIR_Right) ObjectComMovement(this,COMD_Stop);
else { ObjectComMovement(this,COMD_Right); ObjectComLetGo(this,+1); }
break;
case COM_Up: ObjectComMovement(this,COMD_Up); break;
case COM_Down: ObjectComMovement(this,COMD_Down); break;
case COM_Throw: PlayerObjectCommand(Owner,C4CMD_Drop); break;
}
break;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
case DFA_HANGLE:
switch (byCom)
{
case COM_Left: ObjectComMovement(this,COMD_Left); break;
case COM_Right: ObjectComMovement(this,COMD_Right); break;
case COM_Up: ObjectComMovement(this,COMD_Stop); break;
case COM_Down: ObjectComLetGo(this,0); break;
case COM_Throw: PlayerObjectCommand(Owner,C4CMD_Drop); break;
}
break;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
case DFA_DIG:
switch (byCom)
{
case COM_Left: if (Inside<int32_t>(Action.ComDir,COMD_UpRight,COMD_Left)) Action.ComDir++; break;
case COM_Right: if (Inside<int32_t>(Action.ComDir,COMD_Right,COMD_UpLeft)) Action.ComDir--; break;
case COM_Down: ObjectComStop(this); break;
case COM_Dig_D: ObjectComDigDouble(this); break;
case COM_Dig_S: Action.Data = (!Action.Data); break; // Dig mat 2 object request
}
break;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
case DFA_SWIM:
switch (byCom)
{
case COM_Left: ObjectComMovement(this,COMD_Left); break;
case COM_Right: ObjectComMovement(this,COMD_Right); break;
case COM_Up:
ObjectComMovement(this,COMD_Up);
ObjectComUp(this); break;
case COM_Down: ObjectComMovement(this,COMD_Down); break;
case COM_Throw: PlayerObjectCommand(Owner,C4CMD_Drop); break;
case COM_Dig_D: ObjectComDigDouble(this); break;
}
break;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
case DFA_BRIDGE: case DFA_BUILD: case DFA_CHOP:
switch (byCom)
{
case COM_Down: ObjectComStop(this); break;
}
break;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
case DFA_FIGHT:
switch (byCom)
{
case COM_Left: ObjectComMovement(this,COMD_Left); break;
case COM_Right: ObjectComMovement(this,COMD_Right); break;
case COM_Down: ObjectComStop(this); break;
}
break;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
case DFA_PUSH:
{
bool fGrabControlOverload = false;
if(Action.Target)
{
// New grab-control model: objects version 4.95 or higher (CE)
// may overload control of grabbing clonks
C4Def *pTDef = Action.Target->Def;
if(CompareVersion(pTDef->rC4XVer[0],pTDef->rC4XVer[1],pTDef->rC4XVer[2],pTDef->rC4XVer[3],4,9,5,0) >= 0)
fGrabControlOverload = true;
}
// Call object control first in case it overloads
if (fGrabControlOverload)
if (Action.Target)
if (Action.Target->CallControl(pController, byCom, &C4AulParSet(C4VObj(this))))
return;
// Clonk direct control
switch (byCom)
{
case COM_Left: ObjectComMovement(this,COMD_Left); break;
case COM_Right: ObjectComMovement(this,COMD_Right); break;
case COM_Up:
// Target -> enter
if (ObjectComEnter(Action.Target))
ObjectComMovement(this,COMD_Stop);
// Else, comdir up for target straightening
else
ObjectComMovement(this,COMD_Up);
break;
case COM_Down: ObjectComMovement(this,COMD_Stop); break;
case COM_Down_D: ObjectComUnGrab(this); break;
case COM_Throw: PlayerObjectCommand(Owner,C4CMD_Throw); break;
}
// Action target call control late for old objects
if (!fGrabControlOverload)
if (Action.Target)
Action.Target->CallControl(pController, byCom, &C4AulParSet(C4VObj(this)));
break;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
}
}
void C4Object::AutoStopDirectCom(BYTE byCom, int32_t iData) // By DirecCom
{
C4Player * pPlayer = Game.Players.Get(Controller);
// Control by procedure
switch (GetProcedure())
{
case DFA_WALK:
switch (byCom)
{
case COM_Up: ObjectComUp(this); break;
case COM_Down:
// inhibit controldownsingle on freshly grabbed objects
if (ObjectComDownDouble(this))
pPlayer->LastCom = COM_None;
break;
case COM_Dig_S: ObjectComDig(this); break;
case COM_Dig_D: ObjectComDigDouble(this); break;
case COM_Throw: PlayerObjectCommand(Owner,C4CMD_Throw); break;
default: AutoStopUpdateComDir();
}
break;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
case DFA_FLIGHT:
switch (byCom)
{
case COM_Throw:
// Drop when pressing left, right or down
if (pPlayer->PressedComs & ((1<<COM_Left)|(1<<COM_Right)|(1<<COM_Down)))
PlayerObjectCommand(Owner,C4CMD_Drop);
else
// This will fail, but whatever.
PlayerObjectCommand(Owner,C4CMD_Throw);
break;
default: AutoStopUpdateComDir();
}
break;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
case DFA_KNEEL: case DFA_THROW:
switch (byCom)
{
case COM_Throw: PlayerObjectCommand(Owner,C4CMD_Throw); break;
default: AutoStopUpdateComDir();
}
break;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
case DFA_SCALE:
switch (byCom)
{
case COM_Left:
if (Action.Dir == DIR_Right) ObjectComLetGo(this,-1);
else AutoStopUpdateComDir();
break;
case COM_Right:
if (Action.Dir == DIR_Left) ObjectComLetGo(this,+1);
else AutoStopUpdateComDir();
break;
case COM_Dig: ObjectComLetGo(this,(Action.Dir == DIR_Left) ? +1 : -1);
case COM_Throw: PlayerObjectCommand(Owner,C4CMD_Drop); break;
default: AutoStopUpdateComDir();
}
break;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
case DFA_HANGLE:
switch (byCom)
{
case COM_Down: ObjectComLetGo(this,0); break;
case COM_Dig: ObjectComLetGo(this,0); break;
case COM_Throw: PlayerObjectCommand(Owner,C4CMD_Drop); break;
default: AutoStopUpdateComDir();
}
break;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
case DFA_DIG:
switch (byCom)
{
// Dig mat 2 object request
case COM_Throw: case COM_Dig: Action.Data = (!Action.Data); break;
default: AutoStopUpdateComDir();
}
break;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
case DFA_SWIM:
switch (byCom)
{
case COM_Up:
AutoStopUpdateComDir();
ObjectComUp(this);
break;
case COM_Throw: PlayerObjectCommand(Owner,C4CMD_Drop); break;
case COM_Dig_D: ObjectComDigDouble(this); break;
default: AutoStopUpdateComDir();
}
break;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
case DFA_BRIDGE: case DFA_BUILD: case DFA_CHOP:
switch (byCom)
{
case COM_Down: ObjectComStop(this); break;
}
break;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
case DFA_FIGHT:
switch (byCom)
{
case COM_Down: ObjectComStop(this); break;
default: AutoStopUpdateComDir();
}
break;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
case DFA_PUSH:
{
bool fGrabControlOverload = false;
if(Action.Target)
{
// New grab-control model: objects version 4.95 or higher (CE)
// may overload control of grabbing clonks
C4Def *pTDef = Action.Target->Def;
if(CompareVersion(pTDef->rC4XVer[0],pTDef->rC4XVer[1],pTDef->rC4XVer[2],pTDef->rC4XVer[3],4,9,5,0) >= 0)
fGrabControlOverload = true;
// Call object control first in case it overloads
if (fGrabControlOverload)
{
if (Action.Target->CallControl(pPlayer, byCom, &C4AulParSet(C4VObj(this))))
{
return;
}
}
}
// Clonk direct control
switch (byCom)
{
case COM_Up:
// Target -> enter
if (ObjectComEnter(Action.Target))
ObjectComMovement(this,COMD_Stop);
// Else, comdir up for target straightening
else
AutoStopUpdateComDir();
break;
case COM_Down:
// FIXME: replace constants
// ComOrder(3) is COM_Down, ComOrder(11) is COM_Down_S and ComOrder(19) is COM_Down_D
if(Action.Target
&& !DrawCommandQuery(Controller, Action.Target->Def->Script, Action.Target->Def->Script.ControlMethod, 3)
&& !DrawCommandQuery(Controller, Action.Target->Def->Script, Action.Target->Def->Script.ControlMethod, 11)
&& !DrawCommandQuery(Controller, Action.Target->Def->Script, Action.Target->Def->Script.ControlMethod, 19))
{
ObjectComUnGrab(this);
}
break;
case COM_Down_D: ObjectComUnGrab(this); break;
case COM_Throw: PlayerObjectCommand(Owner,C4CMD_Drop); break;
default:
AutoStopUpdateComDir();
}
// Action target call control late for old objects
if (!fGrabControlOverload && Action.Target)
Action.Target->CallControl(pPlayer, byCom, &C4AulParSet(C4VObj(this)));
break;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
}
}
void C4Object::AutoStopUpdateComDir()
{
C4Player * pPlr = Game.Players.Get(Controller);
if (!pPlr || pPlr->Cursor != this) return;
int32_t NewComDir = Coms2ComDir(pPlr->PressedComs);
if (Action.ComDir == NewComDir) return;
if (NewComDir == COMD_Stop && GetProcedure() == DFA_DIG)
{
ObjectComStop(this);
return;
}
ObjectComMovement(this, NewComDir);
}
BOOL C4Object::MenuCommand(const char *szCommand)
{
// Native script execution

View File

@ -607,10 +607,10 @@ BOOL ObjectComPut(C4Object *cObj, C4Object *pTarget, C4Object *pThing)
if (pTarget!=cObj->Contained)
if (!(pTarget->Def->GrabPutGet & C4D_Grab_Put))
{
// Was meant to be a drop anyway
if (ValidPlr(cObj->Owner))
if (Game.Players.Get(cObj->Owner)->LastComDownDouble)
return ObjectComDrop(cObj, pThing);
// Was meant to be a drop anyway - probably obsolete as controls are being revised
//if (ValidPlr(cObj->Owner))
// if (Game.Players.Get(cObj->Owner)->LastComDownDouble)
// return ObjectComDrop(cObj, pThing);
// No grab put: fail
return FALSE;
}
@ -1009,8 +1009,8 @@ BOOL PlayerObjectCommand(int32_t plr, int32_t cmdf, C4Object *pTarget, int32_t t
if (cmdf==C4CMD_Throw)
{
bool fConvertToDrop = false;
// Drop on down-down-throw (classic)
if (pPlr->LastComDownDouble)
// Drop on down-down-throw (classic) - obsolete?
/*if (pPlr->LastComDownDouble)
{
fConvertToDrop = true;
// Dropping one object automatically reenables LastComDownDouble to
@ -1021,7 +1021,7 @@ BOOL PlayerObjectCommand(int32_t plr, int32_t cmdf, C4Object *pTarget, int32_t t
pPlr->LastComDownDouble = C4DoubleClick;
}
// Jump'n'Run: Drop on combined Down/Left/Right+Throw
if (pPlr->PrefControlStyle && (pPlr->PressedComs & (1 << COM_Down))) fConvertToDrop = true;
if (pPlr->PrefControlStyle && (pPlr->PressedComs & (1 << COM_Down))) fConvertToDrop = true;*/
if (fConvertToDrop) return pPlr->ObjectCommand(C4CMD_Drop,pTarget,tx,ty,NULL,0,iAddMode);
}
// Route to player

View File

@ -434,20 +434,20 @@ void C4ObjectMenu::Execute()
void C4ObjectMenu::OnUserSelectItem(int32_t Player, int32_t iIndex)
{
// queue....
Game.Input.Add(CID_PlrControl, new C4ControlPlayerControl(Player,COM_MenuSelect,iIndex | C4MN_AdjustPosition));
// queue.... 2do
Game.Input.Add(CID_PlrControl, new C4ControlPlayerControl(Player,Game.PlayerControlDefs.InternalCons.CON_MenuSelect,iIndex | C4MN_AdjustPosition));
}
void C4ObjectMenu::OnUserEnter(int32_t Player, int32_t iIndex, bool fRight)
{
// object menu: Through queue
Game.Input.Add(CID_PlrControl, new C4ControlPlayerControl(Player,fRight ? COM_MenuEnterAll : COM_MenuEnter,iIndex));
// object menu: Through queue 2do
Game.Input.Add(CID_PlrControl, new C4ControlPlayerControl(Player,fRight ? Game.PlayerControlDefs.InternalCons.CON_MenuEnterAll : Game.PlayerControlDefs.InternalCons.CON_MenuEnter,iIndex));
}
void C4ObjectMenu::OnUserClose()
{
// Queue
Game.Input.Add(CID_PlrControl, new C4ControlPlayerControl(Game.MouseControl.GetPlayer(),COM_MenuClose,0));
// Queue 2do
Game.Input.Add(CID_PlrControl, new C4ControlPlayerControl(Game.MouseControl.GetPlayer(),Game.PlayerControlDefs.InternalCons.CON_MenuClose,0));
}
bool C4ObjectMenu::IsReadOnly()

View File

@ -113,7 +113,7 @@ const C4PktHandlingData PktHandlingData[] =
{ CID_JoinPlr, PC_Control, "Join Player", false, true, 0, PKT_UNPACK(C4ControlJoinPlayer) },
{ CID_RemovePlr, PC_Control, "Remove Player", false, true, 0, PKT_UNPACK(C4ControlRemovePlr) },
{ CID_PlrSelect, PC_Control, "Player Select", false, true, 0, PKT_UNPACK(C4ControlPlayerSelect)},
{ CID_PlrControl, PC_Control, "Player Control", false, true, 0, PKT_UNPACK(C4ControlPlayerControl)},
{ CID_PlrControl, PC_Control, "Player Control", false, true, 0, PKT_UNPACK(C4ControlPlayerControl)},
{ CID_PlrCommand, PC_Control, "Player Command", false, true, 0, PKT_UNPACK(C4ControlPlayerCommand)},
{ CID_Message, PC_Control, "Message", false, true, 0, PKT_UNPACK(C4ControlMessage) },
{ CID_EMMoveObj, PC_Control, "EM Move Obj", false, true, 0, PKT_UNPACK(C4ControlEMMoveObject)},

View File

@ -1081,7 +1081,6 @@ void C4Player::Default()
ControlCount = ActionCount = 0;
LastControlType = PCID_None;
LastControlID = 0;
PressedComs = 0;
pMsgBoardQuery = NULL;
pGamepad = NULL;
NoEliminationCheck = false;
@ -1209,26 +1208,7 @@ BOOL C4Player::MakeCrewMember(C4Object *pObj, bool fForceInfo, bool fDoCalls)
void C4Player::ExecuteControl()
{
// LastCom
if (LastCom != COM_None)
{
// Advance delay counter
LastComDelay++;
// Check for COM_Single com (after delay)
if (LastComDelay > C4DoubleClick)
{
// Pass additional COM_Single com (unless it already was a single com in the first place)
if (!(LastCom & COM_Single))
DirectCom(LastCom | COM_Single, 0); // Currently, com data is not stored for single coms...
LastCom = COM_None;
LastComDelay = 0;
}
}
// LastComDownDouble
if (LastComDownDouble>0) LastComDownDouble--;
Control.Execute();
}
void C4Player::AdjustCursorCommand()
@ -1375,30 +1355,6 @@ void C4Player::UpdateSelectionToggleStatus()
CursorToggled=0;
}
BOOL C4Player::ObjectCom(BYTE byCom, int32_t iData) // By DirectCom
{
if (Eliminated) return FALSE;
#ifdef DEBUGREC_OBJCOM
C4RCObjectCom rc = { byCom, iData, Number };
AddDbgRec(RCT_PlrCom, &rc, sizeof(C4RCObjectCom));
#endif
// Hide startup
ShowStartup=FALSE;
// If regular com, update cursor & selection status
if (!(byCom & COM_Single) && !(byCom & COM_Double) && (byCom < COM_ReleaseFirst || byCom > COM_ReleaseLast))
UpdateSelectionToggleStatus();
// Apply direct com to cursor object
if (Cursor)
{
// update controller
Cursor->Controller = Number;
// send com
Cursor->DirectCom(byCom,iData);
}
// Done
return TRUE;
}
BOOL C4Player::ObjectCommand(int32_t iCommand, C4Object *pTarget, int32_t iX, int32_t iY, C4Object *pTarget2, int32_t iData, int32_t iMode)
{
// Eliminated
@ -1455,71 +1411,6 @@ void C4Player::ObjectCommand2Obj(C4Object *cObj, int32_t iCommand, C4Object *pTa
else if (iMode & C4P_Command_Set) cObj->SetCommand(iCommand,pTarget,iX,iY,pTarget2,TRUE,iData);
}
void C4Player::DirectCom(BYTE byCom, int32_t iData) // By InCom or ExecuteControl
{
switch (byCom)
{
case COM_CursorLeft: CursorLeft(); break;
case COM_CursorRight: CursorRight(); break;
case COM_CursorToggle: CursorToggle(); break;
case COM_CursorToggle_D: SelectAllCrew(); break;
default: ObjectCom(byCom,iData); break;
}
}
void C4Player::InCom(BYTE byCom, int32_t iData)
{
#ifdef DEBUGREC_OBJCOM
C4RCObjectCom rc = { byCom, iData, Number };
AddDbgRec(RCT_PlrInCom, &rc, sizeof(C4RCObjectCom));
#endif
// Cursor object menu active: convert regular com to menu com
if (Cursor) if (Cursor->Menu)
{
int32_t iCom = byCom;
Cursor->Menu->ConvertCom(iCom,iData, false);
byCom = iCom;
}
// Menu control: no single/double processing
if (Inside(byCom,COM_MenuFirst,COM_MenuLast))
{ DirectCom(byCom,iData); return; }
// Ignore KeyRelease for Single/Double
if (!Inside(byCom, COM_ReleaseFirst, COM_ReleaseLast))
{
// Reset view
ResetCursorView();
// Update state
if (Inside<int>(byCom, COM_ReleaseFirst - 16, COM_ReleaseLast - 16))
PressedComs |= 1 << byCom;
// Check LastCom buffer for prior COM_Single
if (LastCom!=COM_None)
if (LastCom!=byCom)
{
DirectCom(LastCom | COM_Single,iData);
// AutoStopControl uses a single COM_Down instead of DOM_Down_D for drop
// So a COM_Down_S does what a COM_Down_D normally does, if generated by another key
// instead of a timeout
if (PrefControlStyle && LastCom == COM_Down) LastComDownDouble = C4DoubleClick;
}
// Check LastCom buffer for COM_Double
if (LastCom==byCom) byCom|=COM_Double;
// LastCom/Del process
// this is set before issuing the DirectCom, so DirectCom-scripts may delete it
LastCom=byCom; LastComDelay=0;
}
else
{
// Update state
if (Inside(byCom, COM_ReleaseFirst, COM_ReleaseLast))
PressedComs &= ~(1 << (byCom - 16));
}
// Pass regular/COM_Double byCom to player
DirectCom(byCom,iData);
// LastComDownDouble process
if (byCom == COM_Down_D) LastComDownDouble = C4DoubleClick;
}
void C4Player::CompileFunc(StdCompiler *pComp)
{
assert(ID);
@ -1534,7 +1425,7 @@ void C4Player::CompileFunc(StdCompiler *pComp)
pComp->Value(mkNamingAdapt(Evaluated, "Evaluated", false));
pComp->Value(mkNamingAdapt(Color, "Color", -1));
pComp->Value(mkNamingAdapt(ColorDw, "ColorDw", 0u));
pComp->Value(mkNamingAdapt(Control, "Control", 0));
pComp->Value(mkNamingAdapt(ControlSet, "Control", 0));
pComp->Value(mkNamingAdapt(MouseControl, "MouseControl", 0));
pComp->Value(mkNamingAdapt(Position, "Position", 0));
pComp->Value(mkNamingAdapt(ViewMode, "ViewMode", C4PVM_Cursor));
@ -1563,10 +1454,6 @@ void C4Player::CompileFunc(StdCompiler *pComp)
pComp->Value(mkNamingAdapt((int32_t&)Cursor, "Cursor", 0));
pComp->Value(mkNamingAdapt((int32_t&)ViewCursor,"ViewCursor", 0));
pComp->Value(mkNamingAdapt((int32_t&)Captain, "Captain", 0));
pComp->Value(mkNamingAdapt(LastCom, "LastCom", 0));
pComp->Value(mkNamingAdapt(LastComDelay, "LastComDel", 0));
pComp->Value(mkNamingAdapt(PressedComs, "PressedComs", 0));
pComp->Value(mkNamingAdapt(LastComDownDouble, "LastComDownDouble", 0));
pComp->Value(mkNamingAdapt(CursorSelection, "CursorSelection", 0));
pComp->Value(mkNamingAdapt(CursorToggled, "CursorToggled", 0));
pComp->Value(mkNamingAdapt(MessageStatus, "MessageStatus", 0));
@ -1672,7 +1559,7 @@ void C4Player::DefaultRuntimeData()
AtClient=C4ClientIDUnknown;
SCopy("Local",AtClientName);
Color=-1;
Control=C4P_Control_None;
ControlSet=C4P_Control_None;
MouseControl=FALSE;
Position=-1;
PlrStartIndex=0;
@ -1694,9 +1581,6 @@ void C4Player::DefaultRuntimeData()
Cursor=ViewCursor=NULL;
SelectCount=0;
SelectFlash=CursorFlash=30;
LastCom=0;
LastComDelay=0;
LastComDownDouble=0;
CursorSelection=CursorToggled=0;
MessageStatus=0;
MessageBuf[0]=0;
@ -1836,7 +1720,7 @@ void C4Player::InitControl()
if (!GetInfo() || GetInfo()->GetType() == C4PT_User)
LocalControl=TRUE;
// Set control
Control=C4P_Control_None;
ControlSet=C4P_Control_None;
// Preferred control
int32_t iControl = PrefControl;
// gamepad control safety
@ -1848,32 +1732,35 @@ void C4Player::InitControl()
if (Game.Players.ControlTaken(iControl))
{
// Preferred control taken, search for available keyboard control
for (iControl=C4P_Control_Keyboard1; iControl<=C4P_Control_Keyboard4; iControl++)
for (iControl=C4P_Control_Keyboard1; iControl<=C4P_Control_Keyboard2; iControl++)
if (!Game.Players.ControlTaken(iControl)) // Available control found
break;
// No available control found
if (iControl>C4P_Control_Keyboard4)
if (iControl>C4P_Control_Keyboard2)
iControl=C4P_Control_None;
}
// Set control
Control=iControl;
ControlSet=iControl;
// init gamepad
if (pGamepad) { delete pGamepad; pGamepad=NULL; }
if (Inside<int32_t>(Control, C4P_Control_GamePad1, C4P_Control_GamePadMax))
if (Inside<int32_t>(ControlSet, C4P_Control_GamePad1, C4P_Control_GamePadMax))
{
pGamepad = new C4GamePadOpener(Control - C4P_Control_GamePad1);
pGamepad = new C4GamePadOpener(ControlSet - C4P_Control_GamePad1);
}
// Mouse
if (PrefMouse && !Game.Control.isReplay())
if (!Game.C4S.Head.DisableMouse)
if (Inside<int32_t>(Control, C4P_Control_Keyboard1, C4P_Control_GamePadMax))
if (Inside<int32_t>(ControlSet, C4P_Control_Keyboard1, C4P_Control_GamePadMax))
if (!Game.Players.MouseControlTaken())
MouseControl=TRUE;
// no controls issued yet
ControlCount = ActionCount = 0;
LastControlType = PCID_None;
LastControlID = 0;
PressedComs = 0;
// init control callbacks
StdStrBuf sKeysetName;
sKeysetName.Format("Keyboard%d%s", ControlSet, PrefControlStyle ? "" : "Classic");
Control.RegisterKeyset(Number, Game.PlayerControlAssignmentSets.GetSetByName(sKeysetName.getData()));
}
int igOffX, igOffY;

View File

@ -66,14 +66,24 @@ bool C4PlayerControlDef::operator ==(const C4PlayerControlDef &cmp) const
/* C4PlayerControlDefs */
void C4PlayerControlDefs::UpdateInternalCons()
{
InternalCons.CON_MenuSelect = GetControlIndexByIdentifier("MenuSelect");
InternalCons.CON_MenuEnter = GetControlIndexByIdentifier("MenuEnter");
InternalCons.CON_MenuEnterAll = GetControlIndexByIdentifier("MenuEnterAll");
InternalCons.CON_MenuClose = GetControlIndexByIdentifier("MenuClose");
}
void C4PlayerControlDefs::Clear()
{
Defs.clear();
UpdateInternalCons();
}
void C4PlayerControlDefs::CompileFunc(StdCompiler *pComp)
{
pComp->Value(mkNamingAdapt(mkSTLContainerAdapt(Defs, StdCompiler::SEP_NONE), "ControlDefs", DefVecImpl()));
if (pComp->isCompiler()) UpdateInternalCons();
}
void C4PlayerControlDefs::MergeFrom(const C4PlayerControlDefs &Src)
@ -94,9 +104,10 @@ void C4PlayerControlDefs::MergeFrom(const C4PlayerControlDefs &Src)
Defs.push_back(SrcDef);
}
}
UpdateInternalCons();
}
C4PlayerControlDef *C4PlayerControlDefs::GetControlByIndex(int32_t idx)
const C4PlayerControlDef *C4PlayerControlDefs::GetControlByIndex(int32_t idx) const
{
// safe index
if (idx<0 || idx>=Defs.size()) return NULL;
@ -201,6 +212,49 @@ bool C4PlayerControlAssignment::ResolveRefs(C4PlayerControlAssignmentSet *pParen
return true;
}
bool C4PlayerControlAssignment::IsComboMatched(const C4PlayerControlRecentKeyList &DownKeys, const C4PlayerControlRecentKeyList &RecentKeys) const
{
assert(HasCombo());
// check if combo is currently fulfilled (assuming TriggerKey is already matched)
if (fComboIsSequence)
{
DWORD tKeyLast = timeGetTime();
// combo is a sequence: The last keys of RecentKeys must match the sequence
// the last ComboKey is the TriggerKey, which is omitted because it has already been matched and is not to be found in RecentKeys yet
C4PlayerControlRecentKeyList::const_reverse_iterator ri = RecentKeys.rbegin();
for (KeyComboVec::const_reverse_iterator i = KeyCombo.rbegin()+1; i!=KeyCombo.rend(); ++i,++ri)
{
// no more keys pressed but combo didn't end? -> no combo match
if (ri == RecentKeys.rend()) return false;
const C4PlayerControlRecentKey &rk = *ri;
// user waited for too long?
DWORD tKeyRecent = rk.tTime;
if (tKeyLast - tKeyRecent > C4PlayerControl::MaxSequenceKeyDelay) return false;
// key doesn't match?
const KeyComboItem &k = *i;
if (!(rk.Key == k.Key)) return false;
// key OK
}
}
else
{
// combo requires keys to be down simultanuously: check that all keys of the combo are in the down-list
for (KeyComboVec::const_iterator i = KeyCombo.begin(); i!=KeyCombo.end(); ++i)
{
const KeyComboItem &k = *i;
bool fFound = false;
for (C4PlayerControlRecentKeyList::const_iterator di = DownKeys.begin(); di!=DownKeys.end(); ++di)
{
const C4PlayerControlRecentKey &dk = *di;
if (dk.Key == k.Key) { fFound = true; break; }
}
if (!fFound) return false;
}
}
// combo OK!
return true;
}
bool C4PlayerControlAssignment::operator ==(const C4PlayerControlAssignment &cmp) const
{
// doesn't compare resolved TriggerKey/iControl
@ -267,6 +321,63 @@ bool C4PlayerControlAssignmentSet::operator ==(const C4PlayerControlAssignmentSe
&& sName == cmp.sName;
}
void C4PlayerControlAssignmentSet::GetAssignmentsByKey(const C4PlayerControlDefs &rDefs, const C4KeyCodeEx &key, bool fHoldKeysOnly, C4PlayerControlAssignmentPVec *pOutVec, const C4PlayerControlRecentKeyList &DownKeys, const C4PlayerControlRecentKeyList &RecentKeys) const
{
assert(pOutVec);
// primary match by TriggerKey
for (C4PlayerControlAssignmentVec::const_iterator i = Assignments.begin(); i != Assignments.end(); ++i)
{
const C4PlayerControlAssignment &rAssignment = *i;
if (!(rAssignment.GetTriggerKey() == key)) continue;
// check linked control def
const C4PlayerControlDef *pCtrl = rDefs.GetControlByIndex(rAssignment.GetControl());
if (!pCtrl) continue;
// only want hold keys?
if (fHoldKeysOnly)
{
// a hold/release-trigger key is not a real hold key, even if the underlying control is
if (!pCtrl->IsHoldKey() || (rAssignment.GetTriggerMode() & (C4PlayerControlAssignment::CTM_Hold | C4PlayerControlAssignment::CTM_Release))) continue;
}
else if (rAssignment.HasCombo())
{
// hold-only events match the trigger key only (i.e., Release-events are generated as soon as the trigger key goes up)
// other events must match either the sequence or the down-key-combination
if (!rAssignment.IsComboMatched(DownKeys, RecentKeys)) continue;
}
// we got match! Store it
pOutVec->push_back(&rAssignment);
}
}
void C4PlayerControlAssignmentSet::GetTriggerKeys(const C4PlayerControlDefs &rDefs, C4KeyCodeExVec *pRegularKeys, C4KeyCodeExVec *pHoldKeys) const
{
// put all trigger keys of keyset into output vectors
// first all hold keys
for (C4PlayerControlAssignmentVec::const_iterator i = Assignments.begin(); i != Assignments.end(); ++i)
{
const C4PlayerControlAssignment &rAssignment = *i;
const C4PlayerControlDef *pDef = rDefs.GetControlByIndex(rAssignment.GetControl());
if (pDef && pDef->IsHoldKey())
{
const C4KeyCodeEx &rKey = rAssignment.GetTriggerKey();
if (std::find(pHoldKeys->begin(), pHoldKeys->end(), rKey) == pHoldKeys->end()) pHoldKeys->push_back(rKey);
}
}
// then all regular keys that aren't in the hold keys list yet
for (C4PlayerControlAssignmentVec::const_iterator i = Assignments.begin(); i != Assignments.end(); ++i)
{
const C4PlayerControlAssignment &rAssignment = *i;
const C4PlayerControlDef *pDef = rDefs.GetControlByIndex(rAssignment.GetControl());
if (pDef && !pDef->IsHoldKey())
{
const C4KeyCodeEx &rKey = rAssignment.GetTriggerKey();
if (std::find(pHoldKeys->begin(), pHoldKeys->end(), rKey) == pHoldKeys->end())
if (std::find(pRegularKeys->begin(), pRegularKeys->end(), rKey) == pRegularKeys->end())
pRegularKeys->push_back(rKey);
}
}
}
/* C4PlayerControlAssignmentSets */
@ -355,6 +466,67 @@ void C4PlayerControlFile::Clear()
/* C4PlayerControl */
void C4PlayerControl::CSync::ControlDownState::CompileFunc(StdCompiler *pComp)
{
pComp->Value(DownState);
pComp->Seperator();
pComp->Value(iDownFrame);
pComp->Seperator();
pComp->Value(fDownByUser);
}
bool C4PlayerControl::CSync::ControlDownState::operator ==(const ControlDownState &cmp) const
{
return DownState == cmp.DownState && iDownFrame == cmp.iDownFrame && fDownByUser == cmp.fDownByUser;
}
const C4PlayerControl::CSync::ControlDownState *C4PlayerControl::CSync::GetControlDownState(int32_t iControl) const
{
// safe access
if (iControl < 0 || iControl >= ControlDownStates.size()) return NULL;
return &ControlDownStates[iControl];
}
int32_t C4PlayerControl::CSync::GetControlDisabled(int32_t iControl) const
{
// safe access
if (iControl < 0 || iControl >= ControlDisableStates.size()) return 0;
return ControlDisableStates[iControl];
}
void C4PlayerControl::CSync::SetControlDownState(int32_t iControl, const C4KeyEventData &rDownState, int32_t iDownFrame, bool fDownByUser)
{
// update state
if (iControl < 0) return;
if (iControl >= ControlDownStates.size()) ControlDownStates.resize(iControl+1);
ControlDownState &rState = ControlDownStates[iControl];
rState.DownState = rDownState;
rState.iDownFrame = iDownFrame;
rState.fDownByUser = fDownByUser;
}
void C4PlayerControl::CSync::SetControlDisabled(int32_t iControl, int32_t iVal)
{
// disable control
if (iControl < 0) return;
if (iControl >= ControlDisableStates.size()) ControlDisableStates.resize(iControl+1);
ControlDisableStates[iControl] = iVal;
// if a control is disabled, its down-state is reset silently
const ControlDownState *pDownState = GetControlDownState(iControl);
if (pDownState && pDownState->IsDown())
{
C4KeyEventData KeyDownState = pDownState->DownState;
KeyDownState.iStrength = 0;
SetControlDownState(iControl, KeyDownState, 0, false);
}
}
void C4PlayerControl::CSync::Clear()
{
ControlDownStates.clear();
ControlDisableStates.clear();
}
void C4PlayerControl::CSync::CompileFunc(StdCompiler *pComp)
{
pComp->Value(mkNamingAdapt(mkSTLContainerAdapt(ControlDownStates), "Down", DownStateVec()));
@ -376,20 +548,22 @@ void C4PlayerControl::CompileFunc(StdCompiler *pComp)
bool C4PlayerControl::ProcessKeyEvent(const C4KeyCodeEx &key, bool fUp, const C4KeyEventData &rKeyExtraData)
{
// collect all matching keys
C4PlayerControlAssignmentVec Matches;
pControlSet->GetAssignmentsByKey(key, fUp, &Matches, DownKeys, RecentKeys);
C4PlayerControlAssignmentPVec Matches;
assert(pControlSet); // shouldn't get this callback for players without control set
pControlSet->GetAssignmentsByKey(ControlDefs, key, fUp, &Matches, DownKeys, RecentKeys);
// process async controls
C4ControlPlayerControl2 *pControlPacket = NULL;
for (C4PlayerControlAssignmentVec::const_iterator i = Matches.begin(); i != Matches.end(); ++i)
C4ControlPlayerControl *pControlPacket = NULL;
for (C4PlayerControlAssignmentPVec::const_iterator i = Matches.begin(); i != Matches.end(); ++i)
{
const C4PlayerControlAssignment &rAssignment = *i;
int32_t iControlIndex = rAssignment.GetControl();
C4PlayerControlDef *pControlDef = ControlDefs.GetControlByIndex(iControlIndex);
const C4PlayerControlAssignment *pAssignment = *i;
assert(pAssignment);
int32_t iControlIndex = pAssignment->GetControl();
const 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()))
if (ExecuteControl(iControlIndex, fUp, rKeyExtraData, pAssignment->GetTriggerMode(), key.IsRepeated()))
return true;
}
else
@ -399,24 +573,31 @@ bool C4PlayerControl::ProcessKeyEvent(const C4KeyCodeEx &key, bool fUp, const C4
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());
if (!pControlPacket) pControlPacket = new C4ControlPlayerControl(iPlr, fUp, rKeyExtraData);
pControlPacket->AddControl(iControlIndex, pAssignment->GetTriggerMode());
break;
}
}
}
// push sync control to input
if (pControlPacket) Game.Input.Add(CID_PlrControl2, pControlPacket);
if (pControlPacket)
{
Game.Input.Add(CID_PlrControl2, pControlPacket);
// assume processed (although we can't really know that yet)
return true;
}
return false;
}
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));
C4PlayerControlRecentKey RKey(key,timeGetTime());
if (std::find(DownKeys.begin(), DownKeys.end(), C4PlayerControlRecentKey(key,0)) == DownKeys.end()) DownKeys.push_back(RKey);
// 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));
if (!key.IsRepeated()) RecentKeys.push_back(RKey);
return fResult;
}
@ -429,14 +610,14 @@ bool C4PlayerControl::ProcessKeyUp(const C4KeyCodeEx &key)
return ProcessKeyEvent(key, true, Game.KeyboardInput.GetLastKeyExtraData());
}
void C4PlayerControl::ExecuteControlPacket(const class C4ControlPlayerControl2 *pCtrl)
void C4PlayerControl::ExecuteControlPacket(const class C4ControlPlayerControl *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)
for (C4ControlPlayerControl::ControlItemVec::const_iterator i = pCtrl->GetControlItems().begin(); i != pCtrl->GetControlItems().end(); ++i)
{
const C4ControlPlayerControl2::ControlItem &rItem = *i;
C4PlayerControlDef *pCtrlDef = ControlDefs.GetControlByIndex(rItem.iControl);
const C4ControlPlayerControl::ControlItem &rItem = *i;
const C4PlayerControlDef *pCtrlDef = ControlDefs.GetControlByIndex(rItem.iControl);
if (pCtrlDef)
{
if (ExecuteControl(rItem.iControl, pCtrl->IsReleaseControl(), pCtrl->GetExtraData(), rItem.iTriggerMode, false))
@ -449,10 +630,12 @@ void C4PlayerControl::ExecuteControlPacket(const class C4ControlPlayerControl2 *
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);
const C4PlayerControlDef *pControlDef = ControlDefs.GetControlByIndex(iControl);
if (!pControlDef || Sync.IsControlDisabled(iControl)) return false;
C4PlayerControlDef::Actions eAction = pControlDef->GetAction();
C4KeyEventData KeyExtraData(rKeyExtraData);
const CSync::ControlDownState *pCtrlDownState = Sync.GetControlDownState(iControl);
bool fWasDown = pCtrlDownState ? pCtrlDownState->IsDown() : false;
// global controls only in global context
if (IsGlobal() != pControlDef->IsGlobal()) return false;
// hold-actions only work on script controls with the hold flag
@ -462,9 +645,6 @@ bool C4PlayerControl::ExecuteControl(int32_t iControl, bool fUp, const C4KeyEven
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?
@ -479,6 +659,7 @@ bool C4PlayerControl::ExecuteControl(int32_t iControl, bool fUp, const C4KeyEven
else //if (iTriggerMode & C4PlayerControlAssignment::CTM_Hold) - must be true
{
// control is down but trigger key is pressed again: Refresh down state
// (this will restart the KeyRepeat time)
Sync.SetControlDownState(iControl, KeyExtraData, Game.FrameCounter, false);
// now process as a regular, repeated "down" event
fRepeated = true;
@ -503,10 +684,14 @@ bool C4PlayerControl::ExecuteControl(int32_t iControl, bool fUp, const C4KeyEven
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;
Sync.SetControlDownState(iControl, KeyExtraData, Game.FrameCounter, true);
}
else if (pControlDef->IsHoldKey())
{
// regular ControlDown on Hold Key: Set in down list
Sync.SetControlDownState(iControl, KeyExtraData, Game.FrameCounter, true);
fRepeated = fWasDown;
}
// perform action for this control
bool fHandled = ExecuteControlAction(iControl, eAction, pControlDef->GetExtraData(), fUp, KeyExtraData, fRepeated);
@ -546,6 +731,19 @@ bool C4PlayerControl::ExecuteControlAction(int32_t iControl, C4PlayerControlDef:
bool C4PlayerControl::ExecuteControlScript(int32_t iControl, C4ID idControlExtraData, bool fUp, const C4KeyEventData &rKeyExtraData, bool fRepeated)
{
C4Player *pPlr = Game.Players.Get(iPlr);
if (pPlr)
{
// Not for eliminated (checked again in DirectCom, but make sure no control is generated for eliminated players!)
if (pPlr->Eliminated) return false;
// control count for statistics
pPlr->CountControl(C4Player::PCID_DirectCom, iControl*2+fUp);
}
else if (iPlr > -1)
{
// player lost?
return false;
}
if (!fUp)
{
// control down
@ -567,7 +765,39 @@ bool C4PlayerControl::ExecuteControlScript(int32_t iControl, C4ID idControlExtra
void C4PlayerControl::Execute()
{
// sync execution: Do keyrepeat, etc.
// sync execution: Do keyrepeat
for (int32_t i=0; i<ControlDefs.GetCount(); ++i)
{
const CSync::ControlDownState *pControlDownState = Sync.GetControlDownState(i);
if (pControlDownState && pControlDownState->IsDown())
{
const C4PlayerControlDef *pCtrlDef = ControlDefs.GetControlByIndex(i);
assert(pCtrlDef);
int32_t iCtrlRepeatDelay = pCtrlDef->GetRepeatDelay();
if (iCtrlRepeatDelay)
{
int32_t iFrameDiff = Game.FrameCounter - pControlDownState->iDownFrame;
int32_t iCtrlInitialRepeatDelay = pCtrlDef->GetInitialRepeatDelay();
if (iFrameDiff && iFrameDiff >= iCtrlInitialRepeatDelay)
{
if (!((iFrameDiff-iCtrlInitialRepeatDelay) % iCtrlRepeatDelay))
{
// it's RepeatTime for this key!
ExecuteControlAction(i, pCtrlDef->GetAction(), pCtrlDef->GetExtraData(), false, pControlDownState->DownState, true);
}
}
}
}
}
// cleanup old recent keys
C4PlayerControlRecentKeyList::iterator irk;
DWORD tNow = timeGetTime();
for (irk = RecentKeys.begin(); irk != RecentKeys.end(); ++irk)
{
C4PlayerControlRecentKey &rk = *irk;
if (rk.tTime + MaxRecentKeyLookback > tNow) break;
}
if (irk != RecentKeys.begin()) RecentKeys.erase(RecentKeys.begin(), irk);
}
C4PlayerControl::C4PlayerControl() : ControlDefs(Game.PlayerControlDefs), iPlr(-1), pControlSet(NULL)
@ -576,10 +806,37 @@ C4PlayerControl::C4PlayerControl() : ControlDefs(Game.PlayerControlDefs), iPlr(-
void C4PlayerControl::Clear()
{
iPlr = NO_OWNER;
pControlSet = NULL;
for (KeyBindingList::iterator i = KeyBindings.begin(); i != KeyBindings.end(); ++i) delete *i;
KeyBindings.clear();
RecentKeys.clear();
DownKeys.clear();
Sync.Clear();
}
void C4PlayerControl::RegisterKeyset(int32_t iPlr, C4PlayerControlAssignmentSet *pKeyset)
{
// clear any previous settings
Clear();
// setup
pControlSet = pKeyset;
this->iPlr = iPlr;
// register all keys into Game.KeyboardInput creating KeyBindings
if (pControlSet)
{
C4KeyCodeExVec RegularKeys, HoldKeys;
pControlSet->GetTriggerKeys(ControlDefs, &RegularKeys, &HoldKeys);
int32_t idx=0;
for (C4KeyCodeExVec::const_iterator i = RegularKeys.begin(); i != RegularKeys.end(); ++i) AddKeyBinding(*i, false, idx++);
for (C4KeyCodeExVec::const_iterator i = HoldKeys.begin(); i != HoldKeys.end(); ++i) AddKeyBinding(*i, true, idx++);
}
}
void C4PlayerControl::AddKeyBinding(const C4KeyCodeEx &key, bool fHoldKey, int32_t idx)
{
KeyBindings.push_back(new C4CustomKey(
key, FormatString("PlrKey%02d", idx).getData(), KEYSCOPE_Control,
new C4KeyCBPassKey<C4PlayerControl>(*this, &C4PlayerControl::ProcessKeyDown, fHoldKey ? &C4PlayerControl::ProcessKeyUp : NULL),
C4CustomKey::PRIO_PlrControl));
}

View File

@ -141,7 +141,7 @@ int C4PlayerList::CheckColorDw(DWORD dwColor, C4Player *pExclude)
BOOL C4PlayerList::ControlTaken(int iControl) const
{
for (C4Player *pPlr=First; pPlr; pPlr=pPlr->Next)
if (pPlr->Control==iControl)
if (pPlr->ControlSet==iControl)
if (pPlr->LocalControl)
return TRUE;
return FALSE;
@ -185,7 +185,7 @@ C4Player* C4PlayerList::GetLocalByKbdSet(int iKbdSet) const
{
for (C4Player *pPlr=First; pPlr; pPlr=pPlr->Next)
if (pPlr->LocalControl)
if (pPlr->Control==iKbdSet)
if (pPlr->ControlSet==iKbdSet)
return pPlr;
return NULL;
}
@ -645,7 +645,7 @@ void C4PlayerList::DenumeratePointers()
int C4PlayerList::ControlTakenBy(int iControl) const
{
for (C4Player *pPlr=First; pPlr; pPlr=pPlr->Next)
if (pPlr->Control==iControl)
if (pPlr->ControlSet==iControl)
if (pPlr->LocalControl)
return pPlr->Number;
return NO_OWNER;

View File

@ -2692,24 +2692,6 @@ static bool FnDoHomebaseProduction(C4AulContext *cthr, long iPlr, C4ID id, long
return Game.Players.Get(iPlr)->HomeBaseProduction.SetIDCount(id,iLastcount+iChange,TRUE);
}
static long FnGetPlrDownDouble(C4AulContext *cthr, long iPlr)
{
if (!ValidPlr(iPlr)) return FALSE;
return Game.Players.Get(iPlr)->LastComDownDouble;
}
static bool FnClearLastPlrCom(C4AulContext *cthr, long iPlr)
{
// get player
C4Player *pPlr = Game.Players.Get(iPlr);
if (!pPlr) return FALSE;
// reset last coms
pPlr->LastCom = COM_None;
pPlr->LastComDownDouble = 0;
// done, success
return TRUE;
}
static bool FnSetPlrKnowledge(C4AulContext *cthr, long iPlr, C4ID id, bool fRemove)
{
C4Player *pPlr=Game.Players.Get(iPlr);
@ -6586,8 +6568,6 @@ void InitFunctionMap(C4AulScriptEngine *pEngine)
AddFunc(pEngine, "SetPlrView", FnSetPlrView);
AddFunc(pEngine, "SetPlrKnowledge", FnSetPlrKnowledge);
AddFunc(pEngine, "SetPlrMagic", FnSetPlrMagic);
AddFunc(pEngine, "GetPlrDownDouble", FnGetPlrDownDouble);
AddFunc(pEngine, "ClearLastPlrCom", FnClearLastPlrCom);
AddFunc(pEngine, "GetPlrViewMode", FnGetPlrViewMode);
AddFunc(pEngine, "GetPlrView", FnGetPlrView);
AddFunc(pEngine, "GetWealth", FnGetWealth);

View File

@ -170,7 +170,7 @@ C4StartupOptionsDlg::KeySelDialog::~KeySelDialog()
delete pKeyListener;
}
bool C4StartupOptionsDlg::KeySelDialog::KeyDown(C4KeyCodeEx key)
bool C4StartupOptionsDlg::KeySelDialog::KeyDown(const C4KeyCodeEx &key)
{
// check if key is valid for this set
// do not mix gamepad and keyboard keys

View File

@ -1407,10 +1407,10 @@ StdStrBuf PlrControlKeyName(int32_t iPlayer, int32_t iControl, bool fShort)
// player control
if (pPlr)
{
if (Inside<int32_t>(pPlr->Control,C4P_Control_Keyboard1,C4P_Control_Keyboard4))
return C4KeyCodeEx::KeyCode2String(Config.Controls.Keyboard[pPlr->Control][iControl], true, fShort);
if (Inside<int32_t>(pPlr->Control,C4P_Control_GamePad1,C4P_Control_GamePadMax))
return C4KeyCodeEx::KeyCode2String(Config.Gamepads[pPlr->Control-C4P_Control_GamePad1].Button[iControl], true, fShort);
if (Inside<int32_t>(pPlr->ControlSet,C4P_Control_Keyboard1,C4P_Control_Keyboard4))
return C4KeyCodeEx::KeyCode2String(Config.Controls.Keyboard[pPlr->ControlSet][iControl], true, fShort);
if (Inside<int32_t>(pPlr->ControlSet,C4P_Control_GamePad1,C4P_Control_GamePadMax))
return C4KeyCodeEx::KeyCode2String(Config.Gamepads[pPlr->ControlSet-C4P_Control_GamePad1].Button[iControl], true, fShort);
}
// global control
else
@ -1461,24 +1461,8 @@ void C4Viewport::DrawPlayerControls(C4TargetFacet &cgo)
ty = cgo.Y+15;
break;
}
int32_t iShowCtrl = Game.Players.Get(Player)->ShowControl;
int32_t iLastCtrl = Com2Control(Game.Players.Get(Player)->LastCom);
int32_t scwdt=size/3,schgt=size/4;
BOOL showtext;
const int32_t C4MaxShowControl = 10;
for (int32_t iCtrl=0; iCtrl<C4MaxShowControl; iCtrl++)
if (iShowCtrl & (1<<iCtrl))
{
showtext= iShowCtrl & (1<<(iCtrl+C4MaxShowControl)) ;
if (iShowCtrl & (1<<(iCtrl+2*C4MaxShowControl)))
if (Tick35>18) showtext=FALSE;
C4Facet ccgo;
ccgo.Set(cgo.Surface,tx+scwdt*(iCtrl%3),ty+schgt*(iCtrl/3),scwdt,schgt);
DrawControlKey(ccgo,iCtrl,(iLastCtrl==iCtrl) ? 1 : 0,
showtext ? PlrControlKeyName(Player,iCtrl,true).getData() : NULL);
}
// TODO
}
extern int32_t DrawMessageOffset;
@ -1496,20 +1480,20 @@ void C4Viewport::DrawPlayerStartup(C4TargetFacet &cgo)
cgo.X+(cgo.Wdt-GfxR->fctKeyboard.Wdt)/2+55,
cgo.Y+cgo.Hgt * 2/3 - 10 + DrawMessageOffset,
0,0);
if (Inside<int32_t>(pPlr->Control,C4P_Control_Keyboard1,C4P_Control_Keyboard4))
if (Inside<int32_t>(pPlr->ControlSet,C4P_Control_Keyboard1,C4P_Control_Keyboard4))
{
GfxR->fctKeyboard.Draw(cgo.Surface,
cgo.X+(cgo.Wdt-GfxR->fctKeyboard.Wdt)/2,
cgo.Y+cgo.Hgt * 2/3 + DrawMessageOffset,
pPlr->Control-C4P_Control_Keyboard1,0);
pPlr->ControlSet-C4P_Control_Keyboard1,0);
iNameHgtOff=GfxR->fctKeyboard.Hgt;
}
else if (Inside<int32_t>(pPlr->Control,C4P_Control_GamePad1,C4P_Control_GamePad4))
else if (Inside<int32_t>(pPlr->ControlSet,C4P_Control_GamePad1,C4P_Control_GamePad4))
{
GfxR->fctGamepad.Draw(cgo.Surface,
cgo.X+(cgo.Wdt-GfxR->fctKeyboard.Wdt)/2,
cgo.Y+cgo.Hgt * 2/3 + DrawMessageOffset,
pPlr->Control-C4P_Control_GamePad1,0);
pPlr->ControlSet-C4P_Control_GamePad1,0);
iNameHgtOff=GfxR->fctGamepad.Hgt;
}