BVB Source Codes

CRYENGINE Show FlowNodeAI.cpp Source code

Return Download CRYENGINE: download FlowNodeAI.cpp Source code - Download CRYENGINE Source code - Type:.cpp
  1. // Copyright 2001-2016 Crytek GmbH / Crytek Group. All rights reserved.
  2.  
  3. /********************************************************************
  4.    -------------------------------------------------------------------------
  5.    File name:   FlowNode_AI.cpp
  6.    $Id$
  7.    Description: place for miscellaneous AI related flow graph nodes
  8.  
  9.    -------------------------------------------------------------------------
  10.    History:
  11.    - 15:6:2005   15:24 : Created by Kirill Bulatsev
  12.  
  13.  *********************************************************************/
  14.  
  15. #include "StdAfx.h"
  16. #include "FlowEntityNode.h"
  17. #include "AIProxy.h"
  18.  
  19. #include <CryAISystem/IAIAction.h>
  20. #include <CryAISystem/IAISystem.h>
  21. #include <CryAISystem/IAgent.h>
  22. #include <CryAISystem/IInterestSystem.h>
  23. #include <CryAISystem/INavigation.h>
  24. #include <CryAISystem/IAIObjectManager.h>
  25. #include <CryAISystem/IAIActor.h>
  26. #include <CryAISystem/IFactionMap.h>
  27. #include <CryAISystem/ICommunicationManager.h>
  28. /*
  29.    //////////////////////////////////////////////////////////////////////////
  30.    // broadcast AI signal
  31.    //////////////////////////////////////////////////////////////////////////
  32.    class CFlowNode_AISignal : public CFlowBaseNode
  33.    {
  34.    public:
  35.    CFlowNode_AISignal( SActivationInfo * pActInfo )
  36.    {
  37.    }
  38.    virtual void GetConfiguration( SFlowNodeConfig &config )
  39.    {
  40.     static const SInputPortConfig in_config[] = {
  41.       InputPortConfig<bool>("send"),
  42.       InputPortConfig<string>("signal",_HELP("AI signal to be send") ),
  43.       InputPortConfig<Vec3>("pos" ),
  44.       InputPortConfig<float>("radius" ),
  45.       {0}
  46.     };
  47.     config.sDescription = _HELP( "broadcast AI signal" );
  48.     config.pInputPorts = in_config;
  49.     config.pOutputPorts = 0;
  50.     config.SetCategory(EFLN_APPROVED);
  51.    }
  52.    virtual void ProcessEvent( EFlowEvent event, SActivationInfo *pActInfo )
  53.    {
  54.     if(event != eFE_Activate || !IsBoolPortActive(pActInfo, 0))
  55.       return;
  56.     string signalText = GetPortString(pActInfo,1);
  57.  
  58.     Vec3        pos = *pActInfo->pInputPorts[2].GetPtr<Vec3>();
  59.     //          Vec3    pos = GetPortVec3(pActInfo,2);
  60.     float       radius = GetPortFloat(pActInfo,3);
  61.     IAISystem *pAISystem(gEnv->pAISystem);
  62.  
  63.     pAISystem->SendAnonymousSignal(1, signalText, pos, radius, NULL);
  64.    }
  65.    private:
  66.    };
  67.  */
  68.  
  69. //////////////////////////////////////////////////////////////////////////
  70. // Counts how many AIs are active
  71. //////////////////////////////////////////////////////////////////////////
  72. class CFlowNode_AIActiveCount : public CFlowBaseNode<eNCT_Instanced>
  73. {
  74.         enum EOutputPorts
  75.         {
  76.                 eOUT_AICount = 0,
  77.                 eOUT_EnemyCount
  78.         };
  79. public:
  80.         CFlowNode_AIActiveCount(SActivationInfo* pActInfo)
  81.                 : m_localAICount(0)
  82.                 , m_localAIEnemyCount(0)
  83.         {
  84.         }
  85.  
  86.         virtual IFlowNodePtr Clone(SActivationInfo* pActInfo) { return new CFlowNode_AIActiveCount(pActInfo); }
  87.  
  88.         void                 Serialize(SActivationInfo* pActInfo, TSerialize ser)
  89.         {
  90.                 ser.Value("LocalAICount", m_localAICount);
  91.                 ser.Value("LocalAIEnemyCount", m_localAIEnemyCount);
  92.  
  93.                 if (ser.IsReading())
  94.                 {
  95.                         m_currentAICount = -1;
  96.                         m_currentAIEnemyCount = -1;
  97.                         m_lastUpdateframeID = -1;
  98.                 }
  99.         }
  100.         virtual void GetConfiguration(SFlowNodeConfig& config)
  101.         {
  102.                 static const SOutputPortConfig out_config[] = {
  103.                         OutputPortConfig<int>("Total"),
  104.                         OutputPortConfig<int>("Enemy"),
  105.                         { 0 }
  106.                 };
  107.  
  108.                 config.sDescription = _HELP("Counts how many AIs are active");
  109.                 config.pInputPorts = 0;
  110.                 config.pOutputPorts = out_config;
  111.                 config.SetCategory(EFLN_APPROVED);
  112.         }
  113.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  114.         {
  115.                 if (event == eFE_Initialize)
  116.                 {
  117.                         pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, true);
  118.                         m_localAICount = m_localAIEnemyCount = -1; // to force a local update
  119.                         m_currentAICount = m_currentAIEnemyCount = -1;
  120.                         m_lastUpdateframeID = -1;
  121.                 }
  122.  
  123.                 if (event != eFE_Update)
  124.                         return;
  125.  
  126.                 float currTime = gEnv->pTimer->GetCurrTime();
  127.  
  128.                 RecalcAICounters();
  129.  
  130.                 if (m_localAICount != m_currentAICount)
  131.                 {
  132.                         m_localAICount = m_currentAICount;
  133.                         ActivateOutput(pActInfo, eOUT_AICount, m_localAICount);
  134.                 }
  135.                 if (m_localAIEnemyCount != m_currentAIEnemyCount)
  136.                 {
  137.                         m_localAIEnemyCount = m_currentAIEnemyCount;
  138.                         ActivateOutput(pActInfo, eOUT_EnemyCount, m_localAIEnemyCount);
  139.                 }
  140.         }
  141.  
  142.         virtual void GetMemoryUsage(ICrySizer* s) const
  143.         {
  144.                 s->Add(*this);
  145.         }
  146. private:
  147.  
  148.         static void RecalcAICounters()
  149.         {
  150.                 int frameID = gEnv->pRenderer->GetFrameID();
  151.  
  152.                 if (frameID != m_lastUpdateframeID)
  153.                 {
  154.                         m_lastUpdateframeID = frameID;
  155.  
  156.                         bool changed = false;
  157.                         int AICount = 0;
  158.                         int AIEnemies = 0;
  159.  
  160.                         const IActor* pLocalPlayer = CCryAction::GetCryAction()->GetClientActor();
  161.                         const IAIObject* pAILocalPlayer = pLocalPlayer ? pLocalPlayer->GetEntity()->GetAI() : NULL;
  162.  
  163.                         IActorIteratorPtr pIter = gEnv->pGameFramework->GetIActorSystem()->CreateActorIterator();
  164.                         while (IActor* pActor = pIter->Next())
  165.                         {
  166.                                 if (!pActor->IsPlayer())
  167.                                 {
  168.                                         const IAIObject* pAIObject = pActor->GetEntity()->GetAI();
  169.                                         if (pAIObject)
  170.                                         {
  171.                                                 const IAIActor* pAIActor = pAIObject->CastToIAIActor();
  172.                                                 if (pAIActor->IsActive() && (pActor->GetHealth() > 0.0f))
  173.                                                 {
  174.                                                         AICount++;
  175.                                                         if (pAIObject->IsHostile(pAILocalPlayer))
  176.                                                                 AIEnemies++;
  177.                                                 }
  178.                                         }
  179.                                 }
  180.                         }
  181.  
  182.                         m_currentAICount = AICount;
  183.                         m_currentAIEnemyCount = AIEnemies;
  184.                 }
  185.         }
  186.  
  187. private:
  188.         // using statics instead a singleton node because we want the outputs to be activated only on change.
  189.         int        m_localAICount;
  190.         int        m_localAIEnemyCount;
  191.         static int m_currentAICount;
  192.         static int m_currentAIEnemyCount;
  193.         static int m_lastUpdateframeID;
  194. };
  195.  
  196. int CFlowNode_AIActiveCount::m_currentAICount = -1;
  197. int CFlowNode_AIActiveCount::m_currentAIEnemyCount = -1;
  198. int CFlowNode_AIActiveCount::m_lastUpdateframeID = -1;
  199.  
  200. //////////////////////////////////////////////////////////////////////////
  201. // Node to count the number of currently active AIs in a faction.
  202. //////////////////////////////////////////////////////////////////////////
  203.  
  204. class CFlowNode_AIActiveCountInFaction : public CFlowBaseNode<eNCT_Instanced>
  205. {
  206. public:
  207.         enum
  208.         {
  209.                 IN_Faction,
  210.                 IN_IncludeHumanPlayers
  211.         };
  212.  
  213.         enum
  214.         {
  215.                 OUT_Count,
  216.                 OUT_CountChanged
  217.         };
  218.  
  219.         CFlowNode_AIActiveCountInFaction(SActivationInfo*)
  220.                 : m_factionID(0)
  221.                 , m_includeHumanPlayers(false)
  222.                 , m_currentCount(0)
  223.         {
  224.         }
  225.  
  226.         virtual IFlowNodePtr Clone(SActivationInfo* pActInfo) override
  227.         {
  228.                 return new CFlowNode_AIActiveCountInFaction(pActInfo);
  229.         }
  230.  
  231.         virtual void GetConfiguration(SFlowNodeConfig& config) override
  232.         {
  233.                 static const SInputPortConfig inputs[] =
  234.                 {
  235.                         InputPortConfig<string>("Faction",           "",    _HELP("Faction to the count the active AIs"),                                      0, "enum_global:Faction"),
  236.                         InputPortConfig<bool>("IncludeHumanPlayers", false, _HELP("Include human players when counting active AIs in the specified faction")),
  237.                         { 0 }
  238.                 };
  239.  
  240.                 static const SOutputPortConfig outputs[] =
  241.                 {
  242.                         OutputPortConfig<int>("Count",        _HELP("The number of active AIs in the specified faction")),
  243.                         OutputPortConfig_Void("CountChanged", _HELP("Triggered whenever the number of active AIs in the specified faction changes"),"Changed"),
  244.                         { 0 }
  245.                 };
  246.  
  247.                 config.pInputPorts = inputs;
  248.                 config.pOutputPorts = outputs;
  249.                 config.nFlags |= EFLN_AISEQUENCE_SUPPORTED;
  250.                 config.sDescription = _HELP("Counts the number of currently active AIs in a specific faction.");
  251.                 config.SetCategory(EFLN_APPROVED);
  252.         }
  253.  
  254.         virtual void GetMemoryUsage(ICrySizer* s) const override
  255.         {
  256.                 s->Add(*this);
  257.         }
  258.  
  259.         virtual void Serialize(SActivationInfo*, TSerialize ser) override
  260.         {
  261.                 ser.Value("m_factionID", m_factionID);
  262.                 ser.Value("m_includeHumanPlayers", m_includeHumanPlayers);
  263.                 ser.Value("m_currentCount", m_currentCount);
  264.         }
  265.  
  266.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo) override
  267.         {
  268.                 switch (event)
  269.                 {
  270.                 case eFE_Initialize:
  271.                         pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, true);
  272.                         m_currentCount = 0;
  273.                         m_factionID = gEnv->pAISystem->GetFactionMap().GetFactionID(GetPortString(pActInfo, IN_Faction).c_str());
  274.                         m_includeHumanPlayers = GetPortBool(pActInfo, IN_IncludeHumanPlayers);
  275.                         break;
  276.  
  277.                 case eFE_Update:
  278.                         {
  279.                                 int count = CountCurrentlyActiveAIsInSpecifiedFaction();
  280.                                 ActivateOutput(pActInfo, OUT_Count, count);
  281.                                 if (count != m_currentCount)
  282.                                 {
  283.                                         ActivateOutput(pActInfo, OUT_CountChanged, true);
  284.                                 }
  285.                                 m_currentCount = count;
  286.                         }
  287.                         break;
  288.                 }
  289.         }
  290.  
  291. private:
  292.         uint8 m_factionID;
  293.         bool  m_includeHumanPlayers; // also include human players when counting AIs of the specified faction
  294.         int   m_currentCount;        // no. of currently active AIs in the specified faction
  295.  
  296.         int CountCurrentlyActiveAIsInSpecifiedFaction()
  297.         {
  298.                 int count = 0;
  299.                 IActorIteratorPtr pIter = gEnv->pGameFramework->GetIActorSystem()->CreateActorIterator();
  300.                 while (IActor* pActor = pIter->Next())
  301.                 {
  302.                         if (!pActor->IsPlayer() || m_includeHumanPlayers)
  303.                         {
  304.                                 if (IAIObject* pAIObject = pActor->GetEntity()->GetAI())
  305.                                 {
  306.                                         if (IAIActor* pAIActor = pAIObject->CastToIAIActor())
  307.                                         {
  308.                                                 if (pAIActor->IsActive() && pActor->GetHealth() > 0.0f && pAIObject->GetFactionID() == m_factionID)
  309.                                                 {
  310.                                                         count++;
  311.                                                 }
  312.                                         }
  313.                                 }
  314.                         }
  315.                 }
  316.                 return count;
  317.         }
  318. };
  319.  
  320. //////////////////////////////////////////////////////////////////////////
  321. // Counts how many AIs are active
  322. //////////////////////////////////////////////////////////////////////////
  323. class CFlowNode_AIActiveCountMonitor : public CFlowBaseNode<eNCT_Instanced>
  324. {
  325. private:
  326.         enum EInputs
  327.         {
  328.                 eInput_StartMonitoring,
  329.                 eInput_StopMonitoring,
  330.                 eInput_MaxActiveAICount,
  331.                 eInput_Loop,
  332.                 eInput_LoopPeriod
  333.         };
  334.  
  335.         enum EOutputs
  336.         {
  337.                 eOutput_SlotsFree,
  338.                 eOutput_SlotsFull,
  339.                 eOutput_CurrentCount,
  340.         };
  341.  
  342.         struct SActiveAIStatistics
  343.         {
  344.                 SActiveAIStatistics()
  345.                         : m_lastUpdateFrameId(-1)
  346.                         , m_currentActiveAIs(0)
  347.                 {
  348.  
  349.                 }
  350.  
  351.                 void Reset()
  352.                 {
  353.                         m_lastUpdateFrameId = -1;
  354.                         m_currentActiveAIs = 0;
  355.                 }
  356.  
  357.                 void Refresh()
  358.                 {
  359.                         const int frameID = gEnv->pRenderer->GetFrameID();
  360.  
  361.                         //Check if some other flow node instance updated this frame to avoid multiple updates
  362.                         if (frameID != m_lastUpdateFrameId)
  363.                         {
  364.                                 m_lastUpdateFrameId = frameID;
  365.  
  366.                                 int aiCount = 0;
  367.  
  368.                                 IActorIteratorPtr pIter = gEnv->pGameFramework->GetIActorSystem()->CreateActorIterator();
  369.                                 while (IActor* pActor = pIter->Next())
  370.                                 {
  371.                                         if (!pActor->IsPlayer() && !pActor->IsDead())
  372.                                         {
  373.                                                 const IAIObject* pAIObject = pActor->GetEntity()->GetAI();
  374.                                                 if (pAIObject && pAIObject->CastToIAIActor()->IsActive())
  375.                                                 {
  376.                                                         aiCount++;
  377.                                                 }
  378.                                         }
  379.                                 }
  380.  
  381.                                 m_currentActiveAIs = aiCount;
  382.                         }
  383.                 }
  384.  
  385.                 ILINE int GetActiveAICount() const { return m_currentActiveAIs; }
  386.  
  387.         private:
  388.                 int m_lastUpdateFrameId;
  389.                 int m_currentActiveAIs;
  390.         };
  391.  
  392. public:
  393.  
  394.         CFlowNode_AIActiveCountMonitor(SActivationInfo* pActInfo)
  395.                 : m_active(false)
  396.                 , m_monitorRefreshTimeout(2.0f)
  397.         {
  398.         }
  399.  
  400.         virtual IFlowNodePtr Clone(SActivationInfo* pActInfo) { return new CFlowNode_AIActiveCountMonitor(pActInfo); }
  401.  
  402.         //////////////////////////////////////////////////////////////////////////
  403.         virtual void GetConfiguration(SFlowNodeConfig& config)
  404.         {
  405.                 static const SInputPortConfig in_config[] =
  406.                 {
  407.                         InputPortConfig_Void("Start",        _HELP("Starts monitoring, looping periodically if configured so")),
  408.                         InputPortConfig_Void("Stop",         _HELP("Stops monitoring loop")),
  409.                         InputPortConfig<int>("MaxActiveAIs", 0,                                                                 _HELP("Maximum number of active AI which is being used as condition for the node outputs")),
  410.                         InputPortConfig<bool>("Loop",        false,                                                             _HELP("Activates monitoring loop mode")),
  411.                         InputPortConfig<float>("LoopPeriod", 2.0f,                                                              _HELP("Period of time between check when loop mode is active")),
  412.                         { 0 }
  413.                 };
  414.  
  415.                 static const SOutputPortConfig out_config[] =
  416.                 {
  417.                         OutputPortConfig_Void("SlotsFree",        _HELP("Activated when the number of active AI goes bellow MaxActiveAI")),
  418.                         OutputPortConfig_Void("SlotsFull",        _HELP("Activated when the number of active AI goes is equal or above MaxActiveAI")),
  419.                         OutputPortConfig<int>("CurrentActiveAIs", _HELP("Outputs number of active AIs")),
  420.                         { 0 }
  421.                 };
  422.  
  423.                 config.sDescription = _HELP("Monitors active AI count against some limit, and outputs periodically the current state. When the condition is met, the monitor loop will stop automatically and it needs to be started manually again if desired.");
  424.                 config.pInputPorts = in_config;
  425.                 config.pOutputPorts = out_config;
  426.                 config.SetCategory(EFLN_APPROVED);
  427.         }
  428.  
  429.         //////////////////////////////////////////////////////////////////////////
  430.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  431.         {
  432.                 switch (event)
  433.                 {
  434.                 case eFE_Update:
  435.                         {
  436.                                 CRY_ASSERT(m_active);
  437.  
  438.                                 const float frameTime = gEnv->pTimer->GetFrameTime();
  439.                                 const float timeOut = m_monitorRefreshTimeout - frameTime;
  440.  
  441.                                 if (timeOut > 0.0f)
  442.                                 {
  443.                                         //No time for check yet, continue running time-out
  444.                                         m_monitorRefreshTimeout = timeOut;
  445.                                 }
  446.                                 else
  447.                                 {
  448.                                         //Refresh statistics, and trigger outputs
  449.                                         s_activeAIStatistics.Refresh();
  450.  
  451.                                         const int activeAICount = s_activeAIStatistics.GetActiveAICount();
  452.  
  453.                                         if (activeAICount < GetPortInt(pActInfo, eInput_MaxActiveAICount))
  454.                                         {
  455.                                                 //Trigger output and deactivate updates at this point, we are done until we are asked to start again
  456.                                                 ActivateOutput(pActInfo, eOutput_SlotsFree, true);
  457.                                                 DeactivateUpdate(pActInfo);
  458.                                         }
  459.                                         else
  460.                                         {
  461.                                                 //Trigger output and check if we need to loop or just stop
  462.                                                 ActivateOutput(pActInfo, eOutput_SlotsFull, true);
  463.  
  464.                                                 const bool loopingMode = GetPortBool(pActInfo, eInput_Loop);
  465.                                                 if (loopingMode)
  466.                                                 {
  467.                                                         m_monitorRefreshTimeout = GetPortFloat(pActInfo, eInput_LoopPeriod);
  468.                                                 }
  469.                                                 else
  470.                                                 {
  471.                                                         DeactivateUpdate(pActInfo);
  472.                                                 }
  473.                                         }
  474.  
  475.                                         ActivateOutput(pActInfo, eOutput_CurrentCount, activeAICount);
  476.                                 }
  477.                         }
  478.                         break;
  479.  
  480.                 case eFE_Activate:
  481.                         {
  482.                                 if (IsPortActive(pActInfo, eInput_StartMonitoring))
  483.                                 {
  484.                                         ActivateUpdate(pActInfo);
  485.                                 }
  486.                                 else if (IsPortActive(pActInfo, eInput_StopMonitoring))
  487.                                 {
  488.                                         DeactivateUpdate(pActInfo);
  489.                                 }
  490.                         }
  491.                         break;
  492.                 }
  493.         }
  494.  
  495.         //////////////////////////////////////////////////////////////////////////
  496.         virtual void Serialize(SActivationInfo* pActInfo, TSerialize ser)
  497.         {
  498.                 ser.Value("MonitoringActive", m_active);
  499.                 ser.Value("MonitoringTimeout", m_monitorRefreshTimeout);
  500.  
  501.                 if (ser.IsReading())
  502.                 {
  503.                         s_activeAIStatistics.Reset();
  504.  
  505.                         //Make sure active state is restored properly
  506.                         if (m_active)
  507.                         {
  508.                                 const float storedRefreshTime = m_monitorRefreshTimeout;
  509.                                 ActivateUpdate(pActInfo);
  510.  
  511.                                 m_monitorRefreshTimeout = storedRefreshTime;
  512.                         }
  513.                         else
  514.                         {
  515.                                 DeactivateUpdate(pActInfo);
  516.                         }
  517.                 }
  518.         }
  519.  
  520.         //////////////////////////////////////////////////////////////////////////
  521.         virtual void GetMemoryUsage(ICrySizer* s) const
  522.         {
  523.                 s->Add(*this);
  524.         }
  525.  
  526. private:
  527.  
  528.         void ActivateUpdate(SActivationInfo* pActInfo)
  529.         {
  530.                 pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, true);
  531.                 m_active = true;
  532.  
  533.                 m_monitorRefreshTimeout = 0.0f; //This is so first update is immediate after activation
  534.         }
  535.  
  536.         void DeactivateUpdate(SActivationInfo* pActInfo)
  537.         {
  538.                 pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, false);
  539.                 m_active = false;
  540.         }
  541.  
  542.         //Shared between all node instances
  543.         static SActiveAIStatistics s_activeAIStatistics;
  544.  
  545.         float                      m_monitorRefreshTimeout;
  546.         bool                       m_active;
  547. };
  548.  
  549. CFlowNode_AIActiveCountMonitor::SActiveAIStatistics CFlowNode_AIActiveCountMonitor::s_activeAIStatistics;
  550.  
  551. //////////////////////////////////////////////////////////////////////////
  552. // Group AI enemies alertness level.
  553. // It represents the current alertness level of AI enemies, more precisely,
  554. // the highest level of alertness of any active agent in a group.
  555. //////////////////////////////////////////////////////////////////////////
  556. class CFlowNode_AIGroupAlertness : public CFlowBaseNode<eNCT_Instanced>
  557. {
  558. public:
  559.         CFlowNode_AIGroupAlertness(SActivationInfo* pActInfo)
  560.                 : m_CurrentAlertness(0)
  561.                 , m_PlayerWasRecognized(false)
  562.                 , m_PendingNotifyOfInitialAlertnessState(true)
  563.         {
  564.         }
  565.         IFlowNodePtr Clone(SActivationInfo* pActInfo)
  566.         {
  567.                 return new CFlowNode_AIGroupAlertness(pActInfo);
  568.         }
  569.         void Serialize(SActivationInfo* pActInfo, TSerialize ser)
  570.         {
  571.                 ser.Value("CurrentAlertness", m_CurrentAlertness);
  572.                 ser.Value("PlayerWasRecognized", m_PlayerWasRecognized);
  573.                 ser.Value("PendingNotifyOfInitialAlertnessState", m_PendingNotifyOfInitialAlertnessState);
  574.         }
  575.         virtual void GetConfiguration(SFlowNodeConfig& config)
  576.         {
  577.                 static const SOutputPortConfig out_config[] = {
  578.                         OutputPortConfig<int>("alertness",      "0 - green\n1 - orange\n2 - red"),
  579.                         OutputPortConfig_Void("green"),
  580.                         OutputPortConfig_Void("orange"),
  581.                         OutputPortConfig_Void("red"),
  582.                         OutputPortConfig_Void("playerSighted"),
  583.                         { 0 }
  584.                 };
  585.  
  586.                 static const SInputPortConfig in_config[] = {
  587.                         InputPortConfig<int>("groupID", _HELP("The group ID of the group to get the alertness from")),
  588.                         { 0 }
  589.                 };
  590.  
  591.                 config.sDescription = _HELP("The highest level of alertness of any agent in the group.");
  592.                 config.pInputPorts = in_config;
  593.                 config.pOutputPorts = out_config;
  594.                 config.SetCategory(EFLN_APPROVED);
  595.         }
  596.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  597.         {
  598.                 if (event == eFE_Initialize)
  599.                 {
  600.                         pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, true);
  601.                         m_CurrentAlertness = 0;
  602.                         m_PlayerWasRecognized = false;
  603.                         m_PendingNotifyOfInitialAlertnessState = true;
  604.                 }
  605.                 else if (event == eFE_Update)
  606.                 {
  607.                         bool playerIsVisible = false;
  608.                         // Get the max alertness of the group.
  609.                         int maxAlertness = 0;
  610.                         IAISystem* pAISystem = gEnv->pAISystem;
  611.                         int groupID = GetPortInt(pActInfo, 0);    // group ID
  612.                         int n = pAISystem->GetGroupCount(groupID, IAISystem::GROUP_ENABLED);
  613.                         for (int i = 0; i < n; i++)
  614.                         {
  615.                                 IAIObject* pMember = pAISystem->GetGroupMember(groupID, i, IAISystem::GROUP_ENABLED);
  616.                                 if (pMember)
  617.                                 {
  618.                                         IAIActorProxy* pMemberProxy = pMember->GetProxy();
  619.                                         if (pMemberProxy)
  620.                                         {
  621.                                                 maxAlertness = max(maxAlertness, pMemberProxy->GetAlertnessState());
  622.                                         }
  623.  
  624.                                         if (!m_PlayerWasRecognized && !playerIsVisible)
  625.                                         {
  626.                                                 if (IAIActor* aiActor = pMember->CastToIAIActor())
  627.                                                 {
  628.                                                         if (aiActor->GetAttentionTargetType() == AITARGET_VISUAL)
  629.                                                         {
  630.                                                                 if (IAIObject* attentionTargetAIObject = aiActor->GetAttentionTarget())
  631.                                                                 {
  632.                                                                         const EntityId localPlayerEntityId = CCryAction::GetCryAction()->GetClientActorId();
  633.                                                                         const EntityId attentionTargetEntityId = attentionTargetAIObject->GetEntityID();
  634.  
  635.                                                                         playerIsVisible = (attentionTargetEntityId != 0 && localPlayerEntityId == attentionTargetEntityId);
  636.                                                                 }
  637.                                                         }
  638.                                                 }
  639.                                         }
  640.                                 }
  641.                         }
  642.  
  643.                         if (maxAlertness != m_CurrentAlertness || m_PendingNotifyOfInitialAlertnessState)
  644.                         {
  645.                                 m_CurrentAlertness = maxAlertness;
  646.                                 ActivateOutput(pActInfo, 0, m_CurrentAlertness);
  647.                                 ActivateOutput(pActInfo, m_CurrentAlertness + 1, true);
  648.                                 m_PendingNotifyOfInitialAlertnessState = false;
  649.                         }
  650.  
  651.                         if (!m_PlayerWasRecognized)
  652.                         {
  653.                                 const bool playerIsRecognized = (playerIsVisible && m_CurrentAlertness == 2);
  654.                                 if (playerIsRecognized)
  655.                                 {
  656.                                         m_PlayerWasRecognized = true;
  657.                                         const int targetVisibleOutputPort = 4;
  658.                                         ActivateOutput(pActInfo, targetVisibleOutputPort, true);
  659.                                 }
  660.                         }
  661.                 }
  662.  
  663.         }
  664.  
  665.         virtual void GetMemoryUsage(ICrySizer* s) const
  666.         {
  667.                 s->Add(*this);
  668.         }
  669. private:
  670.         int  m_CurrentAlertness;
  671.         bool m_PlayerWasRecognized;
  672.         bool m_PendingNotifyOfInitialAlertnessState;
  673. };
  674.  
  675. //////////////////////////////////////////////////////////////////////////
  676. // AI:GroupIDSet
  677. // Merges two AI groups.
  678. //////////////////////////////////////////////////////////////////////////
  679. class CFlowNode_AIMergeGroups : public CFlowBaseNode<eNCT_Singleton>
  680. {
  681. public:
  682.         CFlowNode_AIMergeGroups(SActivationInfo* pActInfo) {}
  683.         virtual void GetConfiguration(SFlowNodeConfig& config)
  684.         {
  685.                 static const SInputPortConfig in_config[] = {
  686.                         InputPortConfig_AnyType("sink",          NULL, _HELP("Sync")),
  687.                         InputPortConfig<int>("fromID",           0,    _HELP("The group which is to be merged.")),
  688.                         InputPortConfig<int>("toID",             0,    _HELP("The group to merge to.")),
  689.                         InputPortConfig<bool>("enableFromGroup", true, _HELP("Set if the members of the 'from' group should be enabled before merging.")),
  690.                         { 0 }
  691.                 };
  692.  
  693.                 config.sDescription = _HELP("Merges AI group 'from' to group 'to'.");
  694.                 config.pInputPorts = in_config;
  695.                 config.pOutputPorts = 0;
  696.                 config.SetCategory(EFLN_ADVANCED);
  697.         }
  698.  
  699.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  700.         {
  701.                 if (event == eFE_Activate && IsPortActive(pActInfo, 0))
  702.                 {
  703.                         int fromID = GetPortInt(pActInfo, 1);
  704.                         int toID = GetPortInt(pActInfo, 2);
  705.                         bool enable = GetPortBool(pActInfo, 3);
  706.  
  707.                         // Collect members
  708.                         std::vector<IAIObject*> members;
  709.                         AutoAIObjectIter it(gEnv->pAISystem->GetAIObjectManager()->GetFirstAIObject(OBJFILTER_GROUP, fromID));
  710.                         for (; it->GetObject(); it->Next())
  711.                                 members.push_back(it->GetObject());
  712.  
  713.                         // Enable entities if they are not currently enabled.
  714.                         if (enable)
  715.                         {
  716.                                 for (unsigned i = 0, ni = members.size(); i < ni; ++i)
  717.                                 {
  718.                                         IEntity* pEntity = members[i]->GetEntity();
  719.                                         if (pEntity)
  720.                                         {
  721.                                                 IEntityScriptComponent* pScriptProxy = (IEntityScriptComponent*)pEntity->GetProxy(ENTITY_PROXY_SCRIPT);
  722.                                                 if (pScriptProxy)
  723.                                                         pScriptProxy->CallEvent("Enable");
  724.                                         }
  725.                                 }
  726.                         }
  727.  
  728.                         // Change group IDs
  729.                         for (unsigned i = 0, ni = members.size(); i < ni; ++i)
  730.                                 members[i]->SetGroupId(toID);
  731.  
  732.                         // Send signals to notify about the change.
  733.                         for (unsigned i = 0, ni = members.size(); i < ni; ++i)
  734.                         {
  735.                                 IAIActor* pAIActor = members[i]->CastToIAIActor();
  736.                                 if (pAIActor)
  737.                                         pAIActor->SetSignal(10, "OnGroupChanged", members[i]->GetEntity(), 0);
  738.                         }
  739.                 }
  740.         }
  741.  
  742.         virtual void GetMemoryUsage(ICrySizer* s) const
  743.         {
  744.                 s->Add(*this);
  745.         }
  746. };
  747.  
  748. //////////////////////////////////////////////////////////////////////////
  749. // AI:GroupID node.
  750. // Returns the groupID of the entity.
  751. //////////////////////////////////////////////////////////////////////////
  752. class CFlowNode_AIGroupID : public CFlowBaseNode<eNCT_Instanced>
  753. {
  754. public:
  755.         CFlowNode_AIGroupID(SActivationInfo* pActInfo) : m_lastID(-1)
  756.         {
  757.         }
  758.  
  759.         IFlowNodePtr Clone(SActivationInfo* pActInfo)
  760.         {
  761.                 return new CFlowNode_AIGroupID(pActInfo);
  762.         }
  763.  
  764.         void Serialize(SActivationInfo*, TSerialize ser)
  765.         {
  766.                 // forces re-triggering on load
  767.                 if (ser.IsReading())
  768.                         m_lastID = -1;
  769.         }
  770.  
  771.         virtual void GetConfiguration(SFlowNodeConfig& config)
  772.         {
  773.  
  774.                 static const SOutputPortConfig out_config[] = {
  775.                         OutputPortConfig<int>("groupID", _HELP("AI Group ID of the entity")),
  776.                         { 0 }
  777.                 };
  778.                 static const SInputPortConfig in_config[] = {
  779.                         InputPortConfig_AnyType("sink", NULL,                                         _HELP("Sync")),
  780.                         InputPortConfig<int>("groupID", _HELP("New group ID to set to the entity.")),
  781.                         { 0 }
  782.                 };
  783.  
  784.                 config.sDescription = _HELP("Sets and outputs AI's group ID");
  785.                 config.pInputPorts = in_config;
  786.                 config.pOutputPorts = out_config;
  787.                 config.nFlags |= EFLN_TARGET_ENTITY;
  788.                 config.SetCategory(EFLN_APPROVED);
  789.         }
  790.  
  791.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  792.         {
  793.                 if (event == eFE_Initialize)
  794.                 {
  795.                         pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, true);
  796.                 }
  797.                 else if (event == eFE_SetEntityId || (event == eFE_Activate && IsPortActive(pActInfo, 0)))
  798.                 {
  799.                         IEntity* pEntity = pActInfo->pEntity;
  800.                         if (pEntity)
  801.                         {
  802.                                 IAIActor* pAIActor = CastToIAIActorSafe(pEntity->GetAI());
  803.                                 if (pAIActor)
  804.                                 {
  805.                                         if (event == eFE_Activate)
  806.                                         {
  807.                                                 // set group of ai object
  808.                                                 AgentParameters ap = pAIActor->GetParameters();
  809.                                                 ap.m_nGroup = GetPortInt(pActInfo, 1);
  810.                                                 pAIActor->SetParameters(ap);
  811.                                         }
  812.                                         m_lastID = pAIActor->GetParameters().m_nGroup;
  813.                                         ActivateOutput(pActInfo, 0, pAIActor->GetParameters().m_nGroup);
  814.                                 }
  815.                         }
  816.                 }
  817.                 else if (event == eFE_Update)
  818.                 {
  819.                         // Update the output when it changes.
  820.                         IEntity* pEntity = pActInfo->pEntity;
  821.                         if (pEntity)
  822.                         {
  823.                                 IAIActor* pAIActor = CastToIAIActorSafe(pEntity->GetAI());
  824.                                 if (pAIActor)
  825.                                 {
  826.                                         int id = pAIActor->GetParameters().m_nGroup;
  827.                                         if (m_lastID != id)
  828.                                         {
  829.                                                 m_lastID = id;
  830.                                                 ActivateOutput(pActInfo, 0, id);
  831.                                         }
  832.                                 }
  833.                         }
  834.                 }
  835.         }
  836.         int m_lastID;
  837.  
  838.         virtual void GetMemoryUsage(ICrySizer* s) const
  839.         {
  840.                 s->Add(*this);
  841.         }
  842. };
  843.  
  844. //////////////////////////////////////////////////////////////////////////
  845. // AI Group count.
  846. // Returns the number of entities in a group.
  847. //////////////////////////////////////////////////////////////////////////
  848. class CFlowNode_AIGroupCount : public CFlowBaseNode<eNCT_Instanced>
  849. {
  850. public:
  851.         CFlowNode_AIGroupCount(SActivationInfo* pActInfo)
  852.                 : m_CurrentCount(-1), m_decreasing(false)
  853.         {
  854.         }
  855.         IFlowNodePtr Clone(SActivationInfo* pActInfo)
  856.         {
  857.                 return new CFlowNode_AIGroupCount(pActInfo);
  858.         }
  859.         void Serialize(SActivationInfo* pActInfo, TSerialize ser)
  860.         {
  861.                 ser.Value("CurrentCount", m_CurrentCount);
  862.         }
  863.         virtual void GetConfiguration(SFlowNodeConfig& config)
  864.         {
  865.                 static const SOutputPortConfig out_config[] = {
  866.                         OutputPortConfig<int>("count", _HELP("The number of agents in a group.")),
  867.                         OutputPortConfig_Void("empty", _HELP("Triggered when the whole group is wasted.")),
  868.                         { 0 }
  869.                 };
  870.  
  871.                 static const SInputPortConfig in_config[] = {
  872.                         InputPortConfig<int>("groupID", _HELP("The group ID of the group to get the alertness from")),
  873.                         { 0 }
  874.                 };
  875.  
  876.                 config.sDescription = _HELP("The highest level of alertness of any agent in the group.");
  877.                 config.pInputPorts = in_config;
  878.                 config.pOutputPorts = out_config;
  879.                 config.SetCategory(EFLN_APPROVED);
  880.         }
  881.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  882.         {
  883.                 if (event == eFE_Initialize)
  884.                 {
  885.                         pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, true);
  886.                         IAISystem* pAISystem = gEnv->pAISystem;
  887.                         int groupID = GetPortInt(pActInfo, 0);      // group ID
  888.                         int n = pAISystem->GetGroupCount(groupID, true);
  889.  
  890.                         m_CurrentCount = n;
  891.                         ActivateOutput(pActInfo, 0, m_CurrentCount);
  892.                         m_decreasing = false;
  893.                 }
  894.                 else if (event == eFE_Update)
  895.                 {
  896.                         IAISystem* pAISystem = gEnv->pAISystem;
  897.                         int groupID = GetPortInt(pActInfo, 0);      // group ID
  898.                         int n = pAISystem->GetGroupCount(groupID, true);
  899.  
  900.                         // Get the max alertness of the group.
  901.                         if (n != m_CurrentCount)
  902.                         {
  903.                                 m_decreasing = n < m_CurrentCount;
  904.  
  905.                                 // If the group count has changed, update it.
  906.                                 m_CurrentCount = n;
  907.                                 ActivateOutput(pActInfo, 0, m_CurrentCount);
  908.                                 // If the current count is zero activate the empty output.
  909.                                 if (m_CurrentCount == 0 && m_decreasing)
  910.                                 {
  911.                                         ActivateOutput(pActInfo, 1, true);
  912.                                 }
  913.                         }
  914.                 }
  915.         }
  916.  
  917.         virtual void GetMemoryUsage(ICrySizer* s) const
  918.         {
  919.                 s->Add(*this);
  920.         }
  921.  
  922. private:
  923.         int  m_CurrentCount;
  924.         bool m_decreasing;
  925. };
  926.  
  927. //////////////////////////////////////////////////////////////////////////
  928. // AI:ActionStart node.
  929. // This should be used as start node in AI Action graphs.
  930. //////////////////////////////////////////////////////////////////////////
  931. class CFlowNode_AIActionStart : public CFlowBaseNode<eNCT_Singleton>
  932. {
  933. public:
  934.         CFlowNode_AIActionStart(SActivationInfo* pActInfo)
  935.         {
  936.         }
  937.         virtual void GetConfiguration(SFlowNodeConfig& config)
  938.         {
  939.                 static const SInputPortConfig in_config[] =
  940.                 {
  941.                         InputPortConfig_Void("restart", "Restarts execution of the whole AI Action from the beginning"),
  942.                         InputPortConfig_Void("cancel",  "Cancels execution"),
  943.                         InputPortConfig_Void("suspend", "Suspends execution"),
  944.                         InputPortConfig_Void("resume",  "Resumes execution if it was suspended"),
  945.                         { 0 }
  946.                 };
  947.                 static const SOutputPortConfig out_config[] =
  948.                 {
  949.                         OutputPortConfig<EntityId>("UserId",   "Entity ID of the agent executing AI Action"),
  950.                         OutputPortConfig<EntityId>("ObjectId", "Entity ID of the object on which the agent is executing AI Action"),
  951.                         OutputPortConfig<Vec3>("Position",     "World position of smart object action."),
  952.                         { 0 }
  953.                 };
  954.                 config.pInputPorts = 0; // in_config;
  955.                 config.pOutputPorts = out_config;
  956.                 config.sDescription = _HELP("Represents the User and the used Object of an AI Action. Use this node to start the AI Action graph.");
  957.                 config.nFlags |= EFLN_AIACTION_START;
  958.                 config.SetCategory(EFLN_APPROVED);
  959.         }
  960.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  961.         {
  962.                 IAIAction* pAIAction = pActInfo->pGraph->GetAIAction();
  963.                 switch (event)
  964.                 {
  965.                 case eFE_Update:
  966.                         pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, false);
  967.                         if (pAIAction)
  968.                         {
  969.                                 IEntity* pUser = pAIAction->GetUserEntity();
  970.  
  971.                                 if (pUser && pUser->HasAI())
  972.                                 {
  973.                                         // Field animFinalLocation always stayed ZERO, so I removed it. [5/21/2010 evgeny]
  974.                                         //IAIActor *pAIActor = pUser->GetAI()->CastToIAIActor();
  975.                                         //Vec3 vSOPosition = pAIActor->GetState()->actorTargetReq.animFinalLocation;
  976.                                         //ActivateOutput( pActInfo, 2, vSOPosition);
  977.                                         ActivateOutput(pActInfo, 2, Vec3Constants<float>::fVec3_Zero);
  978.                                 }
  979.  
  980.                                 ActivateOutput(pActInfo, 0, pUser ? pUser->GetId() : 0);
  981.                                 IEntity* pTarget = pAIAction->GetObjectEntity();
  982.                                 ActivateOutput(pActInfo, 1, pTarget ? pTarget->GetId() : 0);
  983.                         }
  984.                         break;
  985.                 case eFE_Initialize:
  986.                         pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, true);
  987.                         break;
  988.                 case eFE_Activate:
  989.                         break;
  990.                 }
  991.         }
  992.  
  993.         virtual void GetMemoryUsage(ICrySizer* s) const
  994.         {
  995.                 s->Add(*this);
  996.         }
  997. };
  998.  
  999. //////////////////////////////////////////////////////////////////////////
  1000. // AI:ActionEnd node.
  1001. // This should be used as end node in AI Action graphs.
  1002. //////////////////////////////////////////////////////////////////////////
  1003. class CFlowNode_AIActionEnd : public CFlowBaseNode<eNCT_Singleton>
  1004. {
  1005. public:
  1006.         CFlowNode_AIActionEnd(SActivationInfo* pActInfo)
  1007.         {
  1008.         }
  1009.         virtual void GetConfiguration(SFlowNodeConfig& config)
  1010.         {
  1011.                 static const SInputPortConfig in_config[] =
  1012.                 {
  1013.                         InputPortConfig_Void("end",    _HELP("ends execution of AI Action reporting it as succeeded")),
  1014.                         InputPortConfig_Void("cancel", _HELP("ends execution of AI Action reporting it as failed")),
  1015.                         { 0 }
  1016.                 };
  1017.                 config.pInputPorts = in_config;
  1018.                 config.pOutputPorts = NULL;
  1019.                 config.sDescription = _HELP("Use this node to end the AI Action graph.");
  1020.                 config.nFlags |= EFLN_AIACTION_END;
  1021.                 config.SetCategory(EFLN_APPROVED);
  1022.         }
  1023.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  1024.         {
  1025.                 IAIAction* pAIAction = pActInfo->pGraph->GetAIAction();
  1026.                 if (!pAIAction)
  1027.                         return;
  1028.                 if (event != eFE_Activate)
  1029.                         return;
  1030.  
  1031.                 if (IsPortActive(pActInfo, 0))
  1032.                         pAIAction->EndAction();
  1033.                 else if (IsPortActive(pActInfo, 1))
  1034.                         pAIAction->CancelAction();
  1035.         }
  1036.  
  1037.         virtual void GetMemoryUsage(ICrySizer* s) const
  1038.         {
  1039.                 s->Add(*this);
  1040.         }
  1041. };
  1042.  
  1043. //////////////////////////////////////////////////////////////////////////
  1044. // AI:ActionAbort node.
  1045. // This node serves as a destructor in AI Action graphs.
  1046. //////////////////////////////////////////////////////////////////////////
  1047. class CFlowNode_AIActionAbort : public CFlowBaseNode<eNCT_Instanced>
  1048. {
  1049. protected:
  1050.         bool bAborted;
  1051.  
  1052. public:
  1053.         CFlowNode_AIActionAbort(SActivationInfo* pActInfo)
  1054.         {
  1055.                 bAborted = false;
  1056.         }
  1057.         IFlowNodePtr Clone(SActivationInfo* pActInfo)
  1058.         {
  1059.                 return new CFlowNode_AIActionAbort(pActInfo);
  1060.         }
  1061.         void Serialize(SActivationInfo* pActInfo, TSerialize ser)
  1062.         {
  1063.                 ser.Value("Aborted", bAborted);
  1064.         }
  1065.         virtual void GetConfiguration(SFlowNodeConfig& config)
  1066.         {
  1067.                 static const SInputPortConfig in_config[] =
  1068.                 {
  1069.                         InputPortConfig_Void("Abort", "Aborts execution of AI Action"),
  1070.                         { 0 }
  1071.                 };
  1072.                 static const SOutputPortConfig out_config[] =
  1073.                 {
  1074.                         OutputPortConfig<EntityId>("UserId",   "Entity ID of the agent executing AI Action (activated on abort)"),
  1075.                         OutputPortConfig<EntityId>("ObjectId", "Entity ID of the object on which the agent is executing AI Action (activated on abort)"),
  1076.                         { 0 }
  1077.                 };
  1078.                 config.pInputPorts = in_config;
  1079.                 config.pOutputPorts = out_config;
  1080.                 config.sDescription = _HELP("Use this node to define clean-up procedure executed when AI Action is aborted.");
  1081.                 config.SetCategory(EFLN_APPROVED);
  1082.         }
  1083.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  1084.         {
  1085.                 IAIAction* pAIAction = pActInfo->pGraph->GetAIAction();
  1086.                 switch (event)
  1087.                 {
  1088.                 case eFE_Update:
  1089.                         pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, false);
  1090.                         if (pAIAction && !bAborted)
  1091.                         {
  1092.                                 // abort only once
  1093.                                 bAborted = true;
  1094.  
  1095.                                 IEntity* pUser = pAIAction->GetUserEntity();
  1096.                                 ActivateOutput(pActInfo, 0, pUser ? pUser->GetId() : 0);
  1097.                                 IEntity* pTarget = pAIAction->GetObjectEntity();
  1098.                                 ActivateOutput(pActInfo, 1, pTarget ? pTarget->GetId() : 0);
  1099.                         }
  1100.                         break;
  1101.                 case eFE_Initialize:
  1102.                         bAborted = false;
  1103.                         pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, false);
  1104.                         break;
  1105.                 case eFE_Activate:
  1106.                         if (!bAborted && pAIAction && IsPortActive(pActInfo, 0))
  1107.                                 pAIAction->AbortAction();
  1108.                         break;
  1109.                 }
  1110.         }
  1111.  
  1112.         virtual void GetMemoryUsage(ICrySizer* s) const
  1113.         {
  1114.                 s->Add(*this);
  1115.         }
  1116. };
  1117.  
  1118. //////////////////////////////////////////////////////////////////////////
  1119. // AI:AttTarget node.
  1120. // Returns the position of the attention target.
  1121. //////////////////////////////////////////////////////////////////////////
  1122. class CFlowNode_AIAttTarget : public CFlowBaseNode<eNCT_Singleton>
  1123. {
  1124. public:
  1125.         CFlowNode_AIAttTarget(SActivationInfo* pActInfo)
  1126.         {
  1127.         }
  1128.  
  1129.         enum INPUTS
  1130.         {
  1131.                 eIP_Active = 0,
  1132.         };
  1133.  
  1134.         virtual void GetConfiguration(SFlowNodeConfig& config)
  1135.         {
  1136.                 static const SInputPortConfig in_config[] = {
  1137.                         InputPortConfig<bool>("Active", true, _HELP("Activate/deactivate the node")),
  1138.                         { 0 }
  1139.                 };
  1140.                 static const SOutputPortConfig out_config[] = {
  1141.                         OutputPortConfig<Vec3>("pos",          _HELP("Attention target position")),
  1142.                         OutputPortConfig<EntityId>("entityId", _HELP("Entity id of attention target")),
  1143.                         OutputPortConfig_Void("none",          _HELP("Activated when there's no attention target")),
  1144.                         { 0 }
  1145.                 };
  1146.                 config.sDescription = _HELP("Outputs AI's attention target");
  1147.                 config.pInputPorts = in_config;
  1148.                 config.pOutputPorts = out_config;
  1149.                 config.nFlags |= EFLN_TARGET_ENTITY;
  1150.                 config.SetCategory(EFLN_APPROVED);
  1151.         }
  1152.  
  1153.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  1154.         {
  1155.                 switch (event)
  1156.                 {
  1157.                 case eFE_Initialize:
  1158.                         {
  1159.                                 bool needUpdate = (IsPortActive(pActInfo, -1) && GetPortBool(pActInfo, eIP_Active));
  1160.                                 pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, needUpdate);
  1161.                                 break;
  1162.                         }
  1163.  
  1164.                 case eFE_Activate:
  1165.                         {
  1166.                                 if (IsPortActive(pActInfo, eIP_Active))
  1167.                                         pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, GetPortBool(pActInfo, eIP_Active));
  1168.                                 break;
  1169.                         }
  1170.  
  1171.                 case eFE_Update:
  1172.                         {
  1173.                                 IEntity* pEntity = pActInfo->pEntity;
  1174.                                 if (pEntity)
  1175.                                 {
  1176.                                         IAIActor* pAIActor = CastToIAIActorSafe(pEntity->GetAI());
  1177.                                         if (pAIActor)
  1178.                                         {
  1179.                                                 IAIObject* pTarget = pAIActor->GetAttentionTarget();
  1180.                                                 if (pTarget)
  1181.                                                 {
  1182.                                                         ActivateOutput(pActInfo, 0, pTarget->GetPos());
  1183.  
  1184.                                                         if (pTarget->CastToIPipeUser() || pTarget->CastToCAIPlayer())
  1185.                                                         {
  1186.                                                                 pEntity = pTarget->GetEntity();
  1187.                                                                 if (pEntity)
  1188.                                                                         ActivateOutput(pActInfo, 1, pEntity->GetId());
  1189.                                                                 else
  1190.                                                                         ActivateOutput(pActInfo, 1, 0);
  1191.                                                         }
  1192.                                                         else
  1193.                                                                 ActivateOutput(pActInfo, 1, 0);
  1194.                                                 }
  1195.                                                 else
  1196.                                                 {
  1197.                                                         ActivateOutput(pActInfo, 1, 0);
  1198.                                                         ActivateOutput(pActInfo, 2, true);
  1199.                                                 }
  1200.                                         }
  1201.                                 }
  1202.                                 break;
  1203.                         }
  1204.                 }
  1205.         }
  1206.  
  1207.         virtual void GetMemoryUsage(ICrySizer* s) const
  1208.         {
  1209.                 s->Add(*this);
  1210.         }
  1211. };
  1212.  
  1213. //////////////////////////////////////////////////////////////////////////
  1214. // AI:SmartObjectHelper node.
  1215. // This node gives position and orientation of any Smart Object Helper
  1216. //////////////////////////////////////////////////////////////////////////
  1217. class CFlowNode_AISOHelper : public CFlowEntityNodeBase
  1218. {
  1219. public:
  1220.         CFlowNode_AISOHelper(SActivationInfo* pActInfo)
  1221.                 : CFlowEntityNodeBase()
  1222.         {
  1223.                 m_event = ENTITY_EVENT_XFORM;
  1224.                 m_nodeID = pActInfo->myID;
  1225.                 m_pGraph = pActInfo->pGraph;
  1226.                 m_entityId = (EntityId)(UINT_PTR)pActInfo->m_pUserData;
  1227.         }
  1228.  
  1229.         virtual IFlowNodePtr Clone(SActivationInfo* pActInfo) { pActInfo->m_pUserData = (void*)(UINT_PTR)m_entityId; return new CFlowNode_AISOHelper(pActInfo); };
  1230.  
  1231.         virtual void         GetMemoryUsage(ICrySizer* s) const
  1232.         {
  1233.                 s->Add(*this);
  1234.         }
  1235.  
  1236.         virtual void GetConfiguration(SFlowNodeConfig& config)
  1237.         {
  1238.                 static const SInputPortConfig in_config[] = {
  1239.                         InputPortConfig<string>("soclass_class",      _HELP("Smart Object Class for which the helper should be defined")),
  1240.                         InputPortConfig<string>("sonavhelper_helper", _HELP("Helper name")),
  1241.                         { 0 }
  1242.                 };
  1243.                 static const SOutputPortConfig out_config[] = {
  1244.                         OutputPortConfig<Vec3>("pos", _HELP("Position of the Smart Object Helper in world coordinates")),
  1245.                         OutputPortConfig<Vec3>("fwd", _HELP("Forward direction of the Smart Object Helper in world coordinates")),
  1246.                         OutputPortConfig<Vec3>("up",  _HELP("Up direction of the Smart Object Helper in world coordinates")),
  1247.                         { 0 }
  1248.                 };
  1249.                 config.sDescription = _HELP("Outputs AI's attention target parameters");
  1250.                 config.pInputPorts = in_config;
  1251.                 config.pOutputPorts = out_config;
  1252.                 config.nFlags |= EFLN_TARGET_ENTITY;
  1253.                 config.SetCategory(EFLN_APPROVED);
  1254.                 config.SetCategory(EFLN_APPROVED);
  1255.         }
  1256.  
  1257.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  1258.         {
  1259.                 CFlowEntityNodeBase::ProcessEvent(event, pActInfo);
  1260.  
  1261.                 /*if ( event == eFE_Edited )
  1262.                    {
  1263.                    // sent from the editor when an input port is edited
  1264.                    string className = GetPortString( pActInfo, 0 );
  1265.                    string helperName = GetPortString( pActInfo, 1 );
  1266.                    int pos = helperName.find(':');
  1267.                    if ( pos <= 0 || className != helperName.substr(0,pos) )
  1268.                    {
  1269.                    }
  1270.                    return;
  1271.                    }*/
  1272.  
  1273.                 if (event != eFE_SetEntityId)
  1274.                         return;
  1275.  
  1276.                 Compute(pActInfo->pEntity);
  1277.         }
  1278.  
  1279.         void Compute(IEntity* pEntity)
  1280.         {
  1281.                 if (!pEntity)
  1282.                         return;
  1283.  
  1284.                 const string* pClassName = m_pGraph->GetInputValue(m_nodeID, 1)->GetPtr<string>();   // GetPortString( pActInfo, 0 );
  1285.                 const string* pHelperName = m_pGraph->GetInputValue(m_nodeID, 2)->GetPtr<string>();  // GetPortString( pActInfo, 1 );
  1286.                 if (!pClassName || !pHelperName)
  1287.                         return;
  1288.  
  1289.                 string helperName = *pHelperName;
  1290.                 string className = *pClassName;
  1291.  
  1292.                 helperName.erase(0, helperName.find(':') + 1);
  1293.                 if (className.empty() || helperName.empty())
  1294.                         return;
  1295.  
  1296.                 SmartObjectHelper* pHelper = gEnv->pAISystem->GetSmartObjectManager()->GetSmartObjectHelper(className, helperName);
  1297.                 if (!pHelper)
  1298.                         return;
  1299.  
  1300.                 // calculate position and output it
  1301.                 Vec3 pos = pEntity->GetWorldTM().TransformPoint(pHelper->qt.t);
  1302.                 //ActivateOutput( pActInfo, 0, pos );
  1303.                 m_pGraph->ActivatePort(SFlowAddress(m_nodeID, 0, true), pos);
  1304.  
  1305.                 // calculate forward direction and output it
  1306.                 pos = pHelper->qt.q * FORWARD_DIRECTION;
  1307.                 pos = pEntity->GetWorldTM().TransformVector(pos);
  1308.                 pos.NormalizeSafe(FORWARD_DIRECTION);
  1309.                 //ActivateOutput( pActInfo, 1, pos );
  1310.                 m_pGraph->ActivatePort(SFlowAddress(m_nodeID, 1, true), pos);
  1311.  
  1312.                 // calculate up direction and output it
  1313.                 pos = pHelper->qt.q * Vec3(0, 0, 1);
  1314.                 pos = pEntity->GetWorldTM().TransformVector(pos);
  1315.                 pos.NormalizeSafe(Vec3(0, 0, 1));
  1316.                 //ActivateOutput( pActInfo, 2, pos );
  1317.                 m_pGraph->ActivatePort(SFlowAddress(m_nodeID, 2, true), pos);
  1318.         }
  1319.  
  1320.         //////////////////////////////////////////////////////////////////////////
  1321.         // IEntityEventListener
  1322.         virtual void OnEntityEvent(IEntity* pEntity, SEntityEvent& event)
  1323.         {
  1324.                 if (!m_pGraph->IsEnabled() || m_pGraph->IsSuspended() || !m_pGraph->IsActive())
  1325.                         return;
  1326.  
  1327.                 if (event.event == ENTITY_EVENT_XFORM)
  1328.                         Compute(pEntity);
  1329.         };
  1330.         //////////////////////////////////////////////////////////////////////////
  1331.  
  1332. protected:
  1333.         IFlowGraph* m_pGraph;
  1334.         TFlowNodeId m_nodeID;
  1335. };
  1336.  
  1337. //////////////////////////////////////////////////////////////////////////
  1338. // AI:SmartObjectEvent node.
  1339. // Triggers a smart object event.
  1340. //////////////////////////////////////////////////////////////////////////
  1341. class CFlowNode_AISmartObjectEvent : public CFlowBaseNode<eNCT_Singleton>
  1342. {
  1343. public:
  1344.         CFlowNode_AISmartObjectEvent(SActivationInfo* pActInfo) {}
  1345.  
  1346.         virtual void GetMemoryUsage(ICrySizer* s) const
  1347.         {
  1348.                 s->Add(*this);
  1349.         }
  1350.  
  1351.         virtual void GetConfiguration(SFlowNodeConfig& config)
  1352.         {
  1353.                 static const SInputPortConfig in_config[] = {
  1354.                         InputPortConfig<string>("soevent_event", _HELP("smart object event to be triggered")),
  1355.                         InputPortConfig_Void("trigger",          _HELP("triggers the smart object event")),
  1356.                         InputPortConfig<EntityId>("userId",      _HELP("if used will limit the event on only one user")),
  1357.                         InputPortConfig<EntityId>("objectId",    _HELP("if used will limit the event on only one object")),
  1358.                         { 0 }
  1359.                 };
  1360.                 static const SOutputPortConfig out_config[] = {
  1361.                         OutputPortConfig<EntityId>("userId",   _HELP("the used selected by smart object rules")),
  1362.                         OutputPortConfig<EntityId>("objectId", _HELP("the object selected by smart object rules")),
  1363.                         OutputPortConfig_Void("ruleName",      _HELP("activated if a matching rule was found"),    _HELP("start")),
  1364.                         OutputPortConfig_Void("noRule",        _HELP("activated if no matching rule was found")),
  1365.                         //      OutputPortConfig_Void( "Done", _HELP("activated after the executed action is finished") ),
  1366.                         //      OutputPortConfig_Void( "Succeed", _HELP("activated after the executed action is successfully finished") ),
  1367.                         //      OutputPortConfig_Void( "Fail", _HELP("activated if the executed action was failed") ),
  1368.                         { 0 }
  1369.                 };
  1370.                 config.sDescription = _HELP("Triggers a smart object event");
  1371.                 config.pInputPorts = in_config;
  1372.                 config.pOutputPorts = out_config;
  1373.                 config.SetCategory(EFLN_APPROVED);
  1374.         }
  1375.  
  1376.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  1377.         {
  1378.                 switch (event)
  1379.                 {
  1380.                 case eFE_Initialize:
  1381.                         break;
  1382.  
  1383.                 case eFE_Activate:
  1384.                         if (IsPortActive(pActInfo, 1))
  1385.                                 pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, true);
  1386.                         break;
  1387.  
  1388.                 case eFE_Update:
  1389.                         pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, false);
  1390.  
  1391.                         EntityId userId = GetPortEntityId(pActInfo, 2);
  1392.                         EntityId objectId = GetPortEntityId(pActInfo, 3);
  1393.  
  1394.                         IEntity* pUser = userId ? gEnv->pEntitySystem->GetEntity(userId) : NULL;
  1395.                         IEntity* pObject = objectId ? gEnv->pEntitySystem->GetEntity(objectId) : NULL;
  1396.  
  1397.                         const string& actionName = GetPortString(pActInfo, 0);
  1398.                         if (!actionName.empty())
  1399.                         {
  1400.                                 bool highPriority = false;
  1401.                                 if (IAIAction* pAIAction = pActInfo->pGraph->GetAIAction())
  1402.                                         highPriority = pAIAction->IsHighPriority();
  1403.                                 int id = gEnv->pAISystem->GetSmartObjectManager()->SmartObjectEvent(actionName, pUser, pObject, NULL, highPriority);
  1404.                                 if (id)
  1405.                                 {
  1406.                                         if (pUser)
  1407.                                                 ActivateOutput(pActInfo, 0, pUser->GetId());
  1408.                                         if (pObject)
  1409.                                                 ActivateOutput(pActInfo, 1, pObject->GetId());
  1410.                                         ActivateOutput(pActInfo, 2, true);
  1411.                                 }
  1412.                                 else
  1413.                                         ActivateOutput(pActInfo, 3, true);
  1414.                         }
  1415.                         break;
  1416.                 }
  1417.         }
  1418. };
  1419.  
  1420. //////////////////////////////////////////////////////////////////////////
  1421. // control auto disabling
  1422. //////////////////////////////////////////////////////////////////////////
  1423. class CFlowNode_AIAutoDisable : public CFlowBaseNode<eNCT_Singleton>
  1424. {
  1425. public:
  1426.         enum EInputs
  1427.         {
  1428.                 IN_ON,
  1429.                 IN_OFF,
  1430.         };
  1431.         CFlowNode_AIAutoDisable(SActivationInfo* pActInfo) {};
  1432.  
  1433.         /*
  1434.            IFlowNodePtr Clone( SActivationInfo * pActInfo )
  1435.            {
  1436.            return this; // no internal state! // new CFlowNode_AIAutoDisable(pActInfo);
  1437.            }
  1438.          */
  1439.  
  1440.         virtual void GetConfiguration(SFlowNodeConfig& config)
  1441.         {
  1442.                 static const SInputPortConfig in_config[] = {
  1443.                         InputPortConfig_AnyType("ON",  _HELP("allow AutoDisable for target entity")),
  1444.                         InputPortConfig_AnyType("OFF", _HELP("no AutoDisable for target entity")),
  1445.                         { 0 }
  1446.                 };
  1447.                 config.sDescription = _HELP("Controls AutoDisable.");
  1448.                 config.nFlags |= EFLN_TARGET_ENTITY;
  1449.                 config.pInputPorts = in_config;
  1450.                 config.pOutputPorts = 0;
  1451.                 config.SetCategory(EFLN_APPROVED);
  1452.         }
  1453.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  1454.         {
  1455.                 switch (event)
  1456.                 {
  1457.                 case eFE_Activate:
  1458.                         {
  1459.                                 if (!pActInfo->pEntity || !pActInfo->pEntity->GetAI() ||
  1460.                                     !pActInfo->pEntity->GetAI()->GetProxy())
  1461.                                         return;
  1462.                                 CAIProxy* proxy = (CAIProxy*)pActInfo->pEntity->GetAI()->GetProxy();
  1463.                                 if (IsPortActive(pActInfo, IN_ON))
  1464.                                         proxy->UpdateMeAlways(false);
  1465.                                 if (IsPortActive(pActInfo, IN_OFF))
  1466.                                         proxy->UpdateMeAlways(true);
  1467.                                 break;
  1468.                         }
  1469.                 case eFE_Initialize:
  1470.                         break;
  1471.                 }
  1472.                 ;
  1473.         };
  1474.  
  1475.         virtual void GetMemoryUsage(ICrySizer* s) const
  1476.         {
  1477.                 s->Add(*this);
  1478.         }
  1479. };
  1480.  
  1481. //////////////////////////////////////////////////////////////////////////
  1482. // switching species hostility on/off (makes AI ignore enemies/be ignored)
  1483. //////////////////////////////////////////////////////////////////////////
  1484. class CFlowNode_AIIgnore : public CFlowBaseNode<eNCT_Singleton>
  1485. {
  1486. public:
  1487.         enum EInputs
  1488.         {
  1489.                 IN_HOSTILE,
  1490.                 IN_NOHOSTILE,
  1491.                 IN_RESETPERCEPTION,
  1492.         };
  1493.         CFlowNode_AIIgnore(SActivationInfo* pActInfo) {};
  1494.  
  1495.         virtual void GetConfiguration(SFlowNodeConfig& config)
  1496.         {
  1497.                 static const SInputPortConfig in_config[] = {
  1498.                         InputPortConfig_AnyType("Hostile",         _HELP("Default perception")),
  1499.                         InputPortConfig_AnyType("Ignore",          _HELP("Make it ignore enemies/be ignored")),
  1500.                         InputPortConfig_AnyType("ResetPerception", _HELP("Reset current perception state")),
  1501.                         { 0 }
  1502.                 };
  1503.                 config.sDescription = _HELP("Switching species hostility on/off (makes AI ignore enemies/be ignored).");
  1504.                 config.nFlags |= EFLN_TARGET_ENTITY;
  1505.                 config.pInputPorts = in_config;
  1506.                 config.pOutputPorts = 0;
  1507.                 config.SetCategory(EFLN_APPROVED);
  1508.         }
  1509.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  1510.         {
  1511.                 switch (event)
  1512.                 {
  1513.                 case eFE_Activate:
  1514.                         {
  1515.                                 if (!pActInfo->pEntity)
  1516.                                         return;
  1517.  
  1518.                                 if (IsPortActive(pActInfo, IN_HOSTILE))
  1519.                                 {
  1520.                                         IAIActor* pAIActor = CastToIAIActorSafe(pActInfo->pEntity->GetAI());
  1521.                                         if (pAIActor)
  1522.                                         {
  1523.                                                 AgentParameters ap = pAIActor->GetParameters();
  1524.                                                 ap.m_bAiIgnoreFgNode = false;
  1525.                                                 pAIActor->SetParameters(ap);
  1526.                                         }
  1527.                                 }
  1528.                                 if (IsPortActive(pActInfo, IN_NOHOSTILE))
  1529.                                 {
  1530.                                         IAIActor* pAIActor = CastToIAIActorSafe(pActInfo->pEntity->GetAI());
  1531.                                         if (pAIActor)
  1532.                                         {
  1533.                                                 AgentParameters ap = pAIActor->GetParameters();
  1534.                                                 ap.m_bAiIgnoreFgNode = true;
  1535.                                                 pAIActor->SetParameters(ap);
  1536.                                         }
  1537.                                 }
  1538.                                 if (IsPortActive(pActInfo, IN_RESETPERCEPTION))
  1539.                                 {
  1540.                                         IAIActor* pAIActor = CastToIAIActorSafe(pActInfo->pEntity->GetAI());
  1541.                                         if (pAIActor)
  1542.                                                 pAIActor->ResetPerception();
  1543.                                 }
  1544.                                 break;
  1545.                         }
  1546.                 case eFE_Initialize:
  1547.                         break;
  1548.                 }
  1549.                 ;
  1550.         };
  1551.  
  1552.         virtual void GetMemoryUsage(ICrySizer* s) const
  1553.         {
  1554.                 s->Add(*this);
  1555.         }
  1556. };
  1557.  
  1558. //////////////////////////////////////////////////////////////////////////
  1559. // switching species hostility on/off (makes AI ignore enemies/be ignored)
  1560. //////////////////////////////////////////////////////////////////////////
  1561. class CFlowNode_AIFactionReaction : public CFlowBaseNode<eNCT_Singleton>
  1562. {
  1563. public:
  1564.         enum
  1565.         {
  1566.                 InFactionSource = 0,
  1567.                 InFactionTarget,
  1568.                 InReaction,
  1569.                 InGet,
  1570.                 InSet,
  1571.         };
  1572.  
  1573.         enum
  1574.         {
  1575.                 OutNeutral = 0,
  1576.                 OutFriendly,
  1577.                 OutHostile,
  1578.         };
  1579.  
  1580.         CFlowNode_AIFactionReaction(SActivationInfo* pActInfo) {};
  1581.  
  1582.         virtual void GetConfiguration(SFlowNodeConfig& config)
  1583.         {
  1584.                 static const SInputPortConfig in_config[] =
  1585.                 {
  1586.                         InputPortConfig<string>("Source",                                                       "",                                                           _HELP("Source faction"),                               0, "enum_global:Faction"),
  1587.                         InputPortConfig<string>("Target",                                                       "",                                                           _HELP("Target faction"),                               0, "enum_global:Faction"),
  1588.                         InputPortConfig<int>("Reaction",                                                        0,                                                            _HELP("Source faction's reaction to target faction."),
  1589.                                              0,                                                                 _UICONFIG("enum_int:(0)Hostile=0,(1)Neutral=1,(2)Friendly=2")),
  1590.                         InputPortConfig_Void("Get",                                                             _HELP("Get specified faction reaction and trigger output.")),
  1591.                         InputPortConfig_Void("Set",                                                             _HELP("Set specified faction reaction.")),
  1592.                         { 0 }
  1593.                 };
  1594.  
  1595.                 static const SOutputPortConfig out_config[] =
  1596.                 {
  1597.                         OutputPortConfig<bool>("Neutral",  "Source faction's reaction to target faction is neutral."),
  1598.                         OutputPortConfig<bool>("Friendly", "Source faction's reaction to target faction is friendly."),
  1599.                         OutputPortConfig<bool>("Hostile",  "Source faction's reaction to target faction is hostile."),
  1600.                         { 0 },
  1601.                 };
  1602.  
  1603.                 config.sDescription = _HELP("Set/Get Faction reaction info");
  1604.                 config.pInputPorts = in_config;
  1605.                 config.pOutputPorts = out_config;
  1606.                 config.SetCategory(EFLN_APPROVED);
  1607.         }
  1608.  
  1609.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  1610.         {
  1611.                 switch (event)
  1612.                 {
  1613.                 case eFE_Activate:
  1614.                         {
  1615.                                 bool output = false;
  1616.                                 IFactionMap::ReactionType reactionType;
  1617.  
  1618.                                 uint8 source = gEnv->pAISystem->GetFactionMap().GetFactionID(GetPortString(pActInfo, InFactionSource));
  1619.                                 uint8 target = gEnv->pAISystem->GetFactionMap().GetFactionID(GetPortString(pActInfo, InFactionTarget));
  1620.  
  1621.                                 if (IsPortActive(pActInfo, InGet))
  1622.                                 {
  1623.                                         reactionType = (IFactionMap::ReactionType)gEnv->pAISystem->GetFactionMap().GetReaction(source, target);
  1624.                                         output = true;
  1625.                                 }
  1626.  
  1627.                                 if (IsPortActive(pActInfo, InSet))
  1628.                                 {
  1629.                                         reactionType = (IFactionMap::ReactionType)GetPortInt(pActInfo, InReaction);
  1630.                                         gEnv->pAISystem->GetFactionMap().SetReaction(source, target, reactionType);
  1631.                                         output = true;
  1632.                                 }
  1633.  
  1634.                                 if (output)
  1635.                                 {
  1636.                                         switch (reactionType)
  1637.                                         {
  1638.                                         case IFactionMap::Neutral:
  1639.                                                 ActivateOutput<bool>(pActInfo, OutNeutral, true);
  1640.                                                 break;
  1641.                                         case IFactionMap::Friendly:
  1642.                                                 ActivateOutput<bool>(pActInfo, OutFriendly, true);
  1643.                                                 break;
  1644.                                         case IFactionMap::Hostile:
  1645.                                                 ActivateOutput<bool>(pActInfo, OutHostile, true);
  1646.                                                 break;
  1647.                                         default:
  1648.                                                 assert(0);
  1649.                                                 break;
  1650.                                         }
  1651.                                 }
  1652.                                 break;
  1653.                         }
  1654.                 case eFE_Initialize:
  1655.                         break;
  1656.                 }
  1657.                 ;
  1658.         };
  1659.  
  1660.         virtual void GetMemoryUsage(ICrySizer* s) const
  1661.         {
  1662.                 s->Add(*this);
  1663.         }
  1664. };
  1665.  
  1666. //////////////////////////////////////////////////////////////////////////
  1667. // Set the faction an AI character belongs to
  1668. //////////////////////////////////////////////////////////////////////////
  1669. class CFlowNode_AISetFaction : public CFlowBaseNode<eNCT_Singleton>
  1670. {
  1671. public:
  1672.         enum
  1673.         {
  1674.                 InFaction,
  1675.                 InSetToDefault,
  1676.                 InSet
  1677.         };
  1678.  
  1679.         CFlowNode_AISetFaction(SActivationInfo* pActInfo) {}
  1680.  
  1681.         virtual void GetConfiguration(SFlowNodeConfig& config)
  1682.         {
  1683.                 static const SInputPortConfig inConfig[] =
  1684.                 {
  1685.                         InputPortConfig<string>("Faction",    "",                                      _HELP("Faction to set."),                                   0, "enum_global:Faction"),
  1686.                         InputPortConfig<bool>("SetToDefault", false,                                   _HELP("Sets faction to default instead of specified one")),
  1687.                         InputPortConfig_Void("Set",           _HELP("Set the faction as specified.")),
  1688.                         { 0 }
  1689.                 };
  1690.  
  1691.                 config.sDescription = _HELP("Set the faction an AI character belongs to.");
  1692.                 config.nFlags |= EFLN_TARGET_ENTITY;
  1693.                 config.pInputPorts = inConfig;
  1694.                 config.SetCategory(EFLN_APPROVED);
  1695.         }
  1696.  
  1697.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  1698.         {
  1699.                 switch (event)
  1700.                 {
  1701.                 case eFE_Activate:
  1702.                         {
  1703.                                 if (IsPortActive(pActInfo, InSet))
  1704.                                 {
  1705.                                         IEntity* pEntity = pActInfo->pEntity;
  1706.                                         IAIObject* pAi = pEntity ? pEntity->GetAI() : NULL;
  1707.  
  1708.                                         if (pAi)
  1709.                                         {
  1710.                                                 const bool bSetToDefault = GetPortBool(pActInfo, InSetToDefault);
  1711.                                                 const char* szFactionName = NULL;
  1712.  
  1713.                                                 if (!bSetToDefault)
  1714.                                                 {
  1715.                                                         szFactionName = GetPortString(pActInfo, InFaction);
  1716.                                                 }
  1717.                                                 else
  1718.                                                 {
  1719.                                                         SmartScriptTable props;
  1720.                                                         IScriptTable* pScriptTable = pEntity->GetScriptTable();
  1721.                                                         if (pScriptTable && pScriptTable->GetValue("Properties", props))
  1722.                                                         {
  1723.                                                                 props->GetValue("esFaction", szFactionName);
  1724.                                                         }
  1725.                                                 }
  1726.  
  1727.                                                 uint8 faction = gEnv->pAISystem->GetFactionMap().GetFactionID(szFactionName);
  1728.                                                 pAi->SetFactionID(faction);
  1729.                                         }
  1730.                                 }
  1731.  
  1732.                                 break;
  1733.                         }
  1734.  
  1735.                 case eFE_Initialize:
  1736.                         break;
  1737.                 }
  1738.                 ;
  1739.         };
  1740.  
  1741.         virtual void GetMemoryUsage(ICrySizer* s) const
  1742.         {
  1743.                 s->Add(*this);
  1744.         }
  1745. };
  1746.  
  1747. //////////////////////////////////////////////////////////////////////////
  1748. // scales down the perception of assigned AI
  1749. //////////////////////////////////////////////////////////////////////////
  1750. class CFlowNode_AIPerceptionScale : public CFlowBaseNode<eNCT_Singleton>
  1751. {
  1752. public:
  1753.         CFlowNode_AIPerceptionScale(SActivationInfo* pActInfo) {};
  1754.  
  1755.         virtual void GetConfiguration(SFlowNodeConfig& config)
  1756.         {
  1757.                 static const SInputPortConfig in_config[] = {
  1758.                         InputPortConfig_Void("Trigger", _HELP("Desired perception scale is set when this node is activated")),
  1759.                         InputPortConfig<float>("Scale", 1.0f,                                                                 _HELP("Desired visual perception scale factor"),  _HELP("Visual")),
  1760.                         InputPortConfig<float>("Audio", 1.0f,                                                                 _HELP("Desired audio perception scale factor")),
  1761.                         { 0 }
  1762.                 };
  1763.                 config.sDescription = _HELP("Scales the agent's sensitivity");
  1764.                 config.nFlags |= EFLN_TARGET_ENTITY | EFLN_AISEQUENCE_SUPPORTED;
  1765.                 config.pInputPorts = in_config;
  1766.                 config.pOutputPorts = 0;
  1767.                 config.SetCategory(EFLN_APPROVED);
  1768.         }
  1769.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  1770.         {
  1771.                 if (event == eFE_Activate && IsPortActive(pActInfo, 0) && pActInfo->pEntity)
  1772.                 {
  1773.                         IAIActor* pAIActor = CastToIAIActorSafe(pActInfo->pEntity->GetAI());
  1774.                         if (pAIActor)
  1775.                         {
  1776.                                 AgentParameters ap = pAIActor->GetParameters();
  1777.                                 ap.m_PerceptionParams.perceptionScale.visual = GetPortFloat(pActInfo, 1);
  1778.                                 ap.m_PerceptionParams.perceptionScale.audio = GetPortFloat(pActInfo, 2);
  1779.                                 pAIActor->SetParameters(ap);
  1780.                         }
  1781.                 }
  1782.                 ;
  1783.         };
  1784.  
  1785.         virtual void GetMemoryUsage(ICrySizer* s) const
  1786.         {
  1787.                 s->Add(*this);
  1788.         }
  1789. };
  1790.  
  1791. //////////////////////////////////////////////////////////////////////////
  1792. // Nav cost factor
  1793. //////////////////////////////////////////////////////////////////////////
  1794. class CFlowNode_AISetNavCostFactor : public CFlowBaseNode<eNCT_Singleton>
  1795. {
  1796. public:
  1797.         CFlowNode_AISetNavCostFactor(IFlowNode::SActivationInfo* pActInfo) {}
  1798.         virtual void GetConfiguration(SFlowNodeConfig& config);
  1799.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo);
  1800.  
  1801.         virtual void GetMemoryUsage(ICrySizer* s) const
  1802.         {
  1803.                 s->Add(*this);
  1804.         }
  1805. };
  1806.  
  1807. void CFlowNode_AISetNavCostFactor::GetConfiguration(SFlowNodeConfig& config)
  1808. {
  1809.         static const SInputPortConfig in_config[] = {
  1810.                 InputPortConfig_Void("sink",               _HELP("for synchronization only"),                                                             _HELP("sync")),
  1811.                 InputPortConfig<float>("Factor",           _HELP("Nav cost factor. <0 disables navigation. 0 has no effect. >0 discourages navigation")),
  1812.                 InputPortConfig<string>("NavModifierName", _HELP("Name of the cost-factor navigation modifier")),
  1813.                 { 0 }
  1814.         };
  1815.         static const SOutputPortConfig out_config[] = {
  1816.                 OutputPortConfig<int>("Done", _HELP("Done")),
  1817.                 { 0 }
  1818.         };
  1819.         config.sDescription = _HELP("Set navigation cost factor for travelling through a region");
  1820.         config.pInputPorts = in_config;
  1821.         config.pOutputPorts = out_config;
  1822.         config.SetCategory(EFLN_APPROVED);
  1823. }
  1824.  
  1825. //
  1826. //-------------------------------------------------------------------------------------------------------------
  1827. void CFlowNode_AISetNavCostFactor::ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  1828. {
  1829.         if (event == eFE_Activate)
  1830.         {
  1831.                 float factor = GetPortFloat(pActInfo, 1);
  1832.                 const string& pathName = GetPortString(pActInfo, 2);
  1833.  
  1834.                 gEnv->pAISystem->GetINavigation()->ModifyNavCostFactor(pathName.c_str(), factor);
  1835.  
  1836.                 ActivateOutput(pActInfo, 0, 1);
  1837.         }
  1838. }
  1839.  
  1840. //////////////////////////////////////////////////////////////////////////
  1841. // Enable or Disable AIShape
  1842. //////////////////////////////////////////////////////////////////////////
  1843. class CFlowNode_AIEnableShape : public CFlowBaseNode<eNCT_Singleton>
  1844. {
  1845. public:
  1846.         CFlowNode_AIEnableShape(IFlowNode::SActivationInfo* pActInfo) {}
  1847.         virtual void GetConfiguration(SFlowNodeConfig& config);
  1848.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo);
  1849.  
  1850.         virtual void GetMemoryUsage(ICrySizer* s) const
  1851.         {
  1852.                 s->Add(*this);
  1853.         }
  1854. };
  1855.  
  1856. void CFlowNode_AIEnableShape::GetConfiguration(SFlowNodeConfig& config)
  1857. {
  1858.         static const SInputPortConfig in_config[] = {
  1859.                 InputPortConfig_Void("enable",       _HELP("Enables the AI shape"),                        _HELP("Enable")),
  1860.                 InputPortConfig_Void("disable",      _HELP("Disables the AI shape"),                       _HELP("Disable")),
  1861.                 InputPortConfig<string>("ShapeName", _HELP("Name of the shape to set as the territory.")),
  1862.                 { 0 }
  1863.         };
  1864.         config.sDescription = _HELP("Enable or Disable AIShape.");
  1865.         config.nFlags = 0;
  1866.         config.pInputPorts = in_config;
  1867.         config.pOutputPorts = 0;
  1868.         config.SetCategory(EFLN_ADVANCED);
  1869. }
  1870.  
  1871. //
  1872. //-------------------------------------------------------------------------------------------------------------
  1873. void CFlowNode_AIEnableShape::ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  1874. {
  1875.         if (event == eFE_Activate)
  1876.         {
  1877.                 if (IsPortActive(pActInfo, 0))
  1878.                 {
  1879.                         const string& shapeName = GetPortString(pActInfo, 2);
  1880.                         gEnv->pAISystem->EnableGenericShape(shapeName.c_str(), true);
  1881.                 }
  1882.                 else if (IsPortActive(pActInfo, 1))
  1883.                 {
  1884.                         const string& shapeName = GetPortString(pActInfo, 2);
  1885.                         gEnv->pAISystem->EnableGenericShape(shapeName.c_str(), false);
  1886.                 }
  1887.         }
  1888. }
  1889.  
  1890. //////////////////////////////////////////////////////////////////////////
  1891. // AI Event Listener
  1892. //////////////////////////////////////////////////////////////////////////
  1893. class CFlowNode_AIEventListener : public CFlowBaseNode<eNCT_Instanced>, IAIEventListener
  1894. {
  1895. public:
  1896.         CFlowNode_AIEventListener(SActivationInfo* pActInfo)
  1897.                 : m_pos(0, 0, 0), m_radius(0.0f),
  1898.                 m_thresholdSound(0.5f),
  1899.                 m_thresholdCollision(0.5f),
  1900.                 m_thresholdBullet(0.5f),
  1901.                 m_thresholdExplosion(0.5f)
  1902.         {
  1903.                 m_nodeID = pActInfo->myID;
  1904.                 m_pGraph = pActInfo->pGraph;
  1905.         }
  1906.         ~CFlowNode_AIEventListener()
  1907.         {
  1908.                 if (gEnv->pAISystem)
  1909.                         gEnv->pAISystem->UnregisterAIEventListener(this);
  1910.         }
  1911.         IFlowNodePtr Clone(SActivationInfo* pActInfo)
  1912.         {
  1913.                 return new CFlowNode_AIEventListener(pActInfo);
  1914.         }
  1915.         void Serialize(SActivationInfo* pActInfo, TSerialize ser)
  1916.         {
  1917.                 ser.Value("pos", m_pos);
  1918.                 ser.Value("radius", m_radius);
  1919.                 ser.Value("m_thresholdSound", m_thresholdSound);
  1920.                 ser.Value("m_thresholdCollision", m_thresholdCollision);
  1921.                 ser.Value("m_thresholdBullet", m_thresholdBullet);
  1922.                 ser.Value("m_thresholdExplosion", m_thresholdExplosion);
  1923.         }
  1924.         virtual void GetConfiguration(SFlowNodeConfig& config)
  1925.         {
  1926.                 static const SOutputPortConfig out_config[] = {
  1927.                         OutputPortConfig_Void("Sound"),
  1928.                         OutputPortConfig_Void("Collision"),
  1929.                         OutputPortConfig_Void("Bullet"),
  1930.                         OutputPortConfig_Void("Explosion"),
  1931.                         { 0 }
  1932.                 };
  1933.                 static const SInputPortConfig in_config[] = {
  1934.                         InputPortConfig<Vec3>("Pos",                 _HELP("Position of the listener")),
  1935.                         InputPortConfig<float>("Radius",             0.0f,                              _HELP("Radius of the listener")),
  1936.                         InputPortConfig<float>("ThresholdSound",     0.5f,                              _HELP("Sensitivity of the sound output")),
  1937.                         InputPortConfig<float>("ThresholdCollision", 0.5f,                              _HELP("Sensitivity of the collision output")),
  1938.                         InputPortConfig<float>("ThresholdBullet",    0.5f,                              _HELP("Sensitivity of the bullet output")),
  1939.                         InputPortConfig<float>("ThresholdExplosion", 0.5f,                              _HELP("Sensitivity of the explosion output")),
  1940.                         { 0 }
  1941.                 };
  1942.                 config.sDescription = _HELP("The highest level of alertness of any agent in the level");
  1943.                 config.pInputPorts = in_config;
  1944.                 config.pOutputPorts = out_config;
  1945.                 config.SetCategory(EFLN_ADVANCED);
  1946.         }
  1947.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  1948.         {
  1949.                 const int stimFlags = (1 << AISTIM_SOUND) | (1 << AISTIM_EXPLOSION) | (1 << AISTIM_BULLET_HIT) | (1 << AISTIM_COLLISION);
  1950.  
  1951.                 if (event == eFE_Initialize)
  1952.                 {
  1953.                         m_pos = GetPortVec3(pActInfo, 0);
  1954.                         m_radius = GetPortFloat(pActInfo, 1);
  1955.                         gEnv->pAISystem->RegisterAIEventListener(this, m_pos, m_radius, stimFlags);
  1956.  
  1957.                         m_thresholdSound = GetPortFloat(pActInfo, 2);
  1958.                         m_thresholdCollision = GetPortFloat(pActInfo, 3);
  1959.                         m_thresholdBullet = GetPortFloat(pActInfo, 4);
  1960.                         m_thresholdExplosion = GetPortFloat(pActInfo, 5);
  1961.                 }
  1962.  
  1963.                 if (event == eFE_Activate)
  1964.                 {
  1965.                         if (IsPortActive(pActInfo, 0))
  1966.                         {
  1967.                                 // Change pos
  1968.                                 Vec3 pos = GetPortVec3(pActInfo, 0);
  1969.                                 if (Distance::Point_PointSq(m_pos, pos) > sqr(0.01f))
  1970.                                 {
  1971.                                         m_pos = pos;
  1972.                                         gEnv->pAISystem->RegisterAIEventListener(this, m_pos, m_radius, stimFlags);
  1973.                                 }
  1974.                         }
  1975.                         else if (IsPortActive(pActInfo, 1))
  1976.                         {
  1977.                                 // Change radius
  1978.                                 float rad = GetPortFloat(pActInfo, 1);
  1979.                                 if (fabsf(rad - m_radius) > 0.0001f)
  1980.                                 {
  1981.                                         m_radius = rad;
  1982.                                         gEnv->pAISystem->RegisterAIEventListener(this, m_pos, m_radius, stimFlags);
  1983.                                 }
  1984.                         }
  1985.                         else if (IsPortActive(pActInfo, 2))
  1986.                         {
  1987.                                 // Change threshold
  1988.                                 m_thresholdSound = GetPortFloat(pActInfo, 2);
  1989.                         }
  1990.                         else if (IsPortActive(pActInfo, 3))
  1991.                         {
  1992.                                 // Change threshold
  1993.                                 m_thresholdCollision = GetPortFloat(pActInfo, 3);
  1994.                         }
  1995.                         else if (IsPortActive(pActInfo, 4))
  1996.                         {
  1997.                                 // Change threshold
  1998.                                 m_thresholdBullet = GetPortFloat(pActInfo, 4);
  1999.                         }
  2000.                         else if (IsPortActive(pActInfo, 5))
  2001.                         {
  2002.                                 // Change threshold
  2003.                                 m_thresholdExplosion = GetPortFloat(pActInfo, 5);
  2004.                         }
  2005.                 }
  2006.         }
  2007.         virtual void OnAIEvent(EAIStimulusType type, const Vec3& pos, float radius, float threat, EntityId sender)
  2008.         {
  2009.                 CRY_ASSERT(m_pGraph->IsEnabled() && !m_pGraph->IsSuspended() && m_pGraph->IsActive());
  2010.  
  2011.                 float dist = Distance::Point_Point(m_pos, pos);
  2012.                 float u = 0.0f;
  2013.  
  2014.                 if (radius > 0.001f)
  2015.                         u = (1.0f - clamp_tpl((dist - m_radius) / radius, 0.0f, 1.0f)) * threat;
  2016.  
  2017.                 float thr = 0.0f;
  2018.  
  2019.                 switch (type)
  2020.                 {
  2021.                 case AISTIM_SOUND:
  2022.                         thr = m_thresholdSound;
  2023.                         break;
  2024.                 case AISTIM_COLLISION:
  2025.                         thr = m_thresholdCollision;
  2026.                         break;
  2027.                 case AISTIM_BULLET_HIT:
  2028.                         thr = m_thresholdBullet;
  2029.                         break;
  2030.                 case AISTIM_EXPLOSION:
  2031.                         thr = m_thresholdExplosion;
  2032.                         break;
  2033.                 default:
  2034.                         return;
  2035.                 }
  2036.  
  2037.                 if (thr > 0.0f && u > thr)
  2038.                 {
  2039.                         int i = 0;
  2040.                         switch (type)
  2041.                         {
  2042.                         case AISTIM_SOUND:
  2043.                                 i = 0;
  2044.                                 break;
  2045.                         case AISTIM_COLLISION:
  2046.                                 i = 1;
  2047.                                 break;
  2048.                         case AISTIM_BULLET_HIT:
  2049.                                 i = 2;
  2050.                                 break;
  2051.                         case AISTIM_EXPLOSION:
  2052.                                 i = 3;
  2053.                                 break;
  2054.                         default:
  2055.                                 return;
  2056.                         }
  2057.                         SFlowAddress addr(m_nodeID, i, true);
  2058.                         m_pGraph->ActivatePort(addr, true);
  2059.                 }
  2060.         }
  2061.         virtual void GetMemoryUsage(ICrySizer* s) const
  2062.         {
  2063.                 s->Add(*this);
  2064.         }
  2065. private:
  2066.         Vec3 m_pos;
  2067.         float m_radius;
  2068.         float m_thresholdSound;
  2069.         float m_thresholdCollision;
  2070.         float m_thresholdBullet;
  2071.         float m_thresholdExplosion;
  2072.         IFlowGraph* m_pGraph;
  2073.         TFlowNodeId m_nodeID;
  2074. };
  2075.  
  2076. //////////////////////////////////////////////////////////////////////////
  2077.  
  2078. class CFlowNode_AICommunication : public CFlowBaseNode<eNCT_Instanced>
  2079. {
  2080. public:
  2081.         CFlowNode_AICommunication(SActivationInfo* pActInfo) : m_playID(0)
  2082.         {
  2083.  
  2084.         }
  2085.  
  2086.         virtual void GetMemoryUsage(ICrySizer* s) const
  2087.         {
  2088.                 s->Add(*this);
  2089.         }
  2090.  
  2091.         IFlowNodePtr Clone(SActivationInfo* pActInfo)
  2092.         {
  2093.                 return new CFlowNode_AICommunication(pActInfo);
  2094.         };
  2095.  
  2096.         void Serialize(SActivationInfo* pActInfo, TSerialize ser)
  2097.         {
  2098.                 ser.Value("m_playID", m_playID);
  2099.  
  2100.                 if (ser.IsReading() && (bool)m_playID)
  2101.                 {
  2102.                         pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, true);
  2103.                 }
  2104.         }
  2105.  
  2106.         enum EInputs
  2107.         {
  2108.                 EIP_Start,
  2109.                 EIP_Stop,
  2110.                 EIP_CommName,
  2111.                 EIP_ChannelName,
  2112.                 EIP_ContextExpiry,
  2113.                 EIP_SkipSound,
  2114.                 EIP_SkipAnim,
  2115.                 EIP_TargetId,
  2116.                 EIP_TargetPos,
  2117.         };
  2118.  
  2119.         enum EOutputs
  2120.         {
  2121.                 EOP_Done,
  2122.                 EOP_Started,
  2123.                 EOP_Stopped,
  2124.                 EOP_Finished,
  2125.                 EOP_Fail,
  2126.         };
  2127.  
  2128.         virtual bool GetPortGlobalEnum(uint32 portId, IEntity* pNodeEntity, const char* szName, string& outGlobalEnum) const
  2129.         {
  2130.                 if (EIP_CommName == portId && pNodeEntity)
  2131.                 {
  2132.                         IAIObject* pAI = pNodeEntity->GetAI();
  2133.                         IAIActorProxy* pAIProxy = pAI ? pAI->GetProxy() : NULL;
  2134.                         if (pAIProxy)
  2135.                         {
  2136.                                 const char* szCommConfigName = pAIProxy->GetCommunicationConfigName();
  2137.                                 outGlobalEnum.Format("%s_%s", szName, szCommConfigName);
  2138.                                 return true;
  2139.                         }
  2140.                 }
  2141.  
  2142.                 return false;
  2143.         }
  2144.  
  2145.         virtual void GetConfiguration(SFlowNodeConfig& config)
  2146.         {
  2147.                 static const SInputPortConfig inputs[] =
  2148.                 {
  2149.                         InputPortConfig_Void("Start",             _HELP("Starts the communication on the AI")),
  2150.                         InputPortConfig_Void("Stop",              _HELP("Stops the communication played with this node on the AI")),
  2151.                         InputPortConfig<string>("Communication",  "",                                                                           _HELP("Name of the communication to play"),                                                                     0, _UICONFIG("enum_global_def:communications")),
  2152.                         InputPortConfig<string>("Channel",        "group",                                                                      _HELP("Name of the channel to play the communication in"),                                                      0, _UICONFIG("enum_string:=,Global=global,Group=group,Personal=personal")),
  2153.                         InputPortConfig<float>("ContextExpirity", 0.0f,                                                                         _HELP("The context expiration of the communication (how much time must past before it can be played again)")),
  2154.                         InputPortConfig<bool>("SkipSound",        false,                                                                        _HELP("Force communication playback to skip sound component.")),
  2155.                         InputPortConfig<bool>("SkipAnim",         false,                                                                        _HELP("Force communication playback to skip animation component.")),
  2156.                         InputPortConfig<EntityId>("TargetId",     _HELP("Optional entity Id for whom the communication should be targeted at")),
  2157.                         InputPortConfig<Vec3>("TargetPos",        _HELP("Optional position for where the communication should be targeted at")),
  2158.                         { 0 }
  2159.                 };
  2160.  
  2161.                 static const SOutputPortConfig outputs[] =
  2162.                 {
  2163.                         OutputPortConfig_Void("Done",          _HELP("Outputs when any action has been carried out")),
  2164.                         OutputPortConfig<EntityId>("Started",  _HELP("Outputs when communication is started")),
  2165.                         OutputPortConfig<EntityId>("Stopped",  _HELP("Outputs when communication is stopped")),
  2166.                         OutputPortConfig<EntityId>("Finished", _HELP("Outputs when communication finishes playing")),
  2167.                         OutputPortConfig<EntityId>("Fail",     _HELP("Outputs when an error occurs with the last operation")),
  2168.                         { 0 }
  2169.                 };
  2170.  
  2171.                 config.pInputPorts = inputs;
  2172.                 config.pOutputPorts = outputs;
  2173.                 config.nFlags |= EFLN_TARGET_ENTITY;
  2174.                 config.sDescription = _HELP("The specified AI plays the given communication");
  2175.                 config.SetCategory(EFLN_APPROVED);
  2176.         }
  2177.  
  2178.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  2179.         {
  2180.                 if (eFE_Update == event)
  2181.                 {
  2182.                         // Check if still playing
  2183.                         if ((bool)m_playID)
  2184.                         {
  2185.                                 ICommunicationManager* pCommunicationManager = gEnv->pAISystem->GetCommunicationManager();
  2186.                                 assert(pCommunicationManager);
  2187.  
  2188.                                 const bool bIsPlaying = pCommunicationManager->IsPlaying(m_playID);
  2189.                                 if (!bIsPlaying)
  2190.                                 {
  2191.                                         IEntity* pEntity = pActInfo->pEntity;
  2192.                                         ActivateOutput(pActInfo, EOP_Finished, pEntity ? pEntity->GetId() : 0);
  2193.  
  2194.                                         m_playID.id = 0;
  2195.  
  2196.                                         pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, false);
  2197.                                 }
  2198.                         }
  2199.                         else
  2200.                         {
  2201.                                 pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, false);
  2202.                         }
  2203.                 }
  2204.                 else if (eFE_Activate == event)
  2205.                 {
  2206.                         if (IsPortActive(pActInfo, EIP_Start))
  2207.                         {
  2208.                                 StartCommunication(pActInfo);
  2209.                         }
  2210.                         else if (IsPortActive(pActInfo, EIP_Stop))
  2211.                         {
  2212.                                 StopCommunication(pActInfo);
  2213.                         }
  2214.                 }
  2215.         }
  2216.  
  2217.         void StartCommunication(SActivationInfo* pActInfo)
  2218.         {
  2219.                 assert(pActInfo);
  2220.  
  2221.                 ICommunicationManager* pCommunicationManager = gEnv->pAISystem->GetCommunicationManager();
  2222.                 assert(pCommunicationManager);
  2223.  
  2224.                 bool bFailed = true;
  2225.  
  2226.                 IEntity* pEntity = pActInfo->pEntity;
  2227.                 IAIObject* pAI = pEntity ? pEntity->GetAI() : NULL;
  2228.                 IAIActorProxy* pAIProxy = pAI ? pAI->GetProxy() : NULL;
  2229.                 if (pAIProxy)
  2230.                 {
  2231.                         SCommunicationRequest request;
  2232.                         request.actorID = pEntity->GetId();
  2233.                         request.channelID = pCommunicationManager->GetChannelID(GetPortString(pActInfo, EIP_ChannelName));
  2234.                         request.commID = pCommunicationManager->GetCommunicationID(GetPortString(pActInfo, EIP_CommName));
  2235.                         request.configID = pCommunicationManager->GetConfigID(pAIProxy->GetCommunicationConfigName());
  2236.                         request.contextExpiry = GetPortFloat(pActInfo, EIP_ContextExpiry);
  2237.                         request.ordering = SCommunicationRequest::Ordered;
  2238.                         request.skipCommSound = GetPortBool(pActInfo, EIP_SkipSound);
  2239.                         request.skipCommAnimation = GetPortBool(pActInfo, EIP_SkipAnim);
  2240.  
  2241.                         request.targetID = GetPortEntityId(pActInfo, EIP_TargetId);
  2242.                         request.target = GetPortVec3(pActInfo, EIP_TargetPos);
  2243.  
  2244.                         m_playID = pCommunicationManager->PlayCommunication(request);
  2245.                         if ((bool)m_playID)
  2246.                         {
  2247.                                 ActivateOutput(pActInfo, EOP_Started, pEntity->GetId());
  2248.                                 pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, true);
  2249.                                 bFailed = false;
  2250.                         }
  2251.                 }
  2252.  
  2253.                 if (bFailed)
  2254.                 {
  2255.                         ActivateOutput(pActInfo, EOP_Fail, pEntity ? pEntity->GetId() : 0);
  2256.                 }
  2257.  
  2258.                 ActivateOutput(pActInfo, EOP_Done, true);
  2259.         }
  2260.  
  2261.         void StopCommunication(SActivationInfo* pActInfo)
  2262.         {
  2263.                 assert(pActInfo);
  2264.  
  2265.                 ICommunicationManager* pCommunicationManager = gEnv->pAISystem->GetCommunicationManager();
  2266.                 assert(pCommunicationManager);
  2267.  
  2268.                 if ((bool)m_playID)
  2269.                 {
  2270.                         if (pCommunicationManager->IsPlaying(m_playID))
  2271.                         {
  2272.                                 pCommunicationManager->StopCommunication(m_playID);
  2273.  
  2274.                                 IEntity* pEntity = pActInfo->pEntity;
  2275.                                 ActivateOutput(pActInfo, EOP_Stopped, pEntity ? pEntity->GetId() : 0);
  2276.                                 ActivateOutput(pActInfo, EOP_Done, true);
  2277.                         }
  2278.  
  2279.                         m_playID.id = 0;
  2280.                         pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, false);
  2281.                 }
  2282.         }
  2283.  
  2284. private:
  2285.         CommPlayID m_playID;
  2286. };
  2287.  
  2288. //////////////////////////////////////////////////////////////////////////
  2289. class CFlowNode_AIIsAliveCheck : public CFlowBaseNode<eNCT_Singleton>
  2290. {
  2291. public:
  2292.         CFlowNode_AIIsAliveCheck(SActivationInfo* pActInfo)
  2293.         {
  2294.         }
  2295.  
  2296.         enum { NUM_ACTORS = 8 };
  2297.  
  2298.         enum EInputs
  2299.         {
  2300.                 IN_Trigger   = 0,
  2301.                 IN_ActorFirst,
  2302.                 IN_ActorLast = IN_ActorFirst + (NUM_ACTORS - 1)
  2303.         };
  2304.  
  2305.         enum EOutputs
  2306.         {
  2307.                 OUT_AliveCount = 0,
  2308.                 OUT_AliveFirst,
  2309.                 OUT_AliveLast  = OUT_AliveFirst + (NUM_ACTORS - 1)
  2310.         };
  2311.  
  2312.         virtual void GetConfiguration(SFlowNodeConfig& config)
  2313.         {
  2314.                 static const SInputPortConfig inputs[] = {
  2315.                         InputPortConfig_Void("Trigger",      _HELP("Trigger this port to check for alive status of the Actors")),
  2316.                         InputPortConfig<EntityId>("Actor_0", 0,                                                                  _HELP("Entity ID"),  _HELP("Actor 0")),
  2317.                         InputPortConfig<EntityId>("Actor_1", 0,                                                                  _HELP("Entity ID"),  _HELP("Actor 1")),
  2318.                         InputPortConfig<EntityId>("Actor_2", 0,                                                                  _HELP("Entity ID"),  _HELP("Actor 2")),
  2319.                         InputPortConfig<EntityId>("Actor_3", 0,                                                                  _HELP("Entity ID"),  _HELP("Actor 3")),
  2320.                         InputPortConfig<EntityId>("Actor_4", 0,                                                                  _HELP("Entity ID"),  _HELP("Actor 4")),
  2321.                         InputPortConfig<EntityId>("Actor_5", 0,                                                                  _HELP("Entity ID"),  _HELP("Actor 5")),
  2322.                         InputPortConfig<EntityId>("Actor_6", 0,                                                                  _HELP("Entity ID"),  _HELP("Actor 6")),
  2323.                         InputPortConfig<EntityId>("Actor_7", 0,                                                                  _HELP("Entity ID"),  _HELP("Actor 7")),
  2324.                         { 0 }
  2325.                 };
  2326.                 static const SOutputPortConfig outputs[] = {
  2327.                         OutputPortConfig<int>("AliveCount",   _HELP("How many of the actors are alive")),
  2328.                         OutputPortConfig<EntityId>("Alive_0", _HELP("triggered if is alive"),            _HELP("Alive Id 0")),
  2329.                         OutputPortConfig<EntityId>("Alive_1", _HELP("triggered if is alive"),            _HELP("Alive Id 1")),
  2330.                         OutputPortConfig<EntityId>("Alive_2", _HELP("triggered if is alive"),            _HELP("Alive Id 2")),
  2331.                         OutputPortConfig<EntityId>("Alive_3", _HELP("triggered if is alive"),            _HELP("Alive Id 3")),
  2332.                         OutputPortConfig<EntityId>("Alive_4", _HELP("triggered if is alive"),            _HELP("Alive Id 4")),
  2333.                         OutputPortConfig<EntityId>("Alive_5", _HELP("triggered if is alive"),            _HELP("Alive Id 5")),
  2334.                         OutputPortConfig<EntityId>("Alive_6", _HELP("triggered if is alive"),            _HELP("Alive Id 6")),
  2335.                         OutputPortConfig<EntityId>("Alive_7", _HELP("triggered if is alive"),            _HELP("Alive Id 7")),
  2336.                         { 0 }
  2337.                 };
  2338.                 config.pInputPorts = inputs;
  2339.                 config.pOutputPorts = outputs;
  2340.                 config.sDescription = _HELP("Check which actors of a group are alive");
  2341.                 config.SetCategory(EFLN_APPROVED);
  2342.         }
  2343.  
  2344.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  2345.         {
  2346.                 switch (event)
  2347.                 {
  2348.                 case eFE_Activate:
  2349.                         {
  2350.                                 if (IsPortActive(pActInfo, IN_Trigger))
  2351.                                 {
  2352.                                         int numAlive = 0;
  2353.  
  2354.                                         for (int i = 0; i < NUM_ACTORS; ++i)
  2355.                                         {
  2356.                                                 EntityId entityId = GetPortEntityId(pActInfo, IN_ActorFirst + i);
  2357.                                                 if (entityId != 0)
  2358.                                                 {
  2359.                                                         IActor* pActor = gEnv->pGameFramework->GetIActorSystem()->GetActor(entityId);
  2360.                                                         bool isAlive = pActor && !pActor->IsDead();
  2361.                                                         if (isAlive)
  2362.                                                         {
  2363.                                                                 ActivateOutput(pActInfo, OUT_AliveFirst + numAlive, entityId);
  2364.                                                                 ++numAlive;
  2365.                                                         }
  2366.                                                 }
  2367.                                         }
  2368.                                         for (int i = numAlive; i < NUM_ACTORS; ++i)
  2369.                                                 ActivateOutput(pActInfo, OUT_AliveFirst + i, 0);
  2370.                                         ActivateOutput(pActInfo, OUT_AliveCount, numAlive);
  2371.                                 }
  2372.                                 break;
  2373.                         }
  2374.                 }
  2375.         }
  2376.  
  2377.         virtual void GetMemoryUsage(ICrySizer* s) const
  2378.         {
  2379.                 s->Add(*this);
  2380.         }
  2381. };
  2382.  
  2383. class CFlowNode_AIGlobalPerceptionScaling : public CFlowBaseNode<eNCT_Instanced>, public IAIGlobalPerceptionListener
  2384. {
  2385. public:
  2386.  
  2387.         enum EInputs
  2388.         {
  2389.                 IN_Enable = 0,
  2390.                 IN_Disable,
  2391.                 IN_AudioScale,
  2392.                 IN_VisualScale,
  2393.                 IN_FilterAI,
  2394.                 IN_Faction,
  2395.         };
  2396.  
  2397.         enum EOutputs
  2398.         {
  2399.                 OUT_Enabled = 0,
  2400.                 OUT_Disabled,
  2401.         };
  2402.  
  2403.         CFlowNode_AIGlobalPerceptionScaling(SActivationInfo* pActInfo)
  2404.         {
  2405.                 gEnv->pAISystem->RegisterGlobalPerceptionListener(this);
  2406.         }
  2407.  
  2408.         virtual ~CFlowNode_AIGlobalPerceptionScaling()
  2409.         {
  2410.                 gEnv->pAISystem->UnregisterGlobalPerceptionlistener(this);
  2411.         }
  2412.  
  2413.         virtual void GetConfiguration(SFlowNodeConfig& config)
  2414.         {
  2415.                 static const SInputPortConfig inputs[] = {
  2416.                         InputPortConfig_Void("Enable",        _HELP("Enables the perception scaling.")),
  2417.                         InputPortConfig_Void("Disable",       _HELP("Disables the perception scaling.")),
  2418.                         InputPortConfig<float>("AudioScale",  0.0f,                                      _HELP("This is the value used to scale down the audio perception. Value is clamped between [0.0 - 1.0]"),   _HELP("AudioScale")),
  2419.                         InputPortConfig<float>("VisualScale", 0.0f,                                      _HELP("This is the value used to scale fown the visual perception. Value is clamped between [0.0 - 1.0]"),  _HELP("VisualScale")),
  2420.                         InputPortConfig<int>("FilterAI",      0,                                         _HELP("Filter which AIs are used for the alertness value."),                                                _HELP("FilterAI"),    _UICONFIG("enum_int:All=0,Enemies=1,Friends=2,Faction=3")),
  2421.                         InputPortConfig<string>("Faction",    "",                                        _HELP("Only used when 'FilterAI' input is set to 'Faction'. )."),                                           0,                    "enum_global:Faction"),
  2422.                         { 0 },
  2423.                 };
  2424.  
  2425.                 static const SOutputPortConfig outputs[] = {
  2426.                         OutputPortConfig_Void("Enabled",  _HELP("Triggered when the node gets enabled.")),
  2427.                         OutputPortConfig_Void("Disabled", _HELP("Triggered when the node gets disabled.")),
  2428.                         { 0 },
  2429.                 };
  2430.  
  2431.                 config.pInputPorts = inputs;
  2432.                 config.pOutputPorts = outputs;
  2433.                 config.nFlags |= EFLN_AISEQUENCE_SUPPORTED;
  2434.                 config.sDescription = _HELP("Set/Unset a specific global scale for the AI perception.");
  2435.                 config.SetCategory(EFLN_APPROVED);
  2436.         }
  2437.  
  2438.         virtual IFlowNodePtr Clone(SActivationInfo* pActInfo)
  2439.         {
  2440.                 return new CFlowNode_AIGlobalPerceptionScaling(pActInfo);
  2441.         }
  2442.  
  2443.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  2444.         {
  2445.                 switch (event)
  2446.                 {
  2447.                 case eFE_Initialize:
  2448.                         {
  2449.                                 m_actInfo = *pActInfo;
  2450.                                 break;
  2451.                         }
  2452.                 case eFE_Activate:
  2453.                         {
  2454.                                 m_actInfo = *pActInfo;
  2455.                                 if (IsPortActive(pActInfo, IN_Enable))
  2456.                                 {
  2457.                                         float visualScale = ClampPerceptionScale(GetPortFloat(pActInfo, IN_VisualScale));
  2458.                                         float audioScale = ClampPerceptionScale(GetPortFloat(pActInfo, IN_AudioScale));
  2459.                                         EAIFilterType filterAI = GetFilterType(GetPortInt(pActInfo, IN_FilterAI));
  2460.                                         const string& factionName = GetPortString(pActInfo, IN_Faction);
  2461.                                         gEnv->pAISystem->UpdateGlobalPerceptionScale(visualScale, audioScale, filterAI, factionName);
  2462.                                 }
  2463.  
  2464.                                 if (IsPortActive(pActInfo, IN_Disable))
  2465.                                 {
  2466.                                         gEnv->pAISystem->DisableGlobalPerceptionScaling();
  2467.                                 }
  2468.                                 break;
  2469.                         }
  2470.                 }
  2471.         }
  2472.  
  2473.         virtual void GetMemoryUsage(ICrySizer* s) const
  2474.         {
  2475.                 s->Add(*this);
  2476.         }
  2477.  
  2478.         // IAIGlobalPerceptionListener implementation
  2479.         virtual void OnPerceptionScalingEvent(const IAIGlobalPerceptionListener::EGlobalPerceptionScaleEvent event)
  2480.         {
  2481.                 switch (event)
  2482.                 {
  2483.                 case IAIGlobalPerceptionListener::eGPS_Set:
  2484.                         ActivateOutput(&m_actInfo, OUT_Enabled, true);
  2485.                         break;
  2486.                 case IAIGlobalPerceptionListener::eGPS_Disabled:
  2487.                         ActivateOutput(&m_actInfo, OUT_Disabled, true);
  2488.                         break;
  2489.                 default:
  2490.                         assert(0);
  2491.                         break;
  2492.                 }
  2493.         }
  2494.  
  2495. private:
  2496.         float ClampPerceptionScale(float scaleValue)
  2497.         {
  2498.                 return clamp_tpl(scaleValue, 0.0f, 1.0f);
  2499.         }
  2500.  
  2501.         EAIFilterType GetFilterType(uint8 filterType)
  2502.         {
  2503.                 switch (filterType)
  2504.                 {
  2505.                 case 0:
  2506.                         return eAIFT_All;
  2507.                 case 1:
  2508.                         return eAIFT_Enemies;
  2509.                 case 2:
  2510.                         return eAIFT_Friends;
  2511.                 case 3:
  2512.                         return eAIFT_Faction;
  2513.                 default:
  2514.                         return eAIFT_All;
  2515.                 }
  2516.         }
  2517.  
  2518.         SActivationInfo m_actInfo; // Activation info instance
  2519. };
  2520.  
  2521. //////////////////////////////////////////////////////////////////////////
  2522. // Node to controls the communication manager variables
  2523. //////////////////////////////////////////////////////////////////////////
  2524.  
  2525. class CFlowNode_AISetCommunicationVariable : public CFlowBaseNode<eNCT_Instanced>
  2526. {
  2527. public:
  2528.         enum Inputs
  2529.         {
  2530.                 eIN_Set = 0,
  2531.                 eIN_VariableName,
  2532.                 eIN_VariableValue,
  2533.         };
  2534.  
  2535.         CFlowNode_AISetCommunicationVariable(IFlowNode::SActivationInfo* pActInfo) {}
  2536.         virtual ~CFlowNode_AISetCommunicationVariable() {}
  2537.  
  2538.         virtual IFlowNodePtr Clone(SActivationInfo* pActInfo) { return new CFlowNode_AISetCommunicationVariable(pActInfo); }
  2539.  
  2540.         virtual void         GetConfiguration(SFlowNodeConfig& config)
  2541.         {
  2542.                 static const SInputPortConfig in_config[] = {
  2543.                         InputPortConfig_Void("Set"),
  2544.                         InputPortConfig<string>("communicationVariable_VariableName",_HELP("Variable name")),
  2545.                         InputPortConfig<bool>("VariableValue",                       true,                    _HELP("Value that needs to be set for the specified variable.")),
  2546.                         { 0 }
  2547.                 };
  2548.                 static const SOutputPortConfig out_config[] = {
  2549.                         { 0 }
  2550.                 };
  2551.  
  2552.                 config.sDescription = _HELP("");
  2553.                 config.pInputPorts = in_config;
  2554.                 config.pOutputPorts = out_config;
  2555.                 config.SetCategory(EFLN_APPROVED);
  2556.         }
  2557.  
  2558.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  2559.         {
  2560.                 switch (event)
  2561.                 {
  2562.                 case eFE_Initialize:
  2563.                         break;
  2564.                 case eFE_Activate:
  2565.                         assert(gEnv->pAISystem);
  2566.                         ICommunicationManager* pCommunicationManager = gEnv->pAISystem->GetCommunicationManager();
  2567.                         assert(pCommunicationManager);
  2568.  
  2569.                         const string variableName = GetPortString(pActInfo, eIN_VariableName);
  2570.                         const bool variableValue = GetPortBool(pActInfo, eIN_VariableValue);
  2571.  
  2572.                         pCommunicationManager->SetVariableValue(variableName.c_str(), variableValue);
  2573.                         break;
  2574.                 }
  2575.         }
  2576.  
  2577.         virtual void GetMemoryUsage(ICrySizer* s) const { s->Add(*this); }
  2578. };
  2579.  
  2580. //////////////////////////////////////////////////////////////////////////
  2581. // Node to notify AI that when the node is triggered, AI can perform
  2582. // some actions to express the reinforcement requests
  2583. //////////////////////////////////////////////////////////////////////////
  2584.  
  2585. class CFlowNode_AIRequestReinforcementReadability : public CFlowBaseNode<eNCT_Instanced>
  2586. {
  2587. public:
  2588.         enum Inputs
  2589.         {
  2590.                 eIN_Trigger = 0,
  2591.                 eIN_GroupId,
  2592.         };
  2593.  
  2594.         enum Outputs
  2595.         {
  2596.                 eOUT_Done,
  2597.         };
  2598.  
  2599.         CFlowNode_AIRequestReinforcementReadability(IFlowNode::SActivationInfo* pActInfo) {}
  2600.         virtual ~CFlowNode_AIRequestReinforcementReadability() {}
  2601.  
  2602.         virtual IFlowNodePtr Clone(SActivationInfo* pActInfo) { return new CFlowNode_AISetCommunicationVariable(pActInfo); }
  2603.  
  2604.         virtual void         GetConfiguration(SFlowNodeConfig& config)
  2605.         {
  2606.                 static const SInputPortConfig in_config[] = {
  2607.                         InputPortConfig_Void("Trigger"),
  2608.                         InputPortConfig<int>("GroupId", _HELP("Id of the group that needs to be notified.")),
  2609.                         { 0 }
  2610.                 };
  2611.                 static const SOutputPortConfig out_config[] = {
  2612.                         OutputPortConfig_Void("Done", _HELP("This value is outputted when the AI is informed."
  2613.                                                             "(This doesn't mean the AI alread performed the readable action of requesting the reinforcement.)")),
  2614.                         { 0 }
  2615.                 };
  2616.  
  2617.                 config.sDescription = _HELP("");
  2618.                 config.pInputPorts = in_config;
  2619.                 config.pOutputPorts = out_config;
  2620.                 config.SetCategory(EFLN_APPROVED);
  2621.         }
  2622.  
  2623.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  2624.         {
  2625.                 switch (event)
  2626.                 {
  2627.                 case eFE_Initialize:
  2628.                         break;
  2629.                 case eFE_Activate:
  2630.                         const int groupId = GetPortInt(pActInfo, eIN_GroupId);
  2631.                         const char* signalName = "OnRequestReinforcementTriggered";
  2632.  
  2633.                         // Select the first member of the group to use it as a sender
  2634.                         IAIObject* pFirstGroupMember = gEnv->pAISystem->GetGroupMember(groupId, 0);
  2635.                         if (pFirstGroupMember)
  2636.                         {
  2637.                                 gEnv->pAISystem->SendSignal(SIGNALFILTER_GROUPONLY, 1, signalName, pFirstGroupMember);
  2638.  
  2639.                                 ActivateOutput(pActInfo, eOUT_Done, true);
  2640.                         }
  2641.  
  2642.                         break;
  2643.                 }
  2644.         }
  2645.  
  2646.         virtual void GetMemoryUsage(ICrySizer* s) const { s->Add(*this); }
  2647. };
  2648.  
  2649. //////////////////////////////////////////////////////////////////////////
  2650. // Node to regenerate a part or everything of the MNM.
  2651. //////////////////////////////////////////////////////////////////////////
  2652.  
  2653. class CFlowNode_AIRegenerateMNM : public CFlowBaseNode<eNCT_Singleton>
  2654. {
  2655. public:
  2656.         enum Inputs
  2657.         {
  2658.                 eIN_Trigger,
  2659.                 eIN_Min,
  2660.                 eIN_Max,
  2661.         };
  2662.  
  2663.         CFlowNode_AIRegenerateMNM(SActivationInfo* pActInfo)
  2664.         {
  2665.         }
  2666.  
  2667.         virtual void GetConfiguration(SFlowNodeConfig& config) override
  2668.         {
  2669.                 static const SInputPortConfig inputs[] =
  2670.                 {
  2671.                         InputPortConfig_Void("Start", _HELP("Trigger this port to regenerate the MNM.")),
  2672.                         InputPortConfig<Vec3>("Min",  Vec3(ZERO),                                        _HELP("Min position of the AABB")),
  2673.                         InputPortConfig<Vec3>("Max",  Vec3(ZERO),                                        _HELP("Min position of the AABB")),
  2674.                         { 0 }
  2675.                 };
  2676.  
  2677.                 static const SOutputPortConfig outputs[] =
  2678.                 {
  2679.                         { 0 }
  2680.                 };
  2681.  
  2682.                 config.pInputPorts = inputs;
  2683.                 config.pOutputPorts = outputs;
  2684.                 config.nFlags |= EFLN_AISEQUENCE_SUPPORTED;
  2685.                 config.sDescription = _HELP("Triggers recalculation of MNM data for a specified bounding box (leave blank for whole level)");
  2686.                 config.SetCategory(EFLN_APPROVED);
  2687.       &nb