2009-05-25 09:01:26 +00:00
/*
* OpenClonk , http : //www.openclonk.org
*
* Copyright ( c ) 2005 - 2009 , RedWolf Design GmbH , http : //www.clonk.de
*
* Portions might be copyrighted by other authors who have contributed
* to OpenClonk .
*
* Permission to use , copy , modify , and / or distribute this software for any
* purpose with or without fee is hereby granted , provided that the above
* copyright notice and this permission notice appear in all copies .
* See isc_license . txt for full license and disclaimer .
*
* " Clonk " is a registered trademark of Matthes Bender .
* See clonk_trademark_license . txt for full license .
*/
// Input to player control mapping
2009-12-17 13:06:24 +00:00
# include "C4Include.h"
# include "C4PlayerControl.h"
2009-05-25 09:01:26 +00:00
2009-12-17 13:06:24 +00:00
# include "C4LangStringTable.h"
# include "C4Player.h"
# include "C4PlayerList.h"
# include "C4Control.h"
# include "C4Game.h"
# include "C4Log.h"
# include "C4GraphicsResource.h"
# include "C4MouseControl.h"
2010-01-02 00:12:35 +00:00
# include "C4GraphicsSystem.h"
# include "C4Viewport.h"
2009-12-17 13:06:24 +00:00
# include <algorithm>
2009-05-25 09:01:26 +00:00
/* C4PlayerControlDef */
void C4PlayerControlDef : : CompileFunc ( StdCompiler * pComp )
{
2009-05-26 06:10:38 +00:00
if ( ! pComp - > Name ( " ControlDef " ) ) { pComp - > NameEnd ( ) ; pComp - > excNotFound ( " ControlDef " ) ; }
2009-05-25 09:01:26 +00:00
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 " , " " ) ) ;
2009-05-26 06:10:38 +00:00
pComp - > Value ( mkNamingAdapt ( fGlobal , " Global " , false ) ) ;
pComp - > Value ( mkNamingAdapt ( fIsHoldKey , " Hold " , false ) ) ;
pComp - > Value ( mkNamingAdapt ( iRepeatDelay , " RepeatDelay " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( iInitialRepeatDelay , " InitialRepeatDelay " , 0 ) ) ;
2009-05-25 09:01:26 +00:00
pComp - > Value ( mkNamingAdapt ( fDefaultDisabled , " DefaultDisabled " , false ) ) ;
2010-01-25 15:57:57 +00:00
pComp - > Value ( mkNamingAdapt ( idControlExtraData , " ExtraData " , C4ID : : None ) ) ;
2009-05-26 06:10:38 +00:00
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 } ,
2009-12-31 17:20:45 +00:00
{ " ZoomIn " , CDA_ZoomIn } ,
{ " ZoomOut " , CDA_ZoomOut } ,
2009-05-26 06:10:38 +00:00
{ NULL , CDA_None } } ;
pComp - > Value ( mkNamingAdapt ( mkEnumAdapt < Actions , int32_t > ( eAction , ActionNames ) , " Action " , CDA_Script ) ) ;
2009-05-25 09:01:26 +00:00
pComp - > NameEnd ( ) ;
}
bool C4PlayerControlDef : : operator = = ( const C4PlayerControlDef & cmp ) const
{
return sIdentifier = = cmp . sIdentifier
& & sGUIName = = cmp . sGUIName
& & sGUIDesc = = cmp . sGUIDesc
2009-05-26 06:10:38 +00:00
& & fGlobal = = cmp . fGlobal
2009-05-25 09:01:26 +00:00
& & fIsHoldKey = = cmp . fIsHoldKey
2009-05-26 06:10:38 +00:00
& & iRepeatDelay = = cmp . iRepeatDelay
& & iInitialRepeatDelay = = cmp . iInitialRepeatDelay
& & fDefaultDisabled = = cmp . fDefaultDisabled
& & idControlExtraData = = cmp . idControlExtraData
& & eAction = = cmp . eAction ;
2009-05-25 09:01:26 +00:00
}
/* C4PlayerControlDefs */
2009-05-28 00:14:54 +00:00
void C4PlayerControlDefs : : UpdateInternalCons ( )
{
InternalCons . CON_MenuSelect = GetControlIndexByIdentifier ( " MenuSelect " ) ;
InternalCons . CON_MenuEnter = GetControlIndexByIdentifier ( " MenuEnter " ) ;
InternalCons . CON_MenuEnterAll = GetControlIndexByIdentifier ( " MenuEnterAll " ) ;
InternalCons . CON_MenuClose = GetControlIndexByIdentifier ( " MenuClose " ) ;
}
2009-05-26 06:10:38 +00:00
void C4PlayerControlDefs : : Clear ( )
{
Defs . clear ( ) ;
2009-05-28 00:14:54 +00:00
UpdateInternalCons ( ) ;
2009-05-26 06:10:38 +00:00
}
2009-05-25 09:01:26 +00:00
void C4PlayerControlDefs : : CompileFunc ( StdCompiler * pComp )
{
pComp - > Value ( mkNamingAdapt ( mkSTLContainerAdapt ( Defs , StdCompiler : : SEP_NONE ) , " ControlDefs " , DefVecImpl ( ) ) ) ;
2009-05-28 00:14:54 +00:00
if ( pComp - > isCompiler ( ) ) UpdateInternalCons ( ) ;
2009-05-25 09:01:26 +00:00
}
void C4PlayerControlDefs : : MergeFrom ( const C4PlayerControlDefs & Src )
{
// copy all defs from source file; overwrite defs of same name if found
for ( DefVecImpl : : const_iterator i = Src . Defs . begin ( ) ; i ! = Src . Defs . end ( ) ; + + i )
{
const C4PlayerControlDef & SrcDef = * i ;
// overwrite if def of same name existed
int32_t iPrevIdx = GetControlIndexByIdentifier ( SrcDef . GetIdentifier ( ) ) ;
if ( iPrevIdx ! = CON_None )
{
Defs [ iPrevIdx ] = SrcDef ;
}
else
{
// new def: Append a copy
Defs . push_back ( SrcDef ) ;
}
}
2009-05-28 00:14:54 +00:00
UpdateInternalCons ( ) ;
2009-05-25 09:01:26 +00:00
}
2009-05-28 00:14:54 +00:00
const C4PlayerControlDef * C4PlayerControlDefs : : GetControlByIndex ( int32_t idx ) const
2009-05-25 09:01:26 +00:00
{
// safe index
2009-08-10 14:48:25 +00:00
if ( idx < 0 | | idx > = int32_t ( Defs . size ( ) ) ) return NULL ;
2009-05-25 09:01:26 +00:00
return & ( Defs [ idx ] ) ;
}
int32_t C4PlayerControlDefs : : GetControlIndexByIdentifier ( const char * szIdentifier ) const
{
for ( DefVecImpl : : const_iterator i = Defs . begin ( ) ; i ! = Defs . end ( ) ; + + i )
if ( SEqual ( ( * i ) . GetIdentifier ( ) , szIdentifier ) )
return i - Defs . begin ( ) ;
return CON_None ;
}
2009-06-09 23:29:16 +00:00
void C4PlayerControlDefs : : FinalInit ( )
{
// Assume all defs have been loaded
// Register scritp constants
for ( DefVecImpl : : const_iterator i = Defs . begin ( ) ; i ! = Defs . end ( ) ; + + i )
{
const char * szIdtf = ( * i ) . GetIdentifier ( ) ;
if ( szIdtf & & * szIdtf & & ! SEqual ( szIdtf , " None " ) )
{
2009-08-10 14:48:25 +00:00
: : ScriptEngine . RegisterGlobalConstant ( FormatString ( " CON_%s " , szIdtf ) . getData ( ) , C4VInt ( i - Defs . begin ( ) ) ) ;
2009-06-09 23:29:16 +00:00
}
}
}
2009-05-25 09:01:26 +00:00
/* C4PlayerControlAssignment */
void C4PlayerControlAssignment : : KeyComboItem : : CompileFunc ( StdCompiler * pComp )
{
// if key is compiled, also store as a string into KeyName for later resolving
if ( pComp - > isCompiler ( ) )
{
sKeyName . Clear ( ) ;
pComp - > Value ( mkParAdapt ( Key , & sKeyName ) ) ;
if ( ! sKeyName )
{
// key was not assigned during compilation - this means it's a regular key (or undefined)
// store this as the name
sKeyName . Copy ( Key . ToString ( false , false ) ) ;
}
}
else
{
// decompiler: Just write the stored key name; regardless of whether it's a key, undefined or a reference
pComp - > Value ( mkParAdapt ( sKeyName , StdCompiler : : RCT_Idtf ) ) ;
}
}
void C4PlayerControlAssignment : : CompileFunc ( StdCompiler * pComp )
{
2009-05-26 06:10:38 +00:00
if ( ! pComp - > Name ( " Assignment " ) ) { pComp - > NameEnd ( ) ; pComp - > excNotFound ( " Assignment " ) ; }
2009-05-25 09:01:26 +00:00
pComp - > Value ( mkNamingAdapt ( mkSTLContainerAdapt ( KeyCombo ) , " Key " , KeyComboVec ( ) ) ) ;
2009-06-09 23:29:16 +00:00
pComp - > Value ( mkNamingAdapt ( fComboIsSequence , " ComboIsSequence " , false ) ) ;
2009-05-25 09:01:26 +00:00
pComp - > Value ( mkNamingAdapt ( mkParAdapt ( sControlName , StdCompiler : : RCT_Idtf ) , " Control " , " None " ) ) ;
2009-05-26 06:10:38 +00:00
pComp - > Value ( mkNamingAdapt ( iPriority , " Priority " , 0 ) ) ;
const StdBitfieldEntry < int32_t > TriggerModeNames [ ] = {
2009-05-25 09:01:26 +00:00
{ " Default " , CTM_Default } ,
{ " Hold " , CTM_Hold } ,
{ " Release " , CTM_Release } ,
2009-05-26 06:10:38 +00:00
{ " AlwaysUnhandled " , CTM_AlwaysUnhandled } ,
{ NULL , 0 } } ;
pComp - > Value ( mkNamingAdapt ( mkBitfieldAdapt < int32_t > ( iTriggerMode , TriggerModeNames ) , " TriggerMode " , CTM_Default ) ) ;
2009-05-25 09:01:26 +00:00
pComp - > NameEnd ( ) ;
2009-05-26 06:10:38 +00:00
// 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 ( ) )
{
2009-06-16 02:48:53 +00:00
// this is a key reference
// it may be preceded by CON_ to avoid ambigous keus
const char * szKeyName = rKeyComboItem . sKeyName . getData ( ) ;
if ( SEqual2 ( szKeyName , " CON_ " ) ) szKeyName + = 4 ;
// - find it
C4PlayerControlAssignment * pRefAssignment = pParentSet - > GetAssignmentByControlName ( szKeyName ) ;
2009-05-26 06:10:38 +00:00
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 ;
2009-05-25 09:01:26 +00:00
}
2009-05-28 00:14:54 +00:00
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 ;
2009-10-16 14:23:17 +00:00
if ( ! ( rk . matched_key = = k . Key ) ) return false ;
2009-05-28 00:14:54 +00:00
// 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 ;
2009-10-16 14:23:17 +00:00
if ( dk . matched_key = = k . Key ) { fFound = true ; break ; }
2009-05-28 00:14:54 +00:00
}
if ( ! fFound ) return false ;
}
}
// combo OK!
return true ;
}
2009-05-25 09:01:26 +00:00
bool C4PlayerControlAssignment : : operator = = ( const C4PlayerControlAssignment & cmp ) const
{
// doesn't compare resolved TriggerKey/iControl
return KeyCombo = = cmp . KeyCombo
& & sControlName = = cmp . sControlName
2009-05-26 06:10:38 +00:00
& & iTriggerMode = = cmp . iTriggerMode
& & iPriority = = cmp . iPriority ;
2009-05-25 09:01:26 +00:00
}
/* C4PlayerControlAssignmentSet */
void C4PlayerControlAssignmentSet : : CompileFunc ( StdCompiler * pComp )
{
2009-05-26 06:10:38 +00:00
if ( ! pComp - > Name ( " ControlSet " ) ) { pComp - > NameEnd ( ) ; pComp - > excNotFound ( " ControlSet " ) ; }
2009-06-16 00:38:39 +00:00
pComp - > Value ( mkNamingAdapt ( mkParAdapt ( sName , StdCompiler : : RCT_All ) , " Name " , " None " ) ) ; // can't do RCT_Idtf because of wildcards
2009-10-14 21:29:27 +00:00
pComp - > Value ( mkNamingAdapt ( has_keyboard , " Keyboard " , true ) ) ;
pComp - > Value ( mkNamingAdapt ( has_mouse , " Mouse " , true ) ) ;
pComp - > Value ( mkNamingAdapt ( has_gamepad , " Gamepad " , false ) ) ;
2009-05-26 06:10:38 +00:00
pComp - > Value ( mkSTLContainerAdapt ( Assignments , StdCompiler : : SEP_NONE ) ) ;
2009-05-25 09:01:26 +00:00
pComp - > NameEnd ( ) ;
}
void C4PlayerControlAssignmentSet : : MergeFrom ( const C4PlayerControlAssignmentSet & Src , bool fLowPrio )
{
// take over all assignments defined in Src
2009-05-26 06:10:38 +00:00
for ( C4PlayerControlAssignmentVec : : const_iterator i = Src . Assignments . begin ( ) ; i ! = Src . Assignments . end ( ) ; + + i )
2009-05-25 09:01:26 +00:00
{
const C4PlayerControlAssignment & SrcAssignment = * i ;
2009-06-16 02:48:53 +00:00
// overwrite if def of same name existed if it's not low priority anyway?
// not so easy. Keys may be assigned to multiple controls and we may need to overwrite one or more of them...
2009-05-25 09:01:26 +00:00
C4PlayerControlAssignment * pPrevAssignment = GetAssignmentByControlName ( SrcAssignment . GetControlName ( ) ) ;
if ( pPrevAssignment )
{
if ( ! fLowPrio ) * pPrevAssignment = SrcAssignment ;
}
else
{
// new def: Append a copy
Assignments . push_back ( SrcAssignment ) ;
}
}
}
2009-05-26 06:10:38 +00:00
bool C4PlayerControlAssignmentSet : : ResolveRefs ( C4PlayerControlDefs * pDefs )
{
// 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 )
2009-10-14 16:46:22 +00:00
{
2009-05-26 06:10:38 +00:00
for ( C4PlayerControlAssignmentVec : : iterator i = Assignments . begin ( ) ; i ! = Assignments . end ( ) ; + + i )
2009-05-25 09:01:26 +00:00
if ( SEqual ( ( * i ) . GetControlName ( ) , szControlName ) )
2009-06-16 02:48:53 +00:00
// We don't like release keys... (2do)
if ( ! ( ( * i ) . GetTriggerMode ( ) & C4PlayerControlAssignment : : CTM_Release ) )
return & * i ;
2009-05-25 09:01:26 +00:00
return NULL ;
2009-10-14 16:46:22 +00:00
}
C4PlayerControlAssignment * C4PlayerControlAssignmentSet : : GetAssignmentByControl ( int control )
{
// TODO: Might want to stuff this into a vector indexed by control for faster lookup
for ( C4PlayerControlAssignmentVec : : iterator i = Assignments . begin ( ) ; i ! = Assignments . end ( ) ; + + i )
if ( ( * i ) . GetControl ( ) = = control )
// We don't like release keys... (2do)
if ( ! ( ( * i ) . GetTriggerMode ( ) & C4PlayerControlAssignment : : CTM_Release ) )
return & * i ;
return NULL ;
}
2009-05-25 09:01:26 +00:00
2009-05-26 06:10:38 +00:00
bool C4PlayerControlAssignmentSet : : operator = = ( const C4PlayerControlAssignmentSet & cmp ) const
{
return Assignments = = cmp . Assignments
& & sName = = cmp . sName ;
}
2009-05-28 00:14:54 +00:00
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 ) ;
}
}
}
2009-10-14 16:46:22 +00:00
C4Facet C4PlayerControlAssignmentSet : : GetPicture ( ) const
{
// get image to be drawn to represent this control set
// picture per set not implemented yet. So just default to out standard images
if ( HasGamepad ( ) ) return : : GraphicsResource . fctGamepad . GetPhase ( GetGamepadIndex ( ) ) ;
if ( HasKeyboard ( ) ) return : : GraphicsResource . fctKeyboard . GetPhase ( 0 /* todo*/ ) ;
if ( HasMouse ( ) ) return : : GraphicsResource . fctMouse ; // mouse only???
return C4Facet ( ) ;
}
2009-10-17 15:53:26 +00:00
bool C4PlayerControlAssignmentSet : : IsMouseControlAssigned ( int32_t mouseevent ) const
{
// TODO
return true ;
}
2009-05-25 09:01:26 +00:00
/* C4PlayerControlAssignmentSets */
2009-05-26 06:10:38 +00:00
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
2009-06-16 00:38:39 +00:00
bool fIsWildcardSet = SrcSet . IsWildcardName ( ) ;
if ( ! fIsWildcardSet )
2009-05-26 06:10:38 +00:00
{
2009-06-16 00:38:39 +00:00
C4PlayerControlAssignmentSet * pPrevSet = GetSetByName ( SrcSet . GetName ( ) ) ;
if ( pPrevSet )
{
pPrevSet - > MergeFrom ( SrcSet , fLowPrio ) ;
}
else
{
// new def: Append a copy
Sets . push_back ( SrcSet ) ;
}
2009-05-26 06:10:38 +00:00
}
else
{
2009-06-16 00:38:39 +00:00
// source is a wildcard: Merge with all matching sets
for ( AssignmentSetList : : iterator j = Sets . begin ( ) ; j ! = Sets . end ( ) ; + + j )
{
C4PlayerControlAssignmentSet & DstSet = * j ;
if ( WildcardMatch ( SrcSet . GetName ( ) , DstSet . GetName ( ) ) )
{
DstSet . MergeFrom ( SrcSet , fLowPrio ) ;
}
}
2009-05-26 06:10:38 +00:00
}
}
}
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 )
2009-10-13 20:02:44 +00:00
{
2009-05-26 06:10:38 +00:00
for ( AssignmentSetList : : iterator i = Sets . begin ( ) ; i ! = Sets . end ( ) ; + + i )
2009-10-13 20:02:44 +00:00
if ( WildcardMatch ( szName , ( * i ) . GetName ( ) ) )
2009-05-26 06:10:38 +00:00
return & * i ;
return NULL ;
2009-10-13 20:02:44 +00:00
}
2009-05-26 06:10:38 +00:00
2009-10-14 16:46:22 +00:00
C4PlayerControlAssignmentSet * C4PlayerControlAssignmentSets : : GetDefaultSet ( )
{
// default set is first defined control set
if ( Sets . empty ( ) ) return NULL ; // nothing defined :(
return & Sets . front ( ) ;
}
int32_t C4PlayerControlAssignmentSets : : GetSetIndex ( const C4PlayerControlAssignmentSet * set ) const
{
// find set in list; return index
int32_t index = 0 ;
for ( AssignmentSetList : : const_iterator i = Sets . begin ( ) ; i ! = Sets . end ( ) ; + + i , + + index )
if ( & * i = = set )
return index ;
return - 1 ; // not found
}
C4PlayerControlAssignmentSet * C4PlayerControlAssignmentSets : : GetSetByIndex ( int32_t index )
{
// bounds check
if ( index < 0 | | index > = ( int32_t ) Sets . size ( ) ) return NULL ;
// return indexed set
AssignmentSetList : : iterator i = Sets . begin ( ) ;
while ( index - - ) + + i ;
return & * i ;
}
2009-05-26 06:10:38 +00:00
/* 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 */
2009-05-28 00:14:54 +00:00
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
2009-08-10 14:48:25 +00:00
if ( iControl < 0 | | iControl > = int32_t ( ControlDownStates . size ( ) ) ) return NULL ;
2009-05-28 00:14:54 +00:00
return & ControlDownStates [ iControl ] ;
}
int32_t C4PlayerControl : : CSync : : GetControlDisabled ( int32_t iControl ) const
{
// safe access
2009-08-10 14:48:25 +00:00
if ( iControl < 0 | | iControl > = int32_t ( ControlDisableStates . size ( ) ) ) return 0 ;
2009-05-28 00:14:54 +00:00
return ControlDisableStates [ iControl ] ;
}
void C4PlayerControl : : CSync : : SetControlDownState ( int32_t iControl , const C4KeyEventData & rDownState , int32_t iDownFrame , bool fDownByUser )
{
// update state
if ( iControl < 0 ) return ;
2009-08-10 14:48:25 +00:00
if ( iControl > = int32_t ( ControlDownStates . size ( ) ) ) ControlDownStates . resize ( iControl + 1 ) ;
2009-05-28 00:14:54 +00:00
ControlDownState & rState = ControlDownStates [ iControl ] ;
rState . DownState = rDownState ;
rState . iDownFrame = iDownFrame ;
rState . fDownByUser = fDownByUser ;
}
2009-12-27 18:11:14 +00:00
bool C4PlayerControl : : CSync : : SetControlDisabled ( int32_t iControl , int32_t iVal )
2009-05-28 00:14:54 +00:00
{
// disable control
2009-12-27 18:11:14 +00:00
if ( iControl < 0 ) return false ;
2009-08-10 14:48:25 +00:00
if ( iControl > = int32_t ( ControlDisableStates . size ( ) ) ) ControlDisableStates . resize ( iControl + 1 ) ;
2009-05-28 00:14:54 +00:00
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 ) ;
}
2009-12-27 18:11:14 +00:00
return true ;
2009-05-28 00:14:54 +00:00
}
void C4PlayerControl : : CSync : : Clear ( )
{
ControlDownStates . clear ( ) ;
ControlDisableStates . clear ( ) ;
}
2009-05-26 06:10:38 +00:00
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 ( ) ) ) ;
}
2009-10-16 14:23:17 +00:00
bool C4PlayerControl : : ProcessKeyEvent ( const C4KeyCodeEx & pressed_key , const C4KeyCodeEx & matched_key , bool fUp , const C4KeyEventData & rKeyExtraData )
2009-05-26 06:10:38 +00:00
{
// collect all matching keys
2009-05-28 00:14:54 +00:00
C4PlayerControlAssignmentPVec Matches ;
assert ( pControlSet ) ; // shouldn't get this callback for players without control set
2009-10-16 14:23:17 +00:00
pControlSet - > GetAssignmentsByKey ( ControlDefs , matched_key , fUp , & Matches , DownKeys , RecentKeys ) ;
2009-05-26 06:10:38 +00:00
// process async controls
2009-05-28 00:14:54 +00:00
C4ControlPlayerControl * pControlPacket = NULL ;
for ( C4PlayerControlAssignmentPVec : : const_iterator i = Matches . begin ( ) ; i ! = Matches . end ( ) ; + + i )
2009-05-26 06:10:38 +00:00
{
2009-05-28 00:14:54 +00:00
const C4PlayerControlAssignment * pAssignment = * i ;
assert ( pAssignment ) ;
int32_t iControlIndex = pAssignment - > GetControl ( ) ;
const C4PlayerControlDef * pControlDef = ControlDefs . GetControlByIndex ( iControlIndex ) ;
2009-05-26 06:10:38 +00:00
if ( pControlDef & & pControlDef - > IsValid ( ) & & ( ! fUp | | pControlDef - > IsHoldKey ( ) ) )
{
if ( pControlDef - > IsAsync ( ) & & ! pControlPacket )
{
2009-10-16 14:23:17 +00:00
if ( ExecuteControl ( iControlIndex , fUp , rKeyExtraData , pAssignment - > GetTriggerMode ( ) , pressed_key . IsRepeated ( ) ) )
2009-05-26 06:10:38 +00:00
return true ;
}
else
{
// sync control
// ignore key repeats, because we do our own key repeat for sync controls
2009-10-16 14:23:17 +00:00
if ( pressed_key . IsRepeated ( ) ) return false ;
2009-05-26 06:10:38 +00:00
// 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
2009-05-28 00:14:54 +00:00
if ( ! pControlPacket ) pControlPacket = new C4ControlPlayerControl ( iPlr , fUp , rKeyExtraData ) ;
pControlPacket - > AddControl ( iControlIndex , pAssignment - > GetTriggerMode ( ) ) ;
2009-05-26 06:10:38 +00:00
}
}
}
// push sync control to input
2009-05-28 00:14:54 +00:00
if ( pControlPacket )
{
2009-12-30 00:56:52 +00:00
Game . Input . Add ( CID_PlrControl , pControlPacket ) ;
2009-05-28 00:14:54 +00:00
// assume processed (although we can't really know that yet)
return true ;
}
return false ;
2009-05-26 06:10:38 +00:00
}
2009-10-16 14:23:17 +00:00
bool C4PlayerControl : : ProcessKeyDown ( const C4KeyCodeEx & pressed_key , const C4KeyCodeEx & matched_key )
2009-10-17 15:53:26 +00:00
{
2009-05-26 06:10:38 +00:00
// add key to local "down" list if it's not already in there
2009-10-17 15:53:26 +00:00
// except for some mouse events for which a down state does not make sense
2009-10-16 14:23:17 +00:00
C4PlayerControlRecentKey RKey ( pressed_key , matched_key , timeGetTime ( ) ) ;
2009-12-28 13:36:06 +00:00
if ( ! Key_IsMouse ( pressed_key . Key ) | | Inside < uint8_t > ( Key_GetMouseEvent ( pressed_key . Key ) & ~ KEY_MOUSE_GameMask , KEY_MOUSE_Button1 , KEY_MOUSE_ButtonMax ) )
2009-10-17 15:53:26 +00:00
{
if ( std : : find ( DownKeys . begin ( ) , DownKeys . end ( ) , pressed_key ) = = DownKeys . end ( ) ) DownKeys . push_back ( RKey ) ;
}
2009-05-26 06:10:38 +00:00
// process!
2009-10-16 14:23:17 +00:00
bool fResult = ProcessKeyEvent ( pressed_key , matched_key , false , Game . KeyboardInput . GetLastKeyExtraData ( ) ) ;
2009-05-26 06:10:38 +00:00
// add to recent list unless repeated
2009-10-16 14:23:17 +00:00
if ( ! pressed_key . IsRepeated ( ) ) RecentKeys . push_back ( RKey ) ;
2009-05-26 06:10:38 +00:00
return fResult ;
2009-10-17 15:53:26 +00:00
}
2009-05-26 06:10:38 +00:00
2009-10-16 14:23:17 +00:00
bool C4PlayerControl : : ProcessKeyUp ( const C4KeyCodeEx & pressed_key , const C4KeyCodeEx & matched_key )
2009-10-17 15:53:26 +00:00
{
2009-05-26 06:10:38 +00:00
// remove key from "down" list
2009-10-17 15:53:26 +00:00
// except for some mouse events for which a down state does not make sense
if ( ! Key_IsMouse ( pressed_key . Key ) | | Inside < uint8_t > ( Key_GetMouseEvent ( pressed_key . Key ) , KEY_MOUSE_Button1 , KEY_MOUSE_ButtonMax ) )
{
C4PlayerControlRecentKeyList : : iterator i = find ( DownKeys . begin ( ) , DownKeys . end ( ) , pressed_key ) ;
if ( i ! = DownKeys . end ( ) ) DownKeys . erase ( i ) ;
}
2009-05-26 06:10:38 +00:00
// process!
2009-10-16 14:23:17 +00:00
return ProcessKeyEvent ( pressed_key , matched_key , true , Game . KeyboardInput . GetLastKeyExtraData ( ) ) ;
2009-10-17 15:53:26 +00:00
}
2009-05-26 06:10:38 +00:00
2009-05-28 00:14:54 +00:00
void C4PlayerControl : : ExecuteControlPacket ( const class C4ControlPlayerControl * pCtrl )
2009-05-26 06:10:38 +00:00
{
// 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)
2009-05-28 00:14:54 +00:00
for ( C4ControlPlayerControl : : ControlItemVec : : const_iterator i = pCtrl - > GetControlItems ( ) . begin ( ) ; i ! = pCtrl - > GetControlItems ( ) . end ( ) ; + + i )
2009-05-26 06:10:38 +00:00
{
2009-05-28 00:14:54 +00:00
const C4ControlPlayerControl : : ControlItem & rItem = * i ;
const C4PlayerControlDef * pCtrlDef = ControlDefs . GetControlByIndex ( rItem . iControl ) ;
2009-05-26 06:10:38 +00:00
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
2009-05-28 00:14:54 +00:00
const C4PlayerControlDef * pControlDef = ControlDefs . GetControlByIndex ( iControl ) ;
2009-05-26 06:10:38 +00:00
if ( ! pControlDef | | Sync . IsControlDisabled ( iControl ) ) return false ;
C4PlayerControlDef : : Actions eAction = pControlDef - > GetAction ( ) ;
C4KeyEventData KeyExtraData ( rKeyExtraData ) ;
2009-05-28 00:14:54 +00:00
const CSync : : ControlDownState * pCtrlDownState = Sync . GetControlDownState ( iControl ) ;
bool fWasDown = pCtrlDownState ? pCtrlDownState - > IsDown ( ) : false ;
2009-05-26 06:10:38 +00:00
// 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
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
2009-05-28 00:14:54 +00:00
// (this will restart the KeyRepeat time)
2009-05-26 06:10:38 +00:00
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
if ( ! fWasDown ) return false ;
2009-05-28 00:14:54 +00:00
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 ;
2009-05-26 06:10:38 +00:00
}
// perform action for this control
bool fHandled = ExecuteControlAction ( iControl , eAction , pControlDef - > GetExtraData ( ) , fUp , KeyExtraData , fRepeated ) ;
2009-10-16 14:23:17 +00:00
// handled controls hide control display
C4Player * pPlr ;
2010-01-25 04:00:59 +00:00
if ( ( pPlr = : : Players . Get ( iPlr ) ) ) if ( pPlr - > ShowStartup ) pPlr - > ShowStartup = false ;
2009-05-26 06:10:38 +00:00
// 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 ;
2009-12-31 17:20:45 +00:00
C4Viewport * pVP ;
2009-05-26 06:10:38 +00:00
if ( iPlr > - 1 )
{
2009-08-10 14:48:25 +00:00
pPlr = : : Players . Get ( iPlr ) ;
2009-05-26 06:10:38 +00:00
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
2009-12-31 17:20:45 +00:00
case C4PlayerControlDef : : CDA_ZoomIn : if ( ! pPlr | | ! ( pVP = GraphicsSystem . GetViewport ( iPlr ) ) ) return false ; pVP - > ChangeZoom ( C4GFX_ZoomStep ) ; return true ; // viewport zoom
case C4PlayerControlDef : : CDA_ZoomOut : if ( ! pPlr | | ! ( pVP = GraphicsSystem . GetViewport ( iPlr ) ) ) return false ; pVP - > ChangeZoom ( 1.0f / C4GFX_ZoomStep ) ; return true ; // viewport zoom
2009-05-26 06:10:38 +00:00
//unknown action
default : return false ;
}
}
bool C4PlayerControl : : ExecuteControlScript ( int32_t iControl , C4ID idControlExtraData , bool fUp , const C4KeyEventData & rKeyExtraData , bool fRepeated )
{
2009-08-10 14:48:25 +00:00
C4Player * pPlr = : : Players . Get ( iPlr ) ;
2009-05-28 00:14:54 +00:00
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 ;
}
2009-06-16 00:38:39 +00:00
// control down
2009-12-29 23:44:43 +00:00
C4AulFunc * pFunc = : : ScriptEngine . GetFunc ( PSF_PlayerControl , & ScriptEngine , NULL ) ;
2009-06-16 00:38:39 +00:00
if ( ! pFunc ) return false ;
C4AulParSet Pars ( C4VInt ( iPlr ) , C4VInt ( iControl ) , C4VID ( idControlExtraData ) , C4VInt ( rKeyExtraData . x ) , C4VInt ( rKeyExtraData . y ) , C4VInt ( rKeyExtraData . iStrength ) , C4VBool ( fRepeated ) , C4VBool ( fUp ) ) ;
return ! ! pFunc - > Exec ( NULL , & Pars ) ;
2009-05-26 06:10:38 +00:00
}
void C4PlayerControl : : Execute ( )
2009-10-17 15:53:26 +00:00
{
2009-05-28 00:14:54 +00:00
// sync execution: Do keyrepeat
for ( int32_t i = 0 ; i < ControlDefs . GetCount ( ) ; + + i )
2009-10-17 15:53:26 +00:00
{
2009-05-28 00:14:54 +00:00
const CSync : : ControlDownState * pControlDownState = Sync . GetControlDownState ( i ) ;
if ( pControlDownState & & pControlDownState - > IsDown ( ) )
2009-10-17 15:53:26 +00:00
{
2009-05-28 00:14:54 +00:00
const C4PlayerControlDef * pCtrlDef = ControlDefs . GetControlByIndex ( i ) ;
assert ( pCtrlDef ) ;
int32_t iCtrlRepeatDelay = pCtrlDef - > GetRepeatDelay ( ) ;
if ( iCtrlRepeatDelay )
2009-10-17 15:53:26 +00:00
{
2009-05-28 00:14:54 +00:00
int32_t iFrameDiff = Game . FrameCounter - pControlDownState - > iDownFrame ;
int32_t iCtrlInitialRepeatDelay = pCtrlDef - > GetInitialRepeatDelay ( ) ;
if ( iFrameDiff & & iFrameDiff > = iCtrlInitialRepeatDelay )
2009-10-17 15:53:26 +00:00
{
2009-05-28 00:14:54 +00:00
if ( ! ( ( iFrameDiff - iCtrlInitialRepeatDelay ) % iCtrlRepeatDelay ) )
2009-10-17 15:53:26 +00:00
{
2009-05-28 00:14:54 +00:00
// it's RepeatTime for this key!
ExecuteControlAction ( i , pCtrlDef - > GetAction ( ) , pCtrlDef - > GetExtraData ( ) , false , pControlDownState - > DownState , true ) ;
}
}
}
}
2009-10-17 15:53:26 +00:00
}
2009-05-28 00:14:54 +00:00
// cleanup old recent keys
C4PlayerControlRecentKeyList : : iterator irk ;
DWORD tNow = timeGetTime ( ) ;
for ( irk = RecentKeys . begin ( ) ; irk ! = RecentKeys . end ( ) ; + + irk )
2009-10-17 15:53:26 +00:00
{
2009-05-28 00:14:54 +00:00
C4PlayerControlRecentKey & rk = * irk ;
if ( rk . tTime + MaxRecentKeyLookback > tNow ) break ;
2009-05-26 06:10:38 +00:00
}
2009-10-17 15:53:26 +00:00
if ( irk ! = RecentKeys . begin ( ) ) RecentKeys . erase ( RecentKeys . begin ( ) , irk ) ;
}
2009-05-26 06:10:38 +00:00
C4PlayerControl : : C4PlayerControl ( ) : ControlDefs ( Game . PlayerControlDefs ) , iPlr ( - 1 ) , pControlSet ( NULL )
2009-10-17 15:53:26 +00:00
{
}
2009-05-26 06:10:38 +00:00
void C4PlayerControl : : Clear ( )
2009-10-17 15:53:26 +00:00
{
2009-05-28 00:14:54 +00:00
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 ( ) ;
2009-10-17 15:53:26 +00:00
}
2009-05-26 06:10:38 +00:00
void C4PlayerControl : : RegisterKeyset ( int32_t iPlr , C4PlayerControlAssignmentSet * pKeyset )
2009-10-17 15:53:26 +00:00
{
2009-05-28 00:14:54 +00:00
// clear any previous settings
Clear ( ) ;
// setup
pControlSet = pKeyset ;
this - > iPlr = iPlr ;
2009-05-26 06:10:38 +00:00
// register all keys into Game.KeyboardInput creating KeyBindings
2009-05-28 00:14:54 +00:00
if ( pControlSet )
2009-10-17 15:53:26 +00:00
{
2009-05-28 00:14:54 +00:00
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 + + ) ;
2009-05-26 06:10:38 +00:00
}
2009-10-17 15:53:26 +00:00
}
2009-05-26 06:10:38 +00:00
2009-05-28 00:14:54 +00:00
void C4PlayerControl : : AddKeyBinding ( const C4KeyCodeEx & key , bool fHoldKey , int32_t idx )
2009-10-17 15:53:26 +00:00
{
2009-06-09 23:29:16 +00:00
KeyBindings . push_back ( new C4KeyBinding (
2009-05-28 00:14:54 +00:00
key , FormatString ( " PlrKey%02d " , idx ) . getData ( ) , KEYSCOPE_Control ,
2009-10-16 14:23:17 +00:00
new C4KeyCBExPassKey < C4PlayerControl , C4KeyCodeEx > ( * this , key , & C4PlayerControl : : ProcessKeyDown , fHoldKey ? & C4PlayerControl : : ProcessKeyUp : NULL ) ,
2009-05-28 00:14:54 +00:00
C4CustomKey : : PRIO_PlrControl ) ) ;
2009-10-17 15:53:26 +00:00
}
2009-12-31 17:20:45 +00:00
bool C4PlayerControl : : DoMouseInput ( uint8_t mouse_id , int32_t mouseevent , float game_x , float game_y , float gui_x , float gui_y , bool is_ctrl_down , bool is_shift_down , bool is_alt_down , int wheel_dir )
2009-10-17 15:53:26 +00:00
{
// convert moueevent to key code
uint8_t mouseevent_code ;
C4KeyCodeEx mouseevent_keycode ;
2009-10-17 20:20:36 +00:00
bool is_down = true ;
2009-10-17 15:53:26 +00:00
switch ( mouseevent )
{
case C4MC_Button_None : mouseevent_code = KEY_MOUSE_Move ; break ;
2009-10-17 20:20:36 +00:00
case C4MC_Button_LeftUp : is_down = false ; // nobreak
case C4MC_Button_LeftDown : mouseevent_code = KEY_MOUSE_ButtonLeft ; break ;
case C4MC_Button_RightUp : is_down = false ; // nobreak
2009-12-22 20:16:08 +00:00
case C4MC_Button_RightDown : mouseevent_code = KEY_MOUSE_ButtonRight ; break ;
2009-10-17 15:53:26 +00:00
case C4MC_Button_LeftDouble : mouseevent_code = KEY_MOUSE_ButtonLeftDouble ; break ;
case C4MC_Button_RightDouble : mouseevent_code = KEY_MOUSE_ButtonRightDouble ; break ;
2009-10-17 20:20:36 +00:00
case C4MC_Button_MiddleUp : is_down = false ; // nobreak
case C4MC_Button_MiddleDown : mouseevent_code = KEY_MOUSE_ButtonMiddle ; break ;
2009-12-31 17:20:45 +00:00
case C4MC_Button_Wheel :
if ( ! wheel_dir ) return false ;
mouseevent_code = ( wheel_dir > 0 ) ? KEY_MOUSE_Wheel1Up : KEY_MOUSE_Wheel1Down ; break ;
2009-10-17 15:53:26 +00:00
default : assert ( false ) ; return false ;
}
// compose keycode
if ( is_ctrl_down ) mouseevent_keycode . dwShift | = KEYS_Control ;
if ( is_shift_down ) mouseevent_keycode . dwShift | = KEYS_Shift ;
if ( is_alt_down ) mouseevent_keycode . dwShift | = KEYS_Alt ;
mouseevent_keycode . Key = KEY_Mouse ( mouse_id , mouseevent_code , false ) ;
// first, try processing it as GUI mouse event. if not assigned, process as Game mous event
// TODO: May route this through Game.DoKeyboardInput instead - would allow assignment of mouse events in CustomConfig
// and would get rid of the Game.KeyboardInput.SetLastKeyExtraData-hack
C4KeyEventData mouseevent_data ;
2009-10-17 20:20:36 +00:00
mouseevent_data . iStrength = 100 * is_down ; // TODO: May get pressure from tablet here
2009-10-17 15:53:26 +00:00
mouseevent_data . x = uint32_t ( gui_x ) ;
mouseevent_data . y = uint32_t ( gui_y ) ;
Game . KeyboardInput . SetLastKeyExtraData ( mouseevent_data ) ; // ProcessKeyDown/Up queries it from there...
bool result ;
if ( is_down )
result = ProcessKeyDown ( mouseevent_keycode , mouseevent_keycode ) ;
else
result = ProcessKeyUp ( mouseevent_keycode , mouseevent_keycode ) ;
if ( result )
{
// mouse event processed in GUI coordinates
return true ;
2009-05-28 00:14:54 +00:00
}
2009-10-17 15:53:26 +00:00
// try processing in Game coordinates instead
mouseevent_data . x = uint32_t ( game_x ) ;
mouseevent_data . y = uint32_t ( game_y ) ;
2009-10-17 20:40:11 +00:00
Game . KeyboardInput . SetLastKeyExtraData ( mouseevent_data ) ; // ProcessKeyDown/Up queries it from there...
2009-10-17 15:53:26 +00:00
mouseevent_keycode . Key | = KEY_MOUSE_GameMask ;
if ( is_down )
result = ProcessKeyDown ( mouseevent_keycode , mouseevent_keycode ) ;
else
result = ProcessKeyUp ( mouseevent_keycode , mouseevent_keycode ) ;
return result ;
}