/*
* Charged Turbo
* @version: 9-13-2006
* @author: Joseph 'Pcjoe' Florencio
*/

#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "monsters.h"
#include "weapons.h"
#include "nodes.h"
#include "effects.h"
#include "aura.h"
#include "classes.h"
#include "magicattack.h"
#include "explodingattack.h"
#include "player.h"
#include "gamerules.h"
#include "chargedattack.h"
#include "melee.h"
#include "playermelee.h"
#include "swoop.h"
#include "chargedturbo.h"
#include "../common/particletypes.h"

// Natural log limits for exponential decay for powerlevel increasing
#define CT_LN_X_LOWER	1.001
#define CT_LN_X_UPPER	54.5982
#define CT_LN_LOWER		0.001
#define CT_LN_UPPER		4.000

#define CT_SETTLE_RATE_INC 0.6	// Rate is in percent per second
#define CT_SETTLE_RATE_DEC 0.35 // Rate is in percent per second

#define CT_TAP_OFF_TIME		0.3

#define TURBO_PL_MULTIPLIER 1.25

#define TURBO_KI_COST					  2			//cost of turbo per ki-update


extern int gmsgAddEffect;
extern int gmsgRemoveEffect;

extern cvar_t charge_turbo_time;
extern cvar_t charge_turbo_hold_time;
extern cvar_t charge_turbo_use_time;
extern cvar_t charge_turbo_multi_top;
extern cvar_t charge_turbo_cap_time;
extern cvar_t ki_cost_charged_turbo;
extern cvar_t ki_cost_charged_turbo_hold;
extern cvar_t ki_cost_charged_turbo_dec;

// Constructor
CChargedTurbo::CChargedTurbo()
{	Reset();
}

// Reset
void CChargedTurbo::Reset( void )
{	m_pOwner = NULL;
	m_fChargedTurbo = FALSE;
	m_fChargedTurboActive = FALSE;
	m_flTurboKeyPress = 0;
	m_flTurboStatusChange = 0;
	m_flChargeTurboActiveStop = 0;
	m_flChargeTurboTime = 0;
	m_flChargedTurboPercent = 0;
	m_flTurboMultiplier = 1;
	m_flSettleTime = 0;
	m_flTimeDelta = 0;
	m_flLastTime = 0;
}

// Disable charged turbo
void CChargedTurbo::disableChargedTurbo( void )
{	if(m_fChargedTurboActive)
	{	stopActiveCharge();
	}
	m_fChargedTurbo = FALSE;
	m_flTurboKeyPress = 0;
	m_flChargedTurboPercent = 0;
	m_flChargeTurboActiveStop = 0;
	m_flChargeTurboTime = 0;
}

// Manage charged turbo
void CChargedTurbo::manageChargedTurbo( void )
{
	updateTimeDelta();

	if(m_pOwner->m_fTurbo)
	{
		if(m_fChargedTurbo)
		{	// No more charged turbo left, disable
			if(m_flChargedTurboPercent <= 0)
			{	m_fChargedTurbo = FALSE;
			}
		}
		// Just in normal turbo, try to find an opportunity to start up charged turbo
		else
		{	if(m_flTurboKeyPress != 0 && (gpGlobals->time-m_flTurboKeyPress > charge_turbo_hold_time.value))
			{	// Don't allow charged turbo if we're in one of these states
				if(m_pOwner->m_fBecomeCandy || m_pOwner->m_fCharging || m_pOwner->m_fCharging2 || m_pOwner->m_fControl || !m_pOwner->IsAlive() || m_pOwner->m_fObserverFlag || m_pOwner->m_fHoldDisc || m_pOwner->m_fAscending || m_pOwner->m_fMelee || m_pOwner->m_Melee.m_fPowerhit || m_pOwner->m_fShield)
				{	m_flTurboKeyPress = 0;
				}
				else
				{	// Start active charge
					startActiveCharge();
				}
			}
		}
	}

	calculateMultipliers();

	setLastTime();
}

