while (service_reg_it != m_service_register_map.end())
    {
      if (now - service_reg_it->second.second > std::chrono::milliseconds(eCALPAR(CMN, REGISTRATION_TO)))
      {
#ifndef NDEBUG
        // log it
        Logging::Log(log_level_debug1, "CServGate::GetServiceInfo - Removing service due to timeout");
#endif // !NDEBUG
        m_service_register_map.erase(service_reg_it++);
      }
      else
      {
        service_reg_it++;
      }
    }

/*
 *
 * ========================= eCAL LICENSE =================================
*/

/**
 * @brief  eCAL server gateway class
**/

#include <ecal/ecal.h>

#include "ecal_def.h"
#include "ecal_servgate.h"
#include "ecal_config_hlp.h"

#include <iterator>
#include <atomic>

namespace eCAL
{
  // CServGate
  std::atomic<bool> CServGate::m_created;
  CServGate::CServGate() = default;

  CServGate::~CServGate()
  {
    Destroy();
  }

  void CServGate::Create()
  {
    if(m_created) return;
    m_created = true;
  }

  void CServGate::Destroy()
  {
    if(!m_created) return;
    m_created = false;
  }

  bool CServGate::Register(const std::string& service_name_, CServiceServerImpl* service_)
  {
    if(!m_created) return(false);

    // register internal service implementation
    std::lock_guard<std::mutex> lock(m_internal_service_sync);
    m_internal_service_map.emplace(std::pair<std::string, CServiceServerImpl*>(service_name_, service_));

    return(true);
  }

  bool CServGate::Unregister(const std::string& service_name_, CServiceServerImpl* service_)
  {
    if(!m_created) return(false);
    bool ret_state = false;

    std::lock_guard<std::mutex> lock(m_internal_service_sync);
    auto res = m_internal_service_map.equal_range(service_name_);
    for(ServiceNameServiceImplMapT::iterator iter = res.first; iter != res.second; ++iter)
    {
      if(iter->second == service_)
      {
        m_internal_service_map.erase(iter);
        break;
      }
    }

    return(ret_state);
  }

  std::vector<CServGate::SService> CServGate::GetServiceInfo(const std::string& service_name_)
  {
    auto now = RegClockT::now();

    std::vector<CServGate::SService> ret_vec;
    std::lock_guard<std::mutex> lock(m_service_register_sync);

    // Cleanup old services
    auto service_reg_it = m_service_register_map.begin();

    // Look for requested services
    for (auto& service : m_service_register_map)
    {
      if (service.second.first.sname == service_name_)
      {
        ret_vec.push_back(service.second.first);
      }
    }
    return(ret_vec);
  }

  void CServGate::ApplyServiceRegistration(const eCAL::pb::Sample & ecal_sample_)
  {
    auto registration_time = RegClockT::now();

    SService service;
    auto ecal_sample_service = ecal_sample_.service();
    service.hname    = ecal_sample_service.hname();
    service.pname    = ecal_sample_service.pname();
    service.uname    = ecal_sample_service.uname();
    service.pid      = static_cast<int>(ecal_sample_service.pid());
    service.sname    = ecal_sample_service.sname();
    service.tcp_port = static_cast<unsigned short>(ecal_sample_service.tcp_port());

    // register service
    std::lock_guard<std::mutex> lock(m_service_register_sync);
    std::string key = service.sname + ":" + std::to_string(service.tcp_port) + "@" + std::to_string(service.pid) + "@" + service.hname;

    auto existing_service_it = m_service_register_map.find(key);
    if (existing_service_it == m_service_register_map.end())
    {
      // Create new entry
#ifndef NDEBUG
      // log it
      Logging::Log(log_level_debug1, "CServGate::GetServiceInfo - Received new service registration");
#endif // !NDEBUG

      m_service_register_map.emplace(key, std::make_pair(service, registration_time));
    }
    else
    {
      // Update existing entry
      existing_service_it->second.second = registration_time;
    }
  }

  void CServGate::RefreshRegistrations()
  {
    if (!m_created) return;

    // refresh service registrations
    std::lock_guard<std::mutex> lock(m_internal_service_sync);
    for (auto iter : m_internal_service_map)
    {
      iter.second->RefreshRegistration();
    }
  }
};


/*
 * Copyright (c) Contributors to the Open 3D Engine Project.
 *
 *
 */

#include <AzCore/RTTI/BehaviorContext.h>

#include <Atom/RPI.Public/Scene.h>

#include <ScreenSpace/DeferredFogComponentController.h>

