class AreaDamageLooped : AreaDamageManager { //! Current start time in seconds protected float m_CurrentTime = 0.0; //! Previous start time in seconds protected float m_PreviousTime = 0.0; //! How much time has accumulated protected float m_AccumulatedTime = 0.0; //! Loop interval in seconds protected float m_LoopInterval = 1.0; //! Caching of the amount of loops that will be performed in this frame protected int m_AmountOfLoops = 0; //! Decides if the looping will be using the Object as reference or the time since last update loop protected bool m_LoopByObject = true; void AreaDamageLooped(EntityAI parent, bool loopByObject = true) { m_LoopByObject = loopByObject; } //! Gets called when the trigger is spawned, so is the start and also a reset override void OnTriggerCreated() { super.OnTriggerCreated(); m_PreviousTime = g_Game.GetTickTime(); m_AccumulatedTime = 0.0; } override void SetLoopInterval( float time ) { m_LoopInterval = time; } override void OnEnterServerEvent(TriggerInsider insider) { super.OnEnterServerEvent(insider); // Do direct damaging first time on entering if (m_LoopByObject) OnEvaluateDamageEx(insider, 1); } override void OnStayStartServerEvent(int nrOfInsiders) { super.OnStayStartServerEvent(nrOfInsiders); m_CurrentTime = g_Game.GetTickTime(); m_AccumulatedTime += m_CurrentTime - m_PreviousTime; m_PreviousTime = m_CurrentTime; m_AmountOfLoops = m_AccumulatedTime / m_LoopInterval; } override void OnStayServerEvent(TriggerInsider insider, float deltaTime) { super.OnStayServerEvent(insider, deltaTime); // As we are using the Ex variant, we can put the logic in CalculateDamageScale OnEvaluateDamageEx(insider, deltaTime); } override void OnStayFinishServerEvent() { super.OnStayFinishServerEvent(); m_AccumulatedTime -= m_AmountOfLoops * m_LoopInterval; } // TODO: EMH: OnLeaveServerEvent -> perform the remaining buffered damage to be done? override protected float CalculateDamageScale(TriggerInsider insider, float deltaTime) { // If we want the LoopInterval to be dependant on the Object, we will need their lastDamaged time if (m_LoopByObject) { float lastDamaged = 0; AreaDamageTriggerInsider dInsider; if ( CastTo( dInsider, insider ) ) lastDamaged = dInsider.lastDamaged; // First time it is damaged, do full damage if (lastDamaged == 0) return 1; // This way, in case the server lags, it will scale the damage to catch up if necessary // We want to wait until it is at least above 1, to not spam the network with hit messages float damageCoeff = (m_CurrentTime - lastDamaged) / m_LoopInterval; if ( damageCoeff >= 1 ) return damageCoeff; return 0; } else { return m_AmountOfLoops; } } }