BVB Source Codes

CRYENGINE Show FlowEntityNode.cpp Source code

Return Download CRYENGINE: download FlowEntityNode.cpp Source code - Download CRYENGINE Source code - Type:.cpp
  1. // Copyright 2001-2016 Crytek GmbH / Crytek Group. All rights reserved.
  2.  
  3. // -------------------------------------------------------------------------
  4. //  File name:   FlowEntityNode.h
  5. //  Version:     v1.00
  6. //  Created:     23/5/2005 by Timur.
  7. //  Compilers:   Visual Studio.NET 2003
  8. //  Description:
  9. // -------------------------------------------------------------------------
  10. //  History:
  11. //
  12. ////////////////////////////////////////////////////////////////////////////
  13.  
  14. #include "StdAfx.h"
  15. #include "FlowEntityNode.h"
  16.  
  17. #include <IActorSystem.h>
  18. #include <IGameRulesSystem.h>
  19. #include "CryAction.h"
  20.  
  21. //////////////////////////////////////////////////////////////////////////
  22. CFlowEntityClass::CFlowEntityClass(IEntityClass* pEntityClass)
  23. {
  24.         m_nRefCount = 0;
  25.         //m_classname = pEntityClass->GetName();
  26.         m_pEntityClass = pEntityClass;
  27. }
  28.  
  29. //////////////////////////////////////////////////////////////////////////
  30. CFlowEntityClass::~CFlowEntityClass()
  31. {
  32.         Reset();
  33. }
  34.  
  35. //////////////////////////////////////////////////////////////////////////
  36. void CFlowEntityClass::FreeStr(const char* src)
  37. {
  38.         if (src)
  39.                 delete[]src;
  40. }
  41.  
  42. //////////////////////////////////////////////////////////////////////////
  43. void CFlowEntityClass::Reset()
  44. {
  45.         for (std::vector<SInputPortConfig>::iterator it = m_inputs.begin(), itEnd = m_inputs.end(); it != itEnd; ++it)
  46.                 FreeStr(it->name);
  47.  
  48.         for (std::vector<SOutputPortConfig>::iterator it = m_outputs.begin(), itEnd = m_outputs.end(); it != itEnd; ++it)
  49.                 FreeStr(it->name);
  50.  
  51.         stl::free_container(m_inputs);
  52.         stl::free_container(m_outputs);
  53. }
  54.  
  55. //////////////////////////////////////////////////////////////////////////
  56. const char* CFlowEntityClass::CopyStr(const char* src)
  57. {
  58.         char* dst = 0;
  59.         if (src)
  60.         {
  61.                 int len = strlen(src);
  62.                 dst = new char[len + 1];
  63.                 cry_strcpy(dst, len + 1, src);
  64.         }
  65.         return dst;
  66. }
  67.  
  68. //////////////////////////////////////////////////////////////////////////
  69. void MakeHumanName(SInputPortConfig& config)
  70. {
  71.         char* name = strchr((char*)config.name, '_');
  72.         if (name != 0)
  73.                 config.humanName = name + 1;
  74. }
  75.  
  76. //////////////////////////////////////////////////////////////////////////
  77. void CFlowEntityClass::GetInputsOutputs(IEntityClass* pEntityClass)
  78. {
  79.         int nEvents = pEntityClass->GetEventCount();
  80.         for (int i = 0; i < nEvents; i++)
  81.         {
  82.                 IEntityClass::SEventInfo event = pEntityClass->GetEventInfo(i);
  83.                 if (event.bOutput)
  84.                 {
  85.                         // Output
  86.                         switch (event.type)
  87.                         {
  88.                         case IEntityClass::EVT_BOOL:
  89.                                 m_outputs.push_back(OutputPortConfig<bool>(CopyStr(event.name)));
  90.                                 break;
  91.                         case IEntityClass::EVT_INT:
  92.                                 m_outputs.push_back(OutputPortConfig<int>(CopyStr(event.name)));
  93.                                 break;
  94.                         case IEntityClass::EVT_FLOAT:
  95.                                 m_outputs.push_back(OutputPortConfig<float>(CopyStr(event.name)));
  96.                                 break;
  97.                         case IEntityClass::EVT_VECTOR:
  98.                                 m_outputs.push_back(OutputPortConfig<Vec3>(CopyStr(event.name)));
  99.                                 break;
  100.                         case IEntityClass::EVT_ENTITY:
  101.                                 m_outputs.push_back(OutputPortConfig<EntityId>(CopyStr(event.name)));
  102.                                 break;
  103.                         case IEntityClass::EVT_STRING:
  104.                                 m_outputs.push_back(OutputPortConfig<string>(CopyStr(event.name)));
  105.                                 break;
  106.                         }
  107.                 }
  108.                 else
  109.                 {
  110.                         // Input
  111.                         switch (event.type)
  112.                         {
  113.                         case IEntityClass::EVT_BOOL:
  114.                                 m_inputs.push_back(InputPortConfig<bool>(CopyStr(event.name)));
  115.                                 MakeHumanName(m_inputs.back());
  116.                                 break;
  117.                         case IEntityClass::EVT_INT:
  118.                                 m_inputs.push_back(InputPortConfig<int>(CopyStr(event.name)));
  119.                                 MakeHumanName(m_inputs.back());
  120.                                 break;
  121.                         case IEntityClass::EVT_FLOAT:
  122.                                 m_inputs.push_back(InputPortConfig<float>(CopyStr(event.name)));
  123.                                 MakeHumanName(m_inputs.back());
  124.                                 break;
  125.                         case IEntityClass::EVT_VECTOR:
  126.                                 m_inputs.push_back(InputPortConfig<Vec3>(CopyStr(event.name)));
  127.                                 MakeHumanName(m_inputs.back());
  128.                                 break;
  129.                         case IEntityClass::EVT_ENTITY:
  130.                                 m_inputs.push_back(InputPortConfig<EntityId>(CopyStr(event.name)));
  131.                                 MakeHumanName(m_inputs.back());
  132.                                 break;
  133.                         case IEntityClass::EVT_STRING:
  134.                                 m_inputs.push_back(InputPortConfig<string>(CopyStr(event.name)));
  135.                                 MakeHumanName(m_inputs.back());
  136.                                 break;
  137.                         }
  138.                 }
  139.         }
  140.         m_outputs.push_back(OutputPortConfig<bool>(0, 0));
  141.         m_inputs.push_back(InputPortConfig<bool>(0, false));
  142. }
  143.  
  144. //////////////////////////////////////////////////////////////////////////
  145. void CFlowEntityClass::GetConfiguration(SFlowNodeConfig& config)
  146. {
  147.         m_inputs.clear();
  148.         m_outputs.clear();
  149.         GetInputsOutputs(m_pEntityClass);
  150.  
  151.         //if (m_inputs.empty() && m_outputs.empty())
  152.         //      GetInputsOutputs( m_pEntityClass );
  153.  
  154.         static const SInputPortConfig in_config[] = {
  155.                 { 0 }
  156.         };
  157.         static const SOutputPortConfig out_config[] = {
  158.                 { 0 }
  159.         };
  160.  
  161.         config.nFlags |= EFLN_TARGET_ENTITY | EFLN_HIDE_UI;
  162.         config.SetCategory(EFLN_APPROVED); // all Entity flownodes are approved!
  163.  
  164.         config.pInputPorts = in_config;
  165.         config.pOutputPorts = out_config;
  166.  
  167.         if (!m_inputs.empty())
  168.                 config.pInputPorts = &m_inputs[0];
  169.  
  170.         if (!m_outputs.empty())
  171.                 config.pOutputPorts = &m_outputs[0];
  172.  
  173. }
  174.  
  175. //////////////////////////////////////////////////////////////////////////
  176. IFlowNodePtr CFlowEntityClass::Create(IFlowNode::SActivationInfo* pActInfo)
  177. {
  178.         return new CFlowEntityNode(this, pActInfo);
  179. }
  180.  
  181. //////////////////////////////////////////////////////////////////////////
  182. // CFlowEntityNode implementation.
  183. //////////////////////////////////////////////////////////////////////////
  184.  
  185. //////////////////////////////////////////////////////////////////////////
  186. CFlowEntityNode::CFlowEntityNode(CFlowEntityClass* pClass, SActivationInfo* pActInfo)
  187. {
  188.         m_event = ENTITY_EVENT_SCRIPT_EVENT;
  189.         m_pClass = pClass;
  190.         //pActInfo->pGraph->SetRegularlyUpdated( pActInfo->myID, false );
  191.         //      m_entityId = (EntityId)pActInfo->m_pUserData;
  192.  
  193.         m_nodeID = pActInfo->myID;
  194.         m_pGraph = pActInfo->pGraph;
  195.         m_lastInitializeFrameId = -1;
  196. }
  197.  
  198. IFlowNodePtr CFlowEntityNode::Clone(SActivationInfo* pActInfo)
  199. {
  200.         IFlowNode* pNode = new CFlowEntityNode(m_pClass, pActInfo);
  201.         return pNode;
  202. };
  203.  
  204. //////////////////////////////////////////////////////////////////////////
  205. void CFlowEntityNode::GetConfiguration(SFlowNodeConfig& config)
  206. {
  207.         m_pClass->GetConfiguration(config);
  208. }
  209.  
  210. //////////////////////////////////////////////////////////////////////////
  211. void CFlowEntityNode::ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  212. {
  213.         CFlowEntityNodeBase::ProcessEvent(event, pActInfo);
  214.  
  215.         switch (event)
  216.         {
  217.         case eFE_Activate:
  218.                 {
  219.                         IEntity* pEntity = gEnv->pEntitySystem->GetEntity(m_entityId);
  220.                         if (!pEntity)
  221.                         {
  222.                                 return;
  223.                         }
  224.  
  225.                         if (m_pClass->m_pEntityClass->GetFlags() & ECLF_SEND_SCRIPT_EVENTS_FROM_FLOWGRAPH)
  226.                         {
  227.                                 SendEventToEntity(pActInfo, pEntity);
  228.                         }
  229.  
  230.                         IEntityScriptComponent* pScriptProxy = (IEntityScriptComponent*)pEntity->GetProxy(ENTITY_PROXY_SCRIPT);
  231.                         if (!pScriptProxy)
  232.                                 return;
  233.  
  234.                         // Check active ports, and send event to entity.
  235.                         for (int i = 0; i < m_pClass->m_inputs.size() - 1; i++)
  236.                         {
  237.                                 if (IsPortActive(pActInfo, i))
  238.                                 {
  239.                                         EFlowDataTypes type = GetPortType(pActInfo, i);
  240.                                         switch (type)
  241.                                         {
  242.                                         case eFDT_Int:
  243.                                                 pScriptProxy->CallEvent(m_pClass->m_inputs[i].name, (float)GetPortInt(pActInfo, i));
  244.                                                 break;
  245.                                         case eFDT_Float:
  246.                                                 pScriptProxy->CallEvent(m_pClass->m_inputs[i].name, GetPortFloat(pActInfo, i));
  247.                                                 break;
  248.                                         case eFDT_Bool:
  249.                                                 pScriptProxy->CallEvent(m_pClass->m_inputs[i].name, GetPortBool(pActInfo, i));
  250.                                                 break;
  251.                                         case eFDT_Vec3:
  252.                                                 pScriptProxy->CallEvent(m_pClass->m_inputs[i].name, GetPortVec3(pActInfo, i));
  253.                                                 break;
  254.                                         case eFDT_EntityId:
  255.                                                 pScriptProxy->CallEvent(m_pClass->m_inputs[i].name, GetPortEntityId(pActInfo, i));
  256.                                                 break;
  257.                                         case eFDT_String:
  258.                                                 pScriptProxy->CallEvent(m_pClass->m_inputs[i].name, GetPortString(pActInfo, i).c_str());
  259.                                                 break;
  260.                                         }
  261.                                 }
  262.                         }
  263.                 }
  264.                 break;
  265.         case eFE_Initialize:
  266.                 if (gEnv->IsEditor() && m_entityId)
  267.                 {
  268.                         UnregisterEvent(m_event);
  269.                         RegisterEvent(m_event);
  270.                 }
  271.                 const int frameId = gEnv->nMainFrameID;
  272.                 if (frameId != m_lastInitializeFrameId)
  273.                 {
  274.                         m_lastInitializeFrameId = frameId;
  275.                         for (size_t i = 0; i < m_pClass->GetNumOutputs(); i++)
  276.                         {
  277.                                 ActivateOutput(pActInfo, i, SFlowSystemVoid());
  278.                         }
  279.                 }
  280.                 break;
  281.         }
  282. }
  283.  
  284. //////////////////////////////////////////////////////////////////////////
  285. bool CFlowEntityNode::SerializeXML(SActivationInfo*, const XmlNodeRef& root, bool reading)
  286. {
  287.         return true;
  288. }
  289.  
  290. //////////////////////////////////////////////////////////////////////////
  291. void CFlowEntityNode::Serialize(SActivationInfo*, TSerialize ser)
  292. {
  293.         if (ser.IsReading())
  294.                 m_lastInitializeFrameId = -1;
  295. }
  296.  
  297. //////////////////////////////////////////////////////////////////////////
  298. void CFlowEntityNode::SendEventToEntity(SActivationInfo* pActInfo, IEntity* pEntity)
  299. {
  300.         SEntityEvent event(ENTITY_EVENT_SCRIPT_EVENT);
  301.         for (int iInput = 0, inputCount = m_pClass->m_inputs.size() - 1; iInput < inputCount; ++iInput)
  302.         {
  303.                 if (IsPortActive(pActInfo, iInput))
  304.                 {
  305.                         event.nParam[0] = INT_PTR(m_pClass->m_inputs[iInput].name);
  306.                         EFlowDataTypes type = GetPortType(pActInfo, iInput);
  307.                         switch (type)
  308.                         {
  309.                         case eFDT_Int:
  310.                                 {
  311.                                         event.nParam[1] = INT_PTR(IEntityEventHandler::Int);
  312.                                         const int value = GetPortInt(pActInfo, iInput);
  313.                                         event.nParam[2] = INT_PTR(&value);
  314.                                         pEntity->SendEvent(event);
  315.                                         break;
  316.                                 }
  317.                         case eFDT_Float:
  318.                                 {
  319.                                         event.nParam[1] = INT_PTR(IEntityEventHandler::Float);
  320.                                         const float value = GetPortFloat(pActInfo, iInput);
  321.                                         event.nParam[2] = INT_PTR(&value);
  322.                                         pEntity->SendEvent(event);
  323.                                         break;
  324.                                 }
  325.                         case eFDT_EntityId:
  326.                                 {
  327.                                         event.nParam[1] = INT_PTR(IEntityEventHandler::Entity);
  328.                                         const EntityId value = GetPortEntityId(pActInfo, iInput);
  329.                                         event.nParam[2] = INT_PTR(&value);
  330.                                         pEntity->SendEvent(event);
  331.                                         break;
  332.                                 }
  333.                         case eFDT_Vec3:
  334.                                 {
  335.                                         event.nParam[1] = INT_PTR(IEntityEventHandler::Vector);
  336.                                         const Vec3 value = GetPortVec3(pActInfo, iInput);
  337.                                         event.nParam[2] = INT_PTR(&value);
  338.                                         pEntity->SendEvent(event);
  339.                                         break;
  340.                                 }
  341.                         case eFDT_String:
  342.                                 {
  343.                                         event.nParam[1] = INT_PTR(IEntityEventHandler::String);
  344.                                         const string value = GetPortString(pActInfo, iInput);
  345.                                         event.nParam[2] = INT_PTR(value.c_str());
  346.                                         pEntity->SendEvent(event);
  347.                                         break;
  348.                                 }
  349.                         case eFDT_Bool:
  350.                                 {
  351.                                         event.nParam[1] = INT_PTR(IEntityEventHandler::Bool);
  352.                                         const bool value = GetPortBool(pActInfo, iInput);
  353.                                         event.nParam[2] = INT_PTR(&value);
  354.                                         pEntity->SendEvent(event);
  355.                                         break;
  356.                                 }
  357.                         }
  358.                 }
  359.         }
  360. }
  361.  
  362. //////////////////////////////////////////////////////////////////////////
  363. void CFlowEntityNode::OnEntityEvent(IEntity* pEntity, SEntityEvent& event)
  364. {
  365.         if (!m_pGraph->IsEnabled() || m_pGraph->IsSuspended() || !m_pGraph->IsActive())
  366.                 return;
  367.  
  368.         switch (event.event)
  369.         {
  370.         case ENTITY_EVENT_DONE:
  371.                 // The entity being destroyed is not always the entity stored in the input of the node (which is what actually is Get/Set by those functions ).
  372.                 // In the case of AIWaves, when the node is forwarded to newly spawned entities, this event will be called when those spawned entities are destroyed. But
  373.                 //  but the input will still be the original entityId. And should not be zeroed, or the node will stop working after a reset (this only can happen on editor mode)
  374.                 if (m_pGraph->GetEntityId(m_nodeID) == pEntity->GetId())
  375.                         m_pGraph->SetEntityId(m_nodeID, 0);
  376.                 break;
  377.  
  378.         case ENTITY_EVENT_SCRIPT_EVENT:
  379.                 {
  380.                         const char* sEvent = (const char*)event.nParam[0];
  381.                         // Find output port.
  382.                         for (int i = 0; i < m_pClass->m_outputs.size(); i++)
  383.                         {
  384.                                 if (!m_pClass->m_outputs[i].name)
  385.                                         break;
  386.                                 if (strcmp(sEvent, m_pClass->m_outputs[i].name) == 0)
  387.                                 {
  388.                                         SFlowAddress addr(m_nodeID, i, true);
  389.                                         switch (event.nParam[1])
  390.                                         {
  391.                                         case IEntityClass::EVT_INT:
  392.                                                 assert(event.nParam[2] && "Attempt to activate FlowGraph port of type int without value");
  393.                                                 m_pGraph->ActivatePort(addr, *(int*)event.nParam[2]);
  394.                                                 break;
  395.                                         case IEntityClass::EVT_FLOAT:
  396.                                                 assert(event.nParam[2] && "Attempt to activate FlowGraph port of type float without value");
  397.                                                 m_pGraph->ActivatePort(addr, *(float*)event.nParam[2]);
  398.                                                 break;
  399.                                         case IEntityClass::EVT_BOOL:
  400.                                                 assert(event.nParam[2] && "Attempt to activate FlowGraph port of type bool without value");
  401.                                                 m_pGraph->ActivatePort(addr, *(bool*)event.nParam[2]);
  402.                                                 break;
  403.                                         case IEntityClass::EVT_VECTOR:
  404.                                                 assert(event.nParam[2] && "Attempt to activate FlowGraph port of type Vec3 without value");
  405.                                                 m_pGraph->ActivatePort(addr, *(Vec3*)event.nParam[2]);
  406.                                                 break;
  407.                                         case IEntityClass::EVT_ENTITY:
  408.                                                 assert(event.nParam[2] && "Attempt to activate FlowGraph port of type EntityId without value");
  409.                                                 m_pGraph->ActivatePort(addr, *(EntityId*)event.nParam[2]);
  410.                                                 break;
  411.                                         case IEntityClass::EVT_STRING:
  412.                                                 {
  413.                                                         assert(event.nParam[2] && "Attempt to activate FlowGraph port of type string without value");
  414.                                                         const char* str = (const char*)event.nParam[2];
  415.                                                         m_pGraph->ActivatePort(addr, string(str));
  416.                                                 }
  417.                                                 break;
  418.                                         }
  419.                                         //m_pGraph->ActivatePort( addr,(bool)true );
  420.                                         break;
  421.                                 }
  422.                         }
  423.                 }
  424.                 break;
  425.         }
  426. }
  427.  
  428. //////////////////////////////////////////////////////////////////////////
  429. // Flow node for entity position.
  430. //////////////////////////////////////////////////////////////////////////
  431. class CFlowNode_EntityPos : public CFlowEntityNodeBase
  432. {
  433. public:
  434.         enum EInputs
  435.         {
  436.                 IN_POS,
  437.                 IN_ROTATE,
  438.                 IN_SCALE,
  439.                 IN_COORDSYS,
  440.         };
  441.         enum EOutputs
  442.         {
  443.                 OUT_POS,
  444.                 OUT_ROTATE,
  445.                 OUT_SCALE,
  446.                 OUT_YDIR,
  447.                 OUT_XDIR,
  448.                 OUT_ZDIR,
  449.         };
  450.         enum ECoordSys
  451.         {
  452.                 CS_PARENT = 0,
  453.                 CS_WORLD,
  454.         };
  455.  
  456.         enum { ALL_VALUES = ENTITY_XFORM_POS | ENTITY_XFORM_ROT | ENTITY_XFORM_SCL };
  457.  
  458.         CFlowNode_EntityPos(SActivationInfo* pActInfo)
  459.                 : CFlowEntityNodeBase()
  460.                 , m_pGraph(NULL)
  461.                 , m_nodeName(NULL)
  462.         {
  463.                 m_event = ENTITY_EVENT_XFORM;
  464.         }
  465.  
  466.         virtual IFlowNodePtr Clone(SActivationInfo* pActInfo) { pActInfo->m_pUserData = (void*)(UINT_PTR)m_entityId; return new CFlowNode_EntityPos(pActInfo); };
  467.         virtual void         GetConfiguration(SFlowNodeConfig& config)
  468.         {
  469.                 static const SInputPortConfig in_config[] = {
  470.                         InputPortConfig<Vec3>("pos",     _HELP("Entity position vector")),
  471.                         InputPortConfig<Vec3>("rotate",  _HELP("Entity rotation angle in degrees")),
  472.                         InputPortConfig<Vec3>("scale",   _HELP("Entity scale vector")),
  473.                         InputPortConfig<int>("CoordSys", 1,                                         _HELP("In which coordinate system the values are expressed"),_HELP("CoordSys"), _UICONFIG("enum_int:Parent=0,World=1")),
  474.                         { 0 }
  475.                 };
  476.                 static const SOutputPortConfig out_config[] = {
  477.                         OutputPortConfig<Vec3>("pos",      _HELP("Entity position vector")),
  478.                         OutputPortConfig<Vec3>("rotate",   _HELP("Entity rotation angle in degrees")),
  479.                         OutputPortConfig<Vec3>("scale",    _HELP("Entity scale vector")),
  480.                         OutputPortConfig<Vec3>("fwdDir",   _HELP("Entity direction vector - Y axis")),
  481.                         OutputPortConfig<Vec3>("rightDir", _HELP("Entity direction vector - X axis")),
  482.                         OutputPortConfig<Vec3>("upDir",    _HELP("Entity direction vector - Z axis")),
  483.                         { 0 }
  484.                 };
  485.                 config.sDescription = _HELP("Entity Position/Rotation/Scale");
  486.                 config.nFlags |= EFLN_TARGET_ENTITY | EFLN_AISEQUENCE_SUPPORTED;
  487.                 if (!ShouldShowInEditorList())
  488.                         config.nFlags |= EFLN_HIDE_UI;
  489.                 config.pInputPorts = in_config;
  490.                 config.pOutputPorts = out_config;
  491.                 config.SetCategory(EFLN_APPROVED);
  492.         }
  493.  
  494.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  495.         {
  496.                 CFlowEntityNodeBase::ProcessEvent(event, pActInfo);
  497.  
  498.                 IEntity* pEntity = GetEntity();
  499.                 if (!pEntity)
  500.                         return;
  501.  
  502.                 switch (event)
  503.                 {
  504.                 case eFE_Activate:
  505.                         {
  506.                                 ECoordSys coorSys = (ECoordSys)GetPortInt(pActInfo, IN_COORDSYS);
  507.  
  508.                                 if (IsPortActive(pActInfo, IN_POS))
  509.                                 {
  510.                                         const Vec3* v = pActInfo->pInputPorts[IN_POS].GetPtr<Vec3>();
  511.                                         if (coorSys == CS_WORLD)
  512.                                         {
  513.                                                 Matrix34 tm = pEntity->GetWorldTM();
  514.                                                 tm.SetTranslation(*v);
  515.                                                 pEntity->SetWorldTM(tm);
  516.                                         }
  517.                                         else
  518.                                         {
  519.                                                 Matrix34 tm = pEntity->GetLocalTM();
  520.                                                 tm.SetTranslation(*v);
  521.                                                 pEntity->SetLocalTM(tm);
  522.                                         }
  523.                                 }
  524.                                 if (IsPortActive(pActInfo, IN_ROTATE))
  525.                                 {
  526.                                         const Vec3* v = pActInfo->pInputPorts[IN_ROTATE].GetPtr<Vec3>();
  527.                                         Matrix34 tm = Matrix33(Quat::CreateRotationXYZ(Ang3(DEG2RAD(*v))));
  528.                                         if (coorSys == CS_WORLD)
  529.                                         {
  530.                                                 tm.SetTranslation(pEntity->GetWorldPos());
  531.                                                 pEntity->SetWorldTM(tm);
  532.                                         }
  533.                                         else
  534.                                         {
  535.                                                 tm.SetTranslation(pEntity->GetPos());
  536.                                                 pEntity->SetLocalTM(tm);
  537.                                         }
  538.                                 }
  539.                                 if (IsPortActive(pActInfo, IN_SCALE))
  540.                                 {
  541.                                         const Vec3* v = pActInfo->pInputPorts[IN_SCALE].GetPtr<Vec3>();
  542.                                         Vec3 scale = *v;
  543.                                         if (scale.x == 0) scale.x = 1.0f;
  544.                                         if (scale.y == 0) scale.y = 1.0f;
  545.                                         if (scale.z == 0) scale.z = 1.0f;
  546.                                         pEntity->SetScale(scale);
  547.                                 }
  548.                         }
  549.                         break;
  550.                 case eFE_Initialize:
  551.                         {
  552.                                 m_pGraph = pActInfo->pGraph;
  553.                                 m_nodeName = m_pGraph->GetNodeName(pActInfo->myID);
  554.                                 OutputValues(pActInfo, ALL_VALUES);
  555.                         }
  556.                         break;
  557.  
  558.                 case eFE_SetEntityId:
  559.                         OutputValues(pActInfo, ALL_VALUES);
  560.                         break;
  561.                 }
  562.         }
  563.  
  564.         //////////////////////////////////////////////////////////////////////////
  565.         // IEntityEventListener
  566.         virtual void OnEntityEvent(IEntity* pEntity, SEntityEvent& event)
  567.         {
  568.                 if (!m_pGraph || !m_pGraph->IsEnabled() || m_pGraph->IsSuspended() || !m_pGraph->IsActive())
  569.                         return;
  570.  
  571.                 switch (event.event)
  572.                 {
  573.                 case ENTITY_EVENT_XFORM:
  574.                         {
  575.                                 IFlowNode::SActivationInfo actInfo;
  576.                                 if (!m_pGraph->GetActivationInfo(m_nodeName, actInfo))
  577.                                         return;
  578.  
  579.                                 OutputValues(&actInfo, uint32(event.nParam[0]));
  580.                         }
  581.                         break;
  582.                 }
  583.         }
  584.  
  585.         void OutputValues(IFlowNode::SActivationInfo* pActInfo, uint entityFlags)
  586.         {
  587.                 ECoordSys coorSys = (ECoordSys)GetPortInt(pActInfo, IN_COORDSYS);
  588.  
  589.                 bool bAny = (entityFlags & (ENTITY_XFORM_POS | ENTITY_XFORM_ROT | ENTITY_XFORM_SCL)) == 0;
  590.                 IEntity* pEntity = pActInfo->pEntity;
  591.                 if (!pEntity)
  592.                         return;
  593.  
  594.                 switch (coorSys)
  595.                 {
  596.                 case CS_WORLD:
  597.                         {
  598.                                 if (bAny || entityFlags & ENTITY_XFORM_POS)
  599.                                         ActivateOutput(pActInfo, OUT_POS, pEntity->GetWorldPos());
  600.  
  601.                                 if (bAny || entityFlags & ENTITY_XFORM_ROT)
  602.                                 {
  603.                                         ActivateOutput(pActInfo, OUT_ROTATE, Vec3(RAD2DEG(Ang3(pEntity->GetWorldAngles()))));
  604.                                         const Matrix34& mat = pEntity->GetWorldTM();
  605.                                         ActivateOutput(pActInfo, OUT_YDIR, mat.GetColumn1()); // forward -> mat.TransformVector(Vec3(0,1,0)) );
  606.                                         ActivateOutput(pActInfo, OUT_XDIR, mat.GetColumn0()); // right   -> mat.TransformVector(Vec3(1,0,0)) );
  607.                                         ActivateOutput(pActInfo, OUT_ZDIR, mat.GetColumn2()); // up      -> mat.TransformVector(Vec3(0,0,1)) );
  608.                                 }
  609.  
  610.                                 if (bAny || entityFlags & ENTITY_XFORM_SCL)
  611.                                         ActivateOutput(pActInfo, OUT_SCALE, pEntity->GetScale());
  612.                                 break;
  613.                         }
  614.  
  615.                 case CS_PARENT:
  616.                         {
  617.                                 if (bAny || entityFlags & ENTITY_XFORM_POS)
  618.                                         ActivateOutput(pActInfo, OUT_POS, pEntity->GetPos());
  619.  
  620.                                 if (bAny || entityFlags & ENTITY_XFORM_ROT)
  621.                                 {
  622.                                         ActivateOutput(pActInfo, OUT_ROTATE, Vec3(RAD2DEG(Ang3::GetAnglesXYZ(pEntity->GetLocalTM()))));
  623.                                         const Matrix34& mat = pEntity->GetLocalTM();
  624.                                         ActivateOutput(pActInfo, OUT_YDIR, mat.GetColumn1()); // forward -> mat.TransformVector(Vec3(0,1,0)) );
  625.                                         ActivateOutput(pActInfo, OUT_XDIR, mat.GetColumn0()); // right   -> mat.TransformVector(Vec3(1,0,0)) );
  626.                                         ActivateOutput(pActInfo, OUT_ZDIR, mat.GetColumn2()); // up      -> mat.TransformVector(Vec3(0,0,1)) );
  627.                                 }
  628.  
  629.                                 if (bAny || entityFlags & ENTITY_XFORM_SCL)
  630.                                         ActivateOutput(pActInfo, OUT_SCALE, pEntity->GetScale());
  631.                                 break;
  632.                         }
  633.                 }
  634.         }
  635.  
  636.         virtual bool ShouldShowInEditorList() { return true; }
  637.  
  638.         //////////////////////////////////////////////////////////////////////////
  639.  
  640. protected:
  641.         IFlowGraph* m_pGraph;
  642.         const char* m_nodeName;
  643. };
  644.  
  645. //////////////////////////////////////////////////////////////////////////
  646. // Flow node for entity tagpoint.
  647. //////////////////////////////////////////////////////////////////////////
  648. class CFlowNode_EntityTagpoint : public CFlowNode_EntityPos
  649. {
  650. public:
  651.         CFlowNode_EntityTagpoint(SActivationInfo* pActInfo) : CFlowNode_EntityPos(pActInfo)
  652.         {
  653.         }
  654.  
  655.         virtual IFlowNodePtr Clone(SActivationInfo* pActInfo) { pActInfo->m_pUserData = (void*)(UINT_PTR)m_entityId; return new CFlowNode_EntityTagpoint(pActInfo); }
  656.  
  657. protected:
  658.         virtual bool ShouldShowInEditorList() { return false; }
  659. };
  660.  
  661. //////////////////////////////////////////////////////////////////////////
  662. // Flow node for entity position.
  663. //////////////////////////////////////////////////////////////////////////
  664. class CFlowNode_EntityGetPos : public CFlowBaseNode<eNCT_Singleton>
  665. {
  666. public:
  667.         enum EInputs
  668.         {
  669.                 IN_GET,
  670.                 IN_COORDSYS,
  671.         };
  672.         enum EOutputs
  673.         {
  674.                 OUT_POS = 0,
  675.                 OUT_ROTATE,
  676.                 OUT_SCALE,
  677.                 OUT_YDIR,
  678.                 OUT_XDIR,
  679.                 OUT_ZDIR,
  680.         };
  681.  
  682.         enum ECoordSys
  683.         {
  684.                 CS_PARENT = 0,
  685.                 CS_WORLD,
  686.         };
  687.  
  688.         CFlowNode_EntityGetPos(SActivationInfo* pActInfo)
  689.         {
  690.         }
  691.  
  692.         virtual void GetConfiguration(SFlowNodeConfig& config)
  693.         {
  694.                 static const SInputPortConfig in_config[] = {
  695.                         InputPortConfig_Void("Get",      _HELP("Trigger to get current values")),
  696.                         InputPortConfig<int>("CoordSys", 1,                                      _HELP("In which coordinate system the values are expressed"),_HELP("CoordSys"), _UICONFIG("enum_int:Parent=0,World=1")),
  697.                         { 0 }
  698.                 };
  699.                 static const SOutputPortConfig out_config[] = {
  700.                         OutputPortConfig<Vec3>("Pos",      _HELP("Entity position vector")),
  701.                         OutputPortConfig<Vec3>("Rotate",   _HELP("Entity rotation angle in degrees")),
  702.                         OutputPortConfig<Vec3>("Scale",    _HELP("Entity scale vector")),
  703.                         OutputPortConfig<Vec3>("FwdDir",   _HELP("Entity direction vector - Y axis")),
  704.                         OutputPortConfig<Vec3>("RightDir", _HELP("Entity direction vector - X axis")),
  705.                         OutputPortConfig<Vec3>("UpDir",    _HELP("Entity direction vector - Z axis")),
  706.                         { 0 }
  707.                 };
  708.                 config.sDescription = _HELP("Get Entity Position/Rotation/Scale");
  709.                 config.nFlags |= EFLN_TARGET_ENTITY | EFLN_AISEQUENCE_SUPPORTED;
  710.                 config.pInputPorts = in_config;
  711.                 config.pOutputPorts = out_config;
  712.                 config.SetCategory(EFLN_APPROVED);
  713.         }
  714.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  715.         {
  716.                 if (event != eFE_Activate || IsPortActive(pActInfo, IN_GET) == false)
  717.                         return;
  718.                 // only if IN_GET is activated.
  719.  
  720.                 IEntity* pEntity = pActInfo->pEntity;
  721.                 if (pEntity == 0)
  722.                         return;
  723.  
  724.                 ECoordSys coorSys = (ECoordSys)GetPortInt(pActInfo, IN_COORDSYS);
  725.  
  726.                 switch (coorSys)
  727.                 {
  728.                 case CS_WORLD:
  729.                         {
  730.                                 ActivateOutput(pActInfo, OUT_POS, pEntity->GetWorldPos());
  731.                                 ActivateOutput(pActInfo, OUT_ROTATE, Vec3(RAD2DEG(Ang3(pEntity->GetWorldAngles()))));
  732.                                 ActivateOutput(pActInfo, OUT_SCALE, pEntity->GetScale());
  733.  
  734.                                 const Matrix34& mat = pEntity->GetWorldTM();
  735.                                 ActivateOutput(pActInfo, OUT_YDIR, mat.GetColumn1());  // forward -> mat.TransformVector(Vec3(0,1,0)) );
  736.                                 ActivateOutput(pActInfo, OUT_XDIR, mat.GetColumn0());  // right   -> mat.TransformVector(Vec3(1,0,0)) );
  737.                                 ActivateOutput(pActInfo, OUT_ZDIR, mat.GetColumn2());  // up      -> mat.TransformVector(Vec3(0,0,1)) );
  738.                                 break;
  739.                         }
  740.  
  741.                 case CS_PARENT:
  742.                         {
  743.                                 ActivateOutput(pActInfo, OUT_POS, pEntity->GetPos());
  744.                                 ActivateOutput(pActInfo, OUT_ROTATE, Vec3(RAD2DEG(Ang3::GetAnglesXYZ(pEntity->GetLocalTM()))));
  745.                                 ActivateOutput(pActInfo, OUT_SCALE, pEntity->GetScale());
  746.  
  747.                                 const Matrix34& mat = pEntity->GetLocalTM();
  748.                                 ActivateOutput(pActInfo, OUT_YDIR, mat.GetColumn1());  // forward -> mat.TransformVector(Vec3(0,1,0)) );
  749.                                 ActivateOutput(pActInfo, OUT_XDIR, mat.GetColumn0());  // right   -> mat.TransformVector(Vec3(1,0,0)) );
  750.                                 ActivateOutput(pActInfo, OUT_ZDIR, mat.GetColumn2());  // up      -> mat.TransformVector(Vec3(0,0,1)) );
  751.                                 break;
  752.                         }
  753.  
  754.                 }
  755.         }
  756.  
  757.         virtual void GetMemoryUsage(ICrySizer* s) const
  758.         {
  759.                 s->Add(*this);
  760.         }
  761.  
  762. };
  763.  
  764. //////////////////////////////////////////////////////////////////////////
  765. class CFlowNode_EntityCheckDistance : public CFlowBaseNode<eNCT_Singleton>
  766. {
  767. public:
  768.         enum EInputs
  769.         {
  770.                 INP_CHECK,
  771.                 INP_MIN_DIST,
  772.                 INP_MAX_DIST,
  773.                 INP_ENT00,
  774.                 INP_ENT01,
  775.                 INP_ENT02,
  776.                 INP_ENT03,
  777.                 INP_ENT04,
  778.                 INP_ENT05,
  779.                 INP_ENT06,
  780.                 INP_ENT07,
  781.                 INP_ENT08,
  782.                 INP_ENT09,
  783.                 INP_ENT10,
  784.                 INP_ENT11,
  785.                 INP_ENT12,
  786.                 INP_ENT13,
  787.                 INP_ENT14,
  788.                 INP_ENT15,
  789.         };
  790.         enum EOutputs
  791.         {
  792.                 OUT_NEAR_ENT = 0,
  793.                 OUT_NEAR_ENT_DIST,
  794.                 OUT_FAR_ENT,
  795.                 OUT_FAR_ENT_DIST,
  796.                 OUT_NOENTITIES_IN_RANGE,
  797.         };
  798.  
  799.         CFlowNode_EntityCheckDistance(SActivationInfo* pActInfo)
  800.         {
  801.         }
  802.  
  803.         virtual void GetConfiguration(SFlowNodeConfig& config)
  804.         {
  805.                 static const SInputPortConfig in_config[] = {
  806.                         InputPortConfig_Void("Check",         _HELP("Trigger to check distances")),
  807.                         InputPortConfig<float>("MinDistance", _HELP("Any entity that is nearer than this, will be ignored")),
  808.                         InputPortConfig<float>("MaxDistance", _HELP("Any entity that is farther than this, will be ignored (0=no limit)")),
  809.                         InputPortConfig<EntityId>("Entity1",  _HELP("EntityID")),
  810.                         InputPortConfig<EntityId>("Entity2",  _HELP("EntityID")),
  811.                         InputPortConfig<EntityId>("Entity3",  _HELP("EntityID")),
  812.                         InputPortConfig<EntityId>("Entity4",  _HELP("EntityID")),
  813.                         InputPortConfig<EntityId>("Entity5",  _HELP("EntityID")),
  814.                         InputPortConfig<EntityId>("Entity6",  _HELP("EntityID")),
  815.                         InputPortConfig<EntityId>("Entity7",  _HELP("EntityID")),
  816.                         InputPortConfig<EntityId>("Entity8",  _HELP("EntityID")),
  817.                         InputPortConfig<EntityId>("Entity9",  _HELP("EntityID")),
  818.                         InputPortConfig<EntityId>("Entity10", _HELP("EntityID")),
  819.                         InputPortConfig<EntityId>("Entity11", _HELP("EntityID")),
  820.                         InputPortConfig<EntityId>("Entity12", _HELP("EntityID")),
  821.                         InputPortConfig<EntityId>("Entity13", _HELP("EntityID")),
  822.                         InputPortConfig<EntityId>("Entity14", _HELP("EntityID")),
  823.                         InputPortConfig<EntityId>("Entity15", _HELP("EntityID")),
  824.                         InputPortConfig<EntityId>("Entity16", _HELP("EntityID")),
  825.                         { 0 }
  826.                 };
  827.                 static const SOutputPortConfig out_config[] = {
  828.                         OutputPortConfig<EntityId>("NearEntity",  _HELP("Nearest entity")),
  829.                         OutputPortConfig<float>("NearEntityDist", _HELP("Nearest entity distance")),
  830.                         OutputPortConfig<EntityId>("FarEntity",   _HELP("Farthest entity")),
  831.                         OutputPortConfig<float>("FarEntityDist",  _HELP("Farthest entity distance")),
  832.                         OutputPortConfig_AnyType("NoEntInRange",  _HELP("Trigered when none of the entities were between Min and Max distance")),
  833.                         { 0 }
  834.                 };
  835.                 config.sDescription = _HELP("Check distance between the node entity and the entities defined in the inputs");
  836.                 config.nFlags |= EFLN_TARGET_ENTITY | EFLN_AISEQUENCE_SUPPORTED;
  837.                 config.pInputPorts = in_config;
  838.                 config.pOutputPorts = out_config;
  839.                 config.SetCategory(EFLN_APPROVED);
  840.         }
  841.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  842.         {
  843.                 if (event != eFE_Activate || !IsPortActive(pActInfo, INP_CHECK))
  844.                         return;
  845.  
  846.                 IEntity* pEntityNode = pActInfo->pEntity;
  847.                 if (!pEntityNode)
  848.                         return;
  849.  
  850.                 float minRangeDist = GetPortFloat(pActInfo, INP_MIN_DIST);
  851.                 float maxRangeDist = GetPortFloat(pActInfo, INP_MAX_DIST);
  852.                 float minRangeDist2 = minRangeDist * minRangeDist;
  853.                 float maxRangeDist2 = maxRangeDist * maxRangeDist;
  854.                 if (maxRangeDist2 == 0)
  855.                         maxRangeDist2 = FLT_MAX;
  856.  
  857.                 EntityId minEnt = 0;
  858.                 EntityId maxEnt = 0;
  859.                 float minDist2 = maxRangeDist2;
  860.                 float maxDist2 = minRangeDist2;
  861.                 bool anyEntityInRange = false;
  862.  
  863.                 for (uint32 i = INP_ENT00; i <= INP_ENT15; ++i)
  864.                 {
  865.                         EntityId entityIdCheck = GetPortEntityId(pActInfo, i);
  866.                         IEntity* pEntityCheck = gEnv->pEntitySystem->GetEntity(entityIdCheck);
  867.                         if (pEntityCheck)
  868.                         {
  869.                                 float dist2 = pEntityCheck->GetPos().GetSquaredDistance(pEntityNode->GetPos());
  870.                                 if (dist2 >= minRangeDist2 && dist2 <= maxRangeDist2)
  871.                                 {
  872.                                         anyEntityInRange = true;
  873.                                         if (dist2 <= minDist2)
  874.                                         {
  875.                                                 minDist2 = dist2;
  876.                                                 minEnt = entityIdCheck;
  877.                                         }
  878.                                         if (dist2 >= maxDist2)
  879.                                         {
  880.                                                 maxDist2 = dist2;
  881.                                                 maxEnt = entityIdCheck;
  882.                                         }
  883.                                 }
  884.                         }
  885.                 }
  886.  
  887.                 if (anyEntityInRange)
  888.                 {
  889.                         ActivateOutput(pActInfo, OUT_NEAR_ENT, minEnt);
  890.                         ActivateOutput(pActInfo, OUT_NEAR_ENT_DIST, sqrtf(minDist2));
  891.  
  892.                         ActivateOutput(pActInfo, OUT_FAR_ENT, maxEnt);
  893.                         ActivateOutput(pActInfo, OUT_FAR_ENT_DIST, sqrtf(maxDist2));
  894.                 }
  895.                 else
  896.                         ActivateOutput(pActInfo, OUT_NOENTITIES_IN_RANGE, true);
  897.         }
  898.  
  899.         virtual void GetMemoryUsage(ICrySizer* s) const
  900.         {
  901.                 s->Add(*this);
  902.         }
  903.  
  904. };
  905.  
  906. //////////////////////////////////////////////////////////////////////////
  907. class CFlowNode_EntityCheckProjection : public CFlowBaseNode<eNCT_Instanced>
  908. {
  909. public:
  910.         enum EInputs
  911.         {
  912.                 INP_ENABLED = 0,
  913.                 INP_OUT_TYPE,
  914.                 INP_MAX_ANGLE_THRESHOLD,
  915.                 INP_SORT,
  916.                 INP_SHOW_DEBUG,
  917.                 INP_ENT01,
  918.                 INP_ENT02,
  919.                 INP_ENT03,
  920.                 INP_ENT04,
  921.                 INP_ENT05,
  922.                 INP_ENT06,
  923.                 INP_ENT07,
  924.                 INP_ENT08,
  925.                 INP_ENT09,
  926.                 INP_ENT10,
  927.                 INP_ENT11,
  928.                 INP_ENT12,
  929.                 INP_ENT13,
  930.                 INP_ENT14,
  931.                 INP_ENT15,
  932.                 INP_ENT16,
  933.                 INP_FIRST_ENTITY_IDX = INP_ENT01,
  934.                 INP_LAST_ENTITY_IDX  = INP_ENT16,
  935.         };
  936.         enum EOutputs
  937.         {
  938.                 OUT_BEST_ENT = 0,
  939.                 OUT_BEST_ENT_PROJ_VALUE,
  940.                 OUT_BEST_ENT_CHANGED,
  941.                 OUT_ENT01,
  942.                 OUT_ENT01_PROJ,
  943.                 OUT_ENT02,
  944.                 OUT_ENT02_PROJ,
  945.                 OUT_ENT03,
  946.                 OUT_ENT03_PROJ,
  947.                 OUT_ENT04,
  948.                 OUT_ENT04_PROJ,
  949.                 OUT_ENT05,
  950.                 OUT_ENT05_PROJ,
  951.                 OUT_ENT06,
  952.                 OUT_ENT06_PROJ,
  953.                 OUT_ENT07,
  954.                 OUT_ENT07_PROJ,
  955.                 OUT_ENT08,
  956.                 OUT_ENT08_PROJ,
  957.                 OUT_ENT09,
  958.                 OUT_ENT09_PROJ,
  959.                 OUT_ENT10,
  960.                 OUT_ENT10_PROJ,
  961.                 OUT_ENT11,
  962.                 OUT_ENT11_PROJ,
  963.                 OUT_ENT12,
  964.                 OUT_ENT12_PROJ,
  965.                 OUT_ENT13,
  966.                 OUT_ENT13_PROJ,
  967.                 OUT_ENT14,
  968.                 OUT_ENT14_PROJ,
  969.                 OUT_ENT15,
  970.                 OUT_ENT15_PROJ,
  971.                 OUT_ENT16,
  972.                 OUT_ENT16_PROJ,
  973.  
  974.                 OUT_FIRST_ENTITY_IDX = OUT_ENT01,
  975.                 OUT_LAST_ENTITY_IDX  = OUT_ENT16,
  976.         };
  977.  
  978.         enum EProjectionOutput
  979.         {
  980.                 ePO_AngleDegrees = 0,
  981.                 ePO_Percentage
  982.         };
  983.  
  984.         CFlowNode_EntityCheckProjection(SActivationInfo* pActInfo) : m_storedBestEntityId(0)
  985.         {
  986.         }
  987.  
  988.         virtual IFlowNodePtr Clone(SActivationInfo* pActInfo)
  989.         {
  990.                 return new CFlowNode_EntityCheckProjection(pActInfo);
  991.         };
  992.  
  993.         // x1, x2, y1, y2 = pixel coordinates
  994.         void UtilDraw2DLine(float x1, float y1, float x2, float y2, const ColorF& color, float thickness)
  995.         {
  996.                 IRenderer* pRenderer = gEnv->pRenderer;
  997.                 int w = pRenderer->GetWidth();
  998.                 int h = pRenderer->GetHeight();
  999.                 float dx = 1.0f / w;
  1000.                 float dy = 1.0f / h;
  1001.                 x1 *= dx;
  1002.                 x2 *= dx;
  1003.                 y1 *= dy;
  1004.                 y2 *= dy;
  1005.  
  1006.                 ColorB col((uint8)(color.r * 255.0f), (uint8)(color.g * 255.0f), (uint8)(color.b * 255.0f), (uint8)(color.a * 255.0f));
  1007.  
  1008.                 IRenderAuxGeom* pAux = pRenderer->GetIRenderAuxGeom();
  1009.                 SAuxGeomRenderFlags flags = pAux->GetRenderFlags();
  1010.                 SAuxGeomRenderFlags renderFlagsRestore = flags;
  1011.                 flags.SetMode2D3DFlag(e_Mode2D);
  1012.                 flags.SetDrawInFrontMode(e_DrawInFrontOn);
  1013.                 flags.SetDepthTestFlag(e_DepthTestOff);
  1014.                 flags.SetCullMode(e_CullModeNone);
  1015.                 flags.SetDepthWriteFlag(e_DepthWriteOff);
  1016.                 pAux->SetRenderFlags(flags);
  1017.                 pAux->DrawLine(Vec3(x1, y1, 0), col, Vec3(x2, y2, 0), col, thickness);
  1018.  
  1019.                 // restore render flags
  1020.                 pAux->SetRenderFlags(renderFlagsRestore);
  1021.         }
  1022.  
  1023.         virtual void GetConfiguration(SFlowNodeConfig& config)
  1024.         {
  1025.                 static const SInputPortConfig in_config[] = {
  1026.                         InputPortConfig<bool>("Enable",       false,              _HELP("Enable the node's update")),
  1027.                         InputPortConfig<int>("Output",        0,                  _HELP("OutputType"),                                              _HELP("Output Type"),_UICONFIG("enum_int:Angle(Degrees)=0,Percentage=1")),
  1028.                         InputPortConfig<float>("Threshold",   10,                 _HELP("Maximum Projection Angle to consider an entity in range")),
  1029.                         InputPortConfig<bool>("Sort",         false,              _HELP("Sorts the output from best to worst projection")),
  1030.                         InputPortConfig<bool>("Debug",        false,              _HELP("Shows debug information")),
  1031.                         InputPortConfig<EntityId>("Entity1",  _HELP("EntityID")),
  1032.                         InputPortConfig<EntityId>("Entity2",  _HELP("EntityID")),
  1033.                         InputPortConfig<EntityId>("Entity3",  _HELP("EntityID")),
  1034.                         InputPortConfig<EntityId>("Entity4",  _HELP("EntityID")),
  1035.                         InputPortConfig<EntityId>("Entity5",  _HELP("EntityID")),
  1036.                         InputPortConfig<EntityId>("Entity6",  _HELP("EntityID")),
  1037.                         InputPortConfig<EntityId>("Entity7",  _HELP("EntityID")),
  1038.                         InputPortConfig<EntityId>("Entity8",  _HELP("EntityID")),
  1039.                         InputPortConfig<EntityId>("Entity9",  _HELP("EntityID")),
  1040.                         InputPortConfig<EntityId>("Entity10", _HELP("EntityID")),
  1041.                         InputPortConfig<EntityId>("Entity11", _HELP("EntityID")),
  1042.                         InputPortConfig<EntityId>("Entity12", _HELP("EntityID")),
  1043.                         InputPortConfig<EntityId>("Entity13", _HELP("EntityID")),
  1044.                         InputPortConfig<EntityId>("Entity14", _HELP("EntityID")),
  1045.                         InputPortConfig<EntityId>("Entity15", _HELP("EntityID")),
  1046.                         InputPortConfig<EntityId>("Entity16", _HELP("EntityID")),
  1047.                         { 0 }
  1048.                 };
  1049.                 static const SOutputPortConfig out_config[] = {
  1050.                         OutputPortConfig<EntityId>("Best Entity",       _HELP("EntityID with the best projection or 0 if no entity is in range")),
  1051.                         OutputPortConfig<float>("Best Projection",      _HELP("Best projection (in degrees or percentage). If no entity is in range then 180 degrees or 0 percentage")),
  1052.                         OutputPortConfig_AnyType("Best Entity Changed", _HELP("Triggered when the best entity changes")),
  1053.                         OutputPortConfig<EntityId>("Entity1",           _HELP("EntityID")),
  1054.                         OutputPortConfig<float>("Entity1 Projection",   _HELP("Entity's projection (in degrees or percentage)")),
  1055.                         OutputPortConfig<EntityId>("Entity2",           _HELP("EntityID")),
  1056.                         OutputPortConfig<float>("Entity2 Projection",   _HELP("Entity's projection (in degrees or percentage)")),
  1057.                         OutputPortConfig<EntityId>("Entity3",           _HELP("EntityID")),
  1058.                         OutputPortConfig<float>("Entity3 Projection",   _HELP("Entity's projection (in degrees or percentage)")),
  1059.                         OutputPortConfig<EntityId>("Entity4",           _HELP("EntityID")),
  1060.                         OutputPortConfig<float>("Entity4 Projection",   _HELP("Entity's projection (in degrees or percentage)")),
  1061.                         OutputPortConfig<EntityId>("Entity5",           _HELP("EntityID")),
  1062.                         OutputPortConfig<float>("Entity5 Projection",   _HELP("Entity's projection (in degrees or percentage)")),
  1063.                         OutputPortConfig<EntityId>("Entity6",           _HELP("EntityID")),
  1064.                         OutputPortConfig<float>("Entity6 Projection",   _HELP("Entity's projection (in degrees or percentage)")),
  1065.                         OutputPortConfig<EntityId>("Entity7",           _HELP("EntityID")),
  1066.                         OutputPortConfig<float>("Entity7 Projection",   _HELP("Entity's projection (in degrees or percentage)")),
  1067.                         OutputPortConfig<EntityId>("Entity8",           _HELP("EntityID")),
  1068.                         OutputPortConfig<float>("Entity8 Projection",   _HELP("Entity's projection (in degrees or percentage)")),
  1069.                         OutputPortConfig<EntityId>("Entity9",           _HELP("EntityID")),
  1070.                         OutputPortConfig<float>("Entity9 Projection",   _HELP("Entity's projection (in degrees or percentage)")),
  1071.                         OutputPortConfig<EntityId>("Entity10",          _HELP("EntityID")),
  1072.                         OutputPortConfig<float>("Entity10 Projection",  _HELP("Entity's projection (in degrees or percentage)")),
  1073.                         OutputPortConfig<EntityId>("Entity11",          _HELP("EntityID")),
  1074.                         OutputPortConfig<float>("Entity11 Projection",  _HELP("Entity's projection (in degrees or percentage)")),
  1075.                         OutputPortConfig<EntityId>("Entity12",          _HELP("EntityID")),
  1076.                         OutputPortConfig<float>("Entity12 Projection",  _HELP("Entity's projection (in degrees or percentage)")),
  1077.                         OutputPortConfig<EntityId>("Entity13",          _HELP("EntityID")),
  1078.                         OutputPortConfig<float>("Entity13 Projection",  _HELP("Entity's projection (in degrees or percentage)")),
  1079.                         OutputPortConfig<EntityId>("Entity14",          _HELP("EntityID")),
  1080.                         OutputPortConfig<float>("Entity14 Projection",  _HELP("Entity's projection (in degrees or percentage)")),
  1081.                         OutputPortConfig<EntityId>("Entity15",          _HELP("EntityID")),
  1082.                         OutputPortConfig<float>("Entity15 Projection",  _HELP("Entity's projection (in degrees or percentage)")),
  1083.                         OutputPortConfig<EntityId>("Entity16",          _HELP("EntityID")),
  1084.                         OutputPortConfig<float>("Entity16 Projection",  _HELP("Entity's projection (in degrees or percentage)")),
  1085.                         { 0 }
  1086.                 };
  1087.                 config.sDescription = _HELP("Check projection between the node's target entity forward direction (or the camera's view direction if not target entity selected) and the entities defined in the inputs");
  1088.                 config.nFlags |= EFLN_TARGET_ENTITY;
  1089.                 config.pInputPorts = in_config;
  1090.                 config.pOutputPorts = out_config;
  1091.                 config.SetCategory(EFLN_APPROVED);
  1092.         }
  1093.  
  1094.         float CalculateOutputValue(int outputType, float projectionAngleDegrees, float maxAngleDegrees)
  1095.         {
  1096.                 float maxAngle = maxAngleDegrees > 0.f ? maxAngleDegrees : 0.0001f;
  1097.                 return outputType == ePO_AngleDegrees ? projectionAngleDegrees : CLAMP((maxAngleDegrees - projectionAngleDegrees) * 100.f / maxAngle, 0.f, 100.f);
  1098.         }
  1099.  
  1100.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  1101.         {
  1102.                 switch (event)
  1103.                 {
  1104.                 case eFE_Initialize:
  1105.                         {
  1106.                                 if (pActInfo->pGraph != nullptr)
  1107.                                 {
  1108.                                         const bool enabled = GetPortBool(pActInfo, INP_ENABLED);
  1109.                                         pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, enabled);
  1110.                                         m_storedBestEntityId = 0;
  1111.                                 }
  1112.                         }
  1113.                         break;
  1114.  
  1115.                 case eFE_Activate:
  1116.                         {
  1117.                                 if (IsPortActive(pActInfo, INP_ENABLED))
  1118.                                 {
  1119.                                         const bool enabled = GetPortBool(pActInfo, INP_ENABLED);
  1120.                                         pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, enabled);
  1121.                                         if (enabled)
  1122.                                                 m_storedBestEntityId = 0; // reset best entity id just after enabling the node
  1123.                                 }
  1124.                         }
  1125.                         break;
  1126.  
  1127.                 case eFE_Update:
  1128.                         {
  1129.                                 const float WORST_PROJECTION_ANGLE = 180.f;
  1130.                                 IRenderer* pRenderer = gEnv->pRenderer;
  1131.                                 const IEntity* pEntityNode = pActInfo->pEntity;
  1132.                                 if (pEntityNode == nullptr && pRenderer == nullptr)
  1133.                                         return;
  1134.  
  1135.                                 Vec3 viewDir = pEntityNode ? pEntityNode->GetForwardDir() : Vec3(ZERO);
  1136.                                 Vec3 srcPos = pEntityNode ? pEntityNode->GetWorldPos() : Vec3(ZERO);
  1137.  
  1138.                                 if (pEntityNode == nullptr && pRenderer)
  1139.                                 {
  1140.                                         const CCamera& rCam = pRenderer->GetCamera();
  1141.                                         viewDir = rCam.GetViewdir();
  1142.                                         srcPos = rCam.GetPosition();
  1143.                                 }
  1144.  
  1145. #ifndef _RELEASE
  1146.                                 const bool bDebug = GetPortBool(pActInfo, INP_SHOW_DEBUG);
  1147.  
  1148.                                 // Draw screen's centre if projection done from the camera position
  1149.                                 if (bDebug && pEntityNode == nullptr)
  1150.                                 {
  1151.                                         const float w = static_cast<float>(pRenderer->GetWidth());
  1152.                                         const float h = static_cast<float>(pRenderer->GetHeight());
  1153.                                         const float delta = 0.025f * h;
  1154.                                         const float x = 0.5f * w, y = 0.5f * h;
  1155.                                         const ColorF color(1.f, 1.f, 0.f, 1.f);
  1156.                                         UtilDraw2DLine(x - delta, y, x + delta, y, color, 1.f);
  1157.                                         UtilDraw2DLine(x, y - delta, x, y + delta, color, 1.f);
  1158.                                 }
  1159. #endif
  1160.  
  1161.                                 struct SEntityProjection
  1162.                                 {
  1163.                                         SEntityProjection() : id(-1), proj(FLT_MAX) {}
  1164.                                         EntityId id;
  1165.                                         float    proj;
  1166.                                 };
  1167.  
  1168.                                 const size_t kNumInputs = INP_LAST_ENTITY_IDX - INP_FIRST_ENTITY_IDX + 1;
  1169.                                 SEntityProjection bestResult;                   // entity info with the best projection
  1170.                                 SEntityProjection sortedEntities[kNumInputs];   // array of sorted entities' info based on projection
  1171.  
  1172.                                 bool bAnyEntityInRange = false;
  1173.                                 const bool bSort = GetPortBool(pActInfo, INP_SORT);
  1174.                                 const int outputType = GetPortInt(pActInfo, INP_OUT_TYPE);                                                         // either degrees or percentage
  1175.                                 const float maxAngleDegrees = CLAMP(GetPortFloat(pActInfo, INP_MAX_ANGLE_THRESHOLD), 0.f, WORST_PROJECTION_ANGLE); // max angle clamped to [0..180]
  1176.  
  1177.                                 for (uint32 i = INP_FIRST_ENTITY_IDX; i <= INP_LAST_ENTITY_IDX; ++i)
  1178.                                 {
  1179.                                         bool bEntityInRange = false;
  1180.                                         const uint32 inEntityIndex = i - INP_FIRST_ENTITY_IDX;
  1181.                                         const uint32 outEntityIndex = OUT_FIRST_ENTITY_IDX + inEntityIndex * 2;
  1182.                                         const EntityId currentEntityId = GetPortEntityId(pActInfo, i);
  1183.                                         const IEntity* pCurrentEntity = gEnv->pEntitySystem->GetEntity(currentEntityId);
  1184.  
  1185.                                         float outEntityProjData = 0.f;
  1186.                                         float projAngle = WORST_PROJECTION_ANGLE;
  1187.                                         if (pCurrentEntity)
  1188.                                         {
  1189.                                                 const Vec3 currentEntityPos = pCurrentEntity->GetWorldPos();
  1190.                                                 const Vec3 dirToEntity = (currentEntityPos - srcPos).normalized();
  1191.                                                 projAngle = RAD2DEG(acos(viewDir.dot(dirToEntity))); // [0..180]
  1192.  
  1193.                                                 if (projAngle < maxAngleDegrees)
  1194.                                                 {
  1195.                                                         // entity is in range
  1196.                                                         outEntityProjData = CalculateOutputValue(outputType, projAngle, maxAngleDegrees);
  1197.  
  1198.                                                         if (projAngle < bestResult.proj)
  1199.                                                         {
  1200.                                                                 bestResult.proj = projAngle;
  1201.                                                                 bestResult.id = currentEntityId;
  1202.                                                         }
  1203.  
  1204.                                                         bAnyEntityInRange = true;
  1205.                                                         bEntityInRange = true;
  1206.  
  1207. #ifndef _RELEASE
  1208.                                                         if (bDebug) IRenderAuxText::DrawLabelF(currentEntityPos, 1.5f, "%1.2f%s Id:%d", outEntityProjData, outputType == ePO_AngleDegrees ? "deg" : "%", currentEntityId);
  1209. #endif
  1210.                                                 }
  1211.  
  1212. #ifndef _RELEASE
  1213.                                                 if (bDebug)
  1214.                                                 {
  1215.                                                         if (IRenderAuxGeom* pAux = gEnv->pRenderer->GetIRenderAuxGeom()) pAux->DrawSphere(currentEntityPos, 0.15f, ColorB(0xff, 0xff, 0x00, 0xff));
  1216.                                                 }
  1217. #endif
  1218.                                         }
  1219.  
  1220.                                         if (bEntityInRange == false)
  1221.                                         {
  1222.                                                 // entity not in range or invalid
  1223.                                                 outEntityProjData = outputType == ePO_AngleDegrees ? projAngle : 0.f;
  1224.                                         }
  1225.  
  1226.                                         // if sorting, store info otherwise output directly data for current entity
  1227.                                         if (bSort)
  1228.                                         {
  1229.                                                 sortedEntities[inEntityIndex].id = currentEntityId;
  1230.                                                 sortedEntities[inEntityIndex].proj = outEntityProjData;
  1231.                                         }
  1232.                                         else
  1233.                                         {
  1234.                                                 ActivateOutput(pActInfo, outEntityIndex, currentEntityId);
  1235.                                                 ActivateOutput(pActInfo, outEntityIndex + 1, outEntityProjData);
  1236.                                         }
  1237.                                 }
  1238.  
  1239.                                 // Perform sort and output sorted info (if needed)
  1240.                                 if (bSort)
  1241.                                 {
  1242.                                         std::sort(sortedEntities, sortedEntities + kNumInputs,
  1243.                                                   [outputType](const SEntityProjection& a, const SEntityProjection& b) { return (outputType == ePO_AngleDegrees) ? (a.proj < b.proj) : (a.proj > b.proj); }
  1244.                                                   );
  1245.  
  1246.                                         for (size_t i = 0; i < kNumInputs; ++i)
  1247.                                         {
  1248.                                                 const size_t outEntityIdx = OUT_FIRST_ENTITY_IDX + i * 2;
  1249.                                                 ActivateOutput(pActInfo, outEntityIdx, sortedEntities[i].id);
  1250.                                                 ActivateOutput(pActInfo, outEntityIdx + 1, sortedEntities[i].proj);
  1251.                                         }
  1252.  
  1253.                                 }
  1254.  
  1255.                                 // if no entities in projection range make sure we output a best EntityId = 0
  1256.                                 if (!bAnyEntityInRange || bestResult.id <= 0)
  1257.                                 {
  1258.                                         bestResult.id = 0;
  1259.                                         bestResult.proj = WORST_PROJECTION_ANGLE;
  1260.                                 }
  1261.  
  1262.                                 // Output best entity info
  1263.                                 ActivateOutput(pActInfo, OUT_BEST_ENT, bestResult.id);
  1264.                                 ActivateOutput(pActInfo, OUT_BEST_ENT_PROJ_VALUE, CalculateOutputValue(outputType, bestResult.proj, maxAngleDegrees));
  1265.  
  1266.                                 if (m_storedBestEntityId != bestResult.id)
  1267.                                 {
  1268.                                         ActivateOutput(pActInfo, OUT_BEST_ENT_CHANGED, true);
  1269.                                         m_storedBestEntityId = bestResult.id;
  1270.                                 }
  1271.                         }
  1272.                         break;
  1273.                 }
  1274.         }
  1275.  
  1276.         virtual void GetMemoryUsage(ICrySizer* s) const
  1277.         {
  1278.                 s->Add(*this);
  1279.         }
  1280.  
  1281. private:
  1282.         EntityId m_storedBestEntityId;
  1283.  
  1284. };
  1285.  
  1286. //////////////////////////////////////////////////////////////////////////
  1287. // Flow node to get the AABB of an entity
  1288. //////////////////////////////////////////////////////////////////////////
  1289. class CFlowNode_EntityGetBounds : public CFlowBaseNode<eNCT_Singleton>
  1290. {
  1291. public:
  1292.         enum EInputs
  1293.         {
  1294.                 IN_GET,
  1295.                 IN_COORDSYS
  1296.         };
  1297.  
  1298.         enum EOutputs
  1299.         {
  1300.                 OUT_MIN,
  1301.                 OUT_MAX
  1302.         };
  1303.  
  1304.         enum ECoordSys
  1305.         {
  1306.                 CS_LOCAL,
  1307.                 CS_WORLD,
  1308.         };
  1309.  
  1310.         CFlowNode_EntityGetBounds(SActivationInfo* pActInfo)
  1311.         {
  1312.         }
  1313.  
  1314.         virtual void GetConfiguration(SFlowNodeConfig& config) override
  1315.         {
  1316.                 static const SInputPortConfig inputs[] =
  1317.                 {
  1318.                         InputPortConfig_Void("Get",      _HELP("")),
  1319.                         InputPortConfig<int>("CoordSys", 1,         _HELP("In which coordinate system the values are expressed"),_HELP("CoordSys"), _UICONFIG("enum_int:Local=0,World=1")),
  1320.                         { 0 }
  1321.                 };
  1322.  
  1323.                 static const SOutputPortConfig outputs[] =
  1324.                 {
  1325.                         OutputPortConfig<Vec3>("Min", _HELP("Min position of the AABB")),
  1326.                         OutputPortConfig<Vec3>("Max", _HELP("Max position of the AABB")),
  1327.                         { 0 }
  1328.                 };
  1329.  
  1330.                 config.pInputPorts = inputs;
  1331.                 config.pOutputPorts = outputs;
  1332.                 config.nFlags |= EFLN_TARGET_ENTITY | EFLN_AISEQUENCE_SUPPORTED;
  1333.                 config.sDescription = _HELP("Gets the AABB");
  1334.                 config.SetCategory(EFLN_APPROVED);
  1335.         }
  1336.  
  1337.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo) override
  1338.         {
  1339.                 switch (event)
  1340.                 {
  1341.                 case eFE_Activate:
  1342.                         if (IsPortActive(pActInfo, IN_GET) && pActInfo->pEntity)
  1343.                         {
  1344.                                 AABB aabb(Vec3(0, 0, 0), Vec3(0, 0, 0));
  1345.  
  1346.                                 switch (GetPortInt(pActInfo, IN_COORDSYS))
  1347.                                 {
  1348.                                 case CS_LOCAL:
  1349.                                         pActInfo->pEntity->GetLocalBounds(aabb);
  1350.                                         break;
  1351.  
  1352.                                 case CS_WORLD:
  1353.                                         pActInfo->pEntity->GetWorldBounds(aabb);
  1354.                                         break;
  1355.                                 }
  1356.  
  1357.                                 ActivateOutput(pActInfo, OUT_MIN, aabb.min);
  1358.                                 ActivateOutput(pActInfo, OUT_MAX, aabb.max);
  1359.                         }
  1360.                         break;
  1361.                 }
  1362.         }
  1363.  
  1364.         virtual void GetMemoryUsage(ICrySizer* s) const override
  1365.         {
  1366.                 s->Add(*this);
  1367.         }
  1368. };
  1369.  
  1370. //////////////////////////////////////////////////////////////////////////
  1371. // Flow node for controlling the entity look at position.
  1372. //////////////////////////////////////////////////////////////////////////
  1373. class CFlowNode_EntityFaceAt : public CFlowEntityNodeBase
  1374. {
  1375. public:
  1376.         enum EInputs
  1377.         {
  1378.                 IN_TARGET = 0,
  1379.                 IN_VECTOR,
  1380.                 IN_START,
  1381.                 IN_STOP,
  1382.                 IN_FWD_AXIS,
  1383.                 IN_REFERENCE,
  1384.                 IN_BLENDSPEED,
  1385.         };
  1386.         enum EOutputs
  1387.         {
  1388.                 OUT_CURRENT = 0,
  1389.         };
  1390.  
  1391.         enum EFwdAxis
  1392.         {
  1393.                 eFA_XPlus = 0,
  1394.                 eFA_XMinus,
  1395.                 eFA_YPlus,
  1396.                 eFA_YMinus,
  1397.                 eFA_ZPlus,
  1398.                 eFA_ZMinus,
  1399.         };
  1400.  
  1401.         CFlowNode_EntityFaceAt(SActivationInfo* pActInfo)
  1402.                 : CFlowEntityNodeBase()
  1403.                 , m_targetPos(ZERO)
  1404.                 , m_fwdAxis(eFA_XPlus)
  1405.                 , m_referenceVector(ZERO)
  1406.                 , m_targetEntityId(0)
  1407.                 , m_blendDuration (0.0f)
  1408.                 , m_bIsBlending(false)
  1409.         {}
  1410.  
  1411.         virtual IFlowNodePtr Clone(SActivationInfo* pActInfo) { pActInfo->m_pUserData = (void*)(UINT_PTR)m_entityId; return new CFlowNode_EntityFaceAt(pActInfo); }
  1412.  
  1413.         virtual void         GetConfiguration(SFlowNodeConfig& config)
  1414.         {
  1415.                 static const SInputPortConfig in_config[] = {
  1416.                         InputPortConfig<EntityId>("target",            _HELP("face direction of target [EntityID]"), _HELP("Target")),
  1417.                         InputPortConfig<Vec3>("pos",                   Vec3(ZERO),                                   _HELP("target this position [Vec3]")),
  1418.                         InputPortConfig<SFlowSystemVoid>("Activate",   _HELP("start trigger")),
  1419.                         InputPortConfig<SFlowSystemVoid>("Deactivate", _HELP("stop trigger")),
  1420.                         InputPortConfig<int>("FwdDir",                 eFA_XPlus,                                    _HELP("Axis that will be made to point at the target"),        _HELP("FwdDir"),"enum_int:X+=0,X-=1,Y+=2,Y-=3,Z+=4,Z-=5"),
  1421.                         InputPortConfig<Vec3>("ReferenceVec",          Vec3(0.0f,                                    0.0f,                                                          1.0f),  _HELP("This reference vector represents the desired Up (Z+), unless you're using Z+ or Z- as FwdDir, in which case this vector represents the right vector (X+)")),
  1422.                         InputPortConfig<float>("BlendSpeed",           0,                                            _HELP("degrees per second. If 0, then there is no blending.")),
  1423.                         { 0 }
  1424.                 };
  1425.                 static const SOutputPortConfig out_config[] = {
  1426.                         OutputPortConfig<Vec3>("current", _HELP("the current directional vector")),
  1427.                         { 0 }
  1428.                 };
  1429.                 config.sDescription = _HELP("Entity Looks At");
  1430.                 config.nFlags |= EFLN_TARGET_ENTITY;
  1431.                 config.pInputPorts = in_config;
  1432.                 config.pOutputPorts = out_config;
  1433.                 config.SetCategory(EFLN_APPROVED);
  1434.         }
  1435.  
  1436.         void CalcBlendingStartParams(IEntity* pNodeEntity, float blendSpeed)
  1437.         {
  1438.                 m_timeStart = gEnv->pTimer->GetFrameStartTime();
  1439.                 m_quatEntityNodeStart = pNodeEntity->GetRotation();
  1440.  
  1441.                 Matrix34 finalMat;
  1442.                 CalculateLookAtMatrix(pNodeEntity, finalMat);
  1443.                 const Quat finalQuat(finalMat);
  1444.  
  1445.                 Quat qDist = finalQuat * !m_quatEntityNodeStart; // calcs quaternion to go from start to end;
  1446.                 qDist.Normalize();
  1447.  
  1448.                 float angDiff = RAD2DEG(2 * acosf(qDist.w));   // and then use the amount of rotation on that quat
  1449.                 if (angDiff > 180.f)
  1450.                         angDiff = 360.0f - angDiff;
  1451.                 m_blendDuration = angDiff / blendSpeed; // only can be here if blendSpeed >0
  1452.                 if (m_blendDuration < 0.01f)
  1453.                         m_bIsBlending = false;
  1454.         }
  1455.  
  1456.         void SnapToTarget(SActivationInfo* pActInfo)
  1457.         {
  1458.                 IEntity* pNodeEntity = GetEntity();
  1459.                 Matrix34 worldMat;
  1460.  
  1461.                 CalculateLookAtMatrix(pNodeEntity, worldMat);
  1462.                 pNodeEntity->SetWorldTM(worldMat);
  1463.         }
  1464.  
  1465.         void BlendToTarget(SActivationInfo* pActInfo)
  1466.         {
  1467.                 const float timeDone = (gEnv->pTimer->GetFrameStartTime() - m_timeStart).GetSeconds();
  1468.                 const float blendFactor = timeDone / m_blendDuration;
  1469.                 if (blendFactor >= 1)
  1470.                 {
  1471.                         m_bIsBlending = false;
  1472.                         SnapToTarget(pActInfo);
  1473.                 }
  1474.                 else
  1475.                 {
  1476.                         IEntity* pNodeEntity = GetEntity();
  1477.                         Matrix34 finalMat;
  1478.                         CalculateLookAtMatrix(pNodeEntity, finalMat);
  1479.  
  1480.                         const Quat finalQuat(finalMat);
  1481.                         const Quat blendedQuat = Quat::CreateNlerp(m_quatEntityNodeStart, finalQuat, blendFactor);
  1482.  
  1483.                         pNodeEntity->SetRotation(blendedQuat);
  1484.                 }
  1485.         }
  1486.  
  1487.         void CalculateLookAtMatrix(IEntity* pNodeEntity, Matrix34& resMat /*out*/)
  1488.         {
  1489.                 IEntity* pLookAtEntity = gEnv->pEntitySystem->GetEntity(m_targetEntityId);
  1490.                 if (pLookAtEntity)
  1491.                         m_targetPos = pLookAtEntity->GetWorldPos();
  1492.  
  1493.                 const Vec3& worldPos = pNodeEntity->GetWorldPos();
  1494.                 Vec3 facingDirection = (m_targetPos - pNodeEntity->GetWorldPos()).GetNormalized();
  1495.  
  1496.                 Vec3 xAxis(1.0f, 0.0f, 0.0f);
  1497.                 Vec3 yAxis(0.0f, 1.0f, 0.0f);
  1498.                 Vec3 zAxis(0.0f, 0.0f, 1.0f);
  1499.  
  1500.                 switch (m_fwdAxis)
  1501.                 {
  1502.                 case eFA_XMinus:
  1503.                         facingDirection = -facingDirection;
  1504.                 case eFA_XPlus:
  1505.                         xAxis = facingDirection;
  1506.                         yAxis = m_referenceVector ^ xAxis;
  1507.                         zAxis = xAxis ^ yAxis;
  1508.                         break;
  1509.                 case eFA_YMinus:
  1510.                         facingDirection = -facingDirection;
  1511.                 case eFA_YPlus:
  1512.                         yAxis = facingDirection;
  1513.                         xAxis = yAxis ^ m_referenceVector;
  1514.                         zAxis = xAxis ^ yAxis;
  1515.                         break;
  1516.                 case eFA_ZMinus:
  1517.                         facingDirection = -facingDirection;
  1518.                 case eFA_ZPlus:
  1519.                         zAxis = facingDirection;
  1520.                         yAxis = zAxis ^ m_referenceVector;
  1521.                         xAxis = yAxis ^ zAxis;
  1522.                         break;
  1523.                 }
  1524.  
  1525.                 resMat.SetFromVectors(xAxis.GetNormalized(), yAxis.GetNormalized(), zAxis.GetNormalized(), worldPos);
  1526.         }
  1527.  
  1528.         virtual void OnEntityEvent(IEntity* pEntity, SEntityEvent& event)
  1529.         {
  1530.  
  1531.         }
  1532.  
  1533.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  1534.         {
  1535.                 CFlowEntityNodeBase::ProcessEvent(event, pActInfo);
  1536.  
  1537.                 IEntity* pEntity = GetEntity();
  1538.  
  1539.                 switch (event)
  1540.                 {
  1541.                 case eFE_Activate:
  1542.                         {
  1543.                                 if (IsPortActive(pActInfo, IN_STOP)) // Stop
  1544.                                 {
  1545.                                         pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, false);
  1546.                                 }
  1547.  
  1548.                                 if (IsPortActive(pActInfo, IN_TARGET))
  1549.                                 {
  1550.                                         m_targetEntityId = GetPortEntityId(pActInfo, IN_TARGET);
  1551.                                 }
  1552.                                 else if (IsPortActive(pActInfo, IN_VECTOR))
  1553.                                 {
  1554.                                         m_targetPos = GetPortVec3(pActInfo, IN_VECTOR);
  1555.                                 }
  1556.  
  1557.                                 if (IsPortActive(pActInfo, IN_FWD_AXIS))
  1558.                                 {
  1559.                                         m_fwdAxis = static_cast<EFwdAxis>(GetPortInt(pActInfo, IN_FWD_AXIS));
  1560.                                 }
  1561.  
  1562.                                 if (IsPortActive(pActInfo, IN_REFERENCE))
  1563.                                 {
  1564.                                         m_referenceVector = GetPortVec3(pActInfo, IN_REFERENCE);
  1565.                                         m_referenceVector.Normalize();
  1566.                                 }
  1567.  
  1568.                                 if (pEntity && IsPortActive(pActInfo, IN_START))
  1569.                                 {
  1570.                                         pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, true);
  1571.                                         const float blendSpeed = GetPortFloat(pActInfo, IN_BLENDSPEED);
  1572.                                         m_bIsBlending = blendSpeed > 0;
  1573.                                         if (m_bIsBlending)
  1574.                                         {
  1575.                                                 CalcBlendingStartParams(pEntity, blendSpeed);
  1576.                                         }
  1577.                                 }
  1578.                                 break;
  1579.                         }
  1580.  
  1581.                 case eFE_Initialize:
  1582.                         {
  1583.                                 m_targetEntityId = GetPortEntityId(pActInfo, IN_TARGET);
  1584.                                 m_targetPos = GetPortVec3(pActInfo, IN_VECTOR);
  1585.                                 m_fwdAxis = static_cast<EFwdAxis>(GetPortInt(pActInfo, IN_FWD_AXIS));
  1586.                                 m_referenceVector = GetPortVec3(pActInfo, IN_REFERENCE);
  1587.                                 m_referenceVector.Normalize();
  1588.                                 pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, false);
  1589.                                 break;
  1590.                         }
  1591.  
  1592.                 case eFE_Update:
  1593.                         {
  1594.                                 if (pEntity)
  1595.                                 {
  1596.                                         if (m_bIsBlending)
  1597.                                         {
  1598.                                                 BlendToTarget(pActInfo);
  1599.                                         }
  1600.                                         else
  1601.                                         {
  1602.                                                 SnapToTarget(pActInfo);
  1603.                                         }
  1604.  
  1605.                                         ActivateOutput(pActInfo, OUT_CURRENT, Vec3(RAD2DEG(Ang3(pEntity->GetRotation()))));
  1606.                                 }
  1607.                         }
  1608.                 }
  1609.         }
  1610.  
  1611.         virtual void GetMemoryUsage(ICrySizer* s) const
  1612.         {
  1613.                 s->Add(*this);
  1614.         }
  1615.  
  1616. private:
  1617.         Vec3       m_targetPos;
  1618.         EFwdAxis   m_fwdAxis;
  1619.         Vec3       m_referenceVector;
  1620.         EntityId   m_targetEntityId;
  1621.         CTimeValue m_timeStart;
  1622.         float      m_blendDuration;
  1623.         Quat       m_quatEntityNodeStart;
  1624.         bool       m_bIsBlending;
  1625. };
  1626.  
  1627. //////////////////////////////////////////////////////////////////////////
  1628. class CFlowNode_BroadcastEntityEvent : public CFlowBaseNode<eNCT_Singleton>
  1629. {
  1630. public:
  1631.         enum EInputs
  1632.         {
  1633.                 IN_SEND,
  1634.                 IN_EVENT,
  1635.                 IN_NAME,
  1636.         };
  1637.         CFlowNode_BroadcastEntityEvent(SActivationInfo* pActInfo) {}
  1638.         virtual void GetConfiguration(SFlowNodeConfig& config)
  1639.         {
  1640.                 static const SInputPortConfig in_config[] = {
  1641.                         InputPortConfig_AnyType("send",  _HELP("When signal recieved on this input entity event is broadcasted")),
  1642.                         InputPortConfig<string>("event", _HELP("Entity event to be sent")),
  1643.                         InputPortConfig<string>("name",  _HELP("Any part of the entity name to receive event")),
  1644.                         { 0 }
  1645.                 };
  1646.                 config.sDescription = _HELP("This node broadcasts specified event to all entities which names contain sub string in parameter name");
  1647.                 config.pInputPorts = in_config;
  1648.                 config.pOutputPorts = 0;
  1649.                 config.SetCategory(EFLN_APPROVED);
  1650.         }
  1651.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  1652.         {
  1653.                 if (event != eFE_Activate)
  1654.                         return;
  1655.  
  1656.                 if (IsPortActive(pActInfo, IN_SEND))
  1657.                 {
  1658.                         const string& sEvent = GetPortString(pActInfo, IN_EVENT);
  1659.                         const string& sSubName = GetPortString(pActInfo, IN_NAME);
  1660.                         IEntityItPtr pEntityIterator = gEnv->pEntitySystem->GetEntityIterator();
  1661.                         pEntityIterator->MoveFirst();
  1662.                         IEntity* pEntity = 0;
  1663.                         while (pEntity = pEntityIterator->Next())
  1664.                         {
  1665.                                 if (strstr(pEntity->GetName(), sSubName) != 0)
  1666.                                 {
  1667.                                         IEntityScriptComponent* pScriptProxy = (IEntityScriptComponent*)pEntity->GetProxy(ENTITY_PROXY_SCRIPT);
  1668.                                         if (pScriptProxy)
  1669.                                                 pScriptProxy->CallEvent(sEvent);
  1670.                                 }
  1671.                         }
  1672.                 }
  1673.         }
  1674.  
  1675.         virtual void GetMemoryUsage(ICrySizer* s) const
  1676.         {
  1677.                 s->Add(*this);
  1678.         }
  1679. };
  1680.  
  1681. //////////////////////////////////////////////////////////////////////////
  1682. // Flow node for entity ID.
  1683. //////////////////////////////////////////////////////////////////////////
  1684. class CFlowNode_EntityId : public CFlowEntityNodeBase
  1685. {
  1686. public:
  1687.         CFlowNode_EntityId(SActivationInfo* pActInfo) : CFlowEntityNodeBase()
  1688.         {
  1689.                 m_entityId = (EntityId)(UINT_PTR)pActInfo->m_pUserData;
  1690.         }
  1691.         virtual IFlowNodePtr Clone(SActivationInfo* pActInfo) { pActInfo->m_pUserData = (void*)(UINT_PTR)m_entityId; return new CFlowNode_EntityId(pActInfo); };
  1692.         virtual void         GetConfiguration(SFlowNodeConfig& config)
  1693.         {
  1694.                 static const SOutputPortConfig out_config[] = {
  1695.                         OutputPortConfig<int>("Id", _HELP("Entity ID")),
  1696.                         { 0 }
  1697.                 };
  1698.                 config.sDescription = _HELP("Entity ID");
  1699.                 config.nFlags |= EFLN_TARGET_ENTITY;
  1700.                 config.pInputPorts = 0;
  1701.                 config.pOutputPorts = out_config;
  1702.                 config.SetCategory(EFLN_APPROVED);
  1703.         }
  1704.  
  1705.         void         OnEntityEvent(IEntity* pEntity, SEntityEvent& event) {}
  1706.  
  1707.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  1708.         {
  1709.                 CFlowEntityNodeBase::ProcessEvent(event, pActInfo);
  1710.  
  1711.                 if (event == eFE_SetEntityId)
  1712.                 {
  1713.                         EntityId entityId = GetEntityId(pActInfo);
  1714.                         if (entityId > 0)
  1715.                                 ActivateOutput(pActInfo, 0, entityId);
  1716.                 }
  1717.         }
  1718.  
  1719.         virtual void GetMemoryUsage(ICrySizer* s) const
  1720.         {
  1721.                 s->Add(*this);
  1722.         }
  1723.  
  1724.         //////////////////////////////////////////////////////////////////////////
  1725. };
  1726.  
  1727. //////////////////////////////////////////////////////////////////////////
  1728. // Flow node for getting parent's entity ID.
  1729. //////////////////////////////////////////////////////////////////////////
  1730. class CFlowNode_ParentId : public CFlowBaseNode<eNCT_Singleton>
  1731. {
  1732. public:
  1733.         CFlowNode_ParentId(SActivationInfo* pActInfo) {}
  1734.         virtual void GetConfiguration(SFlowNodeConfig& config)
  1735.         {
  1736.                 static const SOutputPortConfig out_config[] = {
  1737.                         OutputPortConfig<int>("parentId", _HELP("Entity ID of the parent entity")),
  1738.                         { 0 }
  1739.                 };
  1740.                 config.sDescription = _HELP("Parent entity ID");
  1741.                 config.nFlags |= EFLN_TARGET_ENTITY;
  1742.                 config.pInputPorts = 0;
  1743.                 config.pOutputPorts = out_config;
  1744.                 config.SetCategory(EFLN_APPROVED);
  1745.         }
  1746.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  1747.         {
  1748.                 if (event != eFE_SetEntityId)
  1749.                         return;
  1750.                 IEntity* pEntity = pActInfo->pEntity;
  1751.                 if (!pEntity)
  1752.                         return;
  1753.                 IEntity* pParentEntity = pEntity->GetParent();
  1754.                 if (!pParentEntity)
  1755.                         return;
  1756.                 ActivateOutput(pActInfo, 0, pParentEntity->GetId());
  1757.         }
  1758.  
  1759.         virtual void GetMemoryUsage(ICrySizer* s) const
  1760.         {
  1761.                 s->Add(*this);
  1762.         }
  1763. };
  1764.  
  1765. //////////////////////////////////////////////////////////////////////////
  1766. // Flow node for setting an entity property
  1767. //////////////////////////////////////////////////////////////////////////
  1768. class CFlowNode_EntitySetProperty : public CFlowEntityNodeBase
  1769. {
  1770. public:
  1771.         enum EInputs
  1772.         {
  1773.                 IN_ACTIVATE,
  1774.                 IN_SMARTNAME,
  1775.                 IN_VALUE,
  1776.                 IN_PERARCHETYPE,
  1777.         };
  1778.         CFlowNode_EntitySetProperty(SActivationInfo* pActInfo) : CFlowEntityNodeBase()
  1779.         {
  1780.                 m_entityId = (EntityId)(UINT_PTR)pActInfo->m_pUserData;
  1781.         }
  1782.         virtual IFlowNodePtr Clone(SActivationInfo* pActInfo) { pActInfo->m_pUserData = (void*)(UINT_PTR)m_entityId; return new CFlowNode_EntitySetProperty(pActInfo); };
  1783.         virtual void         GetConfiguration(SFlowNodeConfig& config)
  1784.         {
  1785.                 static const SInputPortConfig in_config[] = {
  1786.                         InputPortConfig<SFlowSystemVoid>("Set",              _HELP("Trigger it to set the property.")),
  1787.                         InputPortConfig<string>("entityProperties_Property", _HELP("select entity property"),          0,                                                                                                 _UICONFIG("ref_entity=entityId")),
  1788.                         InputPortConfig<string>("Value",                     _HELP("Property string Value")),
  1789.                         InputPortConfig<bool>("perArchetype",                true,                                     _HELP("False: property is a per instance property True: property is a per archetype property.")),
  1790.                         { 0 }
  1791.                 };
  1792.  
  1793.                 static const SOutputPortConfig out_config[] = {
  1794.                         OutputPortConfig_AnyType("Error", _HELP("")),
  1795.                         { 0 }
  1796.                 };
  1797.  
  1798.                 config.sDescription = _HELP("Change entity property value. WARNING!: THIS PROPERTY CHANGE WONT WORK WITH SAVELOAD");
  1799.                 config.nFlags |= EFLN_TARGET_ENTITY;
  1800.                 config.pInputPorts = in_config;
  1801.                 config.pOutputPorts = out_config;
  1802.                 config.SetCategory(EFLN_APPROVED);
  1803.         }
  1804.  
  1805.         SmartScriptTable DoResolveScriptTable(IScriptTable* pTable, const string& key, string& outKey)
  1806.         {
  1807.                 ScriptAnyValue value;
  1808.  
  1809.                 string token;
  1810.                 int pos = 0;
  1811.                 token = key.Tokenize(".", pos);
  1812.                 pTable->GetValueAny(token, value);
  1813.  
  1814.                 token = key.Tokenize(".", pos);
  1815.                 if (token.empty())
  1816.                         return 0;
  1817.  
  1818.                 string nextToken = key.Tokenize(".", pos);
  1819.                 while (nextToken.empty() == false)
  1820.                 {
  1821.                         if (value.type != ANY_TTABLE)
  1822.                                 return 0;
  1823.                         ScriptAnyValue temp;
  1824.                         value.table->GetValueAny(token, temp);
  1825.                         value = temp;
  1826.                         token = nextToken;
  1827.                         nextToken = token.Tokenize(".", pos);
  1828.                 }
  1829.                 outKey = token;
  1830.                 return value.table;
  1831.         }
  1832.  
  1833.         SmartScriptTable ResolveScriptTable(IScriptTable* pTable, const char* sKey, bool bPerArchetype, string& outKey)
  1834.         {
  1835.                 string key = bPerArchetype ? "Properties." : "PropertiesInstance.";
  1836.                 key += sKey;
  1837.                 return DoResolveScriptTable(pTable, key, outKey);
  1838.         }
  1839.  
  1840.         void         OnEntityEvent(IEntity* pEntity, SEntityEvent& event) {}
  1841.  
  1842.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  1843.         {
  1844.                 CFlowEntityNodeBase::ProcessEvent(event, pActInfo);
  1845.  
  1846.                 switch (event)
  1847.                 {
  1848.                 case eFE_Activate:
  1849.                         OnActivate(pActInfo);
  1850.                         break;
  1851.  
  1852.                 case eFE_Initialize:
  1853.                         OnInitialize(pActInfo);
  1854.                         break;
  1855.                 }
  1856.         }
  1857.  
  1858.         void OnInitialize(SActivationInfo* pActInfo)
  1859.         {
  1860.                 if (!s_propertyHistoryMap.empty())
  1861.                 {
  1862.                         for (const TPropertyHistoryMap::value_type& entry : s_propertyHistoryMap)
  1863.                         {
  1864.                                 const EntityId entityId = entry.first.entityId;
  1865.                                 if (IEntity* pEntity = gEnv->pEntitySystem->GetEntity(entityId))
  1866.                                 {
  1867.                                         if (IScriptTable* pScriptTable = pEntity->GetScriptTable())
  1868.                                         {
  1869.                                                 const string& propertyName = entry.first.propertyName;
  1870.                                                 const bool bPerArchetype = entry.first.bPerArchetype;
  1871.                                                 const ScriptAnyValue& value = entry.second;
  1872.  
  1873.                                                 string realPropertyName;
  1874.                                                 if (SmartScriptTable smartScriptTable = ResolveScriptTable(pScriptTable, propertyName, bPerArchetype, realPropertyName))
  1875.                                                 {
  1876.                                                         smartScriptTable->SetValueAny(realPropertyName.c_str(), value);
  1877.  
  1878.                                                         if (pScriptTable->HaveValue("OnPropertyChange"))
  1879.                                                         {
  1880.                                                                 Script::CallMethod(pScriptTable, "OnPropertyChange");
  1881.                                                         }
  1882.                                                 }
  1883.                                         }
  1884.                                 }
  1885.                         }
  1886.                         s_propertyHistoryMap.clear();
  1887.                 }
  1888.         }
  1889.  
  1890.         void OnActivate(SActivationInfo* pActInfo)
  1891.         {
  1892.                 IEntity* pEntity = GetEntity();
  1893.                 if (!pEntity)
  1894.                         return;
  1895.  
  1896.                 const bool bValuePort = IsPortActive(pActInfo, IN_SMARTNAME);
  1897.                 const bool bTriggerPort = IsPortActive(pActInfo, IN_ACTIVATE);
  1898.  
  1899.                 if (bValuePort || bTriggerPort)
  1900.                 {
  1901.                         if (IScriptTable* pScriptTable = pEntity->GetScriptTable())
  1902.                         {
  1903.                                 const string inputPropertyName = GetPortString(pActInfo, IN_SMARTNAME);
  1904.                                 const string inputPropertyValue = GetPortString(pActInfo, IN_VALUE);
  1905.                                 const bool bPerArchetype = GetPortBool(pActInfo, IN_PERARCHETYPE);
  1906.  
  1907.                                 const size_t pos = inputPropertyName.find_first_of(":");
  1908.                                 string plainPropertyName = inputPropertyName.substr(pos + 1, inputPropertyName.length() - pos);
  1909.                                 plainPropertyName.replace(":", ".");
  1910.  
  1911.                                 string realPropertyName;
  1912.                                 SmartScriptTable smartScriptTable = ResolveScriptTable(pScriptTable, plainPropertyName.c_str(), bPerArchetype, realPropertyName);
  1913.  
  1914.                                 if (!smartScriptTable)
  1915.                                 {
  1916.                                         GameWarning("[flow] CFlowNode_EntitySetProperty: Cannot resolve property '%s' in entity '%s'",
  1917.                                                     plainPropertyName.c_str(), pEntity->GetName());
  1918.                                         ActivateOutput(pActInfo, 0, 0);
  1919.                                         return;
  1920.                                 }
  1921.  
  1922.                                 if (gEnv->IsEditor())
  1923.                                 {
  1924.                                         SPropertyKey propertyKey = { pEntity->GetId(), plainPropertyName, bPerArchetype };
  1925.                                         TPropertyHistoryMap::iterator it = s_propertyHistoryMap.find(propertyKey);
  1926.  
  1927.                                         if (it == s_propertyHistoryMap.end())
  1928.                                         {
  1929.                                                 ScriptAnyValue anyValue;
  1930.                                                 const ScriptVarType scriptVarType = smartScriptTable->GetValueType(realPropertyName.c_str());
  1931.  
  1932.                                                 if (scriptVarType == svtObject)
  1933.                                                 {
  1934.                                                         if (GetColorAnyValue(smartScriptTable, realPropertyName, anyValue))
  1935.                                                         {
  1936.                                                                 s_propertyHistoryMap[propertyKey] = anyValue;
  1937.                                                         }
  1938.                                                 }
  1939.                                                 else if (scriptVarType == svtBool || scriptVarType == svtNumber || scriptVarType == svtString)
  1940.                                                 {
  1941.                                                         if (smartScriptTable->GetValueAny(realPropertyName.c_str(), anyValue))
  1942.                                                         {
  1943.                                                                 s_propertyHistoryMap[propertyKey] = anyValue;
  1944.                                                         }
  1945.                                                 }
  1946.                                         }
  1947.                                 }
  1948.  
  1949.                                 ChangeProperty(pActInfo, pEntity, pScriptTable, smartScriptTable, realPropertyName, inputPropertyValue);
  1950.                         }
  1951.                 }
  1952.         }
  1953.  
  1954.         void ChangeProperty(SActivationInfo* pActInfo, IEntity* pEntity, IScriptTable* pScriptTable, SmartScriptTable& smartScriptTable, const string& propertyName, const char* propertyValue)
  1955.         {
  1956.                 const ScriptVarType scriptVarType = smartScriptTable->GetValueType(propertyName.c_str());
  1957.  
  1958.                 switch (scriptVarType)
  1959.                 {
  1960.                 case svtNull:
  1961.                         {
  1962.                                 GameWarning("[flow] CFlowNode_EntitySetProperty: Cannot resolve property '%s' in entity '%s' -> Creating",
  1963.                                             propertyName.c_str(), pEntity->GetName());
  1964.                                 ActivateOutput(pActInfo, 0, 0);
  1965.                                 break;
  1966.                         }
  1967.  
  1968.                 case svtNumber:
  1969.                         {
  1970.                                 float fValue = (float)atof(propertyValue);
  1971.                                 smartScriptTable->SetValue(propertyName.c_str(), fValue);
  1972.                                 if (pScriptTable->HaveValue("OnPropertyChange"))
  1973.                                         Script::CallMethod(pScriptTable, "OnPropertyChange");
  1974.                                 break;
  1975.                         }
  1976.  
  1977.                 case svtBool:
  1978.                         {
  1979.                                 float fValue = (float)atof(propertyValue);
  1980.                                 bool bVal = (bool)(fabs(fValue) > 0.001f);
  1981.                                 smartScriptTable->SetValue(propertyName.c_str(), bVal);
  1982.                                 if (pScriptTable->HaveValue("OnPropertyChange"))
  1983.                                         Script::CallMethod(pScriptTable, "OnPropertyChange");
  1984.                                 break;
  1985.                         }
  1986.  
  1987.                 case svtString:
  1988.                         {
  1989.                                 smartScriptTable->SetValue(propertyName.c_str(), propertyValue);
  1990.                                 if (pScriptTable->HaveValue("OnPropertyChange"))
  1991.                                         Script::CallMethod(pScriptTable, "OnPropertyChange");
  1992.                                 break;
  1993.                         }
  1994.  
  1995.                 case svtObject:
  1996.                         {
  1997.                                 if (IsColorType(propertyName))
  1998.                                 {
  1999.                                         Vec3 clrValue(ZERO);
  2000.                                         StringToVec3(propertyValue, clrValue);
  2001.  
  2002.                                         smartScriptTable->SetValue(propertyName.c_str(), clrValue);
  2003.                                         if (pScriptTable->HaveValue("OnPropertyChange"))
  2004.                                                 Script::CallMethod(pScriptTable, "OnPropertyChange");
  2005.                                 }
  2006.                                 break;
  2007.                         }
  2008.                 }
  2009.         }
  2010.  
  2011.         inline bool IsColorType(const string& propertyName) const
  2012.         {
  2013.                 return strcmp(propertyName.substr(propertyName.find_last_of(".") + 1, 3), "clr") == 0;
  2014.         }
  2015.  
  2016.         void StringToVec3(const string& propertyValue, Vec3& clrValue) const
  2017.         {
  2018.                 const size_t commaFirst = propertyValue.find_first_of(",");
  2019.                 const size_t commaLast = propertyValue.find_last_of(",");
  2020.  
  2021.                 clrValue.x = (float)atof(propertyValue.substr(0, commaFirst));
  2022.                 clrValue.y = (float)atof(propertyValue.substr(commaFirst + 1, commaLast));
  2023.                 clrValue.z = (float)atof(propertyValue.substr(commaLast + 1, propertyValue.length()));
  2024.  
  2025.                 clrValue.x = fabs(min(clrValue.x, 255.f));
  2026.                 clrValue.y = fabs(min(clrValue.y, 255.f));
  2027.                 clrValue.z = fabs(min(clrValue.z, 255.f));
  2028.  
  2029.                 clrValue = clrValue / 255.f;
  2030.         }
  2031.  
  2032.         bool GetColorAnyValue(SmartScriptTable& smartScriptTable, const string& propertyName, ScriptAnyValue& outAnyValue) const
  2033.         {
  2034.                 if (IsColorType(propertyName))
  2035.                 {
  2036.                         if (smartScriptTable->GetValueAny(propertyName.c_str(), outAnyValue))
  2037.                         {
  2038.                                 if (outAnyValue.CopyFromTableToXYZ(outAnyValue.vec3.x, outAnyValue.vec3.y, outAnyValue.vec3.z))
  2039.                                 {
  2040.                                         outAnyValue.type = ANY_TVECTOR;
  2041.                                         return true;
  2042.                                 }
  2043.                         }
  2044.                 }
  2045.                 return false;
  2046.         }
  2047.  
  2048.         virtual void GetMemoryUsage(ICrySizer* s) const
  2049.         {
  2050.                 s->Add(*this);
  2051.         }
  2052.  
  2053. private:
  2054.         struct SPropertyKey
  2055.         {
  2056.                 inline bool operator<(const SPropertyKey& other) const
  2057.                 {
  2058.                         return (entityId < other.entityId) || (entityId == other.entityId
  2059.                                                                && ((bPerArchetype < other.bPerArchetype)
  2060.                                                                    || (bPerArchetype == other.bPerArchetype && propertyName < other.propertyName))
  2061.                                                                );
  2062.                 }
  2063.                 EntityId entityId;
  2064.                 string   propertyName;
  2065.                 bool     bPerArchetype;
  2066.         };
  2067.  
  2068.         typedef std::map<SPropertyKey, ScriptAnyValue> TPropertyHistoryMap;
  2069.         static TPropertyHistoryMap s_propertyHistoryMap;
  2070.  
  2071.         //////////////////////////////////////////////////////////////////////////
  2072. };
  2073.  
  2074. CFlowNode_EntitySetProperty::TPropertyHistoryMap CFlowNode_EntitySetProperty::s_propertyHistoryMap;
  2075.  
  2076. //////////////////////////////////////////////////////////////////////////
  2077. // Flow node for getting an entity property value
  2078. //////////////////////////////////////////////////////////////////////////
  2079. class CFlowNode_EntityGetProperty : public CFlowEntityNodeBase
  2080. {
  2081. public:
  2082.         enum EInputs
  2083.         {
  2084.                 IN_ACTIVATE,
  2085.                 IN_SMARTNAME,
  2086.                 IN_PER_ARCHETYPE,
  2087.         };
  2088.  
  2089.         CFlowNode_EntityGetProperty(SActivationInfo* pActInfo) : CFlowEntityNodeBase()
  2090.         {
  2091.                 m_entityId = (EntityId)(UINT_PTR)pActInfo->m_pUserData;
  2092.         }
  2093.         virtual IFlowNodePtr Clone(SActivationInfo* pActInfo) { pActInfo->m_pUserData = (void*)(UINT_PTR)m_entityId; return new CFlowNode_EntityGetProperty(pActInfo); };
  2094.         virtual void         GetConfiguration(SFlowNodeConfig& config)
  2095.         {
  2096.                 static const SInputPortConfig in_config[] = {
  2097.                         InputPortConfig<SFlowSystemVoid>("Get",              _HELP("Trigger it to get the property!")),
  2098.                         InputPortConfig<string>("entityProperties_Property", _HELP("select entity property"),          0,                                                                                                 _UICONFIG("ref_entity=entityId")),
  2099.                         InputPortConfig<bool>("perArchetype",                true,                                     _HELP("False: property is a per instance property True: property is a per archetype property.")),
  2100.                         { 0 }
  2101.                 };
  2102.                 static const SOutputPortConfig out_config[] = {
  2103.                         OutputPortConfig_AnyType("Value", _HELP("Value of the property")),
  2104.                         OutputPortConfig_AnyType("Error", _HELP("")),
  2105.                         { 0 }
  2106.                 };
  2107.                 config.sDescription = _HELP("Retrieve entity property value");
  2108.                 config.nFlags |= EFLN_TARGET_ENTITY;
  2109.                 config.pInputPorts = in_config;
  2110.                 config.pOutputPorts = out_config;
  2111.                 config.SetCategory(EFLN_APPROVED);
  2112.         }
  2113.  
  2114.         void         OnEntityEvent(IEntity* pEntity, SEntityEvent& event) {}
  2115.  
  2116.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  2117.         {
  2118.                 CFlowEntityNodeBase::ProcessEvent(event, pActInfo);
  2119.  
  2120.                 IEntity* pEntity = GetEntity();
  2121.                 if (!pEntity)
  2122.                         return;
  2123.  
  2124.                 if (event == eFE_Activate)
  2125.                 {
  2126.                         if (IsPortActive(pActInfo, IN_SMARTNAME) || IsPortActive(pActInfo, IN_ACTIVATE))
  2127.                         {
  2128.                                 bool bPerArchetype = GetPortBool(pActInfo, IN_PER_ARCHETYPE);
  2129.  
  2130.                                 IScriptTable* pTable = pEntity->GetScriptTable();
  2131.                                 if (!pTable)
  2132.                                         return;
  2133.  
  2134.                                 string inputValue = GetPortString(pActInfo, IN_SMARTNAME);
  2135.                                 string selectedParameter = inputValue.substr(inputValue.find_first_of(":") + 1, (inputValue.length() - inputValue.find_first_of(":")));
  2136.  
  2137.                                 const char* pKey = (selectedParameter.replace(":", ".")).c_str();
  2138.                                 const char* pPropertiesString = bPerArchetype ? "Properties" : "PropertiesInstance";
  2139.  
  2140.                                 // requested property is a vector?
  2141.                                 if (strcmp(selectedParameter.substr(selectedParameter.find_last_of(".") + 1, 3), "clr") == 0)
  2142.                                 {
  2143.                                         Vec3 vecValue(ZERO);
  2144.  
  2145.                                         for (int i = 0; i < 3; i++)
  2146.                                         {
  2147.                                                 ScriptAnyValue value;
  2148.                                                 char newKey[32];
  2149.  
  2150.                                                 cry_strcpy(newKey, pKey);
  2151.  
  2152.                                                 if (i == 0) cry_strcat(newKey, ".x");
  2153.                                                 if (i == 1) cry_strcat(newKey, ".y");
  2154.                                                 if (i == 2) cry_strcat(newKey, ".z");
  2155.  
  2156.                                                 if (ReadScriptValue(pTable, pPropertiesString, newKey, value))
  2157.                                                 {
  2158.                                                         float fVal;
  2159.                                                         value.CopyTo(fVal);
  2160.  
  2161.                                                         if (i == 0) vecValue.x = fVal;
  2162.                                                         if (i == 1) vecValue.y = fVal;
  2163.                                                         if (i == 2) vecValue.z = fVal;
  2164.                                                 }
  2165.                                                 else
  2166.                                                 {
  2167.                                                         ActivateOutput(pActInfo, 1, 0);
  2168.                                                         return;
  2169.                                                 }
  2170.                                         }
  2171.                                         ActivateOutput(pActInfo, 0, vecValue * 255.f);
  2172.                                         return;
  2173.                                 }
  2174.  
  2175.                                 ScriptAnyValue value;
  2176.                                 bool isValid = ReadScriptValue(pTable, pPropertiesString, pKey, value);
  2177.  
  2178.                                 if (!isValid)
  2179.                                 {
  2180.                                         GameWarning("[flow] CFlowNode_EntityGetProperty: Could not find property '%s.%s' in entity '%s'", pPropertiesString, pKey, pEntity->GetName());
  2181.                                         ActivateOutput(pActInfo, 1, isValid);
  2182.                                         return;
  2183.                                 }
  2184.  
  2185.                                 switch (value.GetVarType())
  2186.                                 {
  2187.                                 case svtNumber:
  2188.                                         {
  2189.                                                 float fVal;
  2190.                                                 value.CopyTo(fVal);
  2191.  
  2192.                                                 // TODO: fix wrong number return type for booleans
  2193.                                                 if (strcmp(selectedParameter.substr(selectedParameter.find_last_of(".") + 1, 1), "b") == 0)
  2194.                                                 {
  2195.                                                         bool bVal = (bool)(fabs(fVal) > 0.001f);
  2196.                                                         ActivateOutput(pActInfo, 0, bVal);
  2197.                                                 }
  2198.                                                 else
  2199.                                                 {
  2200.                                                         ActivateOutput(pActInfo, 0, fVal);
  2201.                                                 }
  2202.                                                 break;
  2203.                                         }
  2204.  
  2205.                                 case svtBool:
  2206.                                         {
  2207.                                                 bool val;
  2208.                                                 value.CopyTo(val);
  2209.                                                 ActivateOutput(pActInfo, 0, val);
  2210.                                                 break;
  2211.                                         }
  2212.  
  2213.                                 case svtString:
  2214.                                         {
  2215.                                                 const char* pVal = NULL;
  2216.                                                 value.CopyTo(pVal);
  2217.                                                 ActivateOutput(pActInfo, 0, string(pVal));
  2218.                                                 break;
  2219.                                         }
  2220.  
  2221.                                 default:
  2222.                                         {
  2223.                                                 GameWarning("[flow] CFlowNode_EntityGetProperty: property '%s.%s' in entity '%s' is of unexpected type('%d')", pPropertiesString, pKey, pEntity->GetName(), value.GetVarType());
  2224.                                                 ActivateOutput(pActInfo, 1, 0);
  2225.                                                 return;
  2226.                                         }
  2227.                                 }
  2228.                         }
  2229.                 }
  2230.         }
  2231.  
  2232.         static bool ReadScriptValue(IScriptTable* pTable, const char* pPropertiesString, const char* pKey, ScriptAnyValue& value)
  2233.         {
  2234.                 pTable->GetValueAny(pPropertiesString, value);
  2235.  
  2236.                 int pos = 0;
  2237.                 string key = pKey;
  2238.                 string nextToken = key.Tokenize(".", pos);
  2239.                 while (!nextToken.empty() && value.type == ANY_TTABLE)
  2240.                 {
  2241.                         ScriptAnyValue temp;
  2242.                         value.table->GetValueAny(nextToken, temp);
  2243.                         value = temp;
  2244.                         nextToken = key.Tokenize(".", pos);
  2245.                 }
  2246.  
  2247.                 return nextToken.empty() && (value.type == ANY_TNUMBER || value.type == ANY_TBOOLEAN || value.type == ANY_TSTRING);
  2248.         }
  2249.  
  2250.         virtual void GetMemoryUsage(ICrySizer* s) const
  2251.         {
  2252.                 s->Add(*this);
  2253.         }
  2254.  
  2255.         //////////////////////////////////////////////////////////////////////////
  2256. };
  2257.  
  2258. //////////////////////////////////////////////////////////////////////////
  2259. // Flow node for Attaching child to parent.
  2260. //////////////////////////////////////////////////////////////////////////
  2261. class CFlowNode_EntityAttachChild : public CFlowBaseNode<eNCT_Singleton>
  2262. {
  2263. public:
  2264.         CFlowNode_EntityAttachChild(SActivationInfo* pActInfo) {}
  2265.         virtual void GetConfiguration(SFlowNodeConfig& config)
  2266.         {
  2267.                 static const SInputPortConfig in_config[] = {
  2268.                         InputPortConfig_Void("Attach",          _HELP("Trigger to attach entity")),
  2269.                         InputPortConfig<EntityId>("Child",      _HELP("Child Entity to Attach")),
  2270.                         InputPortConfig<bool>("KeepTransform",  _HELP("Child entity will remain in the same transformation in world space")),
  2271.                         InputPortConfig<bool>("DisablePhysics", false,                                                                       _HELP("Force disable physics of child entity on attaching")),
  2272.                         { 0 }
  2273.                 };
  2274.                 config.sDescription = _HELP("Attach Child Entity");
  2275.                 config.nFlags |= EFLN_TARGET_ENTITY;
  2276.                 config.pInputPorts = in_config;
  2277.                 config.pOutputPorts = 0;
  2278.                 config.SetCategory(EFLN_APPROVED);
  2279.         }
  2280.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  2281.         {
  2282.                 if (event != eFE_Activate)
  2283.                         return;
  2284.                 if (!pActInfo->pEntity)
  2285.                         return;
  2286.                 if (IsPortActive(pActInfo, 0))
  2287.                 {
  2288.                         EntityId nChildId = GetPortEntityId(pActInfo, 1);
  2289.                         IEntity* pChild = gEnv->pEntitySystem->GetEntity(nChildId);
  2290.                         if (pChild)
  2291.                         {
  2292.                                 int nFlags = 0;
  2293.                                 if (GetPortBool(pActInfo, 2))
  2294.                                         nFlags |= IEntity::ATTACHMENT_KEEP_TRANSFORMATION;
  2295.                                 if (GetPortBool(pActInfo, 3))
  2296.                                 {
  2297.                                         pChild->EnablePhysics(false);
  2298.                                 }
  2299.                                 pActInfo->pEntity->AttachChild(pChild, nFlags);
  2300.                         }
  2301.                 }
  2302.         }
  2303.  
  2304.         virtual void GetMemoryUsage(ICrySizer* s) const
  2305.         {
  2306.                 s->Add(*this);
  2307.         }
  2308. };
  2309.  
  2310. //////////////////////////////////////////////////////////////////////////
  2311. // Flow node for detaching child from parent.
  2312. //////////////////////////////////////////////////////////////////////////
  2313. class CFlowNode_EntityDetachThis : public CFlowBaseNode<eNCT_Singleton>
  2314. {
  2315. public:
  2316.         CFlowNode_EntityDetachThis(SActivationInfo* pActInfo) {}
  2317.         virtual void GetConfiguration(SFlowNodeConfig& config)
  2318.         {
  2319.                 static const SInputPortConfig in_config[] = {
  2320.                         InputPortConfig_Void("Detach",         _HELP("Trigger to detach entity from parent")),
  2321.                         InputPortConfig<bool>("KeepTransform", _HELP("When attaching entity will stay in same transformation in world space")),
  2322.                         InputPortConfig<bool>("EnablePhysics", false,                                                                          _HELP("Force enable physics of entity after detaching")),
  2323.                         { 0 }
  2324.                 };
  2325.                 config.sDescription = _HELP("Detach child from its parent");
  2326.                 config.nFlags |= EFLN_TARGET_ENTITY;
  2327.                 config.pInputPorts = in_config;
  2328.                 config.pOutputPorts = 0;
  2329.                 config.SetCategory(EFLN_APPROVED);
  2330.         }
  2331.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  2332.         {
  2333.                 if (event != eFE_Activate)
  2334.                         return;
  2335.                 if (!pActInfo->pEntity)
  2336.                         return;
  2337.                 if (IsPortActive(pActInfo, 0))
  2338.                 {
  2339.                         int nFlags = 0;
  2340.                         if (GetPortBool(pActInfo, 1))
  2341.                                 nFlags |= IEntity::ATTACHMENT_KEEP_TRANSFORMATION;
  2342.                         if (GetPortBool(pActInfo, 2))
  2343.                         {
  2344.                                 pActInfo->pEntity->EnablePhysics(true);
  2345.                         }
  2346.                         pActInfo->pEntity->DetachThis(nFlags);
  2347.                 }
  2348.         }
  2349.  
  2350.         virtual void GetMemoryUsage(ICrySizer* s) const
  2351.         {
  2352.                 s->Add(*this);
  2353.         }
  2354. };
  2355.  
  2356. //////////////////////////////////////////////////////////////////////////
  2357. // Flow node for beaming an entity
  2358. //////////////////////////////////////////////////////////////////////////
  2359. class CFlowNode_BeamEntity : public CFlowBaseNode<eNCT_Singleton>
  2360. {
  2361. public:
  2362.         CFlowNode_BeamEntity(SActivationInfo* pActInfo) {}
  2363.  
  2364.         enum EInputPorts
  2365.         {
  2366.                 EIP_Beam = 0,
  2367.                 EIP_Pos,
  2368.                 EIP_Rot,
  2369.                 EIP_UseZeroRot,
  2370.                 EIP_Scale,
  2371.                 EIP_Memo
  2372.         };
  2373.  
  2374.         enum EOutputPorts
  2375.         {
  2376.                 EOP_Done = 0,
  2377.         };
  2378.  
  2379.         virtual void GetConfiguration(SFlowNodeConfig& config)
  2380.         {
  2381.                 static const SInputPortConfig in_config[] = {
  2382.                         InputPortConfig_Void("Beam",        _HELP("Trigger to beam the Entity")),
  2383.                         InputPortConfig<Vec3>("Position",   _HELP("Position in World Coords")),
  2384.                         InputPortConfig<Vec3>("Rotation",   _HELP("Rotation [Degrees] in World Coords. (0,0,0) leaves Rotation untouched, unless UseZeroRot is set to 1.")),
  2385.                         InputPortConfig<bool>("UseZeroRot", false,                                                                                                          _HELP("If true, rotation is applied even if is (0,0,0)")),
  2386.                         InputPortConfig<Vec3>("Scale",      _HELP("Scale. (0,0,0) leaves Scale untouched.")),
  2387.                         InputPortConfig<string>("Memo",     _HELP("Memo to log when position is zero")),
  2388.                         { 0 }
  2389.                 };
  2390.                 static const SOutputPortConfig out_config[] = {
  2391.                         OutputPortConfig_Void("Done", _HELP("Triggered when done")),
  2392.                         { 0 }
  2393.                 };
  2394.  
  2395.                 config.sDescription = _HELP("Beam an Entity to a new Position");
  2396.                 config.nFlags |= EFLN_TARGET_ENTITY | EFLN_AISEQUENCE_SUPPORTED;
  2397.                 config.pInputPorts = in_config;
  2398.                 config.pOutputPorts = out_config;
  2399.                 config.SetCategory(EFLN_APPROVED);
  2400.         }
  2401.  
  2402.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  2403.         {
  2404.                 if (event != eFE_Activate)
  2405.                         return;
  2406.                 if (!pActInfo->pEntity)
  2407.                         return;
  2408.                 if (IsPortActive(pActInfo, EIP_Beam))
  2409.                 {
  2410.                         const Vec3* vRot = pActInfo->pInputPorts[EIP_Rot].GetPtr<Vec3>();
  2411.                         const Vec3 vPos = GetPortVec3(pActInfo, EIP_Pos);
  2412.  
  2413.                         bool bUseZeroRot = GetPortBool(pActInfo, EIP_UseZeroRot);
  2414.  
  2415.                         string memo = GetPortString(pActInfo, EIP_Memo);
  2416.                         const char* szEntityName = pActInfo->pEntity->GetName();
  2417.  
  2418.                         const bool bIsPlayer = CCryAction::GetCryAction()->GetClientActorId() == pActInfo->pEntity->GetId();
  2419.  
  2420.                         if (memo.empty() && bIsPlayer == 0)
  2421.                         {
  2422.                                 memo = "<no memo>";
  2423.                         }
  2424.  
  2425.                         if (vPos.IsZero())
  2426.                         {
  2427.                                 CryWarning(VALIDATOR_MODULE_FLOWGRAPH, VALIDATOR_WARNING, "BeamEntity Teleported %s to vPos zero. %s", szEntityName, (!memo.empty()) ? memo.c_str() : "<no memo>");
  2428.                         }
  2429.                         else if (!memo.empty())
  2430.                         {
  2431.                                 CryWarning(VALIDATOR_MODULE_FLOWGRAPH, VALIDATOR_COMMENT, "BeamEntity Teleported %s: %s", szEntityName, memo.c_str());
  2432.                         }
  2433.  
  2434.                         Matrix34 tm;
  2435.                         bool bApplyRot = vRot != nullptr && (!vRot->IsZero() || bUseZeroRot);
  2436.                         if (!bApplyRot)
  2437.                         {
  2438.                                 tm = pActInfo->pEntity->GetWorldTM();
  2439.                         }
  2440.                         else
  2441.                         {
  2442.                                 tm = Matrix33(Quat::CreateRotationXYZ(Ang3(DEG2RAD(*vRot))));
  2443.                         }
  2444.  
  2445.                         tm.SetTranslation(vPos);
  2446.                         pActInfo->pEntity->SetWorldTM(tm, ENTITY_XFORM_TRACKVIEW);
  2447.  
  2448.                         const Vec3* vScale = pActInfo->pInputPorts[EIP_Scale].GetPtr<Vec3>();
  2449.                         if (vScale && vScale->IsZero() == false)
  2450.                                 pActInfo->pEntity->SetScale(*vScale, ENTITY_XFORM_TRACKVIEW);
  2451.  
  2452.                         // TODO: Maybe add some tweaks/checks wrt. physics/collisions
  2453.                         ActivateOutput(pActInfo, EOP_Done, true);
  2454.                 }
  2455.         }
  2456.  
  2457.         virtual void GetMemoryUsage(ICrySizer* s) const
  2458.         {
  2459.                 s->Add(*this);
  2460.         }
  2461. };
  2462.  
  2463. //////////////////////////////////////////////////////////////////////////
  2464. // Flow node for getting entity info.
  2465. //////////////////////////////////////////////////////////////////////////
  2466. class CFlowNode_EntityGetInfo : public CFlowBaseNode<eNCT_Singleton>
  2467. {
  2468. public:
  2469.         CFlowNode_EntityGetInfo(SActivationInfo* pActInfo) {}
  2470.         virtual void GetConfiguration(SFlowNodeConfig& config)
  2471.         {
  2472.                 static const SInputPortConfig in_config[] = {
  2473.                         InputPortConfig_Void("Get", _HELP("Trigger to get info")),
  2474.                         { 0 }
  2475.                 };
  2476.                 static const SOutputPortConfig out_config[] = {
  2477.                         OutputPortConfig<EntityId>("Id",      _HELP("Entity Id")),
  2478.                         OutputPortConfig<string>("Name",      _HELP("Entity Name")),
  2479.                         OutputPortConfig<string>("Class",     _HELP("Entity Class")),
  2480.                         OutputPortConfig<string>("Archetype", _HELP("Entity Archetype")),
  2481.                         { 0 }
  2482.                 };
  2483.                 config.sDescription = _HELP("Get Entity Information");
  2484.                 config.nFlags |= EFLN_TARGET_ENTITY;
  2485.                 config.pInputPorts = in_config;
  2486.                 config.pOutputPorts = out_config;
  2487.                 config.SetCategory(EFLN_APPROVED);
  2488.         }
  2489.         virtual void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  2490.         {
  2491.                 if (event != eFE_Activate)
  2492.                         return;
  2493.                 IEntity* pEntity = pActInfo->pEntity;
  2494.                 if (pEntity == 0)
  2495.                         return;
  2496.                 if (IsPortActive(pActInfo, 0))
  2497.                 {
  2498.                         string empty;
  2499.                         ActivateOutput(pActInfo, 0, pEntity->GetId());
  2500.                         string temp(pEntity->GetName());
  2501.                         ActivateOutput(pActInfo, 1, temp);
  2502.                         temp = pEntity->GetClass()->GetName();
  2503.                         ActivateOutput(pActInfo, 2, temp);
  2504.                         IEntityArchetype* pArchetype = pEntity->GetArchetype();
  2505.                         if (pArchetype)
  2506.                                 temp = pArchetype->GetName();
  2507.                         ActivateOutput(pActInfo, 3, pArchetype ? temp : empty);
  2508.                 }
  2509.         }
  2510.  
  2511.         virtual void GetMemoryUsage(ICrySizer* s) const
  2512.         {
  2513.                 s->Add(*this);
  2514.         }
  2515. };
  2516.  
  2517. ////////////////////////////////////////////////////////////////////////////////////////
  2518. // Flow node for setting entity render parameters (opacity, glow, motionblur, etc)
  2519. ////////////////////////////////////////////////////////////////////////////////////////
  2520. class CFlowNodeRenderParams : public CFlowEntityNodeBase
  2521. {
  2522. public:
  2523.         CFlowNodeRenderParams(SActivationInfo* pActInfo) : CFlowEntityNodeBase()
  2524.         {
  2525.                 m_entityId = (EntityId)(UINT_PTR)pActInfo->m_pUserData;
  2526.         }
  2527.  
  2528.         virtual IFlowNodePtr Clone(SActivationInfo* pActInfo) { pActInfo->m_pUserData = (void*)(UINT_PTR)m_entityId; return new CFlowNodeRenderParams(pActInfo); };
  2529.  
  2530.         enum EInputPorts
  2531.         {
  2532.                 EIP_Trigger,
  2533.                 EIP_ParamFloatName,
  2534.                 EIP_ParamFloatValue,
  2535.         };
  2536.  
  2537.         enum EOutputPorts
  2538.         {
  2539.                 EOP_Success,
  2540.         };
  2541.  
  2542.         virtual void GetConfiguration(SFlowNodeConfig& config)
  2543.         {
  2544.                 static const SInputPortConfig in_config[] = {
  2545.                         InputPortConfig_Void("Set",     _HELP("Trigger to activate the node")),
  2546.                         InputPortConfig<int>("Param",   0,                                     _HELP("Render parameter to set (of type float)"),                   NULL, _UICONFIG("enum_int:None=0,Opacity=1")),
  2547.                         InputPortConfig<float>("Value", 1.0f,                                  _HELP("Value to attribute to the render parameter (type float)")),
  2548.                         { 0 }
  2549.                 };
  2550.  
  2551.                 static const SOutputPortConfig out_config[] = {
  2552.                         OutputPortConfig<bool>("Success", _HELP("Triggers when the node is proc