namespace AZ
{
    namespace Render
    {
        void DeferredFogComponentController::Reflect(ReflectContext* context)
        {
            DeferredFogComponentConfig::Reflect(context);

            if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
            {
                serializeContext->Class<DeferredFogComponentController>()
                    ->Version(0)
                    ->Field("Configuration", &DeferredFogComponentController::m_configuration);
            }

            if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
            {
                behaviorContext->EBus<DeferredFogRequestsBus>("DeferredFogRequestsBus")
                    ->Attribute(AZ::Script::Attributes::Module, "render")
                    ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)

                    // Auto-gen behavior context...
#define PARAM_EVENT_BUS DeferredFogRequestsBus::Events
#define AZ_GFX_COMMON_PARAM(ValueType, Name, MemberName, DefaultValue)                                  \
        ->Event("Set" #Name, &PARAM_EVENT_BUS::Set##Name)                                               \
        ->Event("Get" #Name, &PARAM_EVENT_BUS::Get##Name)                                               \
        ->VirtualProperty(#Name, "Get" #Name, "Set" #Name)                                              \

#include <Atom/Feature/ParamMacros/MapParamCommon.inl>
#include <Atom/Feature/ScreenSpace/DeferredFogParams.inl>
#include <Atom/Feature/ParamMacros/EndParams.inl>
#undef PARAM_EVENT_BUS

                    ;
            }
        }

        void DeferredFogComponentController::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
        {
            provided.push_back(AZ_CRC_CE("DeferredFogService"));
        }

        void DeferredFogComponentController::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
        {
            incompatible.push_back(AZ_CRC_CE("DeferredFogService"));
        }

        void DeferredFogComponentController::GetRequiredServices( [[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& required)
        {   // In the future deferred fog might be required to be anchored to activation locations
            required.push_back(AZ_CRC_CE("PostFXLayerService"));   // For aggregated settings, otherwise settings are not updated
        }

        DeferredFogComponentController::DeferredFogComponentController(const DeferredFogComponentConfig& config)
            : m_configuration(config)
        {
        }

        void DeferredFogComponentController::Activate(EntityId entityId)
        {
            m_entityId = entityId;

            PostProcessFeatureProcessorInterface* featureProcessor = RPI::Scene::GetFeatureProcessorForEntity<PostProcessFeatureProcessorInterface>(m_entityId);
            if (featureProcessor)
            {
                m_postProcessInterface = featureProcessor->GetOrCreateSettingsInterface(m_entityId);
                if (m_postProcessInterface)
                {
                    m_settingsInterface = m_postProcessInterface->GetOrCreateDeferredFogSettingsInterface();
                    OnConfigChanged();
                }
            }
            DeferredFogRequestsBus::Handler::BusConnect(m_entityId);
        }

{
            DeferredFogRequestsBus::Handler::BusDisconnect(m_entityId);

            if (m_postProcessInterface)
            {
                // turn off the lights before leaving
                m_settingsInterface->SetEnabled(false);
                m_settingsInterface->OnSettingsChanged();
                // Now you can leave
                m_postProcessInterface->RemoveDeferredFogSettingsInterface();
            }
            m_settingsInterface = nullptr;
            m_entityId.SetInvalid();
        }

        void DeferredFogComponentController::SetConfiguration(const DeferredFogComponentConfig& config)
        {
            m_configuration = config;
            OnConfigChanged();
        }

        const DeferredFogComponentConfig& DeferredFogComponentController::GetConfiguration() const
        {
            return m_configuration;
        }

        void DeferredFogComponentController::OnConfigChanged()
        {
            if (m_settingsInterface)
            {
                // Set SRG constants
                m_configuration.CopySettingsTo(m_settingsInterface);

                // Set the shader options bits
                m_settingsInterface->SetEnableFogLayerShaderOption(m_configuration.GetEnableFogLayerShaderOption());
                m_settingsInterface->SetUseNoiseTextureShaderOption(m_configuration.GetUseNoiseTextureShaderOption());

                // Enable / disable the pass
                m_settingsInterface->SetEnabled(m_configuration.GetIsEnabled());

                m_settingsInterface->OnSettingsChanged();
            }
        }

        // Auto generated getter/setter functions
        // The setter functions will set the values on the Atom settings class, then get the value back
        // from the settings class to set the local configuration. This is in case the settings class
        // applies some custom logic that results in the set value being different from the input
#define AZ_GFX_COMMON_PARAM(ValueType, Name, MemberName, DefaultValue)                                  \
        ValueType DeferredFogComponentController::Get##Name() const                                     \
        {                                                                                \
            return m_configuration.Get##Name();                                                         \
        }                                                                                \
        void DeferredFogComponentController::Set##Name(ValueType val)                                   \
        {                                                                                \
            if(m_settingsInterface)                                                                     \
            {                                                                                \
                m_configuration.Set##Name( val );                                                       \
                m_settingsInterface->Set##Name(val);                                                    \
                m_settingsInterface->OnSettingsChanged();                                               \
            }                                                                                \
            else                                                                                \
            {                                                                                \
                m_configuration.Set##Name( val );                                                       \
            }                                                                                \
        }                                                                                \

#include <Atom/Feature/ParamMacros/MapParamCommon.inl>
#include <Atom/Feature/ScreenSpace/DeferredFogParams.inl>
#include <Atom/Feature/ParamMacros/EndParams.inl>

    } // namespace Render
} // namespace AZ


{
            return m_configuration;
        }

/*
 * Copyright (c) Contributors to the Open 3D Engine Project.
 *
 *
 */

#include <AzCore/RTTI/BehaviorContext.h>

#include <Atom/RPI.Public/Scene.h>

#include <ScreenSpace/DeferredFogComponentController.h>

namespace AZ
{
    namespace Render
    {
        void DeferredFogComponentController::Reflect(ReflectContext* context)
        {
            DeferredFogComponentConfig::Reflect(context);

            if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
            {
                serializeContext->Class<DeferredFogComponentController>()
                    ->Version(0)
                    ->Field("Configuration", &DeferredFogComponentController::m_configuration);
            }

            if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
            {
                behaviorContext->EBus<DeferredFogRequestsBus>("DeferredFogRequestsBus")
                    ->Attribute(AZ::Script::Attributes::Module, "render")
                    ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)

                    // Auto-gen behavior context...
#define PARAM_EVENT_BUS DeferredFogRequestsBus::Events
#define AZ_GFX_COMMON_PARAM(ValueType, Name, MemberName, DefaultValue)                                  \
        ->Event("Set" #Name, &PARAM_EVENT_BUS::Set##Name)                                               \
        ->Event("Get" #Name, &PARAM_EVENT_BUS::Get##Name)                                               \
        ->VirtualProperty(#Name, "Get" #Name, "Set" #Name)                                              \

#include <Atom/Feature/ParamMacros/MapParamCommon.inl>
#include <Atom/Feature/ScreenSpace/DeferredFogParams.inl>
#include <Atom/Feature/ParamMacros/EndParams.inl>
#undef PARAM_EVENT_BUS

                    ;
            }
        }

        void DeferredFogComponentController::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
        {
            provided.push_back(AZ_CRC_CE("DeferredFogService"));
        }

        void DeferredFogComponentController::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
        {
            incompatible.push_back(AZ_CRC_CE("DeferredFogService"));
        }

        void DeferredFogComponentController::GetRequiredServices( [[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& required)
        {   // In the future deferred fog might be required to be anchored to activation locations
            required.push_back(AZ_CRC_CE("PostFXLayerService"));   // For aggregated settings, otherwise settings are not updated
        }

        DeferredFogComponentController::DeferredFogComponentController(const DeferredFogComponentConfig& config)
            : m_configuration(config)
        {
        }

        void DeferredFogComponentController::Activate(EntityId entityId)
        {
            m_entityId = entityId;

            PostProcessFeatureProcessorInterface* featureProcessor = RPI::Scene::GetFeatureProcessorForEntity<PostProcessFeatureProcessorInterface>(m_entityId);
            if (featureProcessor)
            {
                m_postProcessInterface = featureProcessor->GetOrCreateSettingsInterface(m_entityId);
                if (m_postProcessInterface)
                {
                    m_settingsInterface = m_postProcessInterface->GetOrCreateDeferredFogSettingsInterface();
                    OnConfigChanged();
                }
            }
            DeferredFogRequestsBus::Handler::BusConnect(m_entityId);
        }

        void DeferredFogComponentController::Deactivate()
        {
            DeferredFogRequestsBus::Handler::BusDisconnect(m_entityId);

            if (m_postProcessInterface)
            {
                // turn off the lights before leaving
                m_settingsInterface->SetEnabled(false);
                m_settingsInterface->OnSettingsChanged();
                // Now you can leave
                m_postProcessInterface->RemoveDeferredFogSettingsInterface();
            }
            m_settingsInterface = nullptr;
            m_entityId.SetInvalid();
        }

        void DeferredFogComponentController::SetConfiguration(const DeferredFogComponentConfig& config)
        {
            m_configuration = config;
            OnConfigChanged();
        }

        const DeferredFogComponentConfig& DeferredFogComponentController::GetConfiguration() const

        void DeferredFogComponentController::OnConfigChanged()
        {
            if (m_settingsInterface)
            {
                // Set SRG constants
                m_configuration.CopySettingsTo(m_settingsInterface);

                // Set the shader options bits
                m_settingsInterface->SetEnableFogLayerShaderOption(m_configuration.GetEnableFogLayerShaderOption());
                m_settingsInterface->SetUseNoiseTextureShaderOption(m_configuration.GetUseNoiseTextureShaderOption());

                // Enable / disable the pass
                m_settingsInterface->SetEnabled(m_configuration.GetIsEnabled());

                m_settingsInterface->OnSettingsChanged();
            }
        }

        // Auto generated getter/setter functions
        // The setter functions will set the values on the Atom settings class, then get the value back
        // from the settings class to set the local configuration. This is in case the settings class
        // applies some custom logic that results in the set value being different from the input
#define AZ_GFX_COMMON_PARAM(ValueType, Name, MemberName, DefaultValue)                                  \
        ValueType DeferredFogComponentController::Get##Name() const                                     \
        {                                                                                \
            return m_configuration.Get##Name();                                                         \
        }                                                                                \
        void DeferredFogComponentController::Set##Name(ValueType val)                                   \
        {                                                                                \
            if(m_settingsInterface)                                                                     \
            {                                                                                \
                m_configuration.Set##Name( val );                                                       \
                m_settingsInterface->Set##Name(val);                                                    \
                m_settingsInterface->OnSettingsChanged();                                               \
            }                                                                                \
            else                                                                                \
            {                                                                                \
                m_configuration.Set##Name( val );                                                       \
            }                                                                                \
        }                                                                                \

#include <Atom/Feature/ParamMacros/MapParamCommon.inl>
#include <Atom/Feature/ScreenSpace/DeferredFogParams.inl>
#include <Atom/Feature/ParamMacros/EndParams.inl>

    } // namespace Render
} // namespace AZ


/*
 * Copyright (c) Contributors to the Open 3D Engine Project.
 *
 *
 */

#include <AzCore/RTTI/BehaviorContext.h>

#include <Atom/RPI.Public/Scene.h>

#include <ScreenSpace/DeferredFogComponentController.h>

namespace AZ
{
    namespace Render
    {
        void DeferredFogComponentController::Reflect(ReflectContext* context)
        {
            DeferredFogComponentConfig::Reflect(context);

            if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
            {
                serializeContext->Class<DeferredFogComponentController>()
                    ->Version(0)
                    ->Field("Configuration", &DeferredFogComponentController::m_configuration);
            }

            if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
            {
                behaviorContext->EBus<DeferredFogRequestsBus>("DeferredFogRequestsBus")
                    ->Attribute(AZ::Script::Attributes::Module, "render")
                    ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)

                    // Auto-gen behavior context...
#define PARAM_EVENT_BUS DeferredFogRequestsBus::Events
#define AZ_GFX_COMMON_PARAM(ValueType, Name, MemberName, DefaultValue)                                  \
        ->Event("Set" #Name, &PARAM_EVENT_BUS::Set##Name)                                               \
        ->Event("Get" #Name, &PARAM_EVENT_BUS::Get##Name)                                               \
        ->VirtualProperty(#Name, "Get" #Name, "Set" #Name)                                              \

#include <Atom/Feature/ParamMacros/MapParamCommon.inl>
#include <Atom/Feature/ScreenSpace/DeferredFogParams.inl>
#include <Atom/Feature/ParamMacros/EndParams.inl>
#undef PARAM_EVENT_BUS

                    ;
            }
        }

        void DeferredFogComponentController::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
        {
            provided.push_back(AZ_CRC_CE("DeferredFogService"));
        }

        void DeferredFogComponentController::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
        {
            incompatible.push_bac

        }

        void DeferredFogComponentController::GetRequiredServices( [[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& required)
        {   // In the future deferred fog might be required to be anchored to activation locations
            required.push_back(AZ_CRC_CE("PostFXLayerService"));   // For aggregated settings, otherwise settings are not updated
        }

        DeferredFogComponentController::DeferredFogComponentController(const DeferredFogComponentConfig& config)
            : m_configuration(config)
        {
        }

        void DeferredFogComponentController::Activate(EntityId entityId)
        {
            m_entityId = entityId;

            PostProcessFeatureProcessorInterface* featureProcessor = RPI::Scene::GetFeatureProcessorForEntity<PostProcessFeatureProcessorInterface>(m_entityId);
            if (featureProcessor)
            {
                m_postProcessInterface = featureProcessor->GetOrCreateSettingsInterface(m_entityId);
                if (m_postProcessInterface)
                {
                    m_settingsInterface = m_postProcessInterface->GetOrCreateDeferredFogSettingsInterface();
                    OnConfigChanged();
                }
            }
            DeferredFogRequestsBus::Handler::BusConnect(m_entityId);
        }

        void DeferredFogComponentController::Deactivate()
        {
            DeferredFogRequestsBus::Handler::BusDisconnect(m_entityId);

            if (m_postProcessInterface)
            {
                // turn off the lights before leaving
                m_settingsInterface->SetEnabled(false);
                m_settingsInterface->OnSettingsChanged();
                // Now you can leave
                m_postProcessInterface->RemoveDeferredFogSettingsInterface();
            }
            m_settingsInterface = nullptr;
            m_entityId.SetInvalid();
        }

        void DeferredFogComponentController::SetConfiguration(const DeferredFogComponentConfig& config)
        {
            m_configuration = config;
            OnConfigChanged();
        }

        const DeferredFogComponentConfig& DeferredFogComponentController::GetConfiguration() const
        {
            return m_configuration;
        }

        void DeferredFogComponentController::OnConfigChanged()
        {
            if (m_settingsInterface)
            {
                // Set SRG constants
                m_configuration.CopySettingsTo(m_settingsInterface);

                // Set the shader options bits
                m_settingsInterface->SetEnableFogLayerShaderOption(m_configuration.GetEnableFogLayerShaderOption());
                m_settingsInterface->SetUseNoiseTextureShaderOption(m_configuration.GetUseNoiseTextureShaderOption());

                // Enable / disable the pass
                m_settingsInterface->SetEnabled(m_configuration.GetIsEnabled());

                m_settingsInterface->OnSettingsChanged();
            }
        }

        // Auto generated getter/setter functions
        // The setter functions will set the values on the Atom settings class, then get the value back
        // from the settings class to set the local configuration. This is in case the settings class
        // applies some custom logic that results in the set value being different from the input
#define AZ_GFX_COMMON_PARAM(ValueType, Name, MemberName, DefaultValue)                                  \
        ValueType DeferredFogComponentController::Get##Name() const                                     \
        {                                                                                \
            return m_configuration.Get##Name();                                                         \
        }                                                                                \
        void DeferredFogComponentController::Set##Name(ValueType val)                                   \
        {                                                                                \
            if(m_settingsInterface)                                                                     \
            {                                                                                \
                m_configuration.Set##Name( val );                                                       \
                m_settingsInterface->Set##Name(val);                                                    \
                m_settingsInterface->OnSettingsChanged();                                               \
            }                                                                                \
            else                                                                                \
            {                                                                                \
                m_configuration.Set##Name( val );                                                       \
            }                                                                                \
        }                                                                                \

#include <Atom/Feature/ParamMacros/MapParamCommon.inl>
#include <Atom/Feature/ScreenSpace/DeferredFogParams.inl>
#include <Atom/Feature/ParamMacros/EndParams.inl>

    } // namespace Render
} // namespace AZ


BatchAssociateAssessmentReportEvidenceRequest::BatchAssociateAssessmentReportEvidenceRequest() :
    m_assessmentIdHasBeenSet(false),
    m_evidenceFolderIdHasBeenSet(false),
    m_evidenceIdsHasBeenSet(false)

/**
 */

#include <aws/auditmanager/model/BatchAssociateAssessmentReportEvidenceRequest.h>
#include <aws/core/utils/json/JsonSerializer.h>

#include <utility>

using namespace Aws::AuditManager::Model;
using namespace Aws::Utils::Json;
using namespace Aws::Utils;

{
}

Aws::String BatchAssociateAssessmentReportEvidenceRequest::SerializePayload() const
{
  JsonValue payload;

  if(m_evidenceFolderIdHasBeenSet)
  {
   payload.WithString("evidenceFolderId", m_evidenceFolderId);

  }

  if(m_evidenceIdsHasBeenSet)
  {
   Array<JsonValue> evidenceIdsJsonList(m_evidenceIds.size());
   for(unsigned evidenceIdsIndex = 0; evidenceIdsIndex < evidenceIdsJsonList.GetLength(); ++evidenceIdsIndex)
   {
     evidenceIdsJsonList[evidenceIdsIndex].AsString(m_evidenceIds[evidenceIdsIndex]);
   }
   payload.WithArray("evidenceIds", std::move(evidenceIdsJsonList));

  }

  return payload.View().WriteReadable();
}


/**
 */

#include <aws/auditmanager/model/BatchAssociateAssessmentReportEvidenceRequest.h>
#include <aws/core/utils/json/JsonSerializer.h>

#include <utility>

using namespace Aws::AuditManager::Model;
using namespace Aws::Utils::Json;
using namespace Aws::Utils;

BatchAssociateAssessmentReportEvidenceRequest::BatchAssociateAssessmentReportEvidenceRequest() :
    m_assessmentIdHasBeenSet(false),
    m_evidenceFolderIdHasBeenSet(false),
    m_evidenceIdsHasBeenSet(false)

Aws::String BatchAssociateAssessmentReportEvidenceRequest::SerializePayload() const
{
  JsonValue payload;

  if(m_evidenceFolderIdHasBeenSet)
  {
   payload.WithString("evidenceFolderId", m_evidenceFolderId);

  }

  if(m_evidenceIdsHasBeenSet)
  {
   Array<JsonValue> evidenceIdsJsonList(m_evidenceIds.size());
   for(unsigned evidenceIdsIndex = 0; evidenceIdsIndex < evidenceIdsJsonList.GetLength(); ++evidenceIdsIndex)
   {
     evidenceIdsJsonList[evidenceIdsIndex].AsString(m_evidenceIds[evidenceIdsIndex]);
   }
   payload.WithArray("evidenceIds", std::move(evidenceIdsJsonList));

  }

  return payload.View().WriteReadable();
}


/**
 */

#include <aws/auditmanager/model/BatchAssociateAssessmentReportEvidenceRequest.h>
#include <aws/core/utils/json/JsonSerializer.h>

#include <utility>

using namespace Aws::AuditManager::Model;
using namespace Aws::Utils::Json;
using namespace Aws::Utils;

BatchAssociateAssessmentReportEvidenceRequest::BatchAssociateAssessmentReportEvidenceRequest() :
    m_assessmentIdHasBeenSet(false),
    m_evidenceFolderIdHasBeenSet(false),
    m_evidenceIdsHasBeenSet(false)
{
}

Aws::String BatchAssociateAssessmentReportEvidenceRequest::SerializePayload() const
{
  JsonV

  if(m_evidenceFolderIdHasBeenSet)
  {
   payload.WithString("evidenceFolderId", m_evidenceFolderId);

  }

  if(m_evidenceIdsHasBeenSet)
  {
   Array<JsonValue> evidenceIdsJsonList(m_evidenceIds.size());
   for(unsigned evidenceIdsIndex = 0; evidenceIdsIndex < evidenceIdsJsonList.GetLength(); ++evidenceIdsIndex)
   {
     evidenceIdsJsonList[evidenceIdsIndex].AsString(m_evidenceIds[evidenceIdsIndex]);
   }
   payload.WithArray("evidenceIds", std::move(evidenceIdsJsonList));

  }

  return payload.View().WriteReadable();
}


#include "cbase.h"

#ifdef CLIENT_DLL

#include "achievementmgr.h"
#include "baseachievement.h"
#include "tf_hud_statpanel.h"
#include "c_tf_team.h"
#include "c_tf_player.h"
#include "c_tf_playerresource.h"
#include "tf_gamerules.h"
#include "achievements_tf.h"
#include "c_tf_playerresource.h"
#include "tf_weapon_invis.h"

// SPY ACHIEVEMENT PACK

class CAchievementTFSpy_SpyBackstabSnipers : public CBaseTFAchievement
{
	void Init()
	{
		SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
		SetGoal( 1 );
	}

	void ResetTracking()
	{
		m_iSnipersKilled = 0;
	}

	virtual void ListenForEvents( void )
	{
		ListenForGameEvent( "localplayer_respawn" );
		ListenForGameEvent( "teamplay_round_active" );

		ResetTracking();
	}

	void FireGameEvent_Internal( IGameEvent *event )
	{
		const char *pszEventName = event->GetName();

		if ( FStrEq( pszEventName, "localplayer_respawn" ) ||
			FStrEq( pszEventName, "teamplay_round_active" ) )
		{
			ResetTracking();
		}
	}

	virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
	{
		// Achievement for backstabbing 3 snipers in a single life.
		CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
		if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_SNIPER ) )
		{
			int customkill = event->GetInt( "customkill" );
			if ( customkill == TF_DMG_CUSTOM_BACKSTAB )
			{
				m_iSnipersKilled++;
				if ( m_iSnipersKilled == 3 )
				{
					IncrementCount();
				}
			}
		}
	}

	int m_iSnipersKilled;

};
DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyBackstabSnipers, ACHIEVEMENT_TF_SPY_BACKSTAB_SNIPERS, "TF_SPY_BACKSTAB_SNIPERS", 5 );

class CAchievementTFSpy_FreezecamFlick : public CBaseTFAchievement
{
	// Achievement for freeze camming on a cig flick w/ enemy corpse on screen.
	void Init()
	{
		SetFlags( ACH_SAVE_GLOBAL );
		SetGoal( 1 );
	}
};
DECLARE_ACHIEVEMENT( CAchievementTFSpy_FreezecamFlick, ACHIEVEMENT_TF_SPY_FREEZECAM_FLICK, "TF_SPY_FREEZECAM_FLICK", 5 );

class CAchievementTFSpy_SpyBackstabDisguisedSpy : public CBaseTFAchievement
{
	void Init()
	{
		SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
		SetGoal( 1 );
	}

	virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
	{
		// Achievement for backstabbing a disguised spy.
		CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
		if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_SPY ) )
		{
			int customkill = event->GetInt( "customkill" );
			if ( customkill == TF_DMG_CUSTOM_BACKSTAB )
			{
				if ( pTFVictim->m_Shared.InCond( TF_COND_DISGUISED ) )
				{
					IncrementCount();
				}
			}
		}
	}
};
DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyBackstabDisguisedSpy, ACHIEVEMENT_TF_SPY_BACKSTAB_DISGUISED_SPY, "TF_SPY_BACKSTAB_DISGUISED_SPY", 5 );

class CAchievementTFSpy_SpyBackstabDisguiseTarget : public CBaseTFAchievement
{
	void Init()
	{
		SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
		SetGoal( 1 );
	}

	virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
	{
		// Achievement for backstabbing the player you are disguised as.
		CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
		CTFPlayer *pTFAttacker = ToTFPlayer( pAttacker );
		if ( pTFAttacker && pTFVictim && pTFVictim == pTFAttacker->m_Shared.GetDisguiseTarget().Get() )
		{
			int customkill = event->GetInt( "customkill" );
			if ( customkill == TF_DMG_CUSTOM_BACKSTAB )
			{
				IncrementCount();
			}
		}
	}
};
DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyBackstabDisguiseTarget, ACHIEVEMENT_TF_SPY_BACKSTAB_DISGUISE_TARGET, "TF_SPY_BACKSTAB_DISGUISE_TARGET", 5 );

class CAchievementTFSpy_SpyFastCap : public CBaseTFAchievement
{
	void Init()
	{
		SetFlags( ACH_SAVE_GLOBAL );
		SetGoal( 1 );
	}

	virtual void ListenForEvents( void )
	{
		ListenForGameEvent( "teamplay_point_startcapture" );
	}

	void FireGameEvent_Internal( IGameEvent *event )
	{
		// only on maps with capture points
		if ( TFGameRules() && TFGameRules()->GetGameType() != TF_GAMETYPE_CP && TFGameRules()->GetGameType() != TF_GAMETYPE_ARENA )
			return;

		const char *pszEventName = event->GetName();

		CTFPlayer *pLocalPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() );
		if ( !pLocalPlayer )
			return;

		if ( FStrEq( pszEventName, "teamplay_point_startcapture" ) )
		{
			const char *cappers = event->GetString( "cappers" );
			for ( int i=0; i<Q_strlen( cappers ); i++ )
			{
				int iPlayerIndex = (int) cappers[i];
				CTFPlayer *pPlayer = ToTFPlayer( UTIL_PlayerByIndex( iPlayerIndex ) );
				if ( pPlayer == pLocalPlayer )
				{
					if ( event->GetFloat( "captime" ) < 1.0 )
					{
						IncrementCount();
					}
				}
			}
		}
	}
};
DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyFastCap, ACHIEVEMENT_TF_SPY_FAST_CAP, "TF_SPY_FAST_CAP", 5 );

class CAchievementTFSpy_SpyDominateSniper : public CBaseTFAchievement
{
	void Init()
	{
		SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
		SetGoal( 1 );
	}

	virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
	{
		if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
		{
			bool bDomination = event->GetInt( "death_flags" ) & TF_DEATH_DOMINATION;

			if ( bDomination == true )
			{
				CTFPlayer *pTFVictim = ToTFPlayer( pVictim );

				if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_SNIPER ) )
				{
					IncrementCount();
				}
			}
		}
	}
};
DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyDominateSniper, ACHIEVEMENT_TF_SPY_DOMINATE_SNIPER, "TF_SPY_DOMINATE_SNIPER", 5 );

