
///////////////////////////////////////////////////////////////////////////////
//
// File   : AVP_Actor_DynamicStat.cpp
// Author : Andy Tate
// Date   : 6-Oct-2006
//
// Copyright (C) 2006 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Include files...
////////////////////////////////////////////////////////////////////////////////

#include "Core/Asura.h"
#include "Core/Asura_Maths.h"

// This file's header...
#include "Actor/AVP_Actor_DynamicStat.h"

// Asura independent header-files...

// Asura platform header-files...

// Game independent header-files...

// Game platform header-files...

// Tools header-files...


////////////////////////////////////////////////////////////////////////////////
// Constant declarations...
////////////////////////////////////////////////////////////////////////////////

DEBUGVAR float	dbg_fUpdateEquivalentThreshold	= 0.25f;


////////////////////////////////////////////////////////////////////////////////
// Static variable declarations...
////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////
// Private functions...
////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////
// Protected functions...
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Actor_DynamicStat::UpdateValues
// Author       : Andy Tate
// Date         : 6-Oct-2006
////////////////////////////////////////////////////////////////////////////////

void AVP_Actor_DynamicStat::UpdateValues (const float fValue,
										  const bool bImmediate)
{
	const float	fNewValue	= Asura_Maths::ClampToRange(fValue, m_fMinValue, m_fMaxValue);

	// Is this an immediate change?
	if(bImmediate)
	{
		m_fCurrentValue			= fNewValue;
		m_fTimeAtDesiredValue	= 0.0f;
	}

	// Update the desired value...
	m_fDesiredValue	= fNewValue;
}

/// End of function 'AVP_Actor_DynamicStat::UpdateValues'. ///



////////////////////////////////////////////////////////////////////////////////
// Public functions...
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Actor_DynamicStat::AVP_Actor_DynamicStat
// Author       : Andy Tate
// Date         : 6-Oct-2006
////////////////////////////////////////////////////////////////////////////////

AVP_Actor_DynamicStat::AVP_Actor_DynamicStat (const float fInitial,
											  const float fMin,
											  const float fMax)
: m_fDesiredValue(fInitial)
, m_fCurrentValue(fInitial)
, m_fTimeAtDesiredValue(0.0f)
, m_fInitialValue(fInitial)
, m_fMinValue(fMin)
, m_fMaxValue(fMax)
{
	// Nothing more to initialise...
}

/// End of function 'AVP_Actor_DynamicStat::AVP_Actor_DynamicStat'. ///


void AVP_Actor_DynamicStat::SetMax(const float fValue)
{
	m_fMaxValue = fValue;
	UpdateValues(m_fCurrentValue, true);
}


////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Actor_DynamicStat::Update
// Author       : Andy Tate
// Date         : 6-Oct-2006
////////////////////////////////////////////////////////////////////////////////

void AVP_Actor_DynamicStat::Update (const float fTimeStep,
									const float fChargeParameter,
									UpdateFunction* pfnDrain,
									UpdateFunction* pfnRefill)
{
	// Have we reached the desired value?
	if(m_fDesiredValue == m_fCurrentValue)
	{
		// Yes - update the timer...
		m_fTimeAtDesiredValue	+= fTimeStep;
	}
	else
	{
		// No - are we refilling our draining this stat?
		if(m_fDesiredValue > m_fCurrentValue)
		{
			// Time to refill the current value...
			if(pfnRefill == NULL)
			{
				m_fCurrentValue	= m_fDesiredValue;
			}
			else
			{
				const float	fDifference	= m_fDesiredValue - m_fCurrentValue;

				m_fCurrentValue	= Asura_Maths::ClampToRange( pfnRefill(fTimeStep, m_fCurrentValue, fDifference, fChargeParameter), m_fMinValue, m_fMaxValue );
			}
		}
		else
		{
			// Time to drain the current value...
			if(pfnDrain == NULL)
			{
				m_fCurrentValue	= m_fDesiredValue;
			}
			else
			{
				const float	fDifference	= m_fCurrentValue - m_fDesiredValue;

				m_fCurrentValue	= Asura_Maths::ClampToRange( pfnDrain(fTimeStep, m_fCurrentValue, fDifference, fChargeParameter), m_fMinValue, m_fMaxValue );
			}
		}

		{
			const float	fDifference	= Asura_Maths::Abs(m_fDesiredValue - m_fCurrentValue);

			// Have we reached the desired value?
			if(fDifference < dbg_fUpdateEquivalentThreshold)
			{
				// Yes - or we're close enough...
				m_fCurrentValue	= m_fDesiredValue;
			}

			// Zero the time at this value...
			m_fTimeAtDesiredValue	= 0.0f;
		}
	}
}

/// End of function 'AVP_Actor_DynamicStat::Update'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Actor_DynamicStat::Reset
// Author       : Andy Tate
// Date         : 6-Oct-2006
////////////////////////////////////////////////////////////////////////////////

void AVP_Actor_DynamicStat::Reset (void)
{
	// Reset the changing values...
	m_fDesiredValue			= m_fInitialValue;
	m_fCurrentValue			= m_fInitialValue;
	m_fTimeAtDesiredValue	= 0.0f;
}

/// End of function 'AVP_Actor_DynamicStat::Reset'. ///


/// End of file. ///