// Turbo key press
void CChargedTurbo::turboKeyPress( void )
{	// Currently swooping, check for button presses for swoop pausing
	if(m_pOwner->m_Swoop.CanPause())
	{	m_pOwner->m_Swoop.PausePlayer();
	}
	// Start up turbo
	else if(!m_pOwner->m_fTurbo)
	{	m_pOwner->StartTurbo();
		updateSettle();
		m_flTurboStatusChange = gpGlobals->time;
	}

	m_flTurboKeyPress = gpGlobals->time;
}

// Turbo key release
void CChargedTurbo::turboKeyRelease( void )
{	// Check for unpausing
	if(m_pOwner->m_Swoop.m_fSwoop && m_pOwner->m_Swoop.IsPaused())
	{	m_pOwner->m_Swoop.StopSwoop();
	}
	// Stop turbo
	else if(m_pOwner->m_fTurbo)
	{	// Stop active charge
		if(m_fChargedTurboActive)
		{	stopActiveCharge();

			CSwoop *pSwoop = &m_pOwner->m_Swoop;
			// Direction applied, boost off (shorthand)
			if(pSwoop->GetActiveDirection() != -1)
			{	int iDirection = pSwoop->GetActiveDirection();
				// Use KI
				if(m_pOwner->UseKi(pSwoop->GetSwoopStartKi(FALSE)))
				{	// Add to null keyset
					pSwoop->AddToNullKeyset(pSwoop->DirectionsToFlags(iDirection));

					// Start swoop
					pSwoop->StartSwoop(iDirection, FALSE);
				}
			}
		}
		// stop turbo
		else if(m_flTurboStatusChange != m_flTurboKeyPress && (gpGlobals->time-m_flTurboKeyPress <= CT_TAP_OFF_TIME))
		{	m_pOwner->StopTurbo();
			m_flTurboStatusChange = gpGlobals->time;
		}
	}
	m_flTurboKeyPress = 0;
}

// Start Active Charge
void CChargedTurbo::startActiveCharge( void )
{	// Stop powerup
	if(m_pOwner->m_fPowerUp)
	{	m_pOwner->StopPowerUp();
	}

	// Stop Block
	if(m_pOwner->m_fBlock)
	{	m_pOwner->StopBlock();
	}

	m_flChargedTurboPercent = 0;
	m_flChargeTurboActiveStop = 0;
	m_flChargeTurboTime = gpGlobals->time;
	m_fChargedTurbo = TRUE;
	m_fChargedTurboActive = TRUE;
	m_pOwner->m_flSlowDown = 0.0;

	//stay in the air, if falling down
	if (!(m_pOwner->pev->flags&FL_ONGROUND))
	{	if (!m_pOwner->m_fFlying)
		{	m_pOwner->StartFly();
		}
	}

	// Play extra sound
	EMIT_SOUND(ENT(m_pOwner->pev), CHAN_ITEM, "weapons/chainswoop.wav", 1, ATTN_NORM);

	// add FX
	MESSAGE_BEGIN( MSG_ALL, gmsgAddEffect);
		WRITE_BYTE(CHARGEDTURBO);
		WRITE_SHORT(m_pOwner->entindex());
	MESSAGE_END();
}

// Stop Active Charge
void CChargedTurbo::stopActiveCharge( void )
{	if(m_fChargedTurboActive)
	{	m_fChargedTurboActive = FALSE;
		m_flChargeTurboActiveStop = gpGlobals->time;
		m_flChargeTurboTime = 0;
		m_pOwner->m_flSlowDown = 1.0;

		// remove fx
		MESSAGE_BEGIN( MSG_ALL, gmsgRemoveEffect);
			WRITE_BYTE(CHARGEDTURBO);
			WRITE_SHORT(m_pOwner->entindex());		
		MESSAGE_END();
	}
}