class CAchievementTFSpy_SpyBumpCloakedSpy : public CBaseTFAchievement
{
	void Init()
	{
		SetFlags( ACH_SAVE_GLOBAL );
		SetGoal( 1 );
	}

	// server awards this achievement, no other code within achievement necessary
};
DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyBumpCloakedSpy, ACHIEVEMENT_TF_SPY_BUMP_CLOAKED_SPY, "TF_SPY_BUMP_CLOAKED_SPY", 5 );

class CAchievementTFSpy_SpyKillSpyWithKnife : public CBaseTFAchievement
{
	void Init()
	{
		SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
		SetGoal( 1 );
	}

	virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
	{
		if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
		{
			CTFPlayer *pTFVictim = ToTFPlayer( pVictim );

			if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_SPY ) && pTFVictim->GetActiveTFWeapon() )
			{
				if ( event->GetInt( "weaponid" ) == TF_WEAPON_KNIFE )
				{
					if ( pTFVictim->GetActiveTFWeapon()->GetWeaponID() == TF_WEAPON_REVOLVER )
					{
						IncrementCount();
					}
				}
			}
		}
	}
};
DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyKillSpyWithKnife, ACHIEVEMENT_TF_SPY_KILL_SPY_WITH_KNIFE, "TF_SPY_KILL_SPY_WITH_KNIFE", 5 );

