!I integrate from //ce/main...
[CRYENGINE.git] / Code / CryEngine / CryAction / ActionMap.cpp
blob901add385d9dd972b26dc20f9966462e6696719b
1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
3 /*************************************************************************
4 -------------------------------------------------------------------------
5 $Id$
6 $DateTime$
8 -------------------------------------------------------------------------
9 History:
10 - 7:9:2004 17:48 : Created by Márcio Martins
11 - 15:9:2010 12:30 : Revised by Dean Claassen
13 *************************************************************************/
14 #include "StdAfx.h"
15 #include "ActionMap.h"
16 #include "ActionMapManager.h"
17 #include <CrySystem/IConsole.h>
18 #include <CryCore/CryCrc32.h>
20 #define ACTIONINPUT_NAME_STR "name"
22 #define ACTIONINPUT_ONPRESS_STR "onPress"
23 #define ACTIONINPUT_ONRELEASE_STR "onRelease"
24 #define ACTIONINPUT_ONHOLD_STR "onHold"
25 #define ACTIONINPUT_ALWAYS_STR "always"
27 #define ACTIONINPUT_CONSOLECMD_STR "consoleCmd"
28 #define ACTIONINPUT_NOMODIFIERS_STR "noModifiers"
29 #define ACTIONINPUT_RETRIGGERABLE_STR "retriggerable"
31 #define ACTIONINPUT_PRESSTRIGGERDELAY_STR "pressTriggerDelay"
32 #define ACTIONINPUT_PRESSTRIGGERDELAY_REPEATOVERRIDE_STR "pressTriggerDelayRepeatOverride"
33 #define ACTIONINPUT_PRESSDELAYPRIORITY_STR "pressDelayPriority"
35 #define ACTIONINPUT_HOLDTRIGGERDELAY_STR "holdTriggerDelay"
36 #define ACTIONINPUT_HOLDTRIGGERDELAY_REPEATOVERRIDE_STR "holdTriggerDelayRepeatOverride"
37 #define ACTIONINPUT_HOLDREPEATDELAY_STR "holdRepeatDelay"
38 #define ACTIONINPUT_RELEASETRIGGERTHRESHOLD_STR "releaseTriggerThreshold"
40 #define ACTIONINPUT_INPUTSTOBLOCK_STR "inputsToBlock"
41 #define ACTIONINPUT_INPUTBLOCKTIME_STR "inputBlockTime"
42 #define ACTIONINPUT_INPUTBLOCKACTIVATION_STR "inputBlockActivation"
43 #define ACTIONINPUT_INPUTBLOCKDEVICEINDEX_STR "inputBlockDeviceIndex"
45 #define ACTIONINPUT_INPUTSTOBLOCK_SPECIALTYPE_CLEARALL_STR "CLEARALL"
47 #define ACTIONINPUT_USEANALOGCOMPARE_STR "useAnalogCompare"
48 #define ACTIONINPUT_ANALOGCOMPAREVAL_STR "analogCompareVal"
49 #define ACTIONINPUT_ANALOGCOMPAREOP_STR "analogCompareOp"
51 static const char* s_analogCompareOpEqualsStr = "EQUALS";
52 static const char* s_analogCompareOpNotEqualsStr = "NOTEQUALS";
53 static const char* s_analogCompareOpGreaterThanStr = "GREATERTHAN";
54 static const char* s_analogCompareOpLessThanStr = "LESSTHAN";
56 //------------------------------------------------------------------------
57 struct CryNameSorter
59 //------------------------------------------------------------------------
60 bool operator()(const CCryName& lhs, const CCryName& rhs) const
62 assert(lhs.c_str() != 0);
63 assert(rhs.c_str() != 0);
64 return strcmp(lhs.c_str(), rhs.c_str()) < 0;
68 //------------------------------------------------------------------------
69 CActionMapAction::CActionMapAction()
70 : m_triggeredInput("")
71 , m_actionId("")
72 , m_iNumRebindedInputs(0)
73 , m_pParentActionMap(NULL)
77 //------------------------------------------------------------------------
78 CActionMapAction::~CActionMapAction()
80 RemoveAllActionInputs();
83 //------------------------------------------------------------------------
84 void CActionMapAction::GetMemoryUsage(ICrySizer* pSizer) const
86 TActionInputs::const_iterator iter = m_actionInputs.begin();
87 TActionInputs::const_iterator iterEnd = m_actionInputs.end();
89 for (; iter != iterEnd; ++iter)
91 const SActionInput* pActionInput = *iter;
92 pSizer->AddObject(pActionInput->input);
93 pSizer->AddObject(pActionInput->defaultInput);
97 //------------------------------------------------------------------------
98 bool CActionMapAction::AddActionInput(const SActionInput& actionInput, const int iByDeviceIndex)
100 // Double check no invalid inputs
101 if (strcmp(actionInput.input, "") == 0)
103 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::AddActionInput: Can't add empty input");
104 return false;
107 // Don't require to have a crc when passing in, but if has one, check it
108 uint32 inputCRC = CCrc32::ComputeLowercase(actionInput.input);
109 if (actionInput.inputCRC != 0)
111 if (inputCRC != actionInput.inputCRC)
113 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::AddActionInput: Can't add, string crc specified doesn't match actual crc");
114 return false;
118 SActionInput* pActionInput = FindActionInput(inputCRC);
119 if (pActionInput != NULL)
121 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CAction::AddActionInput::Unable to add input with input: %s, either input already exists, or possibly 2 different inputs sharing same crc value", actionInput.input.c_str());
122 return false;
125 SActionInput* pNewActionInput = new SActionInput();
126 *pNewActionInput = actionInput;
127 pNewActionInput->input.MakeLower();
128 pNewActionInput->defaultInput.MakeLower();
129 pNewActionInput->inputCRC = inputCRC;
131 if (iByDeviceIndex == -1)
133 m_actionInputs.push_back(pNewActionInput);
134 return true;
136 else
138 int iCurrentByDeviceIndex = 0;
140 // Find actual index
141 TActionInputs::iterator iter = m_actionInputs.begin();
142 TActionInputs::iterator iterEnd = m_actionInputs.end();
143 for (; iter != iterEnd; ++iter)
145 SActionInput* pContainedActionInput = *iter;
146 CRY_ASSERT(pContainedActionInput != NULL);
148 if (pContainedActionInput->inputDevice == actionInput.inputDevice && iCurrentByDeviceIndex == iByDeviceIndex)
150 m_actionInputs.insert(iter, pNewActionInput);
151 return true;
153 else
155 ++iCurrentByDeviceIndex;
159 // Reached here so iByDeviceIndex must be incorrect
160 SAFE_DELETE(pNewActionInput);
161 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CAction::AddActionInput: Failed adding input with input: %s, iByDeviceIndex: %d, is incorrect", actionInput.input.c_str(), iByDeviceIndex);
162 return false;
166 //------------------------------------------------------------------------
167 bool CActionMapAction::RemoveActionInput(uint32 inputCRC)
169 TActionInputs::iterator iter = m_actionInputs.begin();
170 TActionInputs::iterator iterEnd = m_actionInputs.end();
171 for (; iter != iterEnd; ++iter)
173 SActionInput* pActionInput = *iter;
174 CRY_ASSERT(pActionInput != NULL);
175 if (pActionInput->inputCRC == inputCRC)
177 SAFE_DELETE(pActionInput);
178 m_actionInputs.erase(iter);
179 return true;
183 return false;
186 //------------------------------------------------------------------------
187 void CActionMapAction::RemoveAllActionInputs()
189 TActionInputs::iterator iter = m_actionInputs.begin();
190 TActionInputs::iterator iterEnd = m_actionInputs.end();
191 for (; iter != iterEnd; ++iter)
193 SActionInput* pActionInput = *iter;
194 CRY_ASSERT(pActionInput != NULL);
195 SAFE_DELETE(pActionInput);
197 m_actionInputs.clear();
200 //------------------------------------------------------------------------
201 SActionInput* CActionMapAction::FindActionInput(uint32 inputCRC)
203 SActionInput* pFoundActionInput = NULL;
205 TActionInputs::iterator iter = m_actionInputs.begin();
206 TActionInputs::iterator iterEnd = m_actionInputs.end();
207 for (; iter != iterEnd; ++iter)
209 SActionInput* pActionInput = *iter;
210 CRY_ASSERT(pActionInput != NULL);
211 if (pActionInput->inputCRC == inputCRC)
213 pFoundActionInput = pActionInput;
214 break;
218 return pFoundActionInput;
221 //------------------------------------------------------------------------
222 const SActionInput* CActionMapAction::FindActionInput(const char* szInput) const
224 uint32 inputCRC = CCrc32::ComputeLowercase(szInput);
226 const SActionInput* pFoundActionInput = NULL;
228 TActionInputs::const_iterator iter = m_actionInputs.begin();
229 TActionInputs::const_iterator iterEnd = m_actionInputs.end();
230 for (; iter != iterEnd; ++iter)
232 const SActionInput* pActionInput = *iter;
233 CRY_ASSERT(pActionInput != NULL);
234 if (pActionInput->inputCRC == inputCRC)
236 pFoundActionInput = pActionInput;
237 break;
241 return pFoundActionInput;
244 //------------------------------------------------------------------------
245 SActionInput* CActionMapAction::GetActionInput(const int iIndex)
247 CRY_ASSERT(iIndex >= 0 && iIndex < (int)m_actionInputs.size());
248 if (iIndex >= 0 && iIndex < (int)m_actionInputs.size())
250 return m_actionInputs[iIndex];
253 return NULL;
256 //------------------------------------------------------------------------
257 SActionInput* CActionMapAction::GetActionInput(const EActionInputDevice device, const int iIndexByDevice)
259 int iCurrentIndexByDevice = 0; // Array may not be sorted, but the index specified by iIndexByDevice means the order in which its found
260 SActionInput* pFoundActionInput = NULL;
261 for (int i = 0; i < m_actionInputs.size(); i++)
263 SActionInput* pActionInput = m_actionInputs[i];
264 CRY_ASSERT(pActionInput != NULL);
266 if (pActionInput->inputDevice == device)
268 if (iCurrentIndexByDevice == iIndexByDevice)
270 pFoundActionInput = pActionInput;
271 break;
273 else // Keep looking for next one
275 iCurrentIndexByDevice++;
280 return pFoundActionInput;
283 //------------------------------------------------------------------------
284 const SActionInput* CActionMapAction::GetActionInput(const int iIndex) const
286 CRY_ASSERT(iIndex >= 0 && iIndex < (int)m_actionInputs.size());
287 if (iIndex >= 0 && iIndex < (int)m_actionInputs.size())
289 return m_actionInputs[iIndex];
292 return NULL;
295 //------------------------------------------------------------------------
296 const SActionInput* CActionMapAction::GetActionInput(const EActionInputDevice device, const int iIndexByDevice) const
298 int iCurrentIndexByDevice = 0; // Array may not be sorted, but the index specified by iIndexByDevice means the order in which its found
299 const SActionInput* pFoundActionInput = NULL;
300 for (int i = 0; i < m_actionInputs.size(); i++)
302 const SActionInput* pActionInput = m_actionInputs[i];
303 CRY_ASSERT(pActionInput != NULL);
305 if (pActionInput->inputDevice == device)
307 if (iCurrentIndexByDevice == iIndexByDevice)
309 pFoundActionInput = pActionInput;
310 break;
312 else // Keep looking for next one
314 iCurrentIndexByDevice++;
319 return pFoundActionInput;
322 //------------------------------------------------------------------------
323 SActionInput* CActionMapAction::AddAndGetActionInput(const SActionInput& actionInput)
325 // Don't require to have a crc when passing in, but if has one, check it
326 uint32 inputCRC = CCrc32::ComputeLowercase(actionInput.input);
327 if (actionInput.inputCRC != 0)
329 if (inputCRC != actionInput.inputCRC)
331 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::AddAndGetActionInput: Can't add, string crc specified doesn't match actual crc");
332 return NULL;
336 SActionInput* pActionInput = FindActionInput(inputCRC);
337 if (pActionInput != NULL)
339 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CAction::AddAndGetActionInput::Unable to add input with input: %s, already exists", actionInput.input.c_str());
340 return NULL;
342 SActionInput* pNewActionInput = new SActionInput();
343 *pNewActionInput = actionInput;
344 pNewActionInput->input.MakeLower();
345 pNewActionInput->defaultInput.MakeLower();
346 pNewActionInput->inputCRC = inputCRC;
347 m_actionInputs.push_back(pNewActionInput);
349 return pNewActionInput;
352 //------------------------------------------------------------------------
353 CActionMap::CActionMap(CActionMapManager* pActionMapManager, const char* name)
354 : m_pActionMapManager(pActionMapManager),
355 m_enabled(!stricmp(name, "default")),
356 m_listenerId(0),
357 m_actionMapListeners(2),
358 m_flownodesListeners(2),
359 m_name(name),
360 m_iNumRebindedInputs(0)
364 //------------------------------------------------------------------------
365 CActionMap::~CActionMap()
367 Clear();
370 //------------------------------------------------------------------------
371 void CActionMap::Release()
373 m_pActionMapManager->RemoveActionMap(m_name);
376 //------------------------------------------------------------------------
377 void CActionMap::Clear()
379 m_pActionMapManager->RemoveBind(this);
380 m_actions.clear();
381 SetNumRebindedInputs(0);
384 //------------------------------------------------------------------------
385 bool CActionMap::CreateAction(const ActionId& actionId)
387 TActionMap::iterator iter = m_actions.find(actionId);
388 if (iter != m_actions.end())
390 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::CreateAction: Unable to create action, %s already exists", actionId.c_str());
391 return false;
394 CActionMapAction action;
395 action.SetActionId(actionId);
396 action.SetParentActionMap(this);
398 m_actions[actionId] = action;
400 return true;
403 //------------------------------------------------------------------------
404 bool CActionMap::RemoveAction(const ActionId& actionId)
406 TActionMap::iterator iter = m_actions.find(actionId);
407 if (iter == m_actions.end())
409 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::RemoveAction: Failed to find action: %s", actionId.c_str());
410 return false;
413 CActionMapAction& action = iter->second;
414 m_pActionMapManager->RemoveBind(&action);
416 // Update new rebind count
417 int newRebindCount = GetNumRebindedInputs();
419 int numActionInputs = action.GetNumActionInputs();
420 for (int i = 0; i < numActionInputs; ++i)
422 SActionInput* pActionInput = action.GetActionInput(i);
423 CRY_ASSERT(pActionInput != NULL);
425 if (pActionInput->input != pActionInput->defaultInput)
427 --newRebindCount;
431 if (newRebindCount != GetNumRebindedInputs())
433 SetNumRebindedInputs(newRebindCount);
436 m_actions.erase(iter);
438 return true;
441 //------------------------------------------------------------------------
442 bool CActionMap::AddActionInput(const ActionId& actionId, const SActionInput& actionInput, const int iByDeviceIndex)
444 CActionMapAction* pAction = NULL;
446 TActionMap::iterator iter = m_actions.find(actionId);
447 if (iter == m_actions.end()) // Don't have an action, so create one to hold the input
449 pAction = CreateAndGetAction(actionId);
450 CRY_ASSERT(pAction != NULL);
451 if (!pAction)
453 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::AddActionInput: Failed to create action: %s", actionId.c_str());
454 return false;
457 else
459 pAction = &iter->second;
460 CRY_ASSERT(pAction != NULL);
463 return pAction->AddActionInput(actionInput, iByDeviceIndex);
466 //------------------------------------------------------------------------
467 bool CActionMap::AddAndBindActionInput(const ActionId& actionId, const SActionInput& actionInput)
469 CActionMapAction* pAction = NULL;
470 TActionMap::iterator iAction = m_actions.find(actionId);
471 if (iAction == m_actions.end())
473 pAction = CreateAndGetAction(actionId);
474 CRY_ASSERT(pAction != NULL);
475 if (pAction == NULL)
477 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::AddAndBindActionInput: Failed to create action: %s", actionId.c_str());
478 return false;
481 else
483 pAction = &iAction->second;
484 CRY_ASSERT(pAction != NULL);
486 SActionInput* pNewActionInput = pAction->AddAndGetActionInput(actionInput);
487 if (pNewActionInput != NULL)
489 return m_pActionMapManager->AddBind(this, pAction, pNewActionInput);
491 else
493 return false;
497 //------------------------------------------------------------------------
498 bool CActionMap::RemoveActionInput(const ActionId& actionId, const char* szInput)
500 TActionMap::iterator iter = m_actions.find(actionId);
501 if (iter == m_actions.end())
503 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::RemoveActionInput: Failed to find action: %s", actionId.c_str());
504 return false;
507 CActionMapAction& action = iter->second;
509 uint32 inputCRC = CCrc32::ComputeLowercase(szInput);
511 SActionInput* pActionInput = action.FindActionInput(inputCRC);
512 if (pActionInput == NULL)
514 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::RemoveActionInput: Failed to find action input for input: %s", szInput);
515 return false;
518 bool bResult = m_pActionMapManager->RemoveBind(this, &action, pActionInput);
519 if (!bResult)
521 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::RemoveActionInput: Failed to remove binding for action input with input: %s", szInput);
522 return false;
525 return action.RemoveActionInput(inputCRC);
528 //------------------------------------------------------------------------
529 bool CActionMap::ReBindActionInput(const ActionId& actionId, const char* szCurrentInput, const char* szNewInput)
531 TActionMap::iterator iter = m_actions.find(actionId);
532 if (iter != m_actions.end())
534 CActionMapAction& action = iter->second;
535 return ReBindActionInput(&action, szCurrentInput, szNewInput);
538 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::ReBindActionInput: Unable to rebind action, %s, doesn't exist", actionId.c_str());
539 return false;
542 //------------------------------------------------------------------------
543 bool CActionMap::ReBindActionInput(const ActionId& actionId,
544 const char* szNewInput,
545 const EActionInputDevice device,
546 const int iByDeviceIndex)
548 TActionMap::iterator iter = m_actions.find(actionId);
549 if (iter == m_actions.end())
551 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::ReBindActionInput: Can't find action: %s", actionId.c_str());
552 return false;
555 CActionMapAction& action = iter->second;
556 return ReBindActionInput(&action, szNewInput, device, iByDeviceIndex);
559 //------------------------------------------------------------------------
560 CActionMapAction* CActionMap::CreateAndGetAction(const ActionId& actionId)
562 TActionMap::iterator iter = m_actions.find(actionId);
563 if (iter != m_actions.end())
565 return NULL;
568 CActionMapAction action;
569 action.SetActionId(actionId);
570 action.SetParentActionMap(this);
572 m_actions[actionId] = action;
574 return &m_actions[actionId];
577 //------------------------------------------------------------------------
578 bool CActionMap::AddAndBindActionInput(CActionMapAction* pAction, const SActionInput& actionInput)
580 CRY_ASSERT(pAction != NULL);
581 if (!pAction)
582 return false;
584 SActionInput* pAddedActionInput = pAction->AddAndGetActionInput(actionInput);
585 if (!pAddedActionInput)
587 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::AddAndBindActionInput: Failed adding actioninput for input: %s", actionInput.input.c_str());
588 return false;
591 bool bResult = m_pActionMapManager->AddBind(this, pAction, pAddedActionInput);
592 if (!bResult)
594 pAction->RemoveActionInput(pAddedActionInput->inputCRC);
595 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::AddAndBindActionInput: Failed binding actioninput");
596 return false;
599 return true;
602 //------------------------------------------------------------------------
603 bool CActionMap::ReBindActionInput(CActionMapAction* pAction, const char* szCurrentInput, const char* szNewInput)
605 uint32 inputCRC = CCrc32::ComputeLowercase(szCurrentInput);
607 SActionInput* pActionInput = pAction->FindActionInput(inputCRC);
608 if (!pActionInput)
610 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::ReBindActionInput: Can't find input: %s for action: %s", szCurrentInput, pAction->GetActionId().c_str());
611 return false;
614 return ReBindActionInput(pAction, *pActionInput, szNewInput);
617 //------------------------------------------------------------------------
618 bool CActionMap::ReBindActionInput(CActionMapAction* pAction, SActionInput& actionInput, const char* szNewInput)
620 CRY_ASSERT(pAction != NULL);
622 if (actionInput.input == szNewInput) // Rebinding to same input
623 return false;
625 if (m_pActionMapManager->HasBind(this, pAction, &actionInput)) // Might not be binded if cleared
627 bool bResult = m_pActionMapManager->RemoveBind(this, pAction, &actionInput);
628 if (!bResult)
630 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::ReBindActionInput: Failed removing bind for input: %s for action: %s", actionInput.input.c_str(), pAction->GetActionId().c_str());
631 return false;
635 actionInput.input = szNewInput;
637 // Possible to assign empty to clear the binding
638 if (szNewInput != NULL && strcmp(szNewInput, "") != 0)
640 actionInput.inputCRC = CCrc32::ComputeLowercase(szNewInput);
642 bool bResult = m_pActionMapManager->AddBind(this, pAction, &actionInput);
643 if (!bResult)
645 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::ReBindActionInput: Failed removing bind for input: %s for action: %s", actionInput.input.c_str(), pAction->GetActionId().c_str());
646 return false;
650 // If input now equals the default, nolonger needs the mark from the previous rebind
651 if (actionInput.input == actionInput.defaultInput)
653 SetNumRebindedInputs(GetNumRebindedInputs() - 1);
654 pAction->SetNumRebindedInputs(pAction->GetNumRebindedInputs() - 1);
656 else // Remember this rebind
658 SetNumRebindedInputs(GetNumRebindedInputs() + 1);
659 pAction->SetNumRebindedInputs(pAction->GetNumRebindedInputs() + 1);
662 return true;
665 //------------------------------------------------------------------------
666 bool CActionMap::ReBindActionInput(CActionMapAction* pAction,
667 const char* szNewInput,
668 const EActionInputDevice device,
669 const int iByDeviceIndex)
672 SActionInput* pActionInput = pAction->GetActionInput(device, iByDeviceIndex);
673 if (!pActionInput)
675 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::ReBindActionInput: Can't get input by index: %d for action: %s", iByDeviceIndex, pAction->GetActionId().c_str());
676 return false;
679 if (pActionInput->input == szNewInput) // Rebinding to same input
680 return false;
682 if (m_pActionMapManager->HasBind(this, pAction, pActionInput)) // Might not be binded if cleared
684 bool bResult = m_pActionMapManager->RemoveBind(this, pAction, pActionInput);
685 if (!bResult)
687 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::ReBindActionInput: Failed removing bind for input: %s for action: %s", pActionInput->input.c_str(), pAction->GetActionId().c_str());
688 return false;
692 pActionInput->input = szNewInput;
694 // Possible to assign empty to clear the binding
695 if (szNewInput != NULL && strcmp(szNewInput, "") != 0)
697 pActionInput->inputCRC = CCrc32::ComputeLowercase(szNewInput);
699 bool bResult = m_pActionMapManager->AddBind(this, pAction, pActionInput);
700 if (!bResult)
702 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::ReBindActionInput: Failed removing bind for input: %s for action: %s", pActionInput->input.c_str(), pAction->GetActionId().c_str());
703 return false;
706 else
708 pActionInput->inputCRC = 0;
711 // If input now equals the default, nolonger needs the mark from the previous rebind
712 if (pActionInput->input == pActionInput->defaultInput)
714 SetNumRebindedInputs(GetNumRebindedInputs() - 1);
715 pAction->SetNumRebindedInputs(pAction->GetNumRebindedInputs() - 1);
717 else // Remember this rebind
719 SetNumRebindedInputs(GetNumRebindedInputs() + 1);
720 pAction->SetNumRebindedInputs(pAction->GetNumRebindedInputs() + 1);
723 return true;
727 //------------------------------------------------------------------------
728 void CActionMap::SetActionListener(EntityId id)
730 m_listenerId = id;
733 //------------------------------------------------------------------------
734 EntityId CActionMap::GetActionListener() const
736 return m_listenerId;
739 //------------------------------------------------------------------------
740 bool CActionMap::Reset()
742 m_enabled = !stricmp(GetName(), "default");
744 for (TActionMap::iterator it = m_actions.begin(); it != m_actions.end(); ++it)
746 CActionMapAction& action = it->second;
748 const int numInputs = action.GetNumActionInputs();
749 for (int i = 0; i < numInputs; i++)
751 SActionInput* pActionInput = action.GetActionInput(i);
752 CRY_ASSERT(pActionInput != NULL);
754 if (pActionInput->input == pActionInput->defaultInput) // Input is already default
755 continue;
757 if (!ReBindActionInput(&action, *pActionInput, pActionInput->defaultInput))
759 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::Reset: Failed resetting binding to default input in action: %s", action.GetActionId().c_str());
760 return false;
765 return true;
768 //------------------------------------------------------------------------
769 const IActionMapAction* CActionMap::GetAction(const ActionId& actionId) const
771 TActionMap::const_iterator actionIter = m_actions.find(actionId);
772 if (actionIter == m_actions.end())
773 return NULL;
775 const CActionMapAction& action = actionIter->second;
777 return &action;
780 //------------------------------------------------------------------------
781 IActionMapAction* CActionMap::GetAction(const ActionId& actionId)
783 TActionMap::iterator actionIter = m_actions.find(actionId);
784 if (actionIter == m_actions.end())
785 return NULL;
787 IActionMapAction& action = actionIter->second;
789 return &action;
792 //------------------------------------------------------------------------
793 bool CActionMap::CanProcessInput(const SInputEvent& inputEvent, CActionMap* pActionMap, CActionMapAction* pAction, SActionInput* pActionInput)
795 CRY_PROFILE_FUNCTION(PROFILE_ACTION);
796 bool bRes = false;
798 float fCurrTime = gEnv->pTimer->GetCurrTime();
799 IGameFramework* pGameFramework = gEnv->pGameFramework;
800 if (pGameFramework && pGameFramework->IsGamePaused())
802 fCurrTime = gEnv->pTimer->GetCurrTime(ITimer::ETIMER_UI);
805 if (m_enabled)
807 // Normal buttons + keys send a press, down, release events
808 // Analog events only send changed
809 // So deal with these totally differently
810 if (pActionInput->activationMode & eAAM_AnalogCompare)
812 switch (pActionInput->analogCompareOp) // Check if fulfills analog condition
814 case eAACO_Equals:
816 if (fabs(inputEvent.value - pActionInput->fAnalogCompareVal) < FLT_EPSILON)
818 bRes = true;
821 break;
822 case eAACO_NotEquals:
824 if (fabs(inputEvent.value - pActionInput->fAnalogCompareVal) >= FLT_EPSILON)
826 bRes = true;
829 break;
830 case eAACO_GreaterThan:
832 if (inputEvent.value > pActionInput->fAnalogCompareVal)
834 bRes = true;
837 break;
838 case eAACO_LessThan:
840 if (inputEvent.value < pActionInput->fAnalogCompareVal)
842 bRes = true;
845 break;
848 if (bRes)
850 // Since analog inputs dont have the concept of being down, create a refire timer to simulate hold
851 // and remove this when analog condition nolonger fulfilled
852 if (!m_pActionMapManager->IsCurrentlyRefiringInput()) // Input event is from refire, dont try to refire a refired event
854 m_pActionMapManager->UpdateRefireData(inputEvent, pActionMap, pAction, pActionInput);
857 if (pActionInput->bAnalogConditionFulfilled != true)
859 pActionInput->fPressedTime = fCurrTime;
860 pActionInput->fLastRepeatTime = fCurrTime;
861 pActionInput->bHoldTriggerFired = false;
862 pActionInput->fCurrentHoldValue = 0.f;
863 pActionInput->bAnalogConditionFulfilled = true;
864 pActionInput->currentState = eIS_Pressed;
866 else if (pActionInput->bHoldTriggerFired)
868 pActionInput->currentState = eIS_Changed;
871 // Although condition is true, result value can be set false again if hold timer conditions aren't true
872 // Only check if action should be processed here
873 bRes = IsActionInputTriggered(inputEvent, pActionMap, pAction, pActionInput);
875 else // Didn't fulfill analog condition
877 if (!m_pActionMapManager->IsCurrentlyRefiringInput() && pActionInput->bAnalogConditionFulfilled != false)
879 pActionInput->bAnalogConditionFulfilled = false;
880 m_pActionMapManager->RemoveRefireData(pActionMap, pAction, pActionInput);
882 pActionInput->fCurrentHoldValue = 0.f;
883 pActionInput->currentState = eIS_Released;
886 else if (inputEvent.state == eIS_Pressed)
888 pActionInput->fPressedTime = fCurrTime;
890 if (pActionInput->activationMode & eAAM_OnHold) // Needed for hold
892 pActionInput->fLastRepeatTime = fCurrTime;
893 if (pActionInput->fHoldTriggerDelay > 0.f)
895 pActionInput->bHoldTriggerFired = false;
897 else // Hold trigger delay is immediate, same with press event, so dont fire twice
899 pActionInput->bHoldTriggerFired = true;
902 pActionInput->fCurrentHoldValue = 0.f;
905 // Check if the action should be processed
906 bRes = IsActionInputTriggered(inputEvent, pActionMap, pAction, pActionInput);
908 else // All other cases
910 // Check if the action should be processed
911 bRes = IsActionInputTriggered(inputEvent, pActionMap, pAction, pActionInput);
914 // Remember the triggered input
916 // Change action's current state
917 if (!bRes)
919 if (inputEvent.state == eIS_Down && pActionInput->currentState == eIS_Pressed && (pActionInput->activationMode & eAAM_OnRelease))
920 pActionInput->currentState = eIS_Pressed;
921 else
922 pActionInput->currentState = eIS_Unknown;
924 else if (inputEvent.state == eIS_Changed && !(pActionInput->activationMode & eAAM_AnalogCompare))
926 pActionInput->currentState = eIS_Changed;
928 else if (inputEvent.state == eIS_Down)
930 pActionInput->currentState = eIS_Down;
932 else if (pActionInput->activationMode & (eAAM_OnPress | eAAM_OnRelease))
934 if (inputEvent.state == eIS_Released || inputEvent.state == eIS_Pressed)
935 pActionInput->currentState = inputEvent.state;
939 return bRes;
942 //------------------------------------------------------------------------
943 bool CActionMap::IsActionInputTriggered(const SInputEvent& inputEvent, CActionMap* pActionMap, CActionMapAction* pAction, SActionInput* pActionInput) const
945 bool bRes = false;
947 if ((inputEvent.modifiers & eMM_Modifiers) &&
948 (pActionInput->activationMode & eAAM_NoModifiers))
950 return bRes;
953 float fCurrTime = gEnv->pTimer->GetCurrTime();
954 IGameFramework* pGameFramework = gEnv->pGameFramework;
955 if (pGameFramework && pGameFramework->IsGamePaused())
957 fCurrTime = gEnv->pTimer->GetCurrTime(ITimer::ETIMER_UI);
960 // currentMode -> bit flag based on key state needed for trigger, and actual key state
961 // Special handling for certain types of logic
962 int currentMode = pActionInput->activationMode & inputEvent.state;
963 const float fTimePressed = fCurrTime - pActionInput->fPressedTime;
964 const bool bJustPressed = fabs(fTimePressed) < FLT_EPSILON;
966 if ((inputEvent.state == eIS_Down) && (pActionInput->activationMode & eAAM_OnHold))
968 if (bJustPressed)
970 return bRes; // When holding, a press event is handled and immediately on same time frame a hold event is passed in, ignore it
972 else
974 currentMode = eAAM_Always; // Held events aren't checked in the above line, always allow them
977 else if (inputEvent.state == eIS_Changed) // Analog events aren't checked in the above line, always allow them
979 if (bJustPressed && ((pActionInput->activationMode & eAAM_OnPress) == 0)) // This is a press from analog event, but input doesn't handle press, ignore
981 return bRes;
984 currentMode = eAAM_Always;
986 else if (inputEvent.state == eIS_Released)
988 pActionInput->fCurrentHoldValue = 0.f;
990 //ignore if we have a release threshold and it's been exceeded
991 if (pActionInput->fReleaseTriggerThreshold >= 0.0f && fTimePressed >= pActionInput->fReleaseTriggerThreshold)
993 return bRes;
997 // Get blocking type based on how the action was triggered
998 if (currentMode)
1000 // Support initial hold trigger delay and repeating
1001 if ((pActionInput->activationMode & eAAM_OnHold) &&
1002 (inputEvent.state == eIS_Down || (inputEvent.state == eIS_Changed && bJustPressed == false))) // Down is for digital controls, changed is for analog (For analog, won't reach here if analog condition is false, only for analog hold, press will go below like normal press)
1004 if (pActionInput->bHoldTriggerFired) // Initial hold trigger already fired
1006 if (fCurrTime < pActionInput->fLastRepeatTime)
1008 pActionInput->fLastRepeatTime = fCurrTime;
1011 if (pActionInput->fHoldRepeatDelay != -1.0f && fCurrTime - pActionInput->fLastRepeatTime >= pActionInput->fHoldRepeatDelay) // fHoldRepeatDelay of -1.0f means no repeat
1013 pActionInput->fLastRepeatTime = fCurrTime;
1014 bRes = true;
1017 else
1019 const bool bIsCurrentKey = (m_pActionMapManager->GetIncomingInputKeyID() == inputEvent.keyId);
1020 // Support overriding hold trigger timer if repeating same input
1021 if ((m_pActionMapManager->IsRepeatedInputHoldTriggerFired()) && // Could have been interrupted by another held key
1022 (bIsCurrentKey) && // Need to check since could have multiple held keys
1023 (pActionInput->fHoldTriggerDelayRepeatOverride >= FLT_EPSILON)) // Default is -1.0f which won't activate this
1025 if (fTimePressed >= pActionInput->fHoldTriggerDelayRepeatOverride)
1027 pActionInput->bHoldTriggerFired = true;
1028 pActionInput->fCurrentHoldValue = 1.f;
1029 pActionInput->fLastRepeatTime = fCurrTime;
1030 bRes = true;
1033 else if (fTimePressed >= pActionInput->fHoldTriggerDelay)
1035 pActionInput->bHoldTriggerFired = true;
1036 pActionInput->fCurrentHoldValue = 1.f;
1037 pActionInput->fLastRepeatTime = fCurrTime;
1038 if (m_pActionMapManager->IsIncomingInputRepeated() && bIsCurrentKey) // Need to check since could have multiple held keys
1040 m_pActionMapManager->SetRepeatedInputHoldTriggerFired(true);
1042 bRes = true;
1044 else
1046 if (pActionInput->fHoldTriggerDelay > 0.f)
1048 pActionInput->fCurrentHoldValue = (fTimePressed / pActionInput->fHoldTriggerDelay);
1050 else
1052 pActionInput->fCurrentHoldValue = 0.f;
1057 else if ((inputEvent.state == eIS_Pressed) &&
1058 (pActionInput->fPressTriggerDelay >= FLT_EPSILON) && // Handle delayed press situation
1059 (!m_pActionMapManager->IsCurrentlyRefiringInput())) // Input event is from refire, dont try to refire a refired event
1061 if ((m_pActionMapManager->IsIncomingInputRepeated()) &&
1062 (m_pActionMapManager->GetIncomingInputKeyID() == inputEvent.keyId) && // Repeated same input, allow override if is one
1063 (pActionInput->fPressTriggerDelayRepeatOverride >= FLT_EPSILON)) // Default is -1.0f which won't activate this
1065 // Remove delayed press fire
1066 m_pActionMapManager->RemoveRefireData(pActionMap, pAction, pActionInput);
1068 bRes = true;
1070 else // Not repeated key, must wait for delay before firing
1072 // Check press delay priority, if greater or equal to current, override
1073 int currentHighestDelayPriority = m_pActionMapManager->GetHighestPressDelayPriority();
1074 if (pActionInput->iPressDelayPriority >= currentHighestDelayPriority)
1076 m_pActionMapManager->RemoveAllDelayedPressRefireData();
1077 m_pActionMapManager->UpdateRefireData(inputEvent, pActionMap, pAction, pActionInput); // Will fire again after delay
1079 bRes = false;
1082 else if ((inputEvent.state == eIS_Released) &&
1083 (pActionInput->fPressTriggerDelay >= FLT_EPSILON) && // Handle delayed press situation
1084 (!m_pActionMapManager->IsCurrentlyRefiringInput())) // Input event is from refire, dont try to refire a refired event
1086 if (fTimePressed - pActionInput->fPressTriggerDelay < FLT_EPSILON) // Press delay hasn't fired yet, release should be fired right after delayed press
1088 m_pActionMapManager->SetRefireDataDelayedPressNeedsRelease(inputEvent, pActionMap, pAction, pActionInput, true);
1089 bRes = false;
1091 else // Ok to fire release since delayed press already fired
1093 bRes = true;
1096 else // Not held
1098 bRes = true;
1102 return bRes;
1105 //------------------------------------------------------------------------
1106 void CActionMap::InputProcessed()
1108 IActionListener* pEntityListener = NULL;
1110 if (IEntity* pEntity = gEnv->pEntitySystem->GetEntity(m_listenerId))
1112 if (IGameObject* pGameObject = static_cast<IGameObject*>(pEntity->GetProxy(ENTITY_PROXY_USER)))
1114 pEntityListener = pGameObject;
1118 if (pEntityListener)
1119 pEntityListener->AfterAction();
1121 for (TActionMapListeners::Notifier notify(m_actionMapListeners); notify.IsValid(); notify.Next())
1123 notify->AfterAction();
1127 //------------------------------------------------------------------------
1128 void CActionMap::ReleaseActionsIfActive()
1130 TActionMap::iterator it = m_actions.begin();
1131 TActionMap::iterator end = m_actions.end();
1132 for (; it != end; ++it)
1134 CActionMapAction& action = it->second;
1135 ReleaseActionIfActiveInternal(action);
1139 //------------------------------------------------------------------------
1140 void CActionMap::ReleaseFilteredActions()
1142 IActionListener* pEntityListener = NULL;
1144 if (IEntity* pEntity = gEnv->pEntitySystem->GetEntity(m_listenerId))
1146 if (IGameObject* pGameObject = static_cast<IGameObject*>(pEntity->GetProxy(ENTITY_PROXY_USER)))
1148 pEntityListener = pGameObject;
1152 IActionListener* pListener = pEntityListener;
1154 for (TActionMap::iterator it = m_actions.begin(), eit = m_actions.end(); it != eit; ++it)
1156 CActionMapAction& action = it->second;
1158 int iNumActionInputs = action.GetNumActionInputs();
1159 for (int i = 0; i < iNumActionInputs; ++i)
1161 SActionInput* pActionInput = action.GetActionInput(i);
1162 CRY_ASSERT(pActionInput != NULL);
1164 bool isPressedOrDown = (pActionInput->currentState == eIS_Pressed) || (pActionInput->currentState == eIS_Down);
1165 bool isChanged = pActionInput->currentState == eIS_Changed;
1167 if ((!isPressedOrDown && !isChanged) || !m_pActionMapManager->ActionFiltered(it->first))
1168 continue;
1170 pActionInput->fCurrentHoldValue = 0.f;
1172 int currentMode = pActionInput->activationMode & eIS_Released;
1173 if (currentMode || isChanged)
1175 if (pListener)
1177 pListener->OnAction(it->first, currentMode, 0);
1180 const TActionListeners& extraActionListeners = m_pActionMapManager->GetExtraActionListeners();
1181 for (TActionListeners::const_iterator extraListener = extraActionListeners.begin(); extraListener != extraActionListeners.end(); ++extraListener)
1182 (*extraListener)->OnAction(it->first, currentMode, 0);
1184 NotifyExtraActionListeners(it->first, currentMode, 0);
1190 //------------------------------------------------------------------------
1191 void CActionMap::AddExtraActionListener(IActionListener* pExtraActionListener)
1193 m_actionMapListeners.Add(pExtraActionListener);
1196 //------------------------------------------------------------------------
1197 void CActionMap::RemoveExtraActionListener(IActionListener* pExtraActionListener)
1199 m_actionMapListeners.Remove(pExtraActionListener);
1202 //------------------------------------------------------------------------
1203 void CActionMap::NotifyFlowNodeActionListeners(const ActionId& action, int currentState, float value)
1205 for (TActionMapListeners::Notifier notify(m_flownodesListeners); notify.IsValid(); notify.Next())
1207 notify->OnAction(action, currentState, value);
1211 //------------------------------------------------------------------------
1212 void CActionMap::AddFlowNodeActionListener(IActionListener* pFlowgraphNodeActionListener)
1214 m_flownodesListeners.Add(pFlowgraphNodeActionListener);
1217 //------------------------------------------------------------------------
1218 void CActionMap::RemoveFlowNodeActionListener(IActionListener* pFlowgraphNodeActionListener)
1220 m_flownodesListeners.Remove(pFlowgraphNodeActionListener);
1223 //------------------------------------------------------------------------
1224 void CActionMap::NotifyExtraActionListeners(const ActionId& action, int currentState, float value)
1226 for (TActionMapListeners::Notifier notify(m_actionMapListeners); notify.IsValid(); notify.Next())
1228 notify->OnAction(action, currentState, value);
1232 //------------------------------------------------------------------------
1233 bool CActionMap::LoadFromXML(const XmlNodeRef& actionMapNode)
1235 const int iNumDeviceData = m_pActionMapManager->GetNumInputDeviceData();
1236 bool bResult;
1238 int iNumActions = actionMapNode->getChildCount();
1239 for (int i = 0; i < iNumActions; ++i)
1241 XmlNodeRef actionNode = actionMapNode->getChild(i);
1242 if (strcmp(actionNode->getTag(), "action") != 0)
1244 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::LoadFromXML: Found non action child, actionmaps should only have action children");
1245 continue;
1248 const char* szActionName = actionNode->getAttr("name");
1249 if (!szActionName || strcmp(szActionName, "") == 0)
1251 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::LoadFromXML: Action missing name, ignoring action");
1252 continue;
1255 ActionId actionName = ActionId(szActionName);
1256 CActionMapAction* pAction = (CActionMapAction*)GetAction(actionName);
1257 if (pAction != NULL)
1259 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::LoadFromXML: Can't add action: %s, already exists", szActionName);
1260 continue;
1263 pAction = CreateAndGetAction(actionName);
1264 if (!pAction)
1266 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::LoadFromXML: Failed to create action: %s", szActionName);
1267 continue;
1270 // Actioninput used originally contains default values from constructor, then each LoadActionInputFromXML is cumulative
1271 // i.e. Only the values in xml will be set to allow attributes specified at topmost level in xml to apply to all children
1272 SActionInput actionInput;
1274 if (actionNode->getNumAttributes() > 1) // Contains attributes to apply to all inputs
1276 bResult = LoadActionInputAttributesFromXML(actionNode, actionInput);
1277 if (!bResult)
1279 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::LoadFromXML: Failed loading action input attributes for action: %s", szActionName);
1280 continue;
1283 // Support specifying all devices in 1 line like before
1285 // All inputs are under a devicetype for organization
1286 // Devicemapping data should be called from game level using
1287 // IActionMapManager::AddInputDeviceMapping
1288 for (int j = 0; j < iNumDeviceData; ++j)
1290 const SActionInputDeviceData* pInputDeviceData = m_pActionMapManager->GetInputDeviceDataByIndex(j);
1292 const char* szInput = actionNode->getAttr(pInputDeviceData->m_typeStr);
1293 if (szInput == NULL || strcmp(szInput, "") == 0) // Not in xml which is fine
1294 continue;
1296 actionInput.input = szInput;
1297 actionInput.defaultInput = szInput;
1298 actionInput.inputDevice = pInputDeviceData->m_type;
1300 bResult = AddAndBindActionInput(pAction, actionInput);
1301 if (!bResult)
1303 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::LoadFromXML: Failed binding action input for action: %s, with input: %s", szActionName, szInput);
1304 continue;
1309 int iNumDeviceChildren = actionNode->getChildCount();
1311 // Check now for action inputs specified per platform
1312 if (iNumDeviceChildren > 0)
1314 // Support specifying separate device with attributes in their own child
1315 for (int j = 0; j < iNumDeviceChildren; ++j)
1317 XmlNodeRef inputDeviceNode = actionNode->getChild(j);
1319 EActionInputDevice inputDeviceNodeDeviceType = eAID_Unknown;
1321 const SActionInputDeviceData* pInputDeviceData = m_pActionMapManager->GetInputDeviceDataByType(inputDeviceNode->getTag());
1322 if (pInputDeviceData != NULL)
1324 inputDeviceNodeDeviceType = pInputDeviceData->m_type;
1326 else
1328 continue;
1331 SActionInput platformInput = actionInput; // Need to copy parent settings since don't want to overwrite for the other nodes
1333 bResult = LoadActionInputAttributesFromXML(inputDeviceNode, platformInput);
1334 if (!bResult)
1336 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::LoadFromXML: Failed loading action input attributes for action: %s", szActionName);
1337 continue;
1340 const char* szPlatformInput = inputDeviceNode->getAttr("input");
1341 if (szPlatformInput != NULL && strcmp(szPlatformInput, "") != 0) // Device specific key is here, dont need to look for children
1343 platformInput.input = szPlatformInput;
1344 platformInput.defaultInput = szPlatformInput;
1345 platformInput.inputDevice = inputDeviceNodeDeviceType;
1347 bResult = AddAndBindActionInput(pAction, platformInput);
1348 if (!bResult)
1350 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::LoadFromXML: Failed binding action input for action: %s, with input: %s", szActionName, szPlatformInput);
1351 continue;
1354 else
1356 int iNumInputData = inputDeviceNode->getChildCount();
1357 for (int k = 0; k < iNumInputData; k++)
1359 // Go through each of the separate inputs
1360 SActionInput platformChildInput = platformInput;
1362 XmlNodeRef platformChildNode = inputDeviceNode->getChild(k);
1363 if (strcmp(platformChildNode->getTag(), "inputdata") != 0)
1365 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::LoadFromXML: Children inside platform tags must be inputdata");
1366 continue;
1369 const char* szPlatformChildInput = platformChildNode->getAttr("input");
1370 if (szPlatformChildInput == NULL || strcmp(szPlatformChildInput, "") == 0)
1372 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::LoadFromXML: inputdata tag must contain input");
1373 continue;
1376 bResult = LoadActionInputAttributesFromXML(platformChildNode, platformChildInput);
1377 if (!bResult)
1379 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::LoadFromXML: Failed loading action input attributes on platform child input node for action: %s", szActionName);
1380 continue;
1383 platformChildInput.input = szPlatformChildInput;
1384 platformChildInput.defaultInput = szPlatformChildInput;
1385 platformChildInput.inputDevice = pInputDeviceData->m_type;
1387 bResult = AddAndBindActionInput(pAction, platformChildInput);
1388 if (!bResult)
1390 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::LoadFromXML: Failed binding action input for action: %s, with input: %s", szActionName, szPlatformChildInput);
1391 continue;
1399 return true;
1402 bool CActionMap::LoadRebindingDataFromXML(const XmlNodeRef& actionMapNode)
1404 int iNumActions = actionMapNode->getChildCount();
1405 for (int i = 0; i < iNumActions; ++i)
1407 XmlNodeRef actionNode = actionMapNode->getChild(i);
1408 if (strcmp(actionNode->getTag(), "action") != 0)
1410 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::LoadRebindingDataFromXML: Found non action child, actionmaps should only have action children");
1411 continue;
1414 const char* szActionName = actionNode->getAttr("name");
1415 if (szActionName == NULL || strcmp(szActionName, "") == 0)
1417 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::LoadRebindingDataFromXML: Action missing name, ignoring action");
1418 continue;
1421 ActionId actionName = ActionId(szActionName);
1422 CActionMapAction* pAction = (CActionMapAction*)GetAction(actionName);
1423 if (pAction == NULL)
1425 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::LoadRebindingDataFromXML: Action: %s, doesn't exist, can't rebind", szActionName);
1426 continue;
1429 // Check now for action inputs specified per platform
1430 int iNumRebindInputs = actionNode->getChildCount();
1431 if (iNumRebindInputs == 0)
1432 continue; // Shouldn't have empty action tags
1434 for (int j = 0; j < iNumRebindInputs; ++j)
1436 XmlNodeRef inputNode = actionNode->getChild(j);
1437 const char* szInput = inputNode->getAttr("input");
1438 if (szInput == NULL)
1440 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::LoadRebindingDataFromXML: Action: %s, has an input tag missing input attribute", szActionName);
1441 continue;
1444 const char* szDevice = inputNode->getAttr("device");
1445 if (szDevice == NULL || strcmp(szDevice, "") == 0)
1447 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::LoadRebindingDataFromXML: Action: %s, has an input tag missing device attribute", szActionName);
1448 continue;
1451 const SActionInputDeviceData* pInputDeviceData = m_pActionMapManager->GetInputDeviceDataByType(szDevice);
1452 if (pInputDeviceData == NULL)
1454 continue;
1457 // Want to allow rebinding without defaultInput to avoid data dependencies
1458 const char* szDefaultInput = inputNode->getAttr("defaultInput");
1459 if (szDefaultInput == NULL || strcmp(szDefaultInput, "") == 0) // Assumes rebinding the first input for that device
1461 if (stricmp(szInput, "DEFAULT") == 0) // Reset to default
1463 SActionInput* pActionInput = pAction->GetActionInput(pInputDeviceData->m_type, 0);
1464 if (pActionInput == NULL)
1466 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::LoadFromXML: Failed trying to find actioninput for input device type: %s", szDevice);
1467 continue;
1470 ReBindActionInput(pAction, pActionInput->defaultInput, pInputDeviceData->m_type, 0);
1472 else
1474 ReBindActionInput(pAction, szInput, pInputDeviceData->m_type, 0);
1477 else
1479 if (stricmp(szInput, "DEFAULT") == 0) // Reset to default
1481 ReBindActionInput(pAction, szDefaultInput, szDefaultInput);
1483 else
1485 ReBindActionInput(pAction, szDefaultInput, szInput);
1491 return true;
1494 bool CActionMap::SaveRebindingDataToXML(XmlNodeRef& actionMapNode) const
1496 #if 0
1497 // for debug reasons, we sort the ActionMap alphabetically
1498 // CryName normally sorts by pointer address
1499 std::map<ActionId, SAction, CryNameSorter> sortedActions(m_actions.begin(), m_actions.end());
1500 std::map<ActionId, SAction, CryNameSorter>::const_iterator iter = sortedActions.begin();
1501 std::map<ActionId, SAction, CryNameSorter>::const_iterator iterEnd = sortedActions.end();
1502 #else
1503 TActionMap::const_iterator iter = m_actions.begin();
1504 TActionMap::const_iterator iterEnd = m_actions.end();
1505 #endif
1507 actionMapNode->setAttr("name", m_name);
1508 for (; iter != iterEnd; ++iter)
1510 ActionId actionId = iter->first;
1511 const CActionMapAction& action = iter->second;
1512 if (action.GetNumRebindedInputs() == 0)
1513 continue;
1515 XmlNodeRef actionNode = actionMapNode->newChild("action");
1516 actionNode->setAttr("name", actionId.c_str());
1518 int numActionInputs = action.GetNumActionInputs();
1519 for (int i = 0; i < numActionInputs; ++i)
1521 const SActionInput* pActionInput = action.GetActionInput(i);
1522 CRY_ASSERT(pActionInput != NULL);
1524 if (pActionInput->input == pActionInput->defaultInput)
1526 continue;
1529 const SActionInputDeviceData* pInputDeviceData = m_pActionMapManager->GetInputDeviceDataByType(pActionInput->inputDevice);
1530 if (pInputDeviceData == NULL)
1532 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::SaveRebindingDataToXML: Failed to find device string");
1533 continue;
1536 XmlNodeRef inputDeviceNode = actionNode->newChild("rebind");
1537 inputDeviceNode->setAttr("device", pInputDeviceData->m_typeStr.c_str());
1538 inputDeviceNode->setAttr("input", pActionInput->input.c_str());
1539 inputDeviceNode->setAttr("defaultInput", pActionInput->defaultInput.c_str());
1543 return true;
1546 bool CActionMap::LoadActionInputAttributesFromXML(const XmlNodeRef& actionInputNode, SActionInput& actionInput)
1548 int& activationFlags = actionInput.activationMode;
1550 LoadActivationModeBitAttributeFromXML(actionInputNode, activationFlags, ACTIONINPUT_ONPRESS_STR, eAAM_OnPress);
1551 LoadActivationModeBitAttributeFromXML(actionInputNode, activationFlags, ACTIONINPUT_ONRELEASE_STR, eAAM_OnRelease);
1552 LoadActivationModeBitAttributeFromXML(actionInputNode, activationFlags, ACTIONINPUT_ONHOLD_STR, eAAM_OnHold);
1553 LoadActivationModeBitAttributeFromXML(actionInputNode, activationFlags, ACTIONINPUT_ALWAYS_STR, eAAM_Always);
1554 LoadActivationModeBitAttributeFromXML(actionInputNode, activationFlags, ACTIONINPUT_CONSOLECMD_STR, eAAM_ConsoleCmd);
1555 LoadActivationModeBitAttributeFromXML(actionInputNode, activationFlags, ACTIONINPUT_NOMODIFIERS_STR, eAAM_NoModifiers);
1556 LoadActivationModeBitAttributeFromXML(actionInputNode, activationFlags, ACTIONINPUT_RETRIGGERABLE_STR, eAAM_Retriggerable);
1558 // If not specified, value is taken from constructor (0.0f)
1559 actionInputNode->getAttr(ACTIONINPUT_PRESSTRIGGERDELAY_STR, actionInput.fPressTriggerDelay);
1560 // If not specified, value is taken from constructor (-1.0f) (Disabled)
1561 actionInputNode->getAttr(ACTIONINPUT_PRESSTRIGGERDELAY_REPEATOVERRIDE_STR, actionInput.fPressTriggerDelayRepeatOverride);
1562 // If not specified, value is taken from constructor (0) (Higher number will override when both delayed (i.e. pressing top right on dpad)
1563 actionInputNode->getAttr(ACTIONINPUT_PRESSDELAYPRIORITY_STR, actionInput.iPressDelayPriority);
1565 // If not specified, value is taken from constructor (0.0f)
1566 actionInputNode->getAttr(ACTIONINPUT_HOLDTRIGGERDELAY_STR, actionInput.fHoldTriggerDelay);
1567 // If not specified, value is taken from constructor (0.0f) (Always repeats)
1568 actionInputNode->getAttr(ACTIONINPUT_HOLDREPEATDELAY_STR, actionInput.fHoldRepeatDelay);
1569 // If not specified, value is taken from constructor (-1.0f) (Disabled)
1570 actionInputNode->getAttr(ACTIONINPUT_HOLDTRIGGERDELAY_REPEATOVERRIDE_STR, actionInput.fHoldTriggerDelayRepeatOverride);
1571 // If not specified, value is taken from constructor (-1.0f) (Disabled)
1572 actionInputNode->getAttr(ACTIONINPUT_RELEASETRIGGERTHRESHOLD_STR, actionInput.fReleaseTriggerThreshold);
1574 if (!strcmp(actionInputNode->getAttr(ACTIONINPUT_USEANALOGCOMPARE_STR), "1"))
1576 activationFlags |= eAAM_AnalogCompare;
1578 const char* analogCompareOp = actionInputNode->getAttr(ACTIONINPUT_ANALOGCOMPAREOP_STR);
1579 if (analogCompareOp == NULL || strcmp(analogCompareOp, "") == 0)
1581 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::LoadActionInputAttributesFromXML: Failed to find analogCompareOp");
1582 return false;
1585 actionInput.analogCompareOp = GetAnalogCompareOpTypeFromStr(analogCompareOp);
1586 if (actionInput.analogCompareOp == eAACO_None)
1588 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::LoadActionInputAttributesFromXML: Failed to find analogCompareOp");
1589 return false;
1592 bool bResult = actionInputNode->getAttr(ACTIONINPUT_ANALOGCOMPAREVAL_STR, actionInput.fAnalogCompareVal);
1593 if (!bResult)
1595 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::LoadActionInputAttributesFromXML: Failed to find analogCompareVal");
1596 return false;
1600 // Input blocking
1601 const char* inputsToBlock = actionInputNode->getAttr(ACTIONINPUT_INPUTSTOBLOCK_STR);
1602 if (inputsToBlock != NULL && strcmp(inputsToBlock, "") != 0)
1604 SActionInputBlockData& inputBlockData = actionInput.inputBlockData;
1606 if (strcmp(inputsToBlock, ACTIONINPUT_INPUTSTOBLOCK_SPECIALTYPE_CLEARALL_STR) == 0)
1608 inputBlockData.blockType = eAIBT_Clear;
1610 else // Must contain list of inputs separated by |
1612 // Must contain a valid block time
1613 actionInputNode->getAttr(ACTIONINPUT_INPUTBLOCKTIME_STR, inputBlockData.fBlockDuration);
1614 if (inputBlockData.fBlockDuration < FLT_EPSILON)
1616 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::LoadActionInputAttributesFromXML: Must have a valid blockTime, value is: %.2f", inputBlockData.fBlockDuration);
1617 return false;
1620 // Read in the blocking activation (Default is always, matches all specified action activations)
1621 const char* inputBlockActivation = actionInputNode->getAttr(ACTIONINPUT_INPUTBLOCKACTIVATION_STR);
1622 bool useAlwaysActivation;
1623 if (inputBlockActivation != NULL && strcmp(inputBlockActivation, "") != 0)
1625 useAlwaysActivation = false;
1626 string inputsBlockActivationStr(inputBlockActivation);
1627 int curPos = 0;
1628 string singleBlockActivation = inputsBlockActivationStr.Tokenize("|", curPos);
1629 bool bEmpty = singleBlockActivation.empty();
1630 if (bEmpty) // Only 1 input
1632 singleBlockActivation = inputsBlockActivationStr;
1633 curPos = 0;
1638 if (strcmp(singleBlockActivation, ACTIONINPUT_ONPRESS_STR) == 0)
1640 inputBlockData.activationMode |= eIS_Pressed;
1642 else if (strcmp(singleBlockActivation, ACTIONINPUT_ONHOLD_STR) == 0)
1644 inputBlockData.activationMode |= eIS_Down;
1646 else if (strcmp(singleBlockActivation, ACTIONINPUT_ONRELEASE_STR) == 0)
1648 inputBlockData.activationMode |= eIS_Released;
1650 else if (strcmp(inputBlockActivation, ACTIONINPUT_ALWAYS_STR) == 0)
1652 useAlwaysActivation = true;
1653 break;
1655 else
1657 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::LoadActionInputAttributesFromXML: Invalid block activation: %s", singleBlockActivation.c_str());
1658 return false;
1661 if (bEmpty)
1663 break;
1666 singleBlockActivation = inputsBlockActivationStr.Tokenize("|", curPos);
1667 bEmpty = singleBlockActivation.empty();
1669 while (!bEmpty);
1671 else
1673 useAlwaysActivation = true;
1676 if (useAlwaysActivation)
1678 inputBlockData.activationMode |= eIS_Pressed;
1679 inputBlockData.activationMode |= eIS_Down;
1680 inputBlockData.activationMode |= eIS_Released;
1683 // Now read in all the inputs to block, separated by |
1684 string inputsToBlockStr(inputsToBlock);
1685 std::vector<string> inputsToBlockVec;
1686 int curPos = 0;
1687 string singleInput = inputsToBlockStr.Tokenize("|", curPos);
1688 if (singleInput.empty()) // Only 1 input
1690 inputsToBlockVec.push_back(inputsToBlockStr);
1692 else
1696 inputsToBlockVec.push_back(singleInput);
1697 singleInput = inputsToBlockStr.Tokenize("|", curPos);
1699 while (!singleInput.empty());
1702 // Read in the device index (Default is all device indices)
1703 int iDeviceIndex = -1;
1704 actionInputNode->getAttr(ACTIONINPUT_INPUTBLOCKDEVICEINDEX_STR, iDeviceIndex);
1706 if (iDeviceIndex != -1)
1708 inputBlockData.bAllDeviceIndices = false;
1709 inputBlockData.deviceIndex = (uint8)iDeviceIndex;
1712 for (size_t i = 0; i < inputsToBlockVec.size(); i++)
1714 const SInputSymbol* pInputSymbol = gEnv->pInput ? gEnv->pInput->GetSymbolByName(inputsToBlockVec[i]) : NULL;
1715 if (!pInputSymbol)
1717 // Data is currently read all in on pc, dont show warnings until thats changed
1718 // CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::LoadActionInputAttributesFromXML: Failed to find input symbol for input name: %s", inputsToBlockVec[i].c_str());
1719 continue;
1722 SActionInputBlocker inputBlockerToSend(pInputSymbol->keyId);
1723 inputBlockData.inputs.push_back(inputBlockerToSend);
1725 if (!inputBlockData.inputs.empty())
1727 inputBlockData.blockType = eAIBT_BlockInputs; // Only having this makes enables blocking
1730 /* Data is currently read all in on pc, dont show warnings until thats changed
1731 else
1733 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::LoadActionInputAttributesFromXML: Failed to find any inputs to block for inputs: %s", inputsToBlock);
1734 return false;
1740 return true;
1743 bool CActionMap::SaveActionInputAttributesToXML(XmlNodeRef& actionInputNode, const SActionInput& actionInput) const
1745 const int activationFlags = actionInput.activationMode;
1747 SaveActivationModeBitAttributeToXML(actionInputNode, activationFlags, ACTIONINPUT_ONPRESS_STR, eAAM_OnPress);
1748 SaveActivationModeBitAttributeToXML(actionInputNode, activationFlags, ACTIONINPUT_ONRELEASE_STR, eAAM_OnRelease);
1749 SaveActivationModeBitAttributeToXML(actionInputNode, activationFlags, ACTIONINPUT_ALWAYS_STR, eAAM_Always);
1750 SaveActivationModeBitAttributeToXML(actionInputNode, activationFlags, ACTIONINPUT_CONSOLECMD_STR, eAAM_ConsoleCmd);
1751 SaveActivationModeBitAttributeToXML(actionInputNode, activationFlags, ACTIONINPUT_NOMODIFIERS_STR, eAAM_NoModifiers);
1752 SaveActivationModeBitAttributeToXML(actionInputNode, activationFlags, ACTIONINPUT_RETRIGGERABLE_STR, eAAM_Retriggerable);
1754 if (actionInput.activationMode & eAAM_OnHold)
1756 actionInputNode->setAttr(ACTIONINPUT_ONHOLD_STR, "1");
1757 actionInputNode->setAttr(ACTIONINPUT_HOLDTRIGGERDELAY_STR, actionInput.fHoldTriggerDelay);
1758 actionInputNode->setAttr(ACTIONINPUT_HOLDREPEATDELAY_STR, actionInput.fHoldRepeatDelay);
1759 actionInputNode->setAttr(ACTIONINPUT_HOLDTRIGGERDELAY_REPEATOVERRIDE_STR, actionInput.fHoldTriggerDelayRepeatOverride);
1761 else
1763 actionInputNode->setAttr(ACTIONINPUT_ONHOLD_STR, "0");
1766 if (actionInput.activationMode & eAAM_AnalogCompare)
1768 actionInputNode->setAttr(ACTIONINPUT_USEANALOGCOMPARE_STR, "1");
1769 actionInputNode->setAttr(ACTIONINPUT_ANALOGCOMPAREOP_STR, GetAnalogCompareOpStr(actionInput.analogCompareOp));
1770 actionInputNode->setAttr(ACTIONINPUT_ANALOGCOMPAREVAL_STR, actionInput.fAnalogCompareVal);
1772 else
1774 actionInputNode->setAttr(ACTIONINPUT_USEANALOGCOMPARE_STR, "0");
1777 // Input blocking
1778 const SActionInputBlockData& inputBlockData = actionInput.inputBlockData;
1779 if (inputBlockData.blockType != eAIBT_None)
1781 if (inputBlockData.blockType == eAIBT_Clear)
1783 actionInputNode->setAttr(ACTIONINPUT_INPUTSTOBLOCK_STR, ACTIONINPUT_INPUTSTOBLOCK_SPECIALTYPE_CLEARALL_STR);
1785 else // Normal blocking inputs
1787 if (inputBlockData.inputs.empty())
1789 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::SaveActionInputAttributesToXML: Failed, using normal blocking inputs type but dont have any inputs");
1790 return false;
1793 if (inputBlockData.fBlockDuration <= (0.0f - FLT_EPSILON))
1795 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::SaveActionInputAttributesToXML: Failed, using normal blocking inputs type but don't have valid block duration");
1796 return false;
1798 actionInputNode->setAttr(ACTIONINPUT_INPUTBLOCKTIME_STR, inputBlockData.fBlockDuration);
1800 // Save input blocking activation mode
1801 if ((inputBlockData.activationMode & eIS_Pressed) &&
1802 (inputBlockData.activationMode & eIS_Down) &&
1803 (inputBlockData.activationMode & eIS_Released))
1805 actionInputNode->setAttr(ACTIONINPUT_INPUTBLOCKACTIVATION_STR, ACTIONINPUT_ALWAYS_STR);
1807 else
1809 CryFixedStringT<32> inputBlockActivationStr("");
1810 bool bAddedActivationMode = false;
1811 if (inputBlockData.activationMode & eIS_Pressed)
1813 inputBlockActivationStr = ACTIONINPUT_ONPRESS_STR;
1814 bAddedActivationMode = true;
1816 if (inputBlockData.activationMode & eIS_Down)
1818 if (bAddedActivationMode)
1820 inputBlockActivationStr += "|";
1822 inputBlockActivationStr += ACTIONINPUT_ONHOLD_STR;
1823 bAddedActivationMode = true;
1825 if (inputBlockData.activationMode & eIS_Released)
1827 if (bAddedActivationMode)
1829 inputBlockActivationStr += "|";
1831 inputBlockActivationStr += ACTIONINPUT_ONRELEASE_STR;
1834 actionInputNode->setAttr(ACTIONINPUT_INPUTBLOCKACTIVATION_STR, inputBlockActivationStr.c_str());
1837 // Now save the blocked inputs
1838 string blockedInputsStr("");
1839 for (size_t i = 0; i < inputBlockData.inputs.size(); i++)
1841 const SActionInputBlocker& inputBlocker = inputBlockData.inputs[i];
1843 if (i != 0)
1845 blockedInputsStr += "|";
1848 const char* szKeyName = gEnv->pInput->GetKeyName(inputBlocker.keyId);
1849 if (!szKeyName)
1851 CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "CActionMap::LoadActionInputAttributesFromXML: Failed to translate keyname for key id: %d", (int)inputBlocker.keyId);
1852 return false;
1855 blockedInputsStr += szKeyName;
1858 // Now save device index data
1859 if (!inputBlockData.bAllDeviceIndices) // Default is true so dont need to save to xml
1861 actionInputNode->setAttr(ACTIONINPUT_INPUTBLOCKDEVICEINDEX_STR, inputBlockData.deviceIndex);
1866 return true;
1869 //------------------------------------------------------------------------
1870 void CActionMap::LoadActivationModeBitAttributeFromXML(const XmlNodeRef& attributeNode, int& activationFlags, const char* szActivationModeName, EActionActivationMode activationMode)
1872 int readFlag;
1874 if (attributeNode->getAttr(szActivationModeName, readFlag))
1876 if (readFlag == 1)
1878 activationFlags |= activationMode;
1880 else
1882 activationFlags &= ~activationMode;
1887 //------------------------------------------------------------------------
1888 void CActionMap::SaveActivationModeBitAttributeToXML(XmlNodeRef& attributeNode, const int activationFlags, const char* szActivationModeName, EActionActivationMode activationMode) const
1890 if (activationFlags & activationMode)
1892 attributeNode->setAttr(szActivationModeName, "1");
1894 else
1896 attributeNode->setAttr(szActivationModeName, "0");
1900 #define USE_SORTED_ACTIONS_ITERATOR
1901 #undef USE_SORTED_ACTIONS_ITERATOR
1903 //------------------------------------------------------------------------
1904 IActionMapActionIteratorPtr CActionMap::CreateActionIterator()
1906 class CActionInfo : public IActionMapActionIterator
1908 #ifndef USE_SORTED_ACTIONS_ITERATOR
1909 typedef TActionMap::iterator TIterator;
1910 #else
1911 typedef std::map<ActionId, CActionMapAction, CryNameSorter> TSortedActionMap;
1912 typedef TSortedActionMap::iterator TIterator;
1913 #endif
1915 public:
1916 CActionInfo(TActionMap::iterator& itBegin, TActionMap::iterator& itEnd)
1917 : m_nRefs(0)
1919 #ifdef USE_SORTED_ACTIONS_ITERATOR
1920 m_sortedActions.insert(itBegin, itEnd);
1921 m_cur = m_sortedActions.begin();
1922 m_end = m_sortedActions.end();
1923 #else
1924 m_cur = itBegin;
1925 m_end = itEnd;
1926 #endif
1929 virtual ~CActionInfo()
1933 const IActionMapAction* Next()
1935 if (m_cur == m_end)
1936 return NULL;
1937 const CActionMapAction& action = m_cur->second;
1939 ++m_cur;
1940 return &action;
1943 void AddRef()
1945 ++m_nRefs;
1948 void Release()
1950 if (--m_nRefs <= 0)
1951 delete this;
1953 int m_nRefs;
1954 TIterator m_cur;
1955 TIterator m_end;
1956 #ifdef USE_SORTED_ACTIONS_ITERATOR
1957 TSortedActionMap m_sortedActions;
1958 #endif
1960 TActionMap::iterator actionsBegin(m_actions.begin());
1961 TActionMap::iterator actionsEnd(m_actions.end());
1962 return new CActionInfo(actionsBegin, actionsEnd);
1965 void CActionMap::Enable(bool enable)
1967 // detect nop
1968 if (enable == m_enabled)
1969 return;
1971 // now things get a bit interesting, when we get disabled we "release" all our
1972 // active actions
1973 if (!enable)
1975 TActionMap::iterator it = m_actions.begin();
1976 TActionMap::iterator end = m_actions.end();
1977 for (; it != end; ++it)
1979 ReleaseActionIfActiveInternal(it->second);
1983 // finally set the flag
1984 m_enabled = enable;
1986 if (m_pActionMapManager)
1988 m_pActionMapManager->BroadcastActionMapEvent(SActionMapEvent(SActionMapEvent::eActionMapManagerEvent_ActionMapStatusChanged, (UINT_PTR)this, (UINT_PTR)m_enabled));
1992 void CActionMap::ReleaseActionIfActive(const ActionId& actionId)
1994 TActionMap::iterator it = m_actions.find(actionId);
1995 if (it != m_actions.end())
1997 ReleaseActionIfActiveInternal(it->second);
2001 void CActionMap::ReleaseActionIfActiveInternal(CActionMapAction& action)
2003 bool bFireOnActionRelease = false;
2004 bool bFireOnActionAlways = false;
2006 int numActionInputs = action.GetNumActionInputs();
2007 for (int i = 0; i < numActionInputs; ++i)
2009 SActionInput* pActionInput = action.GetActionInput(i);
2010 CRY_ASSERT(pActionInput != NULL);
2012 bool hasReleaseMode = (pActionInput->activationMode & eAAM_OnRelease) != 0;
2013 bool isPressedOrDown = (pActionInput->currentState == eIS_Pressed) || (pActionInput->currentState == eIS_Down);
2014 bool isChanged = pActionInput->currentState == eIS_Changed;
2016 if (hasReleaseMode && isPressedOrDown)
2018 bFireOnActionRelease = true;
2021 if (isChanged)
2023 bFireOnActionAlways = true;
2026 pActionInput->fCurrentHoldValue = 0.f;
2029 if (bFireOnActionRelease)
2031 IActionListener* pEntityListener = nullptr;
2033 if (IEntity* pEntity = gEnv->pEntitySystem->GetEntity(m_listenerId))
2035 if (IGameObject* pGameObject = static_cast<IGameObject*>(pEntity->GetProxy(ENTITY_PROXY_USER)))
2037 pEntityListener = pGameObject;
2041 if (pEntityListener)
2043 pEntityListener->OnAction(action.GetActionId(), eAAM_OnRelease, 0.0f);
2046 NotifyExtraActionListeners(action.GetActionId(), eAAM_OnRelease, 0.0f);
2049 if (bFireOnActionAlways)
2051 IActionListener* pEntityListener = nullptr;
2053 if (IEntity* pEntity = gEnv->pEntitySystem->GetEntity(m_listenerId))
2055 if (IGameObject* pGameObject = static_cast<IGameObject*>(pEntity->GetProxy(ENTITY_PROXY_USER)))
2056 pEntityListener = pGameObject;
2059 if (pEntityListener)
2061 pEntityListener->OnAction(action.GetActionId(), eAAM_Always, 0.0f);
2064 NotifyExtraActionListeners(action.GetActionId(), eAAM_Always, 0.0f);
2068 EActionAnalogCompareOperation CActionMap::GetAnalogCompareOpTypeFromStr(const char* szTypeStr)
2070 EActionAnalogCompareOperation compareOpType = eAACO_None;
2071 if (!strcmp(szTypeStr, s_analogCompareOpEqualsStr))
2073 compareOpType = eAACO_Equals;
2075 else if (!strcmp(szTypeStr, s_analogCompareOpNotEqualsStr))
2077 compareOpType = eAACO_NotEquals;
2079 else if (!strcmp(szTypeStr, s_analogCompareOpGreaterThanStr))
2081 compareOpType = eAACO_GreaterThan;
2083 else if (!strcmp(szTypeStr, s_analogCompareOpLessThanStr))
2085 compareOpType = eAACO_LessThan;
2088 return compareOpType;
2091 const char* CActionMap::GetAnalogCompareOpStr(EActionAnalogCompareOperation compareOpType) const
2093 if (compareOpType == eAACO_Equals)
2095 return s_analogCompareOpEqualsStr;
2097 else if (compareOpType == eAACO_NotEquals)
2099 return s_analogCompareOpNotEqualsStr;
2101 else if (compareOpType == eAACO_GreaterThan)
2103 return s_analogCompareOpGreaterThanStr;
2105 else if (compareOpType == eAACO_LessThan)
2107 return s_analogCompareOpLessThanStr;
2109 else
2111 return NULL;
2115 void CActionMap::EnumerateActions(IActionMapPopulateCallBack* pCallBack) const
2117 for (TActionMap::const_iterator actionCit = m_actions.begin(); actionCit != m_actions.end(); ++actionCit)
2119 pCallBack->AddActionName(actionCit->first.c_str());
2123 void CActionMap::GetMemoryUsage(ICrySizer* s) const
2125 s->AddObject(m_actions);
2126 s->AddObject(m_name);