text: //========= Mapbase - https://github.com/mapbase-source/source-sdk-2013 ============//
  //
  // Purpose: Be warned, because this entity is TERRIBLE!
  //
  //=============================================================================
  
  #include "cbase.h"
  #include "ai_basenpc.h"
  #include "saverestore_utlvector.h"
  
  
  
  //-----------------------------------------------------------------------------
  // Purpose: A special CAI_ShotRegulator class designed to be used with ai_weaponmodifier.
  //			I'm too chicken to do anything fun with it.
  //-----------------------------------------------------------------------------
  typedef CAI_ShotRegulator CAI_CustomShotRegulator;
  /*
  class CAI_CustomShotRegulator : public CAI_ShotRegulator
  {
  	DECLARE_CLASS( CAI_CustomShotRegulator, CAI_ShotRegulator );
  public:
  	void SetMinBurstInterval( float flMinBurstInterval ) { m_flMinBurstInterval = flMinBurstInterval; }
  	void SetMaxBurstInterval( float flMaxBurstInterval ) { m_flMaxBurstInterval = flMaxBurstInterval; }
  };
  */
  
  // A lot of functions can't set each range individually, so we have to do this for a lot of them.
  // (again, too chicken to do something useful with CAI_CustomShotRegulator)
  #define WeaponModifierSetRange(string, function) float minimum = 0; \
  		float maximum = 0; \
  		if (sscanf(string, "%f:%f", &minimum, &maximum)) \
  			function(minimum, maximum);
  
  #define WEAPONMODIFIER_MAX_NPCS 16
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  //-----------------------------------------------------------------------------
  class CAI_WeaponModifier : public CLogicalEntity
  {
  	DECLARE_CLASS( CAI_WeaponModifier, CLogicalEntity );
  	DECLARE_DATADESC();
  public:
  
  	void Spawn();
  
  	virtual int			Save( ISave &save ); 
  	virtual int			Restore( IRestore &restore );
  
  	bool KeyValue(const char *szKeyName, const char *szValue);
  
  	void EnableOnNPC(CAI_BaseNPC *pNPC);
  	void DisableOnNPC(CAI_BaseNPC *pNPC);
  
  	// Inputs
  	void InputEnable( inputdata_t &inputdata );
  	void InputDisable( inputdata_t &inputdata );
  	void InputEnableOnNPC( inputdata_t &inputdata );
  	void InputDisableOnNPC( inputdata_t &inputdata );
  
  	void InputSetBurstInterval( inputdata_t &inputdata ) { WeaponModifierSetRange(inputdata.value.String(), m_ModdedRegulator.SetBurstInterval); }
  	void InputSetRestInterval( inputdata_t &inputdata ) { WeaponModifierSetRange(inputdata.value.String(), m_ModdedRegulator.SetRestInterval); }
  	void InputSetBurstShotCountRange( inputdata_t &inputdata ) { WeaponModifierSetRange(inputdata.value.String(), m_ModdedRegulator.SetBurstShotCountRange); }
  	void InputSetBurstShotsRemaining( inputdata_t &inputdata ) { m_ModdedRegulator.SetBurstShotsRemaining(inputdata.value.Int()); }
  
  	void InputEnableShooting( inputdata_t &inputdata ) { m_ModdedRegulator.EnableShooting(); }
  	void InputDisableShooting( inputdata_t &inputdata ) { m_ModdedRegulator.DisableShooting(); }
  	void InputFireNoEarlierThan( inputdata_t &inputdata ) { m_ModdedRegulator.FireNoEarlierThan(gpGlobals->curtime + inputdata.value.Float()); }
  	void InputReset( inputdata_t &inputdata ) { m_ModdedRegulator.Reset(inputdata.value.Bool()); }
  
  	// The NPCs and their original regulators.
  	AIHANDLE m_hNPCs[WEAPONMODIFIER_MAX_NPCS];
  	CAI_ShotRegulator m_StoredRegulators[WEAPONMODIFIER_MAX_NPCS];
  
  	CAI_CustomShotRegulator m_ModdedRegulator;
  
  	bool m_bDisabled;
  };
  
  LINK_ENTITY_TO_CLASS(ai_weaponmodifier, CAI_WeaponModifier);
  
  BEGIN_DATADESC( CAI_WeaponModifier )
  
  	DEFINE_EMBEDDED( m_ModdedRegulator ),
  
  	DEFINE_ARRAY( m_hNPCs, FIELD_EHANDLE, WEAPONMODIFIER_MAX_NPCS ),
  	DEFINE_EMBEDDED_ARRAY( m_StoredRegulators, WEAPONMODIFIER_MAX_NPCS ),
  
  	DEFINE_KEYFIELD( m_bDisabled, FIELD_BOOLEAN, "StartDisabled" ),
  
  	// Inputs
  	DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
  	DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
  	DEFINE_INPUTFUNC( FIELD_EHANDLE, "EnableOnNPC", InputEnableOnNPC ),
  	DEFINE_INPUTFUNC( FIELD_EHANDLE, "DisableOnNPC", InputDisableOnNPC ),
  
  	DEFINE_INPUTFUNC( FIELD_STRING, "SetBurstInterval", InputSetBurstInterval ),
  	DEFINE_INPUTFUNC( FIELD_STRING, "SetRestInterval", InputSetRestInterval ),
  	DEFINE_INPUTFUNC( FIELD_STRING, "SetBurstShotCountRange", InputSetBurstShotCountRange ),
  	DEFINE_INPUTFUNC( FIELD_INTEGER, "SetBurstShotsRemaining", InputSetBurstShotsRemaining ),
  
  	DEFINE_INPUTFUNC( FIELD_VOID, "EnableShooting", InputEnableShooting ),
  	DEFINE_INPUTFUNC( FIELD_VOID, "DisableShooting", InputDisableShooting ),
  	DEFINE_INPUTFUNC( FIELD_FLOAT, "FireNoEarlierThan", InputFireNoEarlierThan ),
  	DEFINE_INPUTFUNC( FIELD_BOOLEAN, "Reset", InputReset ),
  
  END_DATADESC()
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  //-----------------------------------------------------------------------------
  void CAI_WeaponModifier::Spawn()
  {
  	if (!m_bDisabled)
  	{
  		inputdata_t inputdata;
  		InputEnable(inputdata);
  	}
  
  	BaseClass::Spawn();
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  //-----------------------------------------------------------------------------
  int CAI_WeaponModifier::Save( ISave &save )
  {
  	return BaseClass::Save(save);
  }
  
  int CAI_WeaponModifier::Restore( IRestore &restore )
  {
  	return BaseClass::Restore(restore);
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Handles key values from the BSP before spawn is called.
  //-----------------------------------------------------------------------------
  bool CAI_WeaponModifier::KeyValue( const char *szKeyName, const char *szValue )
  {
  	if (FStrEq(szKeyName, "BurstInterval"))
  	{
  		WeaponModifierSetRange(szValue, m_ModdedRegulator.SetBurstInterval);
  	}
  	else if (FStrEq(szKeyName, "RestInterval"))
  	{
  		WeaponModifierSetRange(szValue, m_ModdedRegulator.SetRestInterval);
  	}
  	else if (FStrEq(szKeyName, "BurstShotCountRange"))
  	{
  		WeaponModifierSetRange(szValue, m_ModdedRegulator.SetBurstShotCountRange);
  	}
  	else if (FStrEq(szKeyName, "BurstShotsRemaining"))
  	{
  		m_ModdedRegulator.SetBurstShotsRemaining(atoi(szValue));
  	}
  	else
  		return BaseClass::KeyValue(szKeyName, szValue);
  
  	return true;
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  //-----------------------------------------------------------------------------
  void CAI_WeaponModifier::EnableOnNPC( CAI_BaseNPC *pNPC )
  {
  	for (int i = 0; i < WEAPONMODIFIER_MAX_NPCS; i++)
  	{
  		if (m_hNPCs[i] == NULL)
  		{
  			m_hNPCs[i] = pNPC;
  			m_StoredRegulators[i] = *pNPC->GetShotRegulator();
  
  			pNPC->SetShotRegulator(m_ModdedRegulator);
  		}
  		else if (m_hNPCs[i] == pNPC)
  		{
  			// We're already in it
  			return;
  		}
  	}
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  //-----------------------------------------------------------------------------
  void CAI_WeaponModifier::DisableOnNPC( CAI_BaseNPC *pNPC )
  {
  	for (int i = 0; i < WEAPONMODIFIER_MAX_NPCS; i++)
  	{
  		if (m_hNPCs[i] == pNPC)
  		{
  			pNPC->SetShotRegulator(m_StoredRegulators[i]);
  			m_hNPCs[i] = NULL;
  
  			// Just reset it to our modded one
  			m_StoredRegulators[i] = m_ModdedRegulator;
  		}
  	}
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  //-----------------------------------------------------------------------------
  void CAI_WeaponModifier::InputEnable( inputdata_t &inputdata )
  {
  	CBaseEntity *pEntity = gEntList.FindEntityByName(NULL, STRING(m_target), this, inputdata.pActivator, inputdata.pCaller);
  	while (pEntity)
  	{
  		if (pEntity->IsNPC())
  		{
  			EnableOnNPC(pEntity->MyNPCPointer());
  		}
  
  		pEntity = gEntList.FindEntityByName(pEntity, STRING(m_target), this, inputdata.pActivator, inputdata.pCaller);
  	}
  }
  
  void CAI_WeaponModifier::InputDisable( inputdata_t &inputdata )
  {
  	for (int i = 0; i < WEAPONMODIFIER_MAX_NPCS; i++)
  	{
  		m_hNPCs[i]->SetShotRegulator(m_StoredRegulators[i]);
  		m_hNPCs[i] = NULL;
  
  		// Just reset it to our modded one
  		m_StoredRegulators[i] = m_ModdedRegulator;
  	}
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  //-----------------------------------------------------------------------------
  void CAI_WeaponModifier::InputEnableOnNPC( inputdata_t &inputdata )
  {
  	if (inputdata.value.Entity() && inputdata.value.Entity()->IsNPC())
  	{
  		EnableOnNPC(inputdata.value.Entity()->MyNPCPointer());
  	}
  }
  
  void CAI_WeaponModifier::InputDisableOnNPC( inputdata_t &inputdata )
  {
  	if (inputdata.value.Entity() && inputdata.value.Entity()->IsNPC())
  	{
  		DisableOnNPC(inputdata.value.Entity()->MyNPCPointer());
  	}
  }
  