class CAchievementTFSpy_SpyRevengeBackstab : public CBaseTFAchievement
{
	void Init()
	{
		SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
		SetGoal( 1 );
	}

	virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
	{
		if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
		{
			int customkill = event->GetInt( "customkill" );
			if ( customkill == TF_DMG_CUSTOM_BACKSTAB )
			{
				bool bRevenge = event->GetInt( "death_flags" ) & TF_DEATH_REVENGE;

				if ( bRevenge == true )
				{
					IncrementCount();
				}
			}
		}
	}
};
DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyRevengeBackstab, ACHIEVEMENT_TF_SPY_REVENGE_WITH_BACKSTAB, "TF_SPY_REVENGE_WITH_BACKSTAB", 5 );

class CAchievementTFSpy_SpyKnifeKillWhileJarated : public CBaseTFAchievement
{
	void Init()
	{
		SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
		SetGoal( 1 );
	}

	virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
	{
		if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
		{
			if ( event->GetInt( "weaponid" ) == TF_WEAPON_KNIFE )
			{
				CTFPlayer *pTFAttacker = ToTFPlayer( pAttacker );
				if ( pTFAttacker && pTFAttacker->m_Shared.InCond( TF_COND_URINE ) )
				{
					IncrementCount();
				}
			}
		}
	}
};
DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyKnifeKillWhileJarated, ACHIEVEMENT_TF_SPY_KNIFE_KILL_WHILE_JARATED, "TF_SPY_KNIFE_KILL_WHILE_JARATED", 5 );

class CAchievementTFSpy_SpyBackstabGrind : public CBaseTFAchievement
{
	void Init()
	{
		SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
		SetGoal( 1000 );
		SetStoreProgressInSteam( true );
	}

	virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
	{
		if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
		{
			int customkill = event->GetInt( "customkill" );
			if ( customkill == TF_DMG_CUSTOM_BACKSTAB )
			{
				IncrementCount();
			}
		}
	}
};
DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyBackstabGrind, ACHIEVEMENT_TF_SPY_BACKSTAB_GRIND, "TF_SPY_BACKSTAB_GRIND", 5 );

class CAchievementTFSpy_SpyBackstabMedicCharged : public CBaseTFAchievement
{
	void Init()
	{
		SetFlags( ACH_SAVE_GLOBAL );
		SetGoal( 1 );
	}

	// server awards this achievement, no other code within achievement necessary
};
DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyBackstabMedicCharged, ACHIEVEMENT_TF_SPY_BACKSTAB_MEDIC_CHARGED, "TF_SPY_BACKSTAB_MEDIC_CHARGED", 5 );

class CAchievementTFSpy_SpyBackstabDominatingEnemy : public CBaseTFAchievement
{
	void Init()
	{
		SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
		SetGoal( 1 );
	}

	virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
	{
		if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
		{
			int customkill = event->GetInt( "customkill" );
			if ( customkill == TF_DMG_CUSTOM_BACKSTAB )
			{
				CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
				if ( pTFVictim )
				{
					int nDominationsNeeded = ( event->GetInt( "revenge" ) > 0 ) ? 4 : 3;

					if ( g_TF_PR && g_TF_PR->GetActiveDominations( pTFVictim->entindex() ) >= nDominationsNeeded )
					{
						IncrementCount();
					}
				}
			}
		}
	}
};
DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyBackstabDominatingEnemy, ACHIEVEMENT_TF_SPY_BACKSTAB_DOMINATING_ENEMY, "TF_SPY_BACKSTAB_DOMINATING_ENEMY", 5 );

class CAchievementTFSpy_SpyBackstabFriends : public CBaseTFAchievement
{
	void Init()
	{
		SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
		SetGoal( 10 );
		SetStoreProgressInSteam( true );
	}

	virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
	{
		if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
		{
			int customkill = event->GetInt( "customkill" );
			if ( customkill == TF_DMG_CUSTOM_BACKSTAB )
			{
				if ( !steamapicontext->SteamFriends() || !steamapicontext->SteamUtils() || !g_pGameRules->IsMultiplayer() )
					return;

				player_info_t pi;
				if ( !engine->GetPlayerInfo( pVictim->entindex(), &pi ) )
					return;

				if ( !pi.friendsID )
					return;

				// check and see if they're on the local player's friends list
				CSteamID steamID( pi.friendsID, 1, GetUniverse(), k_EAccountTypeIndividual );
				if ( steamapicontext->SteamFriends()->HasFriend( steamID, k_EFriendFlagImmediate ) )
				{
					IncrementCount();
				}
			}
		}
	}
};
DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyBackstabFriends, ACHIEVEMENT_TF_SPY_BACKSTAB_FRIENDS, "TF_SPY_BACKSTAB_FRIENDS", 5 );

class CAchievementTFSpy_SpyAmbassadorGrind : public CBaseTFAchievement
{

{
		SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
		SetGoal( 50 );
		SetStoreProgressInSteam( true );
	}

	virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
	{
		if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
		{
			if ( event->GetInt( "weaponid" ) == TF_WEAPON_REVOLVER )
			{
				if ( FStrEq( event->GetString( "weapon_logclassname", "" ), "ambassador" ) )
				{
					IncrementCount();
				}
			}
		}
	}
};
DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyAmbassadorGrind, ACHIEVEMENT_TF_SPY_AMBASSADOR_GRIND, "TF_SPY_AMBASSADOR_GRIND", 5 );

class CAchievementTFSpy_SpyAmbassadorSniperGrind : public CBaseTFAchievement
{
	void Init()
	{
		SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
		SetGoal( 20 );
		SetStoreProgressInSteam( true );
	}

	virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
	{
		if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
		{
			CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
			if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_SNIPER ) )
			{
				if ( event->GetInt( "weaponid" ) == TF_WEAPON_REVOLVER )
				{
					if ( FStrEq( event->GetString( "weapon_logclassname", "" ), "ambassador" ) )
					{
						if ( IsHeadshot( event->GetInt( "customkill" ) ) )
						{
							IncrementCount();
						}
					}
				}
			}
		}
	}
};
DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyAmbassadorSniperGrind, ACHIEVEMENT_TF_SPY_AMBASSADOR_SNIPER_GRIND, "TF_SPY_AMBASSADOR_SNIPER_GRIND", 5 );

