2009-05-25 09:01:26 +00:00
/*
* OpenClonk , http : //www.openclonk.org
*
2013-12-17 20:01:09 +00:00
* Copyright ( c ) 2005 - 2009 , RedWolf Design GmbH , http : //www.clonk.de/
* Copyright ( c ) 2009 - 2013 , The OpenClonk Team and contributors
2009-05-25 09:01:26 +00:00
*
2013-12-17 20:01:09 +00:00
* Distributed under the terms of the ISC license ; see accompanying file
* " COPYING " for details .
2009-05-25 09:01:26 +00:00
*
2013-12-17 20:01:09 +00:00
* " Clonk " is a registered trademark of Matthes Bender , used with permission .
* See accompanying file " TRADEMARK " for details .
2009-05-25 09:01:26 +00:00
*
2013-12-17 20:01:09 +00:00
* To redistribute this file separately , substitute the full license texts
* for the above references .
2009-05-25 09:01:26 +00:00
*/
// 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
2011-03-03 16:10:22 +00:00
# include <C4DefList.h>
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-03-21 18:34:22 +00:00
# include "C4GraphicsSystem.h"
2010-01-02 00:12:35 +00:00
# include "C4Viewport.h"
2010-02-08 20:52:46 +00:00
# include "C4Object.h"
# include "C4ObjectMenu.h"
2009-12-17 13:06:24 +00:00
# include <algorithm>
2009-05-25 09:01:26 +00:00
2011-12-28 23:12:21 +00:00
# include "C4Record.h"
2009-05-25 09:01:26 +00:00
/* C4PlayerControlDef */
void C4PlayerControlDef : : CompileFunc ( StdCompiler * pComp )
2010-03-28 18:58:01 +00:00
{
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 " ) ) ;
2011-03-31 14:26:59 +00:00
pComp - > Value ( mkNamingAdapt ( mkParAdapt ( sGUIName , StdCompiler : : RCT_All ) , " GUIName " , " " ) ) ;
2009-05-25 09:01:26 +00:00
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 ) ) ;
2011-11-20 20:49:38 +00:00
const StdEnumEntry < CoordinateSpace > CoordSpaceNames [ ] =
{
{ " Game " , COS_Game } ,
{ " Viewport " , COS_Viewport } ,
{ NULL , COS_Game }
} ;
pComp - > Value ( mkNamingAdapt ( mkEnumAdapt < CoordinateSpace , int32_t > ( eCoordSpace , CoordSpaceNames ) , " CoordinateSpace " , COS_Game ) ) ;
2010-04-10 20:44:00 +00:00
pComp - > Value ( mkNamingAdapt ( fSendCursorPos , " SendCursorPos " , false ) ) ;
2010-03-28 18:58:01 +00:00
const StdEnumEntry < Actions > ActionNames [ ] =
{
2009-05-26 06:10:38 +00:00
{ " 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 } ,
2014-08-10 18:58:26 +00:00
{ " ObjectMenuTextComplete " , CDA_ObjectMenuTextComplete } ,
2010-02-08 20:52:46 +00:00
{ " ObjectMenuOK " , CDA_ObjectMenuOK } ,
{ " ObjectMenuOKAll " , CDA_ObjectMenuOKAll } ,
{ " ObjectMenuSelect " , CDA_ObjectMenuSelect } ,
{ " ObjectMenuCancel " , CDA_ObjectMenuCancel } ,
{ " ObjectMenuLeft " , CDA_ObjectMenuLeft } ,
{ " ObjectMenuUp " , CDA_ObjectMenuUp } ,
{ " ObjectMenuRight " , CDA_ObjectMenuRight } ,
{ " ObjectMenuDown " , CDA_ObjectMenuDown } ,
2009-12-31 17:20:45 +00:00
{ " ZoomIn " , CDA_ZoomIn } ,
{ " ZoomOut " , CDA_ZoomOut } ,
2010-03-28 18:58:01 +00:00
{ NULL , CDA_None }
} ;
2009-05-26 06:10:38 +00:00
pComp - > Value ( mkNamingAdapt ( mkEnumAdapt < Actions , int32_t > ( eAction , ActionNames ) , " Action " , CDA_Script ) ) ;
2009-05-25 09:01:26 +00:00
pComp - > NameEnd ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-25 09:01:26 +00:00
bool C4PlayerControlDef : : operator = = ( const C4PlayerControlDef & cmp ) const
2010-03-28 18:58:01 +00:00
{
2009-05-25 09:01:26 +00:00
return sIdentifier = = cmp . sIdentifier
2010-03-28 18:58:01 +00:00
& & sGUIName = = cmp . sGUIName
& & sGUIDesc = = cmp . sGUIDesc
& & fGlobal = = cmp . fGlobal
& & fIsHoldKey = = cmp . fIsHoldKey
& & iRepeatDelay = = cmp . iRepeatDelay
& & iInitialRepeatDelay = = cmp . iInitialRepeatDelay
& & fDefaultDisabled = = cmp . fDefaultDisabled
& & idControlExtraData = = cmp . idControlExtraData
2010-04-10 20:44:00 +00:00
& & fSendCursorPos = = cmp . fSendCursorPos
2010-03-28 18:58:01 +00:00
& & eAction = = cmp . eAction ;
}
2009-05-25 09:01:26 +00:00
/* C4PlayerControlDefs */
2009-05-28 00:14:54 +00:00
void C4PlayerControlDefs : : UpdateInternalCons ( )
2010-03-28 18:58:01 +00:00
{
2010-02-08 20:52:46 +00:00
InternalCons . CON_ObjectMenuSelect = GetControlIndexByIdentifier ( " ObjectMenuSelect " ) ;
InternalCons . CON_ObjectMenuOK = GetControlIndexByIdentifier ( " ObjectMenuOK " ) ;
InternalCons . CON_ObjectMenuOKAll = GetControlIndexByIdentifier ( " ObjectMenuOKAll " ) ;
InternalCons . CON_ObjectMenuCancel = GetControlIndexByIdentifier ( " ObjectMenuCancel " ) ;
2010-05-07 13:57:56 +00:00
InternalCons . CON_CursorPos = GetControlIndexByIdentifier ( " CursorPos " ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-28 00:14:54 +00:00
2009-05-26 06:10:38 +00:00
void C4PlayerControlDefs : : Clear ( )
2010-03-28 18:58:01 +00:00
{
2011-07-16 09:58:38 +00:00
clear_previous = false ;
2009-05-26 06:10:38 +00:00
Defs . clear ( ) ;
2009-05-28 00:14:54 +00:00
UpdateInternalCons ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-26 06:10:38 +00:00
2009-05-25 09:01:26 +00:00
void C4PlayerControlDefs : : CompileFunc ( StdCompiler * pComp )
2010-03-28 18:58:01 +00:00
{
2011-07-16 09:58:38 +00:00
pComp - > Value ( mkNamingAdapt ( clear_previous , " ClearPrevious " , false ) ) ;
pComp - > Value ( mkSTLContainerAdapt ( Defs , StdCompiler : : SEP_NONE ) ) ;
2009-05-28 00:14:54 +00:00
if ( pComp - > isCompiler ( ) ) UpdateInternalCons ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-25 09:01:26 +00:00
void C4PlayerControlDefs : : MergeFrom ( const C4PlayerControlDefs & Src )
2010-03-28 18:58:01 +00:00
{
2011-07-16 09:58:38 +00:00
// Clear previous defs if specified in merge set
if ( Src . clear_previous ) Defs . clear ( ) ;
2009-05-25 09:01:26 +00:00
// 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 )
2010-03-28 18:58:01 +00:00
{
2009-05-25 09:01:26 +00:00
const C4PlayerControlDef & SrcDef = * i ;
// overwrite if def of same name existed
int32_t iPrevIdx = GetControlIndexByIdentifier ( SrcDef . GetIdentifier ( ) ) ;
if ( iPrevIdx ! = CON_None )
2010-03-28 18:58:01 +00:00
{
2009-05-25 09:01:26 +00:00
Defs [ iPrevIdx ] = SrcDef ;
2010-03-28 18:58:01 +00:00
}
2009-05-25 09:01:26 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-25 09:01:26 +00:00
// new def: Append a copy
Defs . push_back ( SrcDef ) ;
}
}
2010-03-28 18:58:01 +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
2010-03-28 18:58:01 +00:00
{
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 ] ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-25 09:01:26 +00:00
int32_t C4PlayerControlDefs : : GetControlIndexByIdentifier ( const char * szIdentifier ) const
2010-03-28 18:58:01 +00:00
{
2009-05-25 09:01:26 +00:00
for ( DefVecImpl : : const_iterator i = Defs . begin ( ) ; i ! = Defs . end ( ) ; + + i )
if ( SEqual ( ( * i ) . GetIdentifier ( ) , szIdentifier ) )
return i - Defs . begin ( ) ;
return CON_None ;
2010-03-28 18:58:01 +00:00
}
2009-05-25 09:01:26 +00:00
2009-06-09 23:29:16 +00:00
void C4PlayerControlDefs : : FinalInit ( )
2010-03-28 18:58:01 +00:00
{
2009-06-09 23:29:16 +00:00
// Assume all defs have been loaded
// Register scritp constants
for ( DefVecImpl : : const_iterator i = Defs . begin ( ) ; i ! = Defs . end ( ) ; + + i )
2010-03-28 18:58:01 +00:00
{
2009-06-09 23:29:16 +00:00
const char * szIdtf = ( * i ) . GetIdentifier ( ) ;
if ( szIdtf & & * szIdtf & & ! SEqual ( szIdtf , " None " ) )
2010-03-28 18:58:01 +00:00
{
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
}
}
2010-03-28 18:58:01 +00:00
}
2009-06-09 23:29:16 +00:00
2009-05-25 09:01:26 +00:00
/* C4PlayerControlAssignment */
void C4PlayerControlAssignment : : KeyComboItem : : CompileFunc ( StdCompiler * pComp )
2010-03-27 18:08:01 +00:00
{
2009-05-25 09:01:26 +00:00
// if key is compiled, also store as a string into KeyName for later resolving
if ( pComp - > isCompiler ( ) )
2010-03-27 18:08:01 +00:00
{
Key . dwShift = 0 ;
2009-05-25 09:01:26 +00:00
sKeyName . Clear ( ) ;
pComp - > Value ( mkParAdapt ( Key , & sKeyName ) ) ;
2010-03-27 18:08:01 +00:00
}
else
{
2011-03-30 20:11:47 +00:00
// decompiler: If there's a stored key name, just write it. Regardless of whether it's a key, undefined or a reference
2012-10-08 22:54:34 +00:00
// If no key name is stored, it was probably assigned at runtime and sKeyName needs to be recreated
2011-03-30 20:11:47 +00:00
if ( ! sKeyName ) UpdateKeyName ( ) ;
2009-05-25 09:01:26 +00:00
pComp - > Value ( mkParAdapt ( sKeyName , StdCompiler : : RCT_Idtf ) ) ;
}
2010-03-27 18:08:01 +00:00
}
2009-05-25 09:01:26 +00:00
2011-03-30 20:11:47 +00:00
void C4PlayerControlAssignment : : KeyComboItem : : UpdateKeyName ( )
{
// update key name from key
sKeyName . Copy ( Key . ToString ( false , false ) ) ;
2012-10-08 22:54:34 +00:00
if ( Key . dwShift )
sKeyName . Take ( FormatString ( " %s+%s " , C4KeyCodeEx : : KeyShift2String ( ( C4KeyShiftState ) Key . dwShift ) . getData ( ) , sKeyName . getData ( ) ) ) ;
2011-03-30 20:11:47 +00:00
}
2009-05-25 09:01:26 +00:00
void C4PlayerControlAssignment : : CompileFunc ( StdCompiler * pComp )
2010-03-28 18:58:01 +00:00
{
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 " ) ) ;
2012-10-08 20:29:15 +00:00
pComp - > Value ( mkNamingAdapt ( mkParAdapt ( sGUIName , StdCompiler : : RCT_All ) , " GUIName " , " " ) ) ;
pComp - > Value ( mkNamingAdapt ( mkParAdapt ( sGUIDesc , StdCompiler : : RCT_All ) , " GUIDesc " , " " ) ) ;
2012-10-09 21:59:32 +00:00
pComp - > Value ( mkNamingAdapt ( iGUIGroup , " GUIGroup " , 0 ) ) ;
2012-10-09 20:24:48 +00:00
pComp - > Value ( mkNamingAdapt ( fGUIDisabled , " GUIDisabled " , false ) ) ;
2009-05-26 06:10:38 +00:00
pComp - > Value ( mkNamingAdapt ( iPriority , " Priority " , 0 ) ) ;
2010-03-28 18:58:01 +00:00
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 } ,
2013-09-02 15:27:15 +00:00
{ " ClearRecentKeys " , CTM_ClearRecentKeys } ,
2010-03-28 18:58:01 +00:00
{ NULL , 0 }
} ;
2009-05-26 06:10:38 +00:00
pComp - > Value ( mkNamingAdapt ( mkBitfieldAdapt < int32_t > ( iTriggerMode , TriggerModeNames ) , " TriggerMode " , CTM_Default ) ) ;
2010-03-27 18:08:01 +00:00
pComp - > Value ( mkNamingAdapt ( fOverrideAssignments , " OverrideAssignments " , false ) ) ;
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 ;
2010-03-28 18:58:01 +00:00
}
2009-05-26 06:10:38 +00:00
2011-03-30 20:11:47 +00:00
void C4PlayerControlAssignment : : ResetKeyToInherited ( )
{
if ( inherited_assignment ) CopyKeyFrom ( * inherited_assignment ) ;
}
2011-03-31 14:26:59 +00:00
bool C4PlayerControlAssignment : : IsKeyChanged ( ) const
{
// no inherited assignment? Then the key is always custom
if ( ! inherited_assignment ) return true ;
// otherwise, compare
return KeyCombo ! = inherited_assignment - > KeyCombo | | fComboIsSequence ! = inherited_assignment - > fComboIsSequence ;
}
2011-03-30 20:11:47 +00:00
void C4PlayerControlAssignment : : SetKey ( const C4KeyCodeEx & key )
{
// set as one-key-combo
KeyCombo . resize ( 1 ) ;
KeyCombo [ 0 ] . Key = key ;
KeyCombo [ 0 ] . Key . fRepeated = false ;
KeyCombo [ 0 ] . sKeyName . Clear ( ) ;
fComboIsSequence = false ;
TriggerKey = key ;
}
void C4PlayerControlAssignment : : CopyKeyFrom ( const C4PlayerControlAssignment & src_assignment )
{
// just copy key settings; keep control and priorities
KeyCombo = src_assignment . KeyCombo ;
TriggerKey = src_assignment . TriggerKey ;
fComboIsSequence = src_assignment . fComboIsSequence ;
if ( ! src_assignment . fRefsResolved ) fRefsResolved = false ;
}
2009-05-26 06:10:38 +00:00
bool C4PlayerControlAssignment : : ResolveRefs ( C4PlayerControlAssignmentSet * pParentSet , C4PlayerControlDefs * pControlDefs )
2010-03-27 18:08:01 +00:00
{
2009-05-26 06:10:38 +00:00
// avoid circular chains
2012-10-08 18:45:04 +00:00
static int32_t recursion_check = 0 ;
if ( recursion_check > 10 )
2010-03-27 18:08:01 +00:00
{
2012-10-08 18:45:04 +00:00
LogFatal ( FormatString ( " Maximum recursion limit reached while resolving player control assignments of set %s in assignment for key %s. This is probably due to a circular control chain. " , pParentSet - > GetName ( ) , GetControlName ( ) ) . getData ( ) ) ;
2009-05-26 06:10:38 +00:00
return false ;
2010-03-27 18:08:01 +00:00
}
2012-10-08 18:45:04 +00:00
+ + recursion_check ;
2009-05-26 06:10:38 +00:00
// resolve control name
iControl = pControlDefs - > GetControlIndexByIdentifier ( sControlName . getData ( ) ) ;
// resolve keys
KeyComboVec NewCombo ;
for ( KeyComboVec : : iterator i = KeyCombo . begin ( ) ; i ! = KeyCombo . end ( ) ; + + i )
2010-03-27 18:08:01 +00:00
{
2009-05-26 06:10:38 +00:00
KeyComboItem & rKeyComboItem = * i ;
2012-10-08 18:45:04 +00:00
const char * szKeyName = rKeyComboItem . sKeyName . getData ( ) ;
// check if this is a key reference. A key reference must be preceded by CON_
// it may also be preceded by modifiers (Shift+), which are already set in rKeyComboItem.Key.dwShift
bool is_key_reference = false ;
int last_shift_delim_pos ;
if ( szKeyName & & * szKeyName )
2010-03-27 18:08:01 +00:00
{
if ( ( last_shift_delim_pos = SCharLastPos ( ' + ' , szKeyName ) ) > - 1 ) szKeyName + = last_shift_delim_pos + 1 ;
2012-10-08 18:45:04 +00:00
if ( SEqual2 ( szKeyName , " CON_ " ) )
{
is_key_reference = true ;
szKeyName + = 4 ;
}
}
if ( is_key_reference )
{
// this is a key reference
// - find referenced target assignment
2009-06-16 02:48:53 +00:00
C4PlayerControlAssignment * pRefAssignment = pParentSet - > GetAssignmentByControlName ( szKeyName ) ;
2009-05-26 06:10:38 +00:00
if ( pRefAssignment )
2010-03-27 18:08:01 +00:00
{
2009-05-26 06:10:38 +00:00
// resolve itself if necessary
2012-10-08 18:45:04 +00:00
if ( ! pRefAssignment - > IsRefsResolved ( ) ) if ( ! pRefAssignment - > ResolveRefs ( pParentSet , pControlDefs ) ) { - - recursion_check ; return false ; }
2009-05-26 06:10:38 +00:00
// insert all keys of that combo into own combo
2010-03-27 18:08:01 +00:00
// add any extra shift states from reference
DWORD ref_shift = rKeyComboItem . Key . dwShift ;
if ( ref_shift )
{
for ( KeyComboVec : : iterator j = pRefAssignment - > KeyCombo . begin ( ) ; j ! = pRefAssignment - > KeyCombo . end ( ) ; + + j )
{
KeyComboItem assignment_combo_item = * j ;
assignment_combo_item . Key . dwShift | = ref_shift ;
NewCombo . push_back ( assignment_combo_item ) ;
}
2009-05-26 06:10:38 +00:00
}
2010-03-27 18:08:01 +00:00
else
2009-05-26 06:10:38 +00:00
{
2010-03-27 18:08:01 +00:00
NewCombo . insert ( NewCombo . end ( ) , pRefAssignment - > KeyCombo . begin ( ) , pRefAssignment - > KeyCombo . end ( ) ) ;
}
}
else
{
2009-05-26 06:10:38 +00:00
// 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 ( ) ;
}
2010-03-27 18:08:01 +00:00
}
2009-05-26 06:10:38 +00:00
else
2010-03-27 18:08:01 +00:00
{
2012-10-08 18:45:04 +00:00
// non-reference: check if the assignment was valid
2012-11-30 21:16:59 +00:00
# ifndef USE_CONSOLE
2012-10-08 18:45:04 +00:00
if ( rKeyComboItem . Key = = KEY_Default )
2012-11-30 21:16:59 +00:00
LogF ( " WARNING: Control %s of set %s contains undefined key \" %s \" . " , GetControlName ( ) , pParentSet - > GetName ( ) , szKeyName ) ;
# endif
2012-10-08 18:45:04 +00:00
// ...and just keep this item.
2009-05-26 06:10:38 +00:00
NewCombo . push_back ( rKeyComboItem ) ;
}
2010-03-27 18:08:01 +00:00
}
2009-05-26 06:10:38 +00:00
KeyCombo = NewCombo ;
2015-09-01 23:10:34 +00:00
// adjust Control and Shift into key states for non-sequence combo keys
// e.g. LeftControl,A should become LeftControl,Ctrl+A.
if ( KeyCombo . size ( ) > 1 & & ! fComboIsSequence )
{
int32_t shift = 0 ;
for ( KeyComboVec : : iterator i = KeyCombo . begin ( ) ; i ! = KeyCombo . end ( ) ; + + i )
{
if ( i - > Key . Key = = K_CONTROL_L | | i - > Key . Key = = K_CONTROL_R ) shift | = KEYS_Control ;
if ( i - > Key . Key = = K_SHIFT_L | | i - > Key . Key = = K_SHIFT_R ) shift | = KEYS_Shift ;
shift | = i - > Key . dwShift ;
}
for ( KeyComboVec : : iterator i = KeyCombo . begin ( ) ; i ! = KeyCombo . end ( ) ; + + i ) i - > Key . dwShift | = shift ;
}
// remove control/shift duplications
for ( KeyComboVec : : iterator i = KeyCombo . begin ( ) ; i ! = KeyCombo . end ( ) ; + + i ) i - > Key . FixShiftKeys ( ) ;
2009-05-26 06:10:38 +00:00
// the trigger key is always last of the chain
if ( KeyCombo . size ( ) ) TriggerKey = KeyCombo . back ( ) . Key ; else TriggerKey = C4KeyCodeEx ( ) ;
// done
fRefsResolved = true ;
2012-10-08 18:45:04 +00:00
- - recursion_check ;
2009-05-26 06:10:38 +00:00
return true ;
2010-03-27 18:08:01 +00:00
}
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
2010-03-28 18:58:01 +00:00
{
2009-05-28 00:14:54 +00:00
assert ( HasCombo ( ) ) ;
// check if combo is currently fulfilled (assuming TriggerKey is already matched)
if ( fComboIsSequence )
2010-03-28 18:58:01 +00:00
{
2013-12-07 14:27:01 +00:00
C4TimeMilliseconds tKeyLast = C4TimeMilliseconds : : Now ( ) ;
2009-05-28 00:14:54 +00:00
// 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
2012-10-28 16:47:02 +00:00
KeyComboVec : : const_reverse_iterator i = KeyCombo . rbegin ( ) + 1 ;
for ( C4PlayerControlRecentKeyList : : const_reverse_iterator ri = RecentKeys . rbegin ( ) ; i ! = KeyCombo . rend ( ) ; + + ri )
2010-03-28 18:58:01 +00:00
{
2009-05-28 00:14:54 +00:00
// 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?
2013-12-04 12:35:07 +00:00
C4TimeMilliseconds tKeyRecent = rk . tTime ;
2009-05-28 00:14:54 +00:00
if ( tKeyLast - tKeyRecent > C4PlayerControl : : MaxSequenceKeyDelay ) return false ;
// key doesn't match?
const KeyComboItem & k = * i ;
2012-10-28 16:47:02 +00:00
if ( ! ( rk . matched_key = = k . Key ) )
{
// mouse movement commands do not break sequences
if ( Key_IsMouse ( rk . matched_key . Key ) & & Key_GetMouseEvent ( rk . matched_key . Key ) = = KEY_MOUSE_Move ) continue ;
return false ;
}
2009-05-28 00:14:54 +00:00
// key OK
2012-10-28 16:47:02 +00:00
+ + i ;
2009-05-28 00:14:54 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-28 00:14:54 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-28 00:14:54 +00:00
// 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 )
2010-03-28 18:58:01 +00:00
{
2009-05-28 00:14:54 +00:00
const KeyComboItem & k = * i ;
bool fFound = false ;
for ( C4PlayerControlRecentKeyList : : const_iterator di = DownKeys . begin ( ) ; di ! = DownKeys . end ( ) ; + + di )
2010-03-28 18:58:01 +00:00
{
2009-05-28 00:14:54 +00:00
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
}
2010-03-28 18:58:01 +00:00
if ( ! fFound ) return false ;
2009-05-28 00:14:54 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-28 00:14:54 +00:00
// combo OK!
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-28 00:14:54 +00:00
2009-05-25 09:01:26 +00:00
bool C4PlayerControlAssignment : : operator = = ( const C4PlayerControlAssignment & cmp ) const
2010-03-28 18:58:01 +00:00
{
2009-05-25 09:01:26 +00:00
// doesn't compare resolved TriggerKey/iControl
return KeyCombo = = cmp . KeyCombo
2010-03-28 18:58:01 +00:00
& & sControlName = = cmp . sControlName
2012-10-08 20:29:15 +00:00
& & sGUIName = = cmp . sGUIName
& & sGUIDesc = = cmp . sGUIDesc
2012-10-09 20:24:48 +00:00
& & fGUIDisabled = = cmp . fGUIDisabled
2010-03-28 18:58:01 +00:00
& & iTriggerMode = = cmp . iTriggerMode
& & iPriority = = cmp . iPriority ;
}
2009-05-25 09:01:26 +00:00
2012-04-17 15:06:16 +00:00
StdStrBuf C4PlayerControlAssignment : : GetKeysAsString ( bool human_readable , bool short_name ) const
{
// create a short, human-readable string of the assigned key
// to be displayed e.g. in tutorial messages explaining controls
StdStrBuf result ;
if ( ! KeyCombo . size ( ) ) return result ;
// trigger key
KeyComboVec : : const_iterator i = KeyCombo . begin ( ) ;
result . Take ( i - > Key . ToString ( human_readable , short_name ) ) ;
// extra keys of combo
while ( + + i ! = KeyCombo . end ( ) )
{
result . AppendChar ( fComboIsSequence ? ' , ' : ' + ' ) ;
result . Append ( i - > Key . ToString ( human_readable , short_name ) ) ;
}
return result ;
}
2012-10-08 20:29:15 +00:00
const char * C4PlayerControlAssignment : : GetGUIName ( const C4PlayerControlDefs & defs ) const
{
// local name?
if ( sGUIName . getLength ( ) )
{
// special: None defaults to empty name
if ( sGUIName = = " None " ) return " " ;
return sGUIName . getData ( ) ;
}
// otherwise, fall back to def
const C4PlayerControlDef * def = defs . GetControlByIndex ( GetControl ( ) ) ;
if ( def ) return def - > GetGUIName ( ) ;
// no def and no name...
return NULL ;
}
const char * C4PlayerControlAssignment : : GetGUIDesc ( const C4PlayerControlDefs & defs ) const
{
// local desc?
if ( sGUIDesc . getLength ( ) ) return sGUIDesc . getData ( ) ;
// otherwise, fall back to def
const C4PlayerControlDef * def = defs . GetControlByIndex ( GetControl ( ) ) ;
if ( def ) return def - > GetGUIDesc ( ) ;
// no def and no desc...
return NULL ;
}
2012-10-09 20:24:48 +00:00
bool C4PlayerControlAssignment : : IsGUIDisabled ( ) const
{
return fGUIDisabled ;
}
2009-05-25 09:01:26 +00:00
2012-10-09 21:59:32 +00:00
int32_t C4PlayerControlAssignment : : GetGUIGroup ( ) const
{
return iGUIGroup ;
}
2009-05-25 09:01:26 +00:00
/* C4PlayerControlAssignmentSet */
2011-03-30 20:11:47 +00:00
void C4PlayerControlAssignmentSet : : InitEmptyFromTemplate ( const C4PlayerControlAssignmentSet & template_set )
{
// copy all fields except assignments
sName . Copy ( template_set . sName ) ;
sGUIName . Copy ( template_set . sGUIName ) ;
sParentSetName . Copy ( template_set . sParentSetName ) ;
has_keyboard = template_set . has_keyboard ;
has_mouse = template_set . has_mouse ;
has_gamepad = template_set . has_gamepad ;
}
2009-05-25 09:01:26 +00:00
void C4PlayerControlAssignmentSet : : CompileFunc ( StdCompiler * pComp )
2010-03-28 18:58:01 +00:00
{
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
2011-03-30 20:11:47 +00:00
pComp - > Value ( mkNamingAdapt ( mkParAdapt ( sGUIName , StdCompiler : : RCT_All ) , " GUIName " , " undefined " ) ) ;
pComp - > Value ( mkNamingAdapt ( mkParAdapt ( sParentSetName , StdCompiler : : RCT_Idtf ) , " Parent " , " " ) ) ;
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 ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-25 09:01:26 +00:00
2012-10-09 21:59:32 +00:00
2011-03-30 20:11:47 +00:00
void C4PlayerControlAssignmentSet : : MergeFrom ( const C4PlayerControlAssignmentSet & Src , MergeMode merge_mode )
2010-03-27 18:08:01 +00:00
{
2009-05-25 09:01:26 +00:00
// 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 )
2010-03-27 18:08:01 +00:00
{
2009-05-25 09:01:26 +00:00
const C4PlayerControlAssignment & SrcAssignment = * i ;
2010-03-27 18:08:01 +00:00
bool fIsReleaseKey = ! ! ( SrcAssignment . GetTriggerMode ( ) & C4PlayerControlAssignment : : CTM_Release ) ;
// overwrite same def and release key state
2011-03-30 20:11:47 +00:00
if ( merge_mode ! = MM_LowPrio & & SrcAssignment . IsOverrideAssignments ( ) )
2010-03-27 18:08:01 +00:00
{
// high priority override control clears all previous (very inefficient method...might as well recreate the whole list)
bool any_remaining = true ;
while ( any_remaining )
2009-05-25 09:01:26 +00:00
{
2010-03-27 18:08:01 +00:00
any_remaining = false ;
for ( C4PlayerControlAssignmentVec : : iterator j = Assignments . begin ( ) ; j ! = Assignments . end ( ) ; + + j )
if ( SEqual ( ( * j ) . GetControlName ( ) , SrcAssignment . GetControlName ( ) ) )
{
bool fSelfIsReleaseKey = ! ! ( ( * j ) . GetTriggerMode ( ) & C4PlayerControlAssignment : : CTM_Release ) ;
if ( fSelfIsReleaseKey = = fIsReleaseKey )
{
Assignments . erase ( j ) ;
any_remaining = true ;
break ;
}
}
2009-05-25 09:01:26 +00:00
}
}
2011-03-30 20:11:47 +00:00
else if ( merge_mode = = MM_LowPrio | | merge_mode = = MM_ConfigOverload )
2010-03-27 18:08:01 +00:00
{
// if this is low priority, another override control kills this
bool any_override = false ;
for ( C4PlayerControlAssignmentVec : : iterator j = Assignments . begin ( ) ; j ! = Assignments . end ( ) ; + + j )
if ( SEqual ( ( * j ) . GetControlName ( ) , SrcAssignment . GetControlName ( ) ) )
{
bool fSelfIsReleaseKey = ! ! ( ( * j ) . GetTriggerMode ( ) & C4PlayerControlAssignment : : CTM_Release ) ;
if ( fSelfIsReleaseKey = = fIsReleaseKey )
{
any_override = true ;
2011-03-30 20:11:47 +00:00
// config overloads just change the key of the inherited assignment
if ( merge_mode = = MM_ConfigOverload )
{
( * j ) . CopyKeyFrom ( SrcAssignment ) ;
( * j ) . SetInherited ( false ) ;
}
2010-03-27 18:08:01 +00:00
break ;
}
}
if ( any_override ) continue ;
}
// new def: Append a copy
Assignments . push_back ( SrcAssignment ) ;
2011-03-30 20:11:47 +00:00
// inherited marker
if ( merge_mode = = MM_Inherit )
{
Assignments . back ( ) . SetInherited ( true ) ;
Assignments . back ( ) . SetInheritedAssignment ( & SrcAssignment ) ;
}
2009-05-25 09:01:26 +00:00
}
2010-03-27 18:08:01 +00:00
}
2009-05-25 09:01:26 +00:00
2011-03-30 20:11:47 +00:00
C4PlayerControlAssignment * C4PlayerControlAssignmentSet : : CreateAssignmentForControl ( const char * control_name )
{
Assignments . push_back ( C4PlayerControlAssignment ( ) ) ;
Assignments . back ( ) . SetControlName ( control_name ) ;
return & Assignments . back ( ) ;
}
void C4PlayerControlAssignmentSet : : RemoveAssignmentByControlName ( const char * control_name )
{
for ( C4PlayerControlAssignmentVec : : iterator i = Assignments . begin ( ) ; i ! = Assignments . end ( ) ; + + i )
if ( SEqual ( ( * i ) . GetControlName ( ) , control_name ) )
{
Assignments . erase ( i ) ;
return ;
}
}
2009-05-26 06:10:38 +00:00
bool C4PlayerControlAssignmentSet : : ResolveRefs ( C4PlayerControlDefs * pDefs )
2010-03-28 18:58:01 +00:00
{
2012-10-08 18:45:04 +00:00
// reset all resolved flags to allow re-resolve after overloads
for ( C4PlayerControlAssignmentVec : : iterator i = Assignments . begin ( ) ; i ! = Assignments . end ( ) ; + + i )
( * i ) . ResetRefsResolved ( ) ;
2009-05-26 06:10:38 +00:00
// 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 ;
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-26 06:10:38 +00:00
2011-03-31 14:26:59 +00:00
void C4PlayerControlAssignmentSet : : SortAssignments ( )
{
// final init: sort assignments by priority
// note this screws up sorting for config dialog
std : : sort ( Assignments . begin ( ) , Assignments . end ( ) ) ;
}
2011-03-30 20:11:47 +00:00
C4PlayerControlAssignment * C4PlayerControlAssignmentSet : : GetAssignmentByIndex ( int32_t index )
{
if ( index < 0 | | index > = int32_t ( Assignments . size ( ) ) ) return NULL ;
return & Assignments [ index ] ;
}
2009-05-26 06:10:38 +00:00
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
}
2011-03-30 20:11:47 +00:00
C4PlayerControlAssignment * C4PlayerControlAssignmentSet : : GetAssignmentByControl ( int32_t control )
2009-10-14 16:46:22 +00:00
{
// 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
2010-03-28 18:58:01 +00:00
{
2009-05-26 06:10:38 +00:00
return Assignments = = cmp . Assignments
2010-03-28 18:58:01 +00:00
& & sName = = cmp . sName ;
}
2009-05-26 06:10:38 +00:00
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
2010-02-18 17:43:38 +00:00
{
2009-05-28 00:14:54 +00:00
assert ( pOutVec ) ;
2010-02-18 17:43:38 +00:00
// primary match by TriggerKey (todo: Might use a hash map here if matching speed becomes an issue due to large control sets)
2009-05-28 00:14:54 +00:00
for ( C4PlayerControlAssignmentVec : : const_iterator i = Assignments . begin ( ) ; i ! = Assignments . end ( ) ; + + i )
2010-02-18 17:43:38 +00:00
{
2009-05-28 00:14:54 +00:00
const C4PlayerControlAssignment & rAssignment = * i ;
2010-02-18 17:43:38 +00:00
const C4KeyCodeEx & rAssignmentTriggerKey = rAssignment . GetTriggerKey ( ) ;
if ( ! ( rAssignmentTriggerKey . Key = = key . Key ) ) continue ;
// special: hold-keys-only ignore shift, because shift state might have been release during hold
if ( ! fHoldKeysOnly ) if ( rAssignmentTriggerKey . dwShift ! = key . dwShift ) continue ;
2009-05-28 00:14:54 +00:00
// check linked control def
const C4PlayerControlDef * pCtrl = rDefs . GetControlByIndex ( rAssignment . GetControl ( ) ) ;
if ( ! pCtrl ) continue ;
// only want hold keys?
if ( fHoldKeysOnly )
2010-02-18 17:43:38 +00:00
{
2009-05-28 00:14:54 +00:00
// 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 ;
2010-02-18 17:43:38 +00:00
}
2009-05-28 00:14:54 +00:00
else if ( rAssignment . HasCombo ( ) )
2010-02-18 17:43:38 +00:00
{
2009-05-28 00:14:54 +00:00
// 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 ;
2010-02-18 17:43:38 +00:00
}
2009-05-28 00:14:54 +00:00
// we got match! Store it
pOutVec - > push_back ( & rAssignment ) ;
}
2010-02-18 17:43:38 +00:00
}
2009-05-28 00:14:54 +00:00
void C4PlayerControlAssignmentSet : : GetTriggerKeys ( const C4PlayerControlDefs & rDefs , C4KeyCodeExVec * pRegularKeys , C4KeyCodeExVec * pHoldKeys ) const
2010-03-28 18:58:01 +00:00
{
2009-05-28 00:14:54 +00:00
// put all trigger keys of keyset into output vectors
// first all hold keys
for ( C4PlayerControlAssignmentVec : : const_iterator i = Assignments . begin ( ) ; i ! = Assignments . end ( ) ; + + i )
2010-03-28 18:58:01 +00:00
{
2009-05-28 00:14:54 +00:00
const C4PlayerControlAssignment & rAssignment = * i ;
const C4PlayerControlDef * pDef = rDefs . GetControlByIndex ( rAssignment . GetControl ( ) ) ;
if ( pDef & & pDef - > IsHoldKey ( ) )
2010-03-28 18:58:01 +00:00
{
2009-05-28 00:14:54 +00:00
const C4KeyCodeEx & rKey = rAssignment . GetTriggerKey ( ) ;
if ( std : : find ( pHoldKeys - > begin ( ) , pHoldKeys - > end ( ) , rKey ) = = pHoldKeys - > end ( ) ) pHoldKeys - > push_back ( rKey ) ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-28 00:14:54 +00:00
// then all regular keys that aren't in the hold keys list yet
for ( C4PlayerControlAssignmentVec : : const_iterator i = Assignments . begin ( ) ; i ! = Assignments . end ( ) ; + + i )
2010-03-28 18:58:01 +00:00
{
2009-05-28 00:14:54 +00:00
const C4PlayerControlAssignment & rAssignment = * i ;
const C4PlayerControlDef * pDef = rDefs . GetControlByIndex ( rAssignment . GetControl ( ) ) ;
if ( pDef & & ! pDef - > IsHoldKey ( ) )
2010-03-28 18:58:01 +00:00
{
2009-05-28 00:14:54 +00:00
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 ) ;
}
}
2010-03-28 18:58:01 +00:00
}
2009-05-28 00:14:54 +00:00
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 ( ) ) ;
2012-01-29 02:13:55 +00:00
// if (HasMouse()) return ::GraphicsResource.fctMouse; // might be useful again with changing control sets
2012-01-25 04:53:59 +00:00
if ( HasKeyboard ( ) ) return : : GraphicsResource . fctKeyboard . GetPhase ( Game . PlayerControlUserAssignmentSets . GetSetIndex ( this ) ) ;
2009-10-14 16:46:22 +00:00
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 ( )
2010-03-28 18:58:01 +00:00
{
2009-05-26 06:10:38 +00:00
Sets . clear ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-26 06:10:38 +00:00
void C4PlayerControlAssignmentSets : : CompileFunc ( StdCompiler * pComp )
2010-03-28 18:58:01 +00:00
{
2011-03-30 20:11:47 +00:00
if ( pComp - > isDecompiler ( ) & & pComp - > isRegistry ( ) )
{
pComp - > Default ( " ControlSets " ) ; // special registry compiler: Clean out everything before
}
2011-07-16 09:58:38 +00:00
pComp - > Value ( mkNamingAdapt ( clear_previous , " ClearPrevious " , false ) ) ;
pComp - > Value ( mkSTLContainerAdapt ( Sets , StdCompiler : : SEP_NONE ) ) ;
2016-01-12 02:07:00 +00:00
// Remove all sets that have gamepad controls, since gamepad
// support is broken at the moment. Disable this once we have gamepad
// support again!
if ( pComp - > isCompiler ( ) )
{
AssignmentSetList : : iterator iter = Sets . begin ( ) ;
for ( AssignmentSetList : : iterator iter = Sets . begin ( ) ; iter ! = Sets . end ( ) ; )
{
if ( iter - > HasGamepad ( ) )
iter = Sets . erase ( iter ) ;
else
+ + iter ;
}
}
2010-03-28 18:58:01 +00:00
}
2009-05-26 06:10:38 +00:00
2011-03-30 20:11:47 +00:00
bool C4PlayerControlAssignmentSets : : operator = = ( const C4PlayerControlAssignmentSets & cmp ) const
{
2011-07-16 09:58:38 +00:00
return Sets = = cmp . Sets & & clear_previous = = cmp . clear_previous ;
2011-03-30 20:11:47 +00:00
}
void C4PlayerControlAssignmentSets : : MergeFrom ( const C4PlayerControlAssignmentSets & Src , C4PlayerControlAssignmentSet : : MergeMode merge_mode )
2010-03-28 18:58:01 +00:00
{
2011-07-16 09:58:38 +00:00
// if source set is flagged to clear previous, do this!
if ( Src . clear_previous ) Sets . clear ( ) ;
2009-05-26 06:10:38 +00:00
// 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 )
2010-03-28 18:58:01 +00:00
{
2009-05-26 06:10:38 +00:00
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 )
2010-03-28 18:58:01 +00:00
{
2009-06-16 00:38:39 +00:00
C4PlayerControlAssignmentSet * pPrevSet = GetSetByName ( SrcSet . GetName ( ) ) ;
2011-03-30 20:11:47 +00:00
if ( ! pPrevSet & & merge_mode = = C4PlayerControlAssignmentSet : : MM_Inherit )
{
// inherited sets must go through merge procedure to set inherited links
pPrevSet = CreateEmptySetByTemplate ( SrcSet ) ;
}
2009-06-16 00:38:39 +00:00
if ( pPrevSet )
2010-03-28 18:58:01 +00:00
{
2011-03-30 20:11:47 +00:00
pPrevSet - > MergeFrom ( SrcSet , merge_mode ) ;
2010-03-28 18:58:01 +00:00
}
2009-06-16 00:38:39 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-06-16 00:38:39 +00:00
// new def: Append a copy
Sets . push_back ( SrcSet ) ;
2009-05-26 06:10:38 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-26 06:10:38 +00:00
else
2010-03-28 18:58:01 +00:00
{
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 )
2010-03-28 18:58:01 +00:00
{
2009-06-16 00:38:39 +00:00
C4PlayerControlAssignmentSet & DstSet = * j ;
if ( WildcardMatch ( SrcSet . GetName ( ) , DstSet . GetName ( ) ) )
2010-03-28 18:58:01 +00:00
{
2011-03-30 20:11:47 +00:00
DstSet . MergeFrom ( SrcSet , merge_mode ) ;
2009-06-16 00:38:39 +00:00
}
2009-05-26 06:10:38 +00:00
}
}
}
2010-03-28 18:58:01 +00:00
}
2009-05-26 06:10:38 +00:00
bool C4PlayerControlAssignmentSets : : ResolveRefs ( C4PlayerControlDefs * pDefs )
2010-03-28 18:58:01 +00:00
{
2009-05-26 06:10:38 +00:00
for ( AssignmentSetList : : iterator i = Sets . begin ( ) ; i ! = Sets . end ( ) ; + + i )
if ( ! ( * i ) . ResolveRefs ( pDefs ) ) return false ;
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-26 06:10:38 +00:00
2011-03-31 14:26:59 +00:00
void C4PlayerControlAssignmentSets : : SortAssignments ( )
{
for ( AssignmentSetList : : iterator i = Sets . begin ( ) ; i ! = Sets . end ( ) ; + + i )
( * i ) . SortAssignments ( ) ;
}
2009-05-26 06:10:38 +00:00
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 ;
}
2011-03-30 20:11:47 +00:00
C4PlayerControlAssignmentSet * C4PlayerControlAssignmentSets : : CreateEmptySetByTemplate ( const C4PlayerControlAssignmentSet & template_set )
{
Sets . push_back ( C4PlayerControlAssignmentSet ( ) ) ;
Sets . back ( ) . InitEmptyFromTemplate ( template_set ) ;
return & Sets . back ( ) ;
}
void C4PlayerControlAssignmentSets : : RemoveSetByName ( const char * set_name )
{
for ( AssignmentSetList : : iterator i = Sets . begin ( ) ; i ! = Sets . end ( ) ; + + i )
if ( SEqual ( set_name , ( * i ) . GetName ( ) ) )
{
Sets . erase ( i ) ;
return ;
}
}
2009-05-26 06:10:38 +00:00
/* C4PlayerControlFile */
void C4PlayerControlFile : : CompileFunc ( StdCompiler * pComp )
2010-03-28 18:58:01 +00:00
{
2011-07-16 09:58:38 +00:00
pComp - > Value ( mkNamingAdapt ( ControlDefs , " ControlDefs " , C4PlayerControlDefs ( ) ) ) ;
pComp - > Value ( mkNamingAdapt ( AssignmentSets , " ControlSets " , C4PlayerControlAssignmentSets ( ) ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-26 06:10:38 +00:00
bool C4PlayerControlFile : : Load ( C4Group & hGroup , const char * szFilename , C4LangStringTable * pLang )
2010-03-28 18:58:01 +00:00
{
2009-05-26 06:10:38 +00:00
// clear previous
Clear ( ) ;
// load and prepare file contents
StdStrBuf Buf ;
2011-03-05 01:44:26 +00:00
if ( ! hGroup . LoadEntryString ( szFilename , & Buf ) ) return false ;
2009-05-26 06:10:38 +00:00
if ( pLang ) pLang - > ReplaceStrings ( Buf ) ;
// parse it!
if ( ! CompileFromBuf_LogWarn < StdCompilerINIRead > ( * this , Buf , szFilename ) ) return false ;
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-26 06:10:38 +00:00
bool C4PlayerControlFile : : Save ( C4Group & hGroup , const char * szFilename )
2010-03-28 18:58:01 +00:00
{
2009-05-26 06:10:38 +00:00
// 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 ;
2010-03-28 18:58:01 +00:00
}
2009-05-26 06:10:38 +00:00
void C4PlayerControlFile : : Clear ( )
2010-03-28 18:58:01 +00:00
{
2009-05-26 06:10:38 +00:00
ControlDefs . Clear ( ) ;
AssignmentSets . Clear ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-26 06:10:38 +00:00
/* C4PlayerControl */
2009-05-28 00:14:54 +00:00
void C4PlayerControl : : CSync : : ControlDownState : : CompileFunc ( StdCompiler * pComp )
2010-03-28 18:58:01 +00:00
{
2009-05-28 00:14:54 +00:00
pComp - > Value ( DownState ) ;
2010-04-01 21:08:06 +00:00
pComp - > Separator ( ) ;
2009-05-28 00:14:54 +00:00
pComp - > Value ( iDownFrame ) ;
2010-04-01 21:08:06 +00:00
pComp - > Separator ( ) ;
2009-05-28 00:14:54 +00:00
pComp - > Value ( fDownByUser ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-28 00:14:54 +00:00
bool C4PlayerControl : : CSync : : ControlDownState : : operator = = ( const ControlDownState & cmp ) const
2010-03-28 18:58:01 +00:00
{
2009-05-28 00:14:54 +00:00
return DownState = = cmp . DownState & & iDownFrame = = cmp . iDownFrame & & fDownByUser = = cmp . fDownByUser ;
2010-03-28 18:58:01 +00:00
}
2009-05-28 00:14:54 +00:00
const C4PlayerControl : : CSync : : ControlDownState * C4PlayerControl : : CSync : : GetControlDownState ( int32_t iControl ) const
2010-03-28 18:58:01 +00:00
{
2009-05-28 00:14:54 +00:00
// 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 ] ;
2010-03-28 18:58:01 +00:00
}
2009-05-28 00:14:54 +00:00
int32_t C4PlayerControl : : CSync : : GetControlDisabled ( int32_t iControl ) const
2010-03-28 18:58:01 +00:00
{
2009-05-28 00:14:54 +00:00
// 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 ] ;
2010-03-28 18:58:01 +00:00
}
2009-05-28 00:14:54 +00:00
void C4PlayerControl : : CSync : : SetControlDownState ( int32_t iControl , const C4KeyEventData & rDownState , int32_t iDownFrame , bool fDownByUser )
2010-03-28 18:58:01 +00:00
{
2009-05-28 00:14:54 +00:00
// 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 ;
2010-03-28 18:58:01 +00:00
}
2009-05-28 00:14:54 +00:00
2009-12-27 18:11:14 +00:00
bool C4PlayerControl : : CSync : : SetControlDisabled ( int32_t iControl , int32_t iVal )
2010-03-28 18:58:01 +00:00
{
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
2010-07-30 20:30:54 +00:00
ResetControlDownState ( iControl ) ;
return true ;
}
void C4PlayerControl : : CSync : : ResetControlDownState ( int32_t iControl )
{
// silently reset down state of control
2009-05-28 00:14:54 +00:00
const ControlDownState * pDownState = GetControlDownState ( iControl ) ;
if ( pDownState & & pDownState - > IsDown ( ) )
2010-03-28 18:58:01 +00:00
{
2009-05-28 00:14:54 +00:00
C4KeyEventData KeyDownState = pDownState - > DownState ;
KeyDownState . iStrength = 0 ;
SetControlDownState ( iControl , KeyDownState , 0 , false ) ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-28 00:14:54 +00:00
2010-03-26 13:48:28 +00:00
void C4PlayerControl : : CSync : : InitDefaults ( const C4PlayerControlDefs & ControlDefs )
{
const C4PlayerControlDef * def ;
int32_t i = 0 ;
2010-03-26 22:51:52 +00:00
while ( ( def = ControlDefs . GetControlByIndex ( i ) ) )
2010-03-26 13:48:28 +00:00
{
if ( def - > IsDefaultDisabled ( ) ) SetControlDisabled ( i , true ) ;
+ + i ;
}
}
2009-05-28 00:14:54 +00:00
void C4PlayerControl : : CSync : : Clear ( )
2010-03-28 18:58:01 +00:00
{
2009-05-28 00:14:54 +00:00
ControlDownStates . clear ( ) ;
ControlDisableStates . clear ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-28 00:14:54 +00:00
2009-05-26 06:10:38 +00:00
void C4PlayerControl : : CSync : : CompileFunc ( StdCompiler * pComp )
2010-03-28 18:58:01 +00:00
{
2009-05-26 06:10:38 +00:00
pComp - > Value ( mkNamingAdapt ( mkSTLContainerAdapt ( ControlDownStates ) , " Down " , DownStateVec ( ) ) ) ;
pComp - > Value ( mkNamingAdapt ( mkSTLContainerAdapt ( ControlDisableStates ) , " Disabled " , DisableStateVec ( ) ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-26 06:10:38 +00:00
bool C4PlayerControl : : CSync : : operator = = ( const CSync & cmp ) const
2010-03-28 18:58:01 +00:00
{
2009-05-26 06:10:38 +00:00
return ControlDownStates = = cmp . ControlDownStates
2010-03-28 18:58:01 +00:00
& & ControlDisableStates = = cmp . ControlDisableStates ;
}
2009-05-26 06:10:38 +00:00
2010-03-26 13:48:28 +00:00
void C4PlayerControl : : Init ( )
{
// defaultdisabled controls
Sync . InitDefaults ( ControlDefs ) ;
}
2009-05-26 06:10:38 +00:00
void C4PlayerControl : : CompileFunc ( StdCompiler * pComp )
2010-03-28 18:58:01 +00:00
{
2009-05-26 06:10:38 +00:00
// compile sync values only
2010-03-26 13:48:28 +00:00
CSync DefaultSync ;
DefaultSync . InitDefaults ( ControlDefs ) ;
pComp - > Value ( mkNamingAdapt ( Sync , " PlayerControl " , DefaultSync ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-26 06:10:38 +00:00
2013-09-02 15:27:15 +00:00
bool C4PlayerControl : : ProcessKeyEvent ( const C4KeyCodeEx & pressed_key , const C4KeyCodeEx & matched_key , bool fUp , const C4KeyEventData & rKeyExtraData , bool reset_down_states_only , bool * clear_recent_keys )
2010-03-28 18:58:01 +00:00
{
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 )
2010-03-28 18:58:01 +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 ) ;
2010-04-28 22:46:38 +00:00
if ( pControlDef & & pControlDef - > IsValid ( ) & & ! Sync . IsControlDisabled ( iControlIndex ) & & ( ! fUp | | pControlDef - > IsHoldKey ( ) ) )
2010-03-28 18:58:01 +00:00
{
2013-09-02 15:27:15 +00:00
// clear RecentKeys if requested by this assignment. Must be done before sync queue, so multiple combos can be issued in a single control frame.
if ( clear_recent_keys & & ( pAssignment - > GetTriggerMode ( ) & C4PlayerControlAssignment : : CTM_ClearRecentKeys ) ) * clear_recent_keys = true ;
2010-04-10 20:44:00 +00:00
// extra data from key or overwrite by current cursor pos if definition requires it
2009-05-26 06:10:38 +00:00
if ( pControlDef - > IsAsync ( ) & & ! pControlPacket )
2010-03-28 18:58:01 +00:00
{
2010-05-07 13:57:56 +00:00
if ( pControlDef - > IsSendCursorPos ( ) ) IsCursorPosRequested = true ; // async cursor pos request - doesn't really make sense to set this flag for async controls
2010-07-30 20:30:54 +00:00
if ( ExecuteControl ( iControlIndex , fUp , rKeyExtraData , pAssignment - > GetTriggerMode ( ) , pressed_key . IsRepeated ( ) , reset_down_states_only ) )
2009-05-26 06:10:38 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-26 06:10:38 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-26 06:10:38 +00:00
// 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
2010-05-07 13:57:56 +00:00
if ( ! pControlPacket ) pControlPacket = new C4ControlPlayerControl ( iPlr , fUp , rKeyExtraData ) ;
2010-07-30 20:30:54 +00:00
int32_t extra_trigger_mode = 0 ;
if ( reset_down_states_only ) extra_trigger_mode | = C4PlayerControlAssignment : : CTM_HandleDownStatesOnly ;
pControlPacket - > AddControl ( iControlIndex , pAssignment - > GetTriggerMode ( ) | extra_trigger_mode ) ;
2010-05-07 13:57:56 +00:00
// sync cursor pos request; pos will be added to control before it is synced/executed
if ( pControlDef - > IsSendCursorPos ( ) ) IsCursorPosRequested = true ;
2009-05-26 06:10:38 +00:00
}
}
2010-03-28 18:58:01 +00:00
}
2009-05-26 06:10:38 +00:00
// push sync control to input
2009-05-28 00:14:54 +00:00
if ( pControlPacket )
2010-03-28 18:58:01 +00:00
{
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 ;
2009-05-26 06:10:38 +00:00
}
2010-03-28 18:58:01 +00:00
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
2013-12-07 14:27:01 +00:00
C4PlayerControlRecentKey RKey ( pressed_key , matched_key , C4TimeMilliseconds : : Now ( ) ) ;
2011-11-20 20:49:38 +00:00
if ( ! Key_IsMouse ( pressed_key . Key ) | | Inside < uint8_t > ( Key_GetMouseEvent ( pressed_key . Key ) , 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!
2013-09-02 15:27:15 +00:00
bool clear_recent_keys = false ;
bool fResult = ProcessKeyEvent ( pressed_key , matched_key , false , Game . KeyboardInput . GetLastKeyExtraData ( ) , false , & clear_recent_keys ) ;
// unless assignment requests a clear, always add keys to recent list even if not handled
if ( clear_recent_keys )
RecentKeys . clear ( ) ;
else if ( ! pressed_key . IsRepeated ( ) ) // events caused by holding down the key are not added to recent list (so you cannot cause "double-Q" just by holding down Q)
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
2011-11-20 20:49:38 +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!
2011-11-20 20:49:38 +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 )
2010-03-28 18:58:01 +00:00
{
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)
2010-07-30 20:30:54 +00:00
bool fHandleDownStateOnly = false ;
2009-05-28 00:14:54 +00:00
for ( C4ControlPlayerControl : : ControlItemVec : : const_iterator i = pCtrl - > GetControlItems ( ) . begin ( ) ; i ! = pCtrl - > GetControlItems ( ) . end ( ) ; + + i )
2010-03-28 18:58:01 +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 )
2010-03-28 18:58:01 +00:00
{
2013-05-25 20:38:08 +00:00
if ( Config . General . DebugRec )
2011-12-28 23:12:21 +00:00
{
2013-05-25 20:38:08 +00:00
if ( pCtrlDef - > IsSync ( ) )
{
AddDbgRec ( RCT_PlrCom , & rItem . iControl , sizeof ( rItem . iControl ) ) ;
}
2011-12-28 23:12:21 +00:00
}
2010-07-30 20:30:54 +00:00
if ( ExecuteControl ( rItem . iControl , pCtrl - > IsReleaseControl ( ) , pCtrl - > GetExtraData ( ) , rItem . iTriggerMode , false , fHandleDownStateOnly ) )
2009-05-26 06:10:38 +00:00
if ( pCtrlDef - > IsSync ( ) )
2010-07-30 20:30:54 +00:00
{
if ( pCtrl - > IsReleaseControl ( ) )
{
// control processed. however, for key releases, overriden keys are released silently so following down events aren't handled as key repeats
// note this does not affect CTM_Hold/CTM_Release, because they ignore release controls anyway
fHandleDownStateOnly = true ;
}
else
{
break ;
}
}
2009-05-26 06:10:38 +00:00
}
}
2010-03-28 18:58:01 +00:00
}
2009-05-26 06:10:38 +00:00
2010-07-30 20:30:54 +00:00
bool C4PlayerControl : : ExecuteControl ( int32_t iControl , bool fUp , const C4KeyEventData & rKeyExtraData , int32_t iTriggerMode , bool fRepeated , bool fHandleDownStateOnly )
2010-03-28 18:58:01 +00:00
{
2009-05-26 06:10:38 +00:00
// 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 ;
2010-07-30 20:30:54 +00:00
// down state handling only?
if ( iTriggerMode & C4PlayerControlAssignment : : CTM_HandleDownStatesOnly ) fHandleDownStateOnly = true ;
2009-05-26 06:10:38 +00:00
// hold-actions only work on script controls with the hold flag
if ( iTriggerMode & ( C4PlayerControlAssignment : : CTM_Hold | C4PlayerControlAssignment : : CTM_Release ) )
2010-03-28 18:58:01 +00:00
{
2009-05-26 06:10:38 +00:00
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 )
2010-03-28 18:58:01 +00:00
{
2009-05-26 06:10:38 +00:00
// control is currently down: release?
if ( iTriggerMode & C4PlayerControlAssignment : : CTM_Release )
2010-03-28 18:58:01 +00:00
{
2009-05-26 06:10:38 +00:00
KeyExtraData . iStrength = 0 ;
Sync . SetControlDownState ( iControl , KeyExtraData , Game . FrameCounter , false ) ;
// now process as a regular "Up" event
fUp = true ;
fRepeated = false ;
2010-03-28 18:58:01 +00:00
}
2015-03-25 18:04:04 +00:00
else
2010-03-28 18:58:01 +00:00
{
2015-03-25 18:04:04 +00:00
assert ( iTriggerMode & C4PlayerControlAssignment : : CTM_Hold ) ;
2009-05-26 06:10:38 +00:00
// 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 ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-26 06:10:38 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-26 06:10:38 +00:00
// control is currently up. Put into hold-down-state if this is a hold key
if ( iTriggerMode & C4PlayerControlAssignment : : CTM_Hold )
2010-03-28 18:58:01 +00:00
{
2009-05-26 06:10:38 +00:00
Sync . SetControlDownState ( iControl , KeyExtraData , Game . FrameCounter , false ) ;
// now process as a regular "down" event
fRepeated = false ;
2010-03-28 18:58:01 +00:00
}
2009-05-26 06:10:38 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-26 06:10:38 +00:00
//. Ignore if it's only a release key
return false ;
}
}
2010-03-28 18:58:01 +00:00
}
2009-05-26 06:10:38 +00:00
else if ( fUp )
2010-03-28 18:58:01 +00:00
{
2009-05-26 06:10:38 +00:00
// 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 ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-28 00:14:54 +00:00
else if ( pControlDef - > IsHoldKey ( ) )
2010-03-28 18:58:01 +00:00
{
2009-05-28 00:14:54 +00:00
// regular ControlDown on Hold Key: Set in down list
Sync . SetControlDownState ( iControl , KeyExtraData , Game . FrameCounter , true ) ;
fRepeated = fWasDown ;
2010-03-28 18:58:01 +00:00
}
2010-07-30 20:30:54 +00:00
// down state handling done
if ( fHandleDownStateOnly ) return false ;
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 ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-26 06:10:38 +00:00
bool C4PlayerControl : : ExecuteControlAction ( int32_t iControl , C4PlayerControlDef : : Actions eAction , C4ID idControlExtraData , bool fUp , const C4KeyEventData & rKeyExtraData , bool fRepeated )
2010-03-28 18:58:01 +00:00
{
2009-05-26 06:10:38 +00:00
// get affected player
C4Player * pPlr = NULL ;
2009-12-31 17:20:45 +00:00
C4Viewport * pVP ;
2010-02-08 20:52:46 +00:00
C4Object * pCursor = NULL ;
C4Menu * pCursorMenu = NULL ;
2009-05-26 06:10:38 +00:00
if ( iPlr > - 1 )
2010-03-28 18:58:01 +00:00
{
2009-08-10 14:48:25 +00:00
pPlr = : : Players . Get ( iPlr ) ;
2009-05-26 06:10:38 +00:00
if ( ! pPlr ) return false ;
2010-02-08 20:52:46 +00:00
pCursor = pPlr - > Cursor ;
if ( pCursor & & pCursor - > Menu & & pCursor - > Menu - > IsActive ( ) ) pCursorMenu = pCursor - > Menu ;
2010-03-28 18:58:01 +00:00
}
2009-05-26 06:10:38 +00:00
// exec action (on player)
switch ( eAction )
2010-03-28 18:58:01 +00:00
{
2009-05-26 06:10:38 +00:00
// scripted player control
2010-03-28 18:58:01 +00:00
case C4PlayerControlDef : : CDA_Script :
return ExecuteControlScript ( iControl , idControlExtraData , fUp , rKeyExtraData , fRepeated ) ;
2009-05-26 06:10:38 +00:00
// menu controls
2010-03-28 18:58:01 +00:00
case C4PlayerControlDef : : CDA_Menu : if ( ! pPlr | | fUp ) return false ; if ( pPlr - > Menu . IsActive ( ) ) pPlr - > Menu . TryClose ( false , true ) ; 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
2014-08-10 18:58:26 +00:00
case C4PlayerControlDef : : CDA_MenuDown : if ( ! pPlr | | ! pPlr - > Menu . IsActive ( ) | | fUp ) return false ; pPlr - > Menu . Control ( COM_MenuRight , 0 ) ; return true ; // navigate
case C4PlayerControlDef : : CDA_ObjectMenuTextComplete : if ( ! pCursorMenu | | fUp | | ! pCursorMenu - > IsTextProgressing ( ) ) return false ; pCursorMenu - > Control ( COM_MenuShowText , 0 ) ; return true ; // fast-foward text display
2010-03-28 18:58:01 +00:00
case C4PlayerControlDef : : CDA_ObjectMenuOK : if ( ! pCursorMenu | | fUp ) return false ; pCursorMenu - > Control ( COM_MenuEnter , 0 ) ; return true ; // ok on item
case C4PlayerControlDef : : CDA_ObjectMenuOKAll : if ( ! pCursorMenu | | fUp ) return false ; pCursorMenu - > Control ( COM_MenuEnterAll , 0 ) ; return true ; // alt ok on item
case C4PlayerControlDef : : CDA_ObjectMenuSelect : if ( ! pCursorMenu | | fUp ) return false ; pCursorMenu - > Control ( COM_MenuSelect , rKeyExtraData . iStrength ) ; return true ; // select an item directly
case C4PlayerControlDef : : CDA_ObjectMenuCancel : if ( ! pCursorMenu | | fUp ) return false ; pCursorMenu - > Control ( COM_MenuClose , 0 ) ; return true ; // close menu
case C4PlayerControlDef : : CDA_ObjectMenuLeft : if ( ! pCursorMenu | | fUp ) return false ; pCursorMenu - > Control ( COM_MenuLeft , 0 ) ; return true ; // navigate
case C4PlayerControlDef : : CDA_ObjectMenuUp : if ( ! pCursorMenu | | fUp ) return false ; pCursorMenu - > Control ( COM_MenuUp , 0 ) ; return true ; // navigate
case C4PlayerControlDef : : CDA_ObjectMenuRight : if ( ! pCursorMenu | | fUp ) return false ; pCursorMenu - > Control ( COM_MenuRight , 0 ) ; return true ; // navigate
case C4PlayerControlDef : : CDA_ObjectMenuDown : if ( ! pCursorMenu | | fUp ) return false ; pCursorMenu - > Control ( COM_MenuDown , 0 ) ; return true ; // navigate
2010-12-15 01:16:24 +00:00
case C4PlayerControlDef : : CDA_ZoomIn : if ( ! pPlr | | fUp | | ! ( pVP = : : Viewports . GetViewport ( iPlr ) ) ) return false ; pVP - > ChangeZoom ( C4GFX_ZoomStep ) ; return true ; // viewport zoom
case C4PlayerControlDef : : CDA_ZoomOut : if ( ! pPlr | | fUp | | ! ( pVP = : : Viewports . GetViewport ( iPlr ) ) ) return false ; pVP - > ChangeZoom ( 1.0f / C4GFX_ZoomStep ) ; return true ; // viewport zoom
2009-05-26 06:10:38 +00:00
//unknown action
2010-03-28 18:58:01 +00:00
default : return false ;
2009-05-26 06:10:38 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-26 06:10:38 +00:00
bool C4PlayerControl : : ExecuteControlScript ( int32_t iControl , C4ID idControlExtraData , bool fUp , const C4KeyEventData & rKeyExtraData , bool fRepeated )
2010-03-28 18:58:01 +00:00
{
2009-08-10 14:48:25 +00:00
C4Player * pPlr = : : Players . Get ( iPlr ) ;
2009-05-28 00:14:54 +00:00
if ( pPlr )
2010-03-28 18:58:01 +00:00
{
2009-05-28 00:14:54 +00:00
// 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 ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-28 00:14:54 +00:00
else if ( iPlr > - 1 )
2010-03-28 18:58:01 +00:00
{
2009-05-28 00:14:54 +00:00
// player lost?
return false ;
2010-03-28 18:58:01 +00:00
}
2011-11-20 20:49:38 +00:00
// get coordinates
int32_t x , y ;
const C4PlayerControlDef * def = ControlDefs . GetControlByIndex ( iControl ) ;
if ( def & & def - > GetCoordinateSpace ( ) = = C4PlayerControlDef : : COS_Viewport )
{
x = rKeyExtraData . vp_x ; y = rKeyExtraData . vp_y ;
}
else
{
x = rKeyExtraData . game_x ; y = rKeyExtraData . game_y ;
}
2016-01-17 03:06:19 +00:00
C4Value vx = ( x = = C4KeyEventData : : KeyPos_None ) ? C4VNull : C4VInt ( x ) ;
C4Value vy = ( y = = C4KeyEventData : : KeyPos_None ) ? C4VNull : C4VInt ( y ) ;
2011-11-20 20:49:38 +00:00
// exec control function
2016-01-17 03:06:19 +00:00
C4AulParSet Pars ( C4VInt ( iPlr ) , C4VInt ( iControl ) , C4VPropList ( C4Id2Def ( idControlExtraData ) ) , vx , vy , C4VInt ( rKeyExtraData . iStrength ) , C4VBool ( fRepeated ) , C4VBool ( fUp ) ) ;
2011-10-15 20:07:45 +00:00
return : : ScriptEngine . GetPropList ( ) - > Call ( PSF_PlayerControl , & Pars ) . getBool ( ) ;
2010-03-28 18:58:01 +00:00
}
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
2010-04-21 19:12:49 +00:00
for ( size_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
2013-12-07 14:27:01 +00:00
C4TimeMilliseconds tNow = C4TimeMilliseconds : : Now ( ) ;
2009-05-28 00:14:54 +00:00
C4PlayerControlRecentKeyList : : iterator irk ;
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
2010-05-07 13:57:56 +00:00
C4PlayerControl : : C4PlayerControl ( ) : ControlDefs ( Game . PlayerControlDefs ) , iPlr ( - 1 ) , pControlSet ( NULL ) , IsCursorPosRequested ( false )
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 ( ) ;
2010-05-07 13:57:56 +00:00
IsCursorPosRequested = false ;
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
// 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 (
2010-03-28 18:58:01 +00:00
key , FormatString ( " PlrKey%02d " , idx ) . getData ( ) , KEYSCOPE_Control ,
new C4KeyCBExPassKey < C4PlayerControl , C4KeyCodeEx > ( * this , key , & C4PlayerControl : : ProcessKeyDown , fHoldKey ? & C4PlayerControl : : ProcessKeyUp : NULL ) ,
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 )
{
2010-03-28 18:58:01 +00:00
case C4MC_Button_None : mouseevent_code = KEY_MOUSE_Move ; break ;
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
case C4MC_Button_RightDown : mouseevent_code = KEY_MOUSE_ButtonRight ; break ;
case C4MC_Button_LeftDouble : mouseevent_code = KEY_MOUSE_ButtonLeftDouble ; break ;
case C4MC_Button_RightDouble : mouseevent_code = KEY_MOUSE_ButtonRightDouble ; break ;
case C4MC_Button_MiddleUp : is_down = false ; // nobreak
case C4MC_Button_MiddleDown : mouseevent_code = KEY_MOUSE_ButtonMiddle ; break ;
case C4MC_Button_Wheel :
if ( ! wheel_dir ) return false ;
mouseevent_code = ( wheel_dir > 0 ) ? KEY_MOUSE_Wheel1Up : KEY_MOUSE_Wheel1Down ; break ;
default : assert ( false ) ; return false ;
2009-10-17 15:53:26 +00:00
}
// 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 ;
2011-11-20 20:49:38 +00:00
mouseevent_keycode . Key = KEY_Mouse ( mouse_id , mouseevent_code ) ;
2009-10-17 15:53:26 +00:00
// 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
2011-11-20 20:49:38 +00:00
mouseevent_data . vp_x = uint32_t ( gui_x ) ;
mouseevent_data . vp_y = uint32_t ( gui_y ) ;
mouseevent_data . game_x = uint32_t ( game_x ) ;
mouseevent_data . game_y = uint32_t ( game_y ) ;
2009-10-17 15:53:26 +00:00
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 ) ;
return result ;
}
2010-04-10 20:44:00 +00:00
2011-11-20 20:49:38 +00:00
bool C4PlayerControl : : GetCurrentPlayerCursorPos ( int32_t * x_out , int32_t * y_out , int32_t * game_x_out , int32_t * game_y_out )
2010-04-10 20:44:00 +00:00
{
// prefer mouse position if this is a mouse control
if ( pControlSet & & pControlSet - > HasMouse ( ) )
{
if ( MouseControl . GetLastGUIPos ( x_out , y_out ) )
return true ;
// if getting the mouse position failed, better fall back to cursor pos
}
// no mouse position known. Use cursor.
C4Player * plr = Players . Get ( iPlr ) ;
if ( ! plr ) return false ;
C4Object * cursor_obj = plr - > Cursor ;
if ( ! cursor_obj ) return false ;
2010-09-29 01:44:05 +00:00
C4Viewport * vp = : : Viewports . GetViewport ( iPlr ) ;
2010-04-11 11:42:07 +00:00
if ( ! vp ) return false ;
2010-04-10 20:44:00 +00:00
int32_t game_x = cursor_obj - > GetX ( ) , game_y = cursor_obj - > GetY ( ) ;
2011-11-20 20:49:38 +00:00
* game_x_out = game_x ; * game_y_out = game_y ;
2010-04-10 20:44:00 +00:00
// game coordinate to screen coordinates...
2010-04-26 23:32:45 +00:00
float screen_x = ( float ( game_x ) - vp - > last_game_draw_cgo . TargetX - vp - > last_game_draw_cgo . X ) * vp - > GetZoom ( ) ;
float screen_y = ( float ( game_y ) - vp - > last_game_draw_cgo . TargetY - vp - > last_game_draw_cgo . Y ) * vp - > GetZoom ( ) ;
2010-04-10 20:44:00 +00:00
// ...and screen coordinates to GUI coordinates (might push this into a helper function of C4Viewport?)
float gui_x = ( screen_x - vp - > last_game_draw_cgo . X ) / C4GUI : : GetZoom ( ) + vp - > last_game_draw_cgo . X ;
float gui_y = ( screen_y - vp - > last_game_draw_cgo . Y ) / C4GUI : : GetZoom ( ) + vp - > last_game_draw_cgo . Y ;
* x_out = int32_t ( gui_x ) ; * y_out = int32_t ( gui_y ) ;
return true ;
2010-05-07 13:57:56 +00:00
}
void C4PlayerControl : : PrepareInput ( )
{
if ( IsCursorPosRequested )
{
2011-11-20 20:49:38 +00:00
int32_t x , y , game_x , game_y ;
2010-05-07 13:57:56 +00:00
// add current cursor pos in GUI coordinates to input
2011-11-20 20:49:38 +00:00
if ( GetCurrentPlayerCursorPos ( & x , & y , & game_x , & game_y ) )
2010-05-07 13:57:56 +00:00
{
// CON_CursorPos might not have been defined in definition file
if ( ControlDefs . InternalCons . CON_CursorPos ! = CON_None )
{
C4KeyEventData ev ;
ev . iStrength = 0 ;
2011-11-20 20:49:38 +00:00
ev . vp_x = x ; ev . vp_y = y ;
ev . game_x = game_x ; ev . game_y = game_y ;
2010-05-07 13:57:56 +00:00
C4ControlPlayerControl * pControlPacket = new C4ControlPlayerControl ( iPlr , false , ev ) ;
pControlPacket - > AddControl ( ControlDefs . InternalCons . CON_CursorPos , C4PlayerControlAssignment : : CTM_Default ) ;
// make sure it's added at head, because controls that have SendCursorPos=1 set will follow, which will rely
// on the cursor pos being known
Game . Input . AddHead ( CID_PlrControl , pControlPacket ) ;
}
}
else
{
// no cursor is known (e.g.: Cursor Clonk dead, etc.). Don't create a control.
// Script will probably fall back to last known cursor pos
}
IsCursorPosRequested = false ;
}
2010-12-23 00:01:24 +00:00
}