// calculate turbo multipliers
void CChargedTurbo::calculateMultipliers( void )
{	float flDesired = 1.0;

	if(m_pOwner->m_fTurbo)
	{	// Charge turbo is active
		if(m_fChargedTurbo)
		{	// Increasing pl
			if(m_fChargedTurboActive)
			{	m_flChargedTurboPercent += m_flTimeDelta * (1.00/charge_turbo_time.value);
				if(m_flChargedTurboPercent > 1)
				{	m_flChargedTurboPercent = 1;
					// MAXED OUT: Set some flag here
				}
				flDesired = TURBO_PL_MULTIPLIER + getChargedTurboMultiplier() * (charge_turbo_multi_top.value-TURBO_PL_MULTIPLIER);
			}
			// Decreasing pl
			else
			{	// Before we start dropping PL, keep capped out for X seconds so we can have our high pl to play around with
				if(gpGlobals->time-m_flChargeTurboActiveStop > charge_turbo_cap_time.value)
				{	m_flChargedTurboPercent -= m_flTimeDelta * (1.00/charge_turbo_use_time.value);
				}
				if(m_flChargedTurboPercent < 0)
				{	m_flChargedTurboPercent = 0;
					// No more charged turbo, set some flag here...
				}
				flDesired = TURBO_PL_MULTIPLIER + getChargedTurboMultiplier() * (charge_turbo_multi_top.value-TURBO_PL_MULTIPLIER);
			}
		}
		// Regular turbo
		else
		{	flDesired = TURBO_PL_MULTIPLIER;
		}
	}
	// No turbo; drop down to normal pl if we have a multiplier still
	else
	{	flDesired = 1.0;
	}

	// Insert interpolate func here, for now directly set
	settleAmount(m_flTurboMultiplier, flDesired);
}

// Update Settle (enabling settling of powerlevel)
void CChargedTurbo::updateSettle( void )
{	m_flSettleTime = gpGlobals->time;
}

// settle amount (using settle timer)
void CChargedTurbo::settleAmount( float &actual, float desired )
{	if(m_flSettleTime != 0)
	{	if(actual > desired)
		{	actual -= m_flTimeDelta*CT_SETTLE_RATE_DEC;
			if(actual < desired)
			{	m_flSettleTime = 0;
				actual = desired;
			}
		}
		else
		{	actual += m_flTimeDelta*CT_SETTLE_RATE_INC;
			if(actual > desired)
			{	m_flSettleTime = 0;
				actual = desired;
			}
		}
	}
	else
	{	actual = desired;
	}
}

// Get turbo multiplier
float CChargedTurbo::getTurboMultiplier( void )
{	return m_flTurboMultiplier;
}

// Get charged turbo pl multiplier, exponential decay
float CChargedTurbo::getChargedTurboMultiplier( void )
{	float flResult = log(CT_LN_X_LOWER+m_flChargedTurboPercent*(CT_LN_X_UPPER-CT_LN_X_LOWER));
	return (flResult-CT_LN_LOWER)/(CT_LN_UPPER-CT_LN_LOWER);
}

// Update time delta
void CChargedTurbo::updateTimeDelta( void )
{	if(m_flLastTime == 0)
		m_flTimeDelta = 0;
	else
		m_flTimeDelta = gpGlobals->time - m_flLastTime;
}

// Set Last Time
void CChargedTurbo::setLastTime( void )
{	m_flLastTime = gpGlobals->time;
}

// Get KI Burn
int CChargedTurbo::getKIBurn( void )
{	if(m_pOwner->m_fTurbo)
	{	if(m_fChargedTurbo)
		{	if(m_fChargedTurboActive)
			{	// Huge reduced cost for 'holding' turbo at max
				if(m_flChargedTurboPercent >= 1)
					return ki_cost_charged_turbo_hold.value;
				return ki_cost_charged_turbo.value;
			}
			// Slightly reduced cost for just being in charged turbo and not doing much
			if(!m_pOwner->m_fCharging && !m_pOwner->m_fCharging2 && !m_pOwner->m_fControl && !m_pOwner->m_fHoldDisc && !m_pOwner->m_fMelee && !m_pOwner->m_fShield)
				return ki_cost_charged_turbo_dec.value;
		}
		return TURBO_KI_COST;
	}
	return 0;
}

// Get charge time
float CChargedTurbo::getChargeTime( void )
{	return m_flChargeTurboTime;
}

// Is chargeturbo active
BOOL CChargedTurbo::isChargeTurboActive( void )
{	return m_fChargedTurboActive;
}

// Set Owner
void CChargedTurbo::setOwner( CBasePlayer *pPlayer )
{	m_pOwner = pPlayer;
}