class CAchievementTFSpy_SpyAmbassadorScoutGrind : public CBaseTFAchievement
{
	void Init()
	{
		SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
		SetGoal( 3 );
		SetStoreProgressInSteam( true );
	}

	virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
	{
		if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
		{
			CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
			if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_SCOUT ) )
			{
				if ( event->GetInt( "weaponid" ) == TF_WEAPON_REVOLVER )
				{
					if ( FStrEq( event->GetString( "weapon_logclassname", "" ), "ambassador" ) )
					{
						if ( IsHeadshot( event->GetInt( "customkill" ) ) )
						{
							IncrementCount();
						}
					}
				}
			}
		}
	}
};
DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyAmbassadorScoutGrind, ACHIEVEMENT_TF_SPY_AMBASSADOR_SCOUT_GRIND, "TF_SPY_AMBASSADOR_SCOUT_GRIND", 5 );

class CAchievementTFSpy_SpyMedicHealingKillEnemy : public CBaseTFAchievement
{
	void Init()
	{
		SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
		SetGoal( 1 );
	}

	virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
	{
		if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
		{
			for ( int i = 1 ; i <= gpGlobals->maxClients ; i++ )
			{
				CTFPlayer *pTFPlayer = ToTFPlayer( UTIL_PlayerByIndex( i ) );

				// can't kill the enemy medic that's healing you for this one...should be a different enemy
				if ( pTFPlayer && ( pTFPlayer != pAttacker ) && ( pTFPlayer != pVictim ) )
				{
					// make sure they're not on our team
					if ( pAttacker->GetTeamNumber() != pTFPlayer->GetTeamNumber() )
					{
						// are they a medic that's healing me?
						if ( pTFPlayer->IsPlayerClass( TF_CLASS_MEDIC ) && pTFPlayer->MedicGetHealTarget() == pAttacker )
						{
							IncrementCount();
						}
					}
				}
			}
		}
	}
};
DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyMedicHealingKillEnemy, ACHIEVEMENT_TF_SPY_MEDIC_HEALING_KILL_ENEMY, "TF_SPY_MEDIC_HEALING_KILL_ENEMY", 5 );

class CAchievementTFSpy_SpyBackstabQuickKills : public CBaseTFAchievement
{
	void Init()
	{
		SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
		SetGoal( 1 );
	}

	virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
	{
		if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
		{
			int customkill = event->GetInt( "customkill" );
			if ( customkill == TF_DMG_CUSTOM_BACKSTAB )
			{
				int iNewIndex = m_Times.AddToTail();
				m_Times[iNewIndex] = gpGlobals->curtime;

				// we only care about the last three times we backstabbed someone
				if ( m_Times.Count() > 3 )
				{
					m_Times.Remove( 0 );
				}

				if ( m_Times.Count() == 3 )
				{
					if ( m_Times.Tail() - m_Times.Head() <= 10.0 )
					{
						IncrementCount();
					}
				}
			}
		}
	}

private:
	CUtlVector< float >	m_Times;
};
DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyBackstabQuickKills, ACHIEVEMENT_TF_SPY_BACKSTAB_QUICK_KILLS, "TF_SPY_BACKSTAB_QUICK_KILLS", 5 );

class CAchievementTFSpy_SpyTauntKill : public CBaseTFAchievement
{
	void Init()
	{
		SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
		SetGoal( 1 );
	}

	virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
	{
		if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
		{
			// we already know we killed a player because of the ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS flag
			// was this a taunt kill?
			if ( event->GetInt( "customkill" ) == TF_DMG_CUSTOM_TAUNTATK_FENCING )
			{
				IncrementCount();
			}
		}
	}
};
DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyTauntKill, ACHIEVEMENT_TF_SPY_TAUNT_KILL, "TF_SPY_TAUNT_KILL", 5 );

class CAchievementTFSpy_SpyBackstabCappingEnemies : public CBaseTFAchievement
{
	void Init()
	{
		SetFlags( ACH_SAVE_GLOBAL );
		SetGoal( 50 );
		SetStoreProgressInSteam( true );
	}

	// server awards this achievement, no other code within achievement necessary
};
DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyBackstabCappingEnemies, ACHIEVEMENT_TF_SPY_BACKSTAB_CAPPING_ENEMIES, "TF_SPY_BACKSTAB_CAPPING_ENEMIES", 5 );

class CAchievementTFSpy_SpyKillCPDefenders : public CBaseTFAchievement
{
	void Init()
	{
		SetFlags( ACH_SAVE_GLOBAL );
		SetGoal( 15 );
		SetStoreProgressInSteam( true );
	}

	// server awards this achievement, no other code within achievement necessary
};
DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyKillCPDefenders, ACHIEVEMENT_TF_SPY_KILL_CP_DEFENDERS, "TF_SPY_KILL_CP_DEFENDERS", 5 );

//FYI I'm a spy
class CAchievementTFSpy_FYIMedic : public CBaseTFAchievement
{
	void Init()
	{
		SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_KILL_EVENTS );
		SetGoal( 1 );
		m_hTargets.Purge();
	}

	virtual void ListenForEvents( void )
	{
		ListenForGameEvent( "player_healedbymedic" );
	}

	void FireGameEvent_Internal( IGameEvent *event )
	{
		if ( FStrEq( event->GetName(), "player_healedbymedic" ) )
		{
			int iEntity = event->GetInt( "medic" );

			int iMedic = GetTargetIndex( UTIL_PlayerByIndex( iEntity ) );

			if ( iMedic == -1 )
			{
				AddNewTarget( UTIL_PlayerByIndex( iEntity ) );
			}
			else
			{
				m_hTargets[iMedic].flRemoveTime = gpGlobals->curtime + 5.0f;
			}
		}
	}

	virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
	{
		if ( pAttacker == C_TFPlayer::GetLocalTFPlayer() )
		{
			int iMedic = GetTargetIndex( pVictim );

			if ( iMedic != -1 )
			{
				if ( m_hTargets[iMedic].flRemoveTime >= gpGlobals->curtime )
				{
					IncrementCount();
				}

				m_hTargets.Remove( iMedic );
			}
		}
	}

	int	GetTargetIndex( CBaseEntity *pTarget )
	{
		for ( int i = 0; i < m_hTargets.Count(); i++ )
		{
			if ( m_hTargets[i].hTarget == pTarget )
				return i;
		}
		return -1;
	}

	void AddNewTarget( CBaseEntity *pTarget )
	{
		if ( !pTarget )
			return;

		// see if the target is already in our list or get a new index
		int iMedic = GetTargetIndex( pTarget );
		if ( iMedic == -1 )
		{
			iMedic = m_hTargets.AddToTail();
		}

		m_hTargets[iMedic].hTarget = pTarget;
		m_hTargets[iMedic].flRemoveTime = gpGlobals->curtime + 5.0f;
	}

private:
	struct targets_t
	{
		EHANDLE hTarget;
		float flRemoveTime;
	};

	CUtlVector<targets_t> m_hTargets;
};

DECLARE_ACHIEVEMENT( CAchievementTFSpy_FYIMedic, ACHIEVEMENT_TF_SPY_BACKSTAB_MEDIC_HEALING_YOU, "TF_SPY_BACKSTAB_MEDIC_HEALING_YOU", 5 );

// Backstab a medic/heavy pair
// NOTE: Enough of this, this should be a shared achievement class.
class CAchievementTFSpy_KillMedicPair : public CBaseTFAchievement
{
	void Init()
	{
		SetFlags( ACH_SAVE_GLOBAL  | ACH_LISTEN_KILL_ENEMY_EVENTS );
		SetGoal( 1 );
	}

	virtual void ListenForEvents( void )
	{
		ListenForGameEvent( "localplayer_respawn" );
		ListenForGameEvent( "teamplay_round_active" );

		m_hTargets.Purge();
	}

	void FireGameEvent_Internal( IGameEvent *event )
	{
		const char *pszEventName = event->GetName();

		if ( FStrEq( pszEventName, "localplayer_respawn" ) ||
			FStrEq( pszEventName, "teamplay_round_active" ) )
		{
			m_hTargets.Purge();
		}
	}

	int	GetTargetIndex( CBaseEntity *pTarget )
	{
		for ( int i = 0; i < m_hTargets.Count(); i++ )
		{
			if ( m_hTargets[i].hTarget == pTarget )
				return i;
		}
		return -1;
	}

	void AddNewTarget( CBaseEntity *pTarget )
	{
		if ( !pTarget )
			return;

		// see if the target is already in our list or get a new index
		int iTargetIndex = GetTargetIndex( pTarget );
		if ( iTargetIndex == -1 )
		{
			iTargetIndex = m_hTargets.AddToTail();
		}

		m_hTargets[iTargetIndex].hTarget = pTarget;
		m_hTargets[iTargetIndex].flTimeToBeat = gpGlobals->curtime + 10.0f; // 10 seconds to kill the target
	}

	virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
	{
		if ( !pVictim || !pVictim->IsPlayer() )
			return;

		C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();

		int customkill = event->GetInt( "customkill" );

		if ( pLocalPlayer == pAttacker && customkill == TF_DMG_CUSTOM_BACKSTAB )
		{
			// is this victim in our list of targets?
			int index = GetTargetIndex( pVictim );
			if ( index != -1 )
			{
				// did we beat the time?
				if ( m_hTargets[index].flTimeToBeat > gpGlobals->curtime )
				{
					IncrementCount();
				}
			}
			else
			{
				C_TFPlayer *pNewTarget = NULL;
				C_TFPlayer *pTFVictim = ToTFPlayer( pVictim );
				if ( !pTFVictim->IsPlayerClass( TF_CLASS_MEDIC ) )
				{
					for ( int i = 1 ; i <= gpGlobals->maxClients ; i++ )
					{
						pNewTarget = ToTFPlayer( UTIL_PlayerByIndex( i ) );
						if ( pNewTarget && pNewTarget->IsPlayerClass( TF_CLASS_MEDIC ) && pNewTarget->MedicGetHealTarget() == pTFVictim )
						{
							// add all of his Medics to our list of targets (could be more than one Medic)
							AddNewTarget( pNewTarget );
						}
					}
				}
				else
				{
					pNewTarget = ToTFPlayer( pTFVictim->MedicGetHealTarget() );
					if ( pNewTarget )
					{
						AddNewTarget( pNewTarget );
					}
				}
			}
		}
		// is this victim in our list of targets?
		int index_ = GetTargetIndex( pVictim );
		if ( index_ != -1 )
		{
			m_hTargets.Remove( index_ );
		}
	}

private:
	struct targets_t
	{
		EHANDLE hTarget;
		float flTimeToBeat;
	};

	CUtlVector<targets_t> m_hTargets;
};
DECLARE_ACHIEVEMENT( CAchievementTFSpy_KillMedicPair, ACHIEVEMENT_TF_SPY_BACKSTAB_MEDIC_PAIR, "TF_SPY_BACKSTAB_MEDIC_PAIR", 5 );

//Destroy 3 enemy sentries
class CAchievementTFSpy_SapBuildingGrind : public CBaseTFAchievement
{
	void Init()
	{
		SetFlags( ACH_SAVE_GLOBAL );
		SetGoal( 1000 );
		SetStoreProgressInSteam( true );
	}

	virtual void ListenForEvents()
	{
		ListenForGameEvent( "object_destroyed" );
	}

	void FireGameEvent_Internal( IGameEvent *event )
	{
		if ( Q_strcmp( event->GetName(), "object_destroyed" ) == 0 )
		{
			int iIndex = engine->GetPlayerForUserID( event->GetInt( "attacker" ) );

			if ( iIndex == GetLocalPlayerIndex() )
			{
				const char *pWeapon = event->GetString( "weapon" );

				if ( FStrEq( "obj_attachment_sapper", pWeapon ) )
				{
					IncrementCount();
				}
			}
		}
	}
};
DECLARE_ACHIEVEMENT( CAchievementTFSpy_SapBuildingGrind, ACHIEVEMENT_TF_SPY_SAPPER_GRIND, "TF_SPY_SAPPER_GRIND", 5 );

//Kill whoever triggered your feign death
class CAchievementTFSpy_FeignDeathKill : public CBaseTFAchievement
{
	void Init()
	{
		SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
		SetGoal( 1 );
		m_iKillerIndex = 0;
		m_flTriggerTime = gpGlobals->curtime;
	}

	virtual void ListenForEvents()
	{
		ListenForGameEvent( "player_death" );
	}

	void FireGameEvent_Internal( IGameEvent *event )
	{
		if ( Q_strcmp( event->GetName(), "player_death" ) == 0 )
		{
			int iAttacker = engine->GetPlayerForUserID( event->GetInt( "attacker" ) );
			int iVictim = engine->GetPlayerForUserID( event->GetInt( "userid" ) );

			if ( iVictim == GetLocalPlayerIndex() )
			{
				//Someone popped my feign death
				if ( event->GetInt( "death_flags" ) & TF_DEATH_FEIGN_DEATH )
				{
					m_iKillerIndex = iAttacker;
					m_flTriggerTime = gpGlobals->curtime + 20.0f;
				}
			}
		}
	}

	virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
	{
		if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
		{
			C_TFPlayer *pTFVictim = ToTFPlayer( pVictim );

			if ( pTFVictim && pTFVictim->entindex() == m_iKillerIndex && m_flTriggerTime >= gpGlobals->curtime )
			{
				IncrementCount();
			}
		}
	}

private:
	int m_iKillerIndex;
	float m_flTriggerTime;
};
DECLARE_ACHIEVEMENT( CAchievementTFSpy_FeignDeathKill, ACHIEVEMENT_TF_SPY_FEIGN_DEATH_KILL, "TF_SPY_FEIGN_DEATH_KILL", 5 );

//Kill a sniper after breaking his shield
class CAchievementTFSpy_ShieldKill : public CBaseTFAchievement
{
	void Init()
	{
		SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
		SetGoal( 1 );

		m_iBlockerIndex = 0;
		m_flAttackTime = 0.0f;
	}

	virtual void ListenForEvents( void )
	{
		ListenForGameEvent( "player_shield_blocked" );
	}

	void FireGameEvent_Internal( IGameEvent *event )
	{
		if ( FStrEq( event->GetName(), "player_shield_blocked" ) )
		{
			int iAttacker = event->GetInt( "attacker_entindex" );
			int iBlocker = event->GetInt( "blocker_entindex" );

			if ( GetLocalPlayerIndex() != iAttacker )
				return;

			m_iBlockerIndex = iBlocker;
			m_flAttackTime = gpGlobals->curtime + 10.0f;
		}
	}

	virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
	{
		if ( m_flAttackTime <= gpGlobals->curtime )
		{
			m_iBlockerIndex = 0;
			return;
		}

		CTFPlayer *pTFVictim = ToTFPlayer( pVictim );

		if ( pTFVictim && pTFVictim->entindex() == m_iBlockerIndex && pAttacker == C_TFPlayer::GetLocalTFPlayer() )
		{
			IncrementCount();
		}
	}

private:
	int m_iBlockerIndex;
	float m_flAttackTime;
};

DECLARE_ACHIEVEMENT( CAchievementTFSpy_ShieldKill, ACHIEVEMENT_TF_SPY_BREAK_SHIELD_KILL_SNIPER, "TF_SPY_BREAK_SHIELD_KILL_SNIPER", 5 );

class CAchievementTFSpy_KillWorkingEngineer : public CBaseTFAchievement
{
	void Init()
	{
		SetFlags( ACH_SAVE_GLOBAL );
		SetGoal( 1 );
		SetStoreProgressInSteam( true );
	}

	// server awards this achievement, no other code within achievement necessary
};
DECLARE_ACHIEVEMENT( CAchievementTFSpy_KillWorkingEngineer, ACHIEVEMENT_TF_SPY_KILL_WORKING_ENGY, "TF_SPY_KILL_WORKING_ENGY", 5 );

class CAchievementTFSpy_TFSpySurviveBurning : public CBaseTFAchievement
{
	void Init()
	{
		SetFlags( ACH_SAVE_GLOBAL );
		SetGoal( 1 );
		m_bIsThinking = false;
	}

	virtual void ListenForEvents()
	{
		ListenForGameEvent( "player_damaged" );
		ListenForGameEvent( "teamplay_round_start" );
		ListenForGameEvent( "localplayer_respawn" );
		m_bIsThinking = false;
	}

	void FireGameEvent_Internal( IGameEvent *event )
	{
		C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
		if ( !pLocalPlayer )
			return;

		const char *pszEventName = event->GetName();

		if ( FStrEq( pszEventName, "localplayer_respawn" ) || FStrEq( pszEventName, "teamplay_round_active" ) )
		{
			ClearThink();
			m_bIsThinking = false;
			return;
		}

		// Have I taken damage?
		if ( FStrEq( pszEventName, "player_damaged" ))
		{
			int iDmgType = event->GetInt( "type" );

			// Did I survive the damage event?
			if ( pLocalPlayer->IsAlive() && !m_bIsThinking )
			{
				// Am I on fire?
				if ( (iDmgType & DMG_IGNITE) )
				{
					// Am I cloaked?
					if ( pLocalPlayer->m_Shared.InCond ( TF_COND_STEALTHED ) )
					{
						SetNextThink( 30 );
						m_bIsThinking = true;
					}
				}
			}
		}
	}

	virtual void Think( void )
	{
		C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
		if ( pLocalPlayer && pLocalPlayer->IsAlive())
		{
			IncrementCount();
		}
	}

private:
	bool	m_bIsThinking;
};
DECLARE_ACHIEVEMENT( CAchievementTFSpy_TFSpySurviveBurning, ACHIEVEMENT_TF_SPY_SURVIVE_BURNING, "TF_SPY_SURVIVE_BURNING", 5 );

class CAchievementTFSpy_SpyBackstabEnemySwitchPyro : public CBaseTFAchievementSimple
{
	void Init()
	{
		SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
		SetGoal( 1 );

		ResetBackstabbedPlayers();
	}

	virtual void ListenForEvents()
	{
		ListenForGameEvent( "player_spawn" );
		ListenForGameEvent( "localplayer_changeclass" );
		ListenForGameEvent( "localplayer_changeteam" );
	}

	void ResetBackstabbedPlayers( void )
	{
		m_BackstabbedPlayers.Purge();
	}

	virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
	{
		// no progress in endround
		if ( !GameRulesAllowsAchievements() )
			return;

		if ( !IsLocalTFPlayerClass( TF_CLASS_SPY ) )
			return;

		if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
		{
			int customkill = event->GetInt( "customkill" );
			if ( customkill == TF_DMG_CUSTOM_BACKSTAB )
			{
				CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
				if ( pTFVictim && !pTFVictim->IsPlayerClass( TF_CLASS_PYRO ) ) // they can't already be a pyro for this one
				{
					int nUserID = pTFVictim->GetUserID();

					if ( m_BackstabbedPlayers.Find( nUserID ) == m_BackstabbedPlayers.InvalidIndex() )
					{
						// they're not in our list yet, add them
						m_BackstabbedPlayers.AddToTail( nUserID );
					}
				}
			}
		}
	}

	void FireGameEvent_Internal( IGameEvent *event )
	{
		const char *pszEventName = event->GetName();

		if ( FStrEq( pszEventName, "player_spawn" ) )
		{
			// no progress in endround
			if ( !GameRulesAllowsAchievements() )
				return;

			if ( !IsLocalTFPlayerClass( TF_CLASS_SPY ) )
				return;

			const int nUserID = event->GetInt( "userid" );
			int iIndex = m_BackstabbedPlayers.Find( nUserID );
			if ( iIndex != m_BackstabbedPlayers.InvalidIndex() )
			{
				const int nTeam = event->GetInt( "team" );
				if ( nTeam != GetLocalPlayerTeam() )
				{
					const int nClass = event->GetInt( "class" );
					if ( nClass == TF_CLASS_PYRO )
					{
						IncrementCount();
					}
				}

				m_BackstabbedPlayers.Remove( iIndex );
			}
		}
		else if ( FStrEq( pszEventName, "localplayer_changeclass" ) ||
				  FStrEq( pszEventName, "localplayer_changeteam" ) )
		{
			ResetBackstabbedPlayers();
		}
	}

private:
	CUtlVector< int > m_BackstabbedPlayers;
};
DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyBackstabEnemySwitchPyro, ACHIEVEMENT_TF_SPY_BACKSTAB_ENEMY_SWITCH_PYRO, "TF_SPY_BACKSTAB_ENEMY_SWITCH_PYRO", 5 );

class CAchievementTFSpy_SpyBackstabEngySapBuilding : public CBaseTFAchievement
{
	void Init()
	{
		SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
		SetGoal( 1 );

		m_hTargets.Purge();
	}

	virtual void ListenForEvents()
	{
		ListenForGameEvent( "player_sapped_object" );
	}

	int FindEngyInList( CBaseEntity *pTarget )
	{
		for ( int i = 0; i < m_hTargets.Count(); i++ )
		{
			if ( m_hTargets[i].hEngy == pTarget )
				return i;
		}
		return -1;
	}

	int CountSappedObjects( int iIndex )
	{
		int nCount = 0;

		if ( m_hTargets.IsValidIndex( iIndex ) )
		{
			if ( m_hTargets[iIndex].bSentry )
			{
				nCount++;
			}

			if ( m_hTargets[iIndex].bDispenser )
			{
				nCount++;
			}

			if ( m_hTargets[iIndex].bTele )
			{
				nCount++;
			}
		}

		return nCount;
	}

	void SetObjectSapped( int iIndex, int nType )
	{
		if ( m_hTargets.IsValidIndex( iIndex ) )
		{
			switch( nType )
			{
			case OBJ_SENTRYGUN:
				m_hTargets[iIndex].bSentry = true;
				break;
			case OBJ_DISPENSER:
				m_hTargets[iIndex].bDispenser = true;
				break;
			case OBJ_TELEPORTER:
				m_hTargets[iIndex].bTele = true;
				break;
			}
		}
	}

	void CheckAchievementEarned( void )
	{
		for ( int i = m_hTargets.Count() - 1; i >= 0; i-- )
		{
			if ( m_hTargets[i].flTimeToBeat < gpGlobals->curtime )
			{
				// time has run out on this one
				m_hTargets.Remove( i );
			}
			else
			{
				if ( CountSappedObjects( i ) >= 3 )
				{
					IncrementCount();
					m_hTargets.Purge();
					return;
				}
			}
		}
	}

	virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
	{
		if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
		{
			int customkill = event->GetInt( "customkill" );
			if ( customkill == TF_DMG_CUSTOM_BACKSTAB )
			{
				CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
				if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_ENGINEER ) )
				{
					int iIndex = FindEngyInList( pVictim );
					if ( iIndex == -1 )
					{
						iIndex = m_hTargets.AddToTail();
					}

					m_hTargets[iIndex].hEngy = pVictim;
					m_hTargets[iIndex].bSentry = false;
					m_hTargets[iIndex].bDispenser = false;
					m_hTargets[iIndex].bTele = false;
					m_hTargets[iIndex].flTimeToBeat = gpGlobals->curtime + 10.0;
				}
			}

			CheckAchievementEarned(); // checks the achievement list, but also cleans out old entries (based on flTimeToBeat)
		}
	}

	void FireGameEvent_Internal( IGameEvent *event )
	{
		const char *pszEventName = event->GetName();

		if ( FStrEq( pszEventName, "player_sapped_object" ) )
		{
			int nUserID = event->GetInt( "userid" );

			CBasePlayer *pPlayer = UTIL_PlayerByIndex( engine->GetPlayerForUserID( nUserID ) );
			if ( pPlayer == C_BasePlayer::GetLocalPlayer() )
			{
				CBasePlayer *pEngy = UTIL_PlayerByIndex( engine->GetPlayerForUserID( event->GetInt( "ownerid" ) ) );

				int iIndex = FindEngyInList( pEngy );
				if ( iIndex != -1 )
				{
					SetObjectSapped( iIndex, event->GetInt( "object" ) );
				}

				CheckAchievementEarned(); // checks the achievement list, but also cleans out old entries (based on flTimeToBeat)
			}
		}
	}

private:
	struct targets_t
	{
		EHANDLE hEngy;
		bool bSentry;
		bool bDispenser;
		bool bTele;
		float flTimeToBeat;
	};

	CUtlVector<targets_t> m_hTargets;
};
DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyBackstabEngySapBuilding, ACHIEVEMENT_TF_SPY_BACKSTAB_ENGY_SAP_BUILDING, "TF_SPY_BACKSTAB_ENGY_SAP_BUILDING", 5 );

class CAchievementTFSpy_SpySapBuildingBackstabEngy : public CBaseTFAchievement
{
	void Init()
	{
		SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
		SetGoal( 1 );

		m_hTargets.Purge();
	}

	virtual void ListenForEvents()
	{
		ListenForGameEvent( "player_sapped_object" );
	}

	int FindEngyInList( CBaseEntity *pTarget )
	{
		for ( int i = 0; i < m_hTargets.Count(); i++ )
		{
			if ( m_hTargets[i].hEngy == pTarget )
				return i;
		}
		return -1;
	}

	void ValidateList( void )
	{
		for ( int i = m_hTargets.Count() - 1; i >= 0; i-- )
		{
			if ( m_hTargets[i].flTimeToBeat < gpGlobals->curtime )
			{
				// time has run out on this one
				m_hTargets.Remove( i );
			}
		}
	}

	virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
	{
		if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
		{
			int customkill = event->GetInt( "customkill" );
			if ( customkill == TF_DMG_CUSTOM_BACKSTAB )
			{
				CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
				if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_ENGINEER ) )
				{
					int iIndex = FindEngyInList( pVictim );
					if ( iIndex != -1 )
					{
						// they're in our list...is the time still valid?
						if ( m_hTargets[iIndex].flTimeToBeat > gpGlobals->curtime )
						{
							IncrementCount();
							m_hTargets.Purge();
							return;
						}
					}
				}
			}

			ValidateList();
		}
	}

	void FireGameEvent_Internal( IGameEvent *event )
	{
		const char *pszEventName = event->GetName();

		if ( FStrEq( pszEventName, "player_sapped_object" ) )
		{
			int nUserID = event->GetInt( "userid" );

			CBasePlayer *pPlayer = UTIL_PlayerByIndex( engine->GetPlayerForUserID( nUserID ) );
			if ( pPlayer == C_BasePlayer::GetLocalPlayer() )
			{
				CBasePlayer *pEngy = UTIL_PlayerByIndex( engine->GetPlayerForUserID( event->GetInt( "ownerid" ) ) );
				if ( pEngy )
				{
					int iIndex = FindEngyInList( pEngy );
					if ( iIndex == -1 )
					{
						iIndex = m_hTargets.AddToTail();
					}

					m_hTargets[iIndex].hEngy = pEngy;
					m_hTargets[iIndex].flTimeToBeat = gpGlobals->curtime + 5.0;
				}

				ValidateList();
			}
		}
	}

private:
	struct targets_t
	{
		EHANDLE hEngy;
		float flTimeToBeat;
	};

	CUtlVector<targets_t> m_hTargets;
};
DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpySapBuildingBackstabEngy, ACHIEVEMENT_TF_SPY_SAP_BUILDING_BACKSTAB_ENGY, "TF_SPY_SAP_BUILDING_BACKSTAB_ENGY", 5 );

class CAchievementTFSpy_SapperTeamwork : public CBaseTFAchievement
{
	void Init()
	{
		SetFlags( ACH_SAVE_GLOBAL );
		SetGoal( 1 );

		ResetData();
	}

	virtual void ListenForEvents()
	{
		ListenForGameEvent( "player_sapped_object" );
		ListenForGameEvent( "localplayer_changeteam" );
	}

	void ResetData( void )
	{
		m_hTeammates.Purge();

		m_nLocalPlayerTarget = -1;
		m_flLocalPlayerTime = -1;
	}

	int FindSpyInList( int userid )
	{
		for ( int i = 0; i < m_hTeammates.Count(); i++ )
		{
			if ( m_hTeammates[i].nSpy == userid )
				return i;
		}
		return -1;
	}

