BVB Source Codes

CRYENGINE Show FlowWeaponNodes.cpp Source code

Return Download CRYENGINE: download FlowWeaponNodes.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:   FlowWeaponNodes.cpp
  5. //  Version:     v1.00
  6. //  Created:     July 7th 2005 by Julien.
  7. //  Compilers:   Visual Studio.NET 2003
  8. //  Description:
  9. // -------------------------------------------------------------------------
  10. //  History:
  11. //
  12. ////////////////////////////////////////////////////////////////////////////
  13.  
  14. #include "StdAfx.h"
  15. #include "CryAction.h"
  16. #include "IItemSystem.h"
  17. #include "IWeapon.h"
  18. #include "IActorSystem.h"
  19. #include "FlowFrameworkBaseNode.h"
  20.  
  21. #include <CryEntitySystem/IEntitySystem.h>
  22.  
  23. namespace
  24. {
  25. IItem* GetItem(EntityId entityId)
  26. {
  27.         IItemSystem* pItemSystem = CCryAction::GetCryAction()->GetIItemSystem();
  28.         return pItemSystem->GetItem(entityId);
  29. }
  30.  
  31. IWeapon* GetWeapon(EntityId entityId)
  32. {
  33.         IItem* pItem = GetItem(entityId);
  34.         return pItem ? pItem->GetIWeapon() : NULL;
  35. }
  36. } // anon namespace
  37.  
  38. struct SWeaponListener : public IWeaponEventListener
  39. {
  40.         // IWeaponEventListener
  41.         virtual void OnShoot(IWeapon* pWeapon, EntityId shooterId, EntityId ammoId, IEntityClass* pAmmoType, const Vec3& pos, const Vec3& dir, const Vec3& vel) {}
  42.         virtual void OnStartFire(IWeapon* pWeapon, EntityId shooterId)                                                                                          {}
  43.         virtual void OnStopFire(IWeapon* pWeapon, EntityId shooterId)                                                                                           {}
  44.         virtual void OnFireModeChanged(IWeapon* pWeapon, int currentFireMode)                                                                                   {}
  45.         virtual void OnStartReload(IWeapon* pWeapon, EntityId shooterId, IEntityClass* pAmmoType)                                                               {}
  46.         virtual void OnEndReload(IWeapon* pWeapon, EntityId shooterId, IEntityClass* pAmmoType)                                                                 {}
  47.         virtual void OnSetAmmoCount(IWeapon* pWeapon, EntityId shooterId)                                                                                       {}
  48.         virtual void OnOutOfAmmo(IWeapon* pWeapon, IEntityClass* pAmmoType)                                                                                     {}
  49.         virtual void OnReadyToFire(IWeapon* pWeapon)                                                                                                            {}
  50.         virtual void OnPickedUp(IWeapon* pWeapon, EntityId actorId, bool destroyed)                                                                             {}
  51.         virtual void OnDropped(IWeapon* pWeapon, EntityId actorId)                                                                                              {}
  52.         virtual void OnMelee(IWeapon* pWeapon, EntityId shooterId)                                                                                              {}
  53.         virtual void OnStartTargetting(IWeapon* pWeapon)                                                                                                        {}
  54.         virtual void OnStopTargetting(IWeapon* pWeapon)                                                                                                         {}
  55.         virtual void OnSelected(IWeapon* pWeapon, bool select)                                                                                                  {}
  56.         virtual void OnEndBurst(IWeapon* pWeapon, EntityId shooterId)                                                                                           {}
  57.         // ~IWeaponEventListener
  58.  
  59.         virtual void AddListener(EntityId weaponId, IWeaponEventListener* pListener)
  60.         {
  61.                 if (!(weaponId && pListener))
  62.                         return;
  63.  
  64.                 if (IWeapon* pWeapon = GetWeapon(weaponId))
  65.                         pWeapon->AddEventListener(pListener, __FUNCTION__);
  66.         }
  67.  
  68.         virtual void RemoveListener(EntityId weaponId, IWeaponEventListener* pListener)
  69.         {
  70.                 if (!(weaponId && pListener))
  71.                         return;
  72.  
  73.                 if (IWeapon* pWeapon = GetWeapon(weaponId))
  74.                         pWeapon->RemoveEventListener(pListener);
  75.         }
  76. };
  77.  
  78. class CFlowNode_AutoSightWeapon : public CFlowBaseNode<eNCT_Singleton>
  79. {
  80. public:
  81.         CFlowNode_AutoSightWeapon(SActivationInfo* pActInfo)
  82.         {
  83.         }
  84.  
  85.         void GetConfiguration(SFlowNodeConfig& config)
  86.         {
  87.                 static const SInputPortConfig in_ports[] =
  88.                 {
  89.                         InputPortConfig<Vec3>("enemy", _HELP("Connect the enemy position vector to shoot here")),
  90.                         { 0 }
  91.                 };
  92.                 config.pInputPorts = in_ports;
  93.                 config.pOutputPorts = 0;
  94.                 config.nFlags |= EFLN_TARGET_ENTITY;
  95.                 config.SetCategory(EFLN_APPROVED);
  96.         }
  97.  
  98.         void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  99.         {
  100.                 /*if (event == eFE_Activate && IsPortActive(pActInfo,0))
  101.                    {
  102.                    IScriptSystem * pSS = gEnv->pScriptSystem;
  103.                    SmartScriptTable table;
  104.                    pSS->GetGlobalValue("Weapon", table);
  105.                    Script::CallMethod( table, "StartFire");
  106.                    }
  107.                    else */
  108.                 if (event == eFE_Initialize)
  109.                 {
  110.                         pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, true);
  111.                 }
  112.                 else if (event == eFE_Update)
  113.                 {
  114.                         IEntity* pEntity = pActInfo->pEntity;
  115.                         if (pEntity)
  116.                         {
  117.                                 Vec3 dir = GetPortVec3(pActInfo, 0) - pEntity->GetWorldTM().GetTranslation();
  118.  
  119.                                 dir.normalize();
  120.  
  121.                                 Vec3 up(0, 0, 1);
  122.                                 Vec3 right(dir ^ up);
  123.  
  124.                                 if (right.len2() < 0.01f)
  125.                                 {
  126.                                         right = dir.GetOrthogonal();
  127.                                 }
  128.  
  129.                                 Matrix34 tm(pEntity->GetWorldTM());
  130.  
  131.                                 tm.SetColumn(1, dir);
  132.                                 tm.SetColumn(0, right.normalize());
  133.                                 tm.SetColumn(2, right ^ dir);
  134.  
  135.                                 pEntity->SetWorldTM(tm);
  136.                         }
  137.                 }
  138.         }
  139.  
  140.         virtual void GetMemoryUsage(ICrySizer* s) const
  141.         {
  142.                 s->Add(*this);
  143.         }
  144.  
  145. private:
  146. };
  147.  
  148. class CFlowNode_WeaponListener : public CFlowBaseNode<eNCT_Instanced>, public SWeaponListener
  149. {
  150. public:
  151.  
  152.         enum EInputs
  153.         {
  154.                 IN_ENABLE = 0,
  155.                 IN_DISABLE,
  156.                 IN_WEAPONID,
  157.                 IN_WEAPONCLASS,
  158.                 IN_AMMO,
  159.         };
  160.  
  161.         enum EOutputs
  162.         {
  163.                 OUT_ONSHOOT = 0,
  164.                 OUT_AMMOLEFT,
  165.                 OUT_ONMELEE,
  166.                 OUT_ONDROPPED,
  167.         };
  168.  
  169.         CFlowNode_WeaponListener(SActivationInfo* pActInfo)
  170.         {
  171.                 m_active = false;
  172.                 m_ammo = 0;
  173.                 m_weapId = 0;
  174.         }
  175.  
  176.         ~CFlowNode_WeaponListener()
  177.         {
  178.                 RemoveListener(m_weapId, this);
  179.         }
  180.  
  181.         IFlowNodePtr Clone(SActivationInfo* pActInfo)
  182.         {
  183.                 IFlowNode* pNode = new CFlowNode_WeaponListener(pActInfo);
  184.                 return pNode;
  185.         }
  186.  
  187.         void Serialize(SActivationInfo* pActInfo, TSerialize ser)
  188.         {
  189.                 ser.Value("active", m_active);
  190.                 ser.Value("ammo", m_ammo);
  191.                 ser.Value("weaponId", m_weapId);
  192.  
  193.                 if (ser.IsReading())
  194.                 {
  195.                         if (m_active && m_weapId != 0)
  196.                         {
  197.                                 IItemSystem* pItemSys = CCryAction::GetCryAction()->GetIItemSystem();
  198.  
  199.                                 IItem* pItem = pItemSys->GetItem(m_weapId);
  200.  
  201.                                 if (!pItem || !pItem->GetIWeapon())
  202.                                 {
  203.                                         GameWarning("[flow] CFlowNode_WeaponListener: Serialize no item/weapon.");
  204.                                         return;
  205.                                 }
  206.                                 IWeapon* pWeapon = pItem->GetIWeapon();
  207.                                 // set weapon listener
  208.                                 pWeapon->AddEventListener(this, "CFlowNode_WeaponListener");
  209.                                 // CryLog("[flow] CFlowNode_WeaponListener::Serialize() successfully created on '%s'", pItem->GetEntity()->GetName());
  210.                         }
  211.                         else
  212.                         {
  213.                                 Reset();
  214.                         }
  215.                 }
  216.         }
  217.  
  218.         void GetConfiguration(SFlowNodeConfig& config)
  219.         {
  220.                 static const SInputPortConfig inputs[] =
  221.                 {
  222.                         InputPortConfig_Void("Enable",         _HELP("Enable Listener")),
  223.                         InputPortConfig_Void("Disable",        _HELP("Disable Listener")),
  224.                         InputPortConfig<EntityId>("WeaponId",  _HELP("Listener will be set on this weapon if active")),
  225.                         InputPortConfig<string>("WeaponClass", _HELP("Use this if you want to specify the players weapon by name"),     0,                     _UICONFIG("enum_global:weapon")),
  226.                         InputPortConfig<int>("Ammo",           _HELP("Number of times the listener can be triggered. 0 means infinite"),_HELP("ShootCount")),
  227.                         { 0 }
  228.                 };
  229.                 static const SOutputPortConfig outputs[] =
  230.                 {
  231.                         OutputPortConfig_Void("OnShoot",      _HELP("OnShoot")),
  232.                         OutputPortConfig<int>("AmmoLeft",     _HELP("Shoots left"),                        _HELP("ShootsLeft")),
  233.                         OutputPortConfig_Void("OnMelee",      _HELP("Triggered on melee attack")),
  234.                         OutputPortConfig<string>("OnDropped", _HELP("Triggered when weapon was dropped.")),
  235.                         { 0 }
  236.                 };
  237.                 config.sDescription = "Listens on [WeaponId] (or players [WeaponClass], or as fallback current players weapon) and triggers OnShoot when shot.";
  238.                 config.pInputPorts = inputs;
  239.                 config.pOutputPorts = outputs;
  240.                 config.SetCategory(EFLN_APPROVED);
  241.         }
  242.  
  243.         void Reset()
  244.         {
  245.                 if (m_weapId != 0)
  246.                 {
  247.                         RemoveListener(m_weapId, this);
  248.                         m_weapId = 0;
  249.                 }
  250.                 m_active = false;
  251.         }
  252.  
  253.         void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  254.         {
  255.                 switch (event)
  256.                 {
  257.                 case eFE_Initialize:
  258.                         {
  259.                                 m_actInfo = *pActInfo;
  260.                                 Reset();
  261.                         }
  262.                         break;
  263.  
  264.                 case eFE_Activate:
  265.                         {
  266.                                 IItemSystem* pItemSys = CCryAction::GetCryAction()->GetIItemSystem();
  267.  
  268.                                 // create listener
  269.                                 if (IsPortActive(pActInfo, IN_DISABLE))
  270.                                 {
  271.                                         Reset();
  272.                                 }
  273.                                 if (IsPortActive(pActInfo, IN_ENABLE))
  274.                                 {
  275.                                         Reset();
  276.                                         IItem* pItem = 0;
  277.  
  278.                                         EntityId weaponId = GetPortEntityId(pActInfo, IN_WEAPONID);
  279.                                         if (weaponId != 0)
  280.                                         {
  281.                                                 pItem = pItemSys->GetItem(weaponId);
  282.                                         }
  283.                                         else
  284.                                         {
  285.                                                 IActor* pActor = CCryAction::GetCryAction()->GetClientActor();
  286.                                                 if (!pActor)
  287.                                                         return;
  288.  
  289.                                                 IInventory* pInventory = pActor->GetInventory();
  290.                                                 if (!pInventory)
  291.                                                         return;
  292.  
  293.                                                 const string& weaponClass = GetPortString(pActInfo, IN_WEAPONCLASS);
  294.                                                 if (!weaponClass.empty())
  295.                                                 {
  296.                                                         // get actor weapon by class
  297.                                                         IEntityClass* pClass = gEnv->pEntitySystem->GetClassRegistry()->FindClass(weaponClass);
  298.                                                         pItem = pItemSys->GetItem(pInventory->GetItemByClass(pClass));
  299.                                                 }
  300.                                                 else
  301.                                                 {
  302.                                                         // get current actor weapon
  303.                                                         pItem = pItemSys->GetItem(pInventory->GetCurrentItem());
  304.                                                 }
  305.                                         }
  306.  
  307.                                         if (!pItem || !pItem->GetIWeapon())
  308.                                         {
  309.                                                 GameWarning("[flow] CFlowNode_WeaponListener: no item/weapon.");
  310.                                                 return;
  311.                                         }
  312.  
  313.                                         m_weapId = pItem->GetEntity()->GetId();
  314.                                         IWeapon* pWeapon = pItem->GetIWeapon();
  315.  
  316.                                         // set initial ammo
  317.                                         m_ammo = GetPortInt(pActInfo, IN_AMMO);
  318.                                         if (m_ammo == 0)
  319.                                                 m_ammo = -1; // 0 input means infinite
  320.  
  321.                                         // set weapon listener
  322.                                         pWeapon->AddEventListener(this, "CFlowNode_WeaponListener");
  323.  
  324.                                         m_active = true;
  325.  
  326.                                         //CryLog("WeaponListener successfully created on %s", pItem->GetEntity()->GetName());
  327.                                 }
  328.                                 break;
  329.                         }
  330.                 }
  331.         }
  332.  
  333.         virtual void OnShoot(IWeapon* pWeapon, EntityId shooterId, EntityId ammoId, IEntityClass* pAmmoType, const Vec3& pos, const Vec3& dir, const Vec3& vel)
  334.         {
  335.                 if (m_active)
  336.                 {
  337.                         if (m_ammo != 0)
  338.                         {
  339.                                 ActivateOutput(&m_actInfo, OUT_ONSHOOT, true);
  340.                                 if (m_ammo != -1)
  341.                                         --m_ammo;
  342.                         }
  343.                         ActivateOutput(&m_actInfo, OUT_AMMOLEFT, m_ammo);
  344.                 }
  345.         }
  346.  
  347.         virtual void OnDropped(IWeapon* pWeapon, EntityId actorId)
  348.         {
  349.                 if (m_active)
  350.                         ActivateOutput(&m_actInfo, OUT_ONDROPPED, true);
  351.         }
  352.  
  353.         virtual void OnMelee(IWeapon* pWeapon, EntityId shooterId)
  354.         {
  355.                 if (m_active)
  356.                         ActivateOutput(&m_actInfo, OUT_ONMELEE, true);
  357.         }
  358.  
  359.         virtual void GetMemoryUsage(ICrySizer* s) const
  360.         {
  361.                 s->Add(*this);
  362.         }
  363.  
  364. private:
  365.         SActivationInfo m_actInfo;
  366.         EntityId        m_weapId;
  367.         int             m_ammo;
  368.         bool            m_active;
  369. };
  370.  
  371. class CFlowNode_WeaponAmmo : public CFlowFrameworkBaseNode<eNCT_Singleton>
  372. {
  373.         enum EInputs
  374.         {
  375.                 IN_SET = 0,
  376.                 IN_GET,
  377.                 IN_AMMOTYPE,
  378.                 IN_AMMOCOUNT,
  379.                 IN_ADD
  380.         };
  381.  
  382.         enum EOutputs
  383.         {
  384.                 OUT_MAGAZINE = 0,
  385.                 OUT_INVENTORY,
  386.                 OUT_TOTAL
  387.         };
  388.  
  389. public:
  390.         CFlowNode_WeaponAmmo(SActivationInfo* pActInfo) {}
  391.  
  392.         void GetConfiguration(SFlowNodeConfig& config)
  393.         {
  394.                 static const SInputPortConfig in_ports[] =
  395.                 {
  396.                         InputPortConfig_Void("Set",         _HELP("")),
  397.                         InputPortConfig_Void("Get",         _HELP("")),
  398.                         InputPortConfig<string>("AmmoType", _HELP("Select Ammo type"),         _HELP(""),   _UICONFIG("enum_global:ammos")),
  399.                         InputPortConfig<int>("AmountCount", _HELP("Select amount to add/set"), _HELP("")),
  400.                         InputPortConfig<bool>("Add",        _HELP("Add or Set the ammo count"),_HELP("")),
  401.                         { 0 }
  402.                 };
  403.  
  404.                 static const SOutputPortConfig out_ports[] =
  405.                 {
  406.                         OutputPortConfig<int>("MagazineAmmo",  _HELP("")),
  407.                         OutputPortConfig<int>("InventoryAmmo", _HELP("")),
  408.                         OutputPortConfig<int>("TotalAmmo",     _HELP("")),
  409.                         { 0 }
  410.                 };
  411.  
  412.                 config.sDescription = _HELP("Add a specified amount of ammo, of a specified ammo type to the inventory.");
  413.                 config.nFlags |= EFLN_TARGET_ENTITY;
  414.                 config.pInputPorts = in_ports;
  415.                 config.pOutputPorts = out_ports;
  416.                 config.SetCategory(EFLN_APPROVED);
  417.         }
  418.  
  419.         void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  420.         {
  421.                 if (event == eFE_Activate && (IsPortActive(pActInfo, IN_GET) || IsPortActive(pActInfo, IN_SET)))
  422.                 {
  423.                         IActor* pActor = GetInputActor(pActInfo);
  424.                         if (!pActor)
  425.                                 return;
  426.  
  427.                         IInventory* pInventory = pActor->GetInventory();
  428.                         if (pInventory)
  429.                         {
  430.                                 const string& ammoType = GetPortString(pActInfo, IN_AMMOTYPE);
  431.                                 IEntityClass* pAmmoClass = gEnv->pEntitySystem->GetClassRegistry()->FindClass(ammoType.c_str());
  432.  
  433.                                 if (pAmmoClass)
  434.                                 {
  435.                                         if (IsPortActive(pActInfo, IN_SET))
  436.                                         {
  437.                                                 const bool bAdd = GetPortBool(pActInfo, IN_ADD);
  438.                                                 const int ammoAmount = GetPortInt(pActInfo, IN_AMMOCOUNT);
  439.  
  440.                                                 pInventory->SetAmmoCount(pAmmoClass, bAdd ? (ammoAmount + pInventory->GetAmmoCount(pAmmoClass)) : (ammoAmount));
  441.                                         }
  442.  
  443.                                         int magazineAmmo = 0;
  444.                                         int inventoryAmmo = pInventory->GetAmmoCount(pAmmoClass);
  445.  
  446.                                         if (IItem* pItem = pActor->GetCurrentItem())
  447.                                         {
  448.                                                 IWeapon* pCurrentWeapon = GetWeapon(pItem->GetEntityId());
  449.  
  450.                                                 if (pCurrentWeapon)
  451.                                                 {
  452.                                                         magazineAmmo = pCurrentWeapon->GetAmmoCount(pAmmoClass);
  453.                                                 }
  454.                                         }
  455.  
  456.                                         ActivateOutput(pActInfo, OUT_MAGAZINE, magazineAmmo);
  457.                                         ActivateOutput(pActInfo, OUT_INVENTORY, inventoryAmmo);
  458.                                         ActivateOutput(pActInfo, OUT_TOTAL, (magazineAmmo + inventoryAmmo));
  459.                                 }
  460.                         }
  461.                 }
  462.         }
  463.  
  464.         virtual void GetMemoryUsage(ICrySizer* s) const
  465.         {
  466.                 s->Add(*this);
  467.         }
  468. };
  469. //#define DEBUG_NODEFIREWEAPON
  470.  
  471. #ifdef DEBUG_NODEFIREWEAPON
  472. static Vec3 posTarget = Vec3(0, 0, 0);
  473. static Vec3 posOrig = Vec3(0, 0, 0);
  474. static Vec3 posShot = Vec3(0, 0, 0);
  475. #endif
  476.  
  477. class CFlowNode_FireWeapon : public CFlowBaseNode<eNCT_Instanced>, public SWeaponListener
  478. {
  479. public:
  480.         enum EInputs
  481.         {
  482.                 IN_TARGETID = 0,
  483.                 IN_TARGETPOS,
  484.                 IN_ALIGNTOTARGET,
  485.                 IN_STARTFIRE,
  486.                 IN_STOPFIRE,
  487.                 IN_NUMBEROFSHOTS,
  488.                 IN_ACCURACY,
  489.         };
  490.  
  491.         enum EOutputs
  492.         {
  493.                 OUT_STARTEDFIRING = 0,
  494.                 OUT_STOPPEDFIRING,
  495.         };
  496.  
  497.         CFlowNode_FireWeapon(SActivationInfo* pActInfo)
  498.         {
  499.                 m_weapId = 0;
  500.                 m_isFiring = false;
  501.                 m_numShotsDone = 0;
  502.                 m_numShots = 0;
  503.                 m_firingPos = Vec3(0, 0, 0);
  504.                 m_lastPos = Vec3(0, 0, 0);
  505.                 m_lastRotation = Quat(1, 0, 0, 0);
  506.         }
  507.         ~CFlowNode_FireWeapon()
  508.         {
  509.                 RemoveListener(m_weapId, this);
  510.         }
  511.  
  512.         void Serialize(SActivationInfo* pActInfo, TSerialize ser)
  513.         {
  514.                 ser.Value("weaponId", m_weapId);
  515.                 ser.Value("firing", m_isFiring);
  516.                 ser.Value("numShotsDone", m_numShotsDone);
  517.                 ser.Value("numShots", m_numShots);
  518.                 ser.Value("lastPos", m_lastPos);
  519.                 ser.Value("lastRotation", m_lastRotation);
  520.         }
  521.  
  522.         IFlowNodePtr Clone(SActivationInfo* pActInfo)
  523.         {
  524.                 IFlowNode* pNode = new CFlowNode_FireWeapon(pActInfo);
  525.                 return pNode;
  526.         }
  527.  
  528.         void GetConfiguration(SFlowNodeConfig& config)
  529.         {
  530.                 static const SInputPortConfig inputs[] =
  531.                 {
  532.                         InputPortConfig<EntityId>("TargetId",  _HELP("Target entity")),
  533.                         InputPortConfig<Vec3>("TargetPos",     _HELP("Alternatively, Target position")),
  534.                         InputPortConfig<bool>("AlignToTarget", true,                                             _HELP("If true, weapon entity will be aligned to target direction. Using this can have side effects. Do not use on self-aligning weapons.")),
  535.                         InputPortConfig_Void("StartFire",      _HELP("Trigger this to start fire.")),
  536.                         InputPortConfig_Void("StopFire",       _HELP("Trigger this to stop fire.")),
  537.                         InputPortConfig<int>("NumberOfShots",  _HELP("number of shots to fire (0 = unlimited)")),
  538.                         InputPortConfig<float>("Accuracy",     1.f,                                              _HELP("value between 0..1.  1 = 100% accuracy.")),
  539.                         { 0 }
  540.                 };
  541.                 static const SOutputPortConfig outputs[] = {
  542.                         OutputPortConfig<bool>("FireStarted", _HELP("True if StartFire command was successful")),
  543.                         OutputPortConfig<bool>("FireStopped", _HELP("True if StopFire command was successful or max number of shots completed")),
  544.                         { 0 }
  545.                 };
  546.  
  547.                 config.sDescription = _HELP("Fires a weapon and sets a target entity or a target position.");
  548.                 config.pInputPorts = inputs;
  549.                 config.pOutputPorts = outputs;
  550.                 config.nFlags |= EFLN_TARGET_ENTITY;
  551.                 config.SetCategory(EFLN_APPROVED);
  552.         }
  553.  
  554.         IWeapon* GetWeapon(SActivationInfo* pActInfo)
  555.         {
  556.                 if (pActInfo->pEntity)
  557.                         return ::GetWeapon(pActInfo->pEntity->GetId());
  558.  
  559.                 return NULL;
  560.         }
  561.  
  562.         //////////////////////////////////////////////////////////////////////////
  563.         Vec3 GetTargetPos(SActivationInfo* pActInfo)
  564.         {
  565.                 EntityId targetId = GetPortEntityId(pActInfo, IN_TARGETID);
  566.  
  567.                 Vec3 targetPos(0, 0, 0);
  568.  
  569.                 if (targetId)
  570.                 {
  571.                         IEntity* pTarget = gEnv->pEntitySystem->GetEntity(targetId);
  572.                         if (pTarget)
  573.                         {
  574.                                 AABB box;
  575.                                 pTarget->GetWorldBounds(box);
  576.                                 targetPos = box.GetCenter();
  577.                         }
  578.                 }
  579.                 else
  580.                 {
  581.                         targetPos = GetPortVec3(pActInfo, IN_TARGETPOS);
  582.                 }
  583.                 return targetPos;
  584.         }
  585.  
  586.         //////////////////////////////////////////////////////////////////////////
  587.         void CalcFiringPosition(SActivationInfo* pActInfo, IWeapon* pWeapon)
  588.         {
  589.                 Vec3 realTargetPos = GetTargetPos(pActInfo);
  590.                 m_firingPos = realTargetPos;
  591.  
  592.                 float acc = GetPortFloat(pActInfo, IN_ACCURACY);
  593.                 if (acc < 1)
  594.                 {
  595.                         bool itHits = cry_random(0.0f, 1.0f) < acc;
  596.                         if (!itHits)
  597.                         {
  598.                                 // what this code does is:
  599.                                 // - in the plane perpendicular to the shooting vector, and located at the target, it builds a vector, centered in the target, and rotates it to point in a random direction, but always in the plane
  600.                                 // - then it moves along that vector, a random distance (error distance)
  601.                                 // - and that is the final to-fire position
  602.  
  603.                                 const float MAX_ERROR_LENGTH = 6.f; // meters
  604.                                 const float MIN_ERROR_ANGLE = 2.f;  // degrees
  605.                                 const float MAX_ERROR_ANGLE = 5.f;  // degrees
  606.  
  607.                                 // error angle from weapon to target
  608.                                 float errorAngle = cry_random(MIN_ERROR_ANGLE, MAX_ERROR_ANGLE);
  609.  
  610.                                 // 2d angle, in the plane normal to the vector from weapon to target.
  611.                                 float dirErrorAngle = cry_random(0.0f, 360.0f);
  612.  
  613.                                 // could be done with just 1 sqrt instead 2, but is not really worth it here.
  614.                                 Vec3 vecToTarget = pActInfo->pEntity->GetPos() - realTargetPos;
  615.                                 Vec3 vecToTargetNorm = vecToTarget.GetNormalizedSafe();
  616.                                 Vec3 dirError2D = vecToTargetNorm.GetOrthogonal();
  617.                                 dirError2D = dirError2D.GetRotated(vecToTargetNorm, DEG2RAD(dirErrorAngle));
  618.  
  619.                                 float dist = vecToTarget.len();
  620.                                 float errorLen = std::min(dist * tanf(DEG2RAD(errorAngle)), MAX_ERROR_LENGTH);
  621.  
  622.                                 m_firingPos = realTargetPos + (dirError2D * errorLen);
  623.  
  624. #ifdef DEBUG_NODEFIREWEAPON
  625.                                 posTarget = realTargetPos;
  626.                                 posOrig = pActInfo->pEntity->GetPos();
  627.                                 posShot = m_firingPos;
  628. #endif
  629.                         }
  630.                 }
  631.                 if (GetPortBool(pActInfo, IN_ALIGNTOTARGET))
  632.                 {
  633.                         UpdateWeaponTM(pActInfo, m_firingPos);
  634.                         m_lastPos = pActInfo->pEntity->GetWorldPos();
  635.                         m_lastRotation = pActInfo->pEntity->GetWorldRotation();
  636.                 }
  637.                 pWeapon->SetDestination(m_firingPos);
  638.         }
  639.  
  640.         //////////////////////////////////////////////////////////////////////////
  641.         void UpdateWeaponTM(SActivationInfo* pActInfo, const Vec3& targetPos)
  642.         {
  643.                 // update entity rotation
  644.                 IEntity* pEntity = pActInfo->pEntity;
  645.                 Vec3 dir = targetPos - pEntity->GetWorldPos();
  646.                 dir.NormalizeSafe(Vec3Constants<float>::fVec3_OneY);
  647.  
  648.                 if (IEntity* pParent = pEntity->GetParent())
  649.                 {
  650.                         dir = pParent->GetWorldRotation().GetInverted() * dir;
  651.                 }
  652.  
  653.                 Matrix33 rotation = Matrix33::CreateRotationVDir(dir);
  654.                 pEntity->SetRotation(Quat(rotation));
  655.         }
  656.  
  657.         //////////////////////////////////////////////////////////////////////////
  658.         void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  659.         {
  660.                 IWeapon* pWeapon = GetWeapon(pActInfo);
  661.  
  662.                 if (!pWeapon)
  663.                         return;
  664.  
  665.                 switch (event)
  666.                 {
  667.                 case eFE_Initialize:
  668.                         {
  669.                                 m_isFiring = false;
  670.                                 m_numShots = GetPortInt(pActInfo, IN_NUMBEROFSHOTS);
  671.                                 m_actInfo = *pActInfo;
  672.                                 m_numShotsDone = 0;
  673.  
  674.                                 pWeapon->StopFire();
  675.  
  676.                                 if (pActInfo->pEntity->GetId() != m_weapId)
  677.                                         RemoveListener(m_weapId, this);
  678.  
  679.                                 m_weapId = pActInfo->pEntity->GetId();
  680.                                 pWeapon->AddEventListener(this, __FUNCTION__);
  681.  
  682. #ifdef DEBUG_NODEFIREWEAPON
  683.                                 pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, true);
  684. #endif
  685.                                 break;
  686.                         }
  687.  
  688.                 case eFE_Activate:
  689.                         {
  690.                                 m_actInfo = *pActInfo;
  691.                                 if (IsPortActive(pActInfo, IN_NUMBEROFSHOTS))
  692.                                         m_numShots = GetPortBool(pActInfo, IN_NUMBEROFSHOTS);
  693.  
  694.                                 if (IsPortActive(pActInfo, IN_STOPFIRE))
  695.                                 {
  696.                                         StopFiring(pActInfo, pWeapon);
  697.                                 }
  698.                                 if (IsPortActive(pActInfo, IN_STARTFIRE))
  699.                                 {
  700.                                         m_numShotsDone = 0;
  701.                                         ReplenishAmmo(pWeapon);
  702.                                         pWeapon->StopFire();
  703.                                         StartFiring(pActInfo, pWeapon);
  704.                                 }
  705.                                 break;
  706.                         }
  707.  
  708.                 case eFE_Update:
  709.                         {
  710.                                 // this fixes the problem when the entity is being externally moved/rotated, in the interval of time between when the weapon is aimed an the actual shot happens
  711.                                 if (m_isFiring && GetPortBool(pActInfo, IN_ALIGNTOTARGET))
  712.                                         if (pActInfo->pEntity->GetWorldPos() != m_lastPos || pActInfo->pEntity->GetWorldRotation() != m_lastRotation)
  713.                                                 CalcFiringPosition(pActInfo, pWeapon);
  714.  
  715. #ifdef DEBUG_NODEFIREWEAPON
  716.                                 ColorB colorRed(255, 0, 0);
  717.                                 ColorB colorGreen(0, 255, 0);
  718.                                 gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine(posOrig, colorRed, posTarget, colorRed);
  719.                                 gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine(posTarget, colorGreen, posShot, colorGreen);
  720. #endif
  721.                                 break;
  722.                         }
  723.                 }
  724.         }
  725.  
  726.         //////////////////////////////////////////////////////////////////////////
  727.         virtual void StartFiring(SActivationInfo* pActInfo, IWeapon* pWeapon)
  728.         {
  729.                 CalcFiringPosition(pActInfo, pWeapon);
  730.                 pWeapon->StartFire();
  731.                 m_isFiring = true;
  732.  
  733.                 ActivateOutput(pActInfo, OUT_STARTEDFIRING, true);
  734.                 pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, true);
  735.         }
  736.  
  737.         //////////////////////////////////////////////////////////////////////////
  738.         virtual void StopFiring(SActivationInfo* pActInfo, IWeapon* pWeapon)
  739.         {
  740.                 pWeapon->StopFire();
  741.                 m_isFiring = false;
  742.  
  743.                 ActivateOutput(pActInfo, OUT_STOPPEDFIRING, true);
  744.                 pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, false);
  745.         }
  746.  
  747.         //////////////////////////////////////////////////////////////////////////
  748.         virtual void OnShoot(IWeapon* pWeapon, EntityId shooterId, EntityId ammoId, IEntityClass* pAmmoType, const Vec3& pos, const Vec3& dir, const Vec3& vel)
  749.         {
  750.                 ++m_numShotsDone;
  751.  
  752.                 if (m_numShots != 0 && m_numShotsDone >= m_numShots)
  753.                         StopFiring(&m_actInfo, pWeapon);
  754.                 else
  755.                 {
  756.                         CalcFiringPosition(&m_actInfo, pWeapon);
  757.                 }
  758.         }
  759.  
  760.         //////////////////////////////////////////////////////////////////////////
  761.         void ReplenishAmmo(IWeapon* pWeapon)
  762.         {
  763.                 IFireMode* pFireMode = pWeapon->GetFireMode(pWeapon->GetCurrentFireMode());
  764.                 if (pFireMode)
  765.                         pWeapon->SetAmmoCount(pFireMode->GetAmmoType(), pFireMode->GetClipSize());
  766.         }
  767.  
  768.         //////////////////////////////////////////////////////////////////////////
  769.         virtual void OnOutOfAmmo(IWeapon* pWeapon, IEntityClass* pAmmoType)
  770.         {
  771.                 ReplenishAmmo(pWeapon);
  772.                 StartFiring(&m_actInfo, pWeapon);
  773.         }
  774.  
  775.         virtual void GetMemoryUsage(ICrySizer* s) const
  776.         {
  777.                 s->Add(*this);
  778.         }
  779.  
  780. private:
  781.         EntityId        m_weapId;
  782.         SActivationInfo m_actInfo;
  783.         int             m_numShotsDone;
  784.         int             m_numShots;
  785.         bool            m_isFiring;
  786.         Vec3            m_firingPos; // if accuracy is not 1, this could be not the actual target position
  787.         Vec3            m_lastPos;
  788.         Quat            m_lastRotation;
  789.  
  790. };
  791.  
  792. class CFlowNode_ChangeFireMode : public CFlowBaseNode<eNCT_Singleton>
  793. {
  794. public:
  795.         enum EInputs
  796.         {
  797.                 IN_SWITCH,
  798.         };
  799.  
  800.         CFlowNode_ChangeFireMode(SActivationInfo* pActInfo)
  801.         {
  802.         }
  803.         ~CFlowNode_ChangeFireMode()
  804.         {
  805.         }
  806.  
  807.         void GetConfiguration(SFlowNodeConfig& config)
  808.         {
  809.                 static const SInputPortConfig inputs[] =
  810.                 {
  811.                         InputPortConfig_Void("Switch", _HELP("Trigger this to switch fire modes.")),
  812.                         { 0 }
  813.                 };
  814.                 static const SOutputPortConfig outputs[] = {
  815.                         { 0 }
  816.                 };
  817.  
  818.                 config.sDescription = _HELP("Switched the weapon fire mode.");
  819.                 config.pInputPorts = inputs;
  820.                 config.pOutputPorts = outputs;
  821.                 config.nFlags |= EFLN_TARGET_ENTITY;
  822.                 config.SetCategory(EFLN_APPROVED);
  823.         }
  824.  
  825.         IWeapon* GetWeapon(SActivationInfo* pActInfo)
  826.         {
  827.                 if (pActInfo->pEntity)
  828.                         return ::GetWeapon(pActInfo->pEntity->GetId());
  829.  
  830.                 return NULL;
  831.         }
  832.  
  833.         void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
  834.         {
  835.                 IWeapon* pWeapon = GetWeapon(pActInfo);
  836.  
  837.                 if (!pWeapon)
  838.                         return;
  839.  
  840.                 switch (event)
  841.                 {
  842.                 case eFE_Activate:
  843.                         if (pWeapon)
  844.                                 pWeapon->StartChangeFireMode();
  845.                         break;
  846.                 }
  847.         }
  848.  
  849.         virtual void GetMemoryUsage(ICrySizer* s) const
  850.         {
  851.                 s->Add(*this);
  852.         }
  853. };
  854.  
  855. REGISTER_FLOW_NODE("Weapon:AutoSightWeapon", CFlowNode_AutoSightWeapon);
  856. REGISTER_FLOW_NODE("Weapon:FireWeapon", CFlowNode_FireWeapon);
  857. REGISTER_FLOW_NODE("Weapon:Listener", CFlowNode_WeaponListener);
  858. REGISTER_FLOW_NODE("Weapon:Ammo", CFlowNode_WeaponAmmo);
  859. REGISTER_FLOW_NODE("Weapon:ChangeFireMode", CFlowNode_ChangeFireMode);
  860.  
downloadFlowWeaponNodes.cpp Source code - Download CRYENGINE Source code
Related Source Codes/Software:
postal - 2017-06-11
reactide - Reactide is the first dedicated IDE for React web ... 2017-06-11
rkt - rkt is a pod-native container engine for Linux. It... 2017-06-11
uWebSockets - Tiny WebSockets https://for... 2017-06-11
realworld - TodoMVC for the RealWorld - Exemplary fullstack Me... 2017-06-11
CRYENGINE - CRYENGINE is a powerful real-time game development... 2017-06-11
goreplay - GoReplay is an open-source tool for capturing and ... 2017-06-10
pyenv - Simple Python version management 2017-06-10
redux-saga - An alternative side effect model for Redux apps ... 2017-06-10
angular-starter - 2017-06-10

 Back to top