	void CheckAchievementEarned( void )
	{
		// has the local player sapped anything?
		if ( m_nLocalPlayerTarget == -1 && m_flLocalPlayerTime == -1 )
			return;

		// has it been longer than 3 seconds since the local player sapped something?
		if ( gpGlobals->curtime - m_flLocalPlayerTime > 3.0 )
		{
			// reset the local player target and time, this fixes the local player sapping something and
			// then a teammate saps something > 3 seconds later (otherwise, the new entry would be removed in the for loop below)
			m_nLocalPlayerTarget = -1;
			m_flLocalPlayerTime = -1;
			return;
		}

		for ( int i = m_hTeammates.Count() - 1; i >= 0; i-- )
		{
			if ( m_hTeammates[i].nTarget != m_nLocalPlayerTarget ) // different guns
			{
				if ( fabs( m_hTeammates[i].flTime - m_flLocalPlayerTime ) <= 3.0 )
				{
					IncrementCount();
					ResetData();
					return;
				}
				else
				{
					m_hTeammates.Remove( i );
				}
			}
		}
	}

	void FireGameEvent_Internal( IGameEvent *event )
	{
		const char *pszEventName = event->GetName();

		if ( FStrEq( pszEventName, "player_sapped_object" ) )
		{
			if ( event->GetInt( "object" ) == OBJ_SENTRYGUN )
			{
				int nUserID = event->GetInt( "userid" );

				CTFPlayer *pSpy = ToTFPlayer( UTIL_PlayerByIndex( engine->GetPlayerForUserID( nUserID ) ) );
				if ( pSpy && pSpy->GetTeamNumber() == GetLocalPlayerTeam() )
				{
					if ( pSpy == C_BasePlayer::GetLocalPlayer() )
					{
						m_nLocalPlayerTarget = event->GetInt( "ownerid" );
						m_flLocalPlayerTime = gpGlobals->curtime;
					}
					else
					{
						int iIndex = FindSpyInList( nUserID );
						if ( iIndex == -1 )
						{
							iIndex = m_hTeammates.AddToTail();
						}

						m_hTeammates[iIndex].nSpy = nUserID;
						m_hTeammates[iIndex].nTarget = event->GetInt( "ownerid" );
						m_hTeammates[iIndex].flTime = gpGlobals->curtime;
					}

					CheckAchievementEarned(); // checks the achievement list, but also cleans out old entries (based on time)
				}
			}
		}
		else if ( FStrEq( pszEventName, "localplayer_changeteam" ) )
		{
			ResetData();
		}
	}

private:
	struct teammates_t
	{
		int	nSpy; // who built the sapper
		int nTarget; // owner of the gun
		float flTime; // time it was sapped
	};

	CUtlVector<teammates_t> m_hTeammates; // list of teammates who have sapped guns

	int m_nLocalPlayerTarget; // owner of the gun
	float m_flLocalPlayerTime; // time it was sapped
};
DECLARE_ACHIEVEMENT( CAchievementTFSpy_SapperTeamwork, ACHIEVEMENT_TF_SPY_SAPPER_TEAMWORK, "TF_SPY_SAPPER_TEAMWORK", 5 );

class CAchievementTFSpy_SpyCampPosition : public CBaseTFAchievement
{
	void Init()
	{
		SetFlags( ACH_SAVE_GLOBAL | ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS );
		SetGoal( 1 );

		ResetData();
	}

	void ResetData()
	{
		m_hTargets.Purge();
	}

	virtual void ListenForEvents( void )
	{
		ListenForGameEvent( "localplayer_respawn" );
		ListenForGameEvent( "teamplay_round_active" );

		ResetData();
	}

	int FindEnemyInList( CBaseEntity *pTarget )
	{
		for ( int i = 0; i < m_hTargets.Count(); i++ )
		{
			if ( m_hTargets[i].hEnemy == pTarget )
				return i;
		}
		return -1;
	}

	void FireGameEvent_Internal( IGameEvent *event )
	{
		const char *pszEventName = event->GetName();

		if ( FStrEq( pszEventName, "localplayer_respawn" ) ||
			 FStrEq( pszEventName, "teamplay_round_active" ) )
		{
			ResetData();
		}
	}

	bool LocalPlayerHasMotionCloakEquipped( void )
	{
		CTFPlayer *pPlayer = ToTFPlayer( C_BasePlayer::GetLocalPlayer() );
		if ( pPlayer )
		{
			CTFWeaponInvis *pWeapon = (CTFWeaponInvis *) pPlayer->Weapon_OwnsThisID( TF_WEAPON_INVIS );
			if ( pWeapon && pWeapon->HasMotionCloak() )
			{
				return true;
			}
		}

		return false;
	}

	virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
	{
		if ( pAttacker == C_BasePlayer::GetLocalPlayer() )
		{
			if ( LocalPlayerHasMotionCloakEquipped() )
			{
				int iIndex = FindEnemyInList( pVictim );
				if ( iIndex != -1 )
				{
					// they're already in our list
					Vector vecOrigin = pVictim->GetAbsOrigin();

					if ( ( m_hTargets[iIndex].vecOrigin - vecOrigin ).LengthSqr() > (1024*1024) )
					{
						// we killed them too far away from our last position, so reset
						m_hTargets[iIndex].nKillCount = 1;
						m_hTargets[iIndex].vecOrigin = vecOrigin;
					}
					else
					{
						// they were close enough, so add to our kill count
						m_hTargets[iIndex].nKillCount++;
					}
				}
				else
				{
					// they're new to our list
					iIndex = m_hTargets.AddToTail();

					m_hTargets[iIndex].hEnemy = pVictim;
					m_hTargets[iIndex].nKillCount = 1;
					m_hTargets[iIndex].vecOrigin = pVictim->GetAbsOrigin();
				}

				if ( m_hTargets[iIndex].nKillCount >= 3 )
				{
					IncrementCount();
					ResetData();
				}
			}
			else
			{
				// Not using motion cloak anymore
				ResetData();
			}
		}
	}

private:
	struct targets_t
	{
		EHANDLE hEnemy;
		int nKillCount;
		Vector vecOrigin;
	};

	CUtlVector<targets_t> m_hTargets;

};
DECLARE_ACHIEVEMENT( CAchievementTFSpy_SpyCampPosition, ACHIEVEMENT_TF_SPY_CAMP_POSITION, "TF_SPY_CAMP_POSITION", 5 );

class CAchievementTFSpy_AchieveProgress1 : public CAchievement_AchievedCount
{
public:
	DECLARE_CLASS( CAchievementTFSpy_AchieveProgress1, CAchievement_AchievedCount );
	void Init()
	{
		BaseClass::Init();
		SetAchievementsRequired( 5, ACHIEVEMENT_TF_SPY_START_RANGE, ACHIEVEMENT_TF_SPY_END_RANGE );
	}
};
DECLARE_ACHIEVEMENT( CAchievementTFSpy_AchieveProgress1, ACHIEVEMENT_TF_SPY_ACHIEVE_PROGRESS1, "TF_SPY_ACHIEVE_PROGRESS1", 5 );

class CAchievementTFSpy_AchieveProgress2 : public CAchievement_AchievedCount
{
public:
	DECLARE_CLASS( CAchievementTFSpy_AchieveProgress2, CAchievement_AchievedCount );
	void Init()
	{
		BaseClass::Init();
		SetAchievementsRequired( 11, ACHIEVEMENT_TF_SPY_START_RANGE, ACHIEVEMENT_TF_SPY_END_RANGE );
	}
};
DECLARE_ACHIEVEMENT( CAchievementTFSpy_AchieveProgress2, ACHIEVEMENT_TF_SPY_ACHIEVE_PROGRESS2, "TF_SPY_ACHIEVE_PROGRESS2", 5 );

class CAchievementTFSpy_AchieveProgress3 : public CAchievement_AchievedCount
{
public:
	DECLARE_CLASS( CAchievementTFSpy_AchieveProgress3, CAchievement_AchievedCount );
	void Init()
	{
		BaseClass::Init();
		SetAchievementsRequired( 17, ACHIEVEMENT_TF_SPY_START_RANGE, ACHIEVEMENT_TF_SPY_END_RANGE );
	}
};
DECLARE_ACHIEVEMENT( CAchievementTFSpy_AchieveProgress3, ACHIEVEMENT_TF_SPY_ACHIEVE_PROGRESS3, "TF_SPY_ACHIEVE_PROGRESS3", 5 );

class CAchievementTFSpy_KillBackScatterScout : public CBaseTFAchievement
{
public:
	void Init()
	{
		SetFlags( ACH_LISTEN_PLAYER_KILL_ENEMY_EVENTS | ACH_SAVE_GLOBAL );
		SetGoal( 1 );
	}

	virtual void Event_EntityKilled( CBaseEntity *pVictim, CBaseEntity *pAttacker, CBaseEntity *pInflictor, IGameEvent *event )
	{
		CTFPlayer *pTFVictim = ToTFPlayer( pVictim );
		if ( pTFVictim && pTFVictim->IsPlayerClass( TF_CLASS_SCOUT ) && ( pAttacker == C_TFPlayer::GetLocalTFPlayer() ) )
		{
			if ( event->GetInt( "customkill" ) == TF_DMG_CUSTOM_BACKSTAB )
			{
				CTFWeaponBase *pWeapon = pTFVictim->GetActiveTFWeapon();
				if ( pWeapon && ( pWeapon->GetWeaponID() == TF_WEAPON_SCATTERGUN ) )
				{
					int iMiniCritBackAttack = 0;
					CALL_ATTRIB_HOOK_INT_ON_OTHER( pWeapon, iMiniCritBackAttack, closerange_backattack_minicrits );
					if ( iMiniCritBackAttack > 0 )
					{
						IncrementCount();
					}
				}
			}
		}
	}
};
DECLARE_ACHIEVEMENT( CAchievementTFSpy_KillBackScatterScout, ACHIEVEMENT_TF_SPY_KILL_BACKSCATTER_SCOUT, "TF_SPY_KILL_BACKSCATTER_SCOUT", 5 );

#endif // CLIENT_DLL