/**
* Transformation FX
* @version: 9-14-2002
* @author Joseph 'Pcjoe' Florencio
*/

#include "hud.h"
#include "parsemsg.h"
#include "const.h"
#include "cl_util.h"
#include "r_efx.h"
#include "pm_defs.h"
#include "pmtrace.h"
#include "event_api.h"
#include "transformfx.h"
#include "vrml.h"
#include "r_studioint.h"

#define ENG_PM_POINT_CONTENTS gEngfuncs.PM_PointContents
#define DRAMATIC_TRANSFX 9.0

extern part_manager_s *pPartJobs;
extern char *sLocalisedClasses[];
extern engine_studio_api_t IEngineStudio;
trans_event_manager *pTrans;
VRMLData gVRMLAura;
VRMLData gVRMLAura2;
VRMLData gVRMLLowAura;
VRMLData gVRMLRock;
/* removed by harSens
VRMLData gVRMLDiamond;
*/
HSPRITE g_hsprAuraVRML;
HSPRITE g_hsprAuraWhiteVRML;
HSPRITE g_hsprLighting;
HSPRITE g_hsprRockVRML;

DECLARE_MESSAGE(m_TransformFX, TransformFX);
DECLARE_MESSAGE(m_TransformFX, StopTransFX);

int CHudTransformFX::Init(void)
{	HOOK_MESSAGE(TransformFX);
	HOOK_MESSAGE(StopTransFX);

	ResetInit();

	gHUD.AddHudElem(this);
	m_iFlags |= HUD_ACTIVE;
	return 1;
}

void CHudTransformFX::ResetInit(void)
{	// Reset Particle FX
	part_manager_s *pCurrent = pPartJobs;
	trans_event_manager *pCurrent2 = pTrans;

	while(pCurrent)
		pCurrent = Partsys.RemoveSystem( pCurrent );

	while(pCurrent2)
		pCurrent2 = DeleteTransFx( pCurrent2 );

	pTrans = NULL;
	pPartJobs = NULL;
	m_flTime = 0;
	m_blMp3Pause = false;
	m_flDrawTime = 0;
}

int CHudTransformFX::VidInit(void)
{	ParseVRML("models/aura.wrl", gVRMLAura);
	ParseVRML("models/aura2.wrl", gVRMLAura2);
	ParseVRML("models/auralow.wrl", gVRMLLowAura);
	ParseVRML("models/rock.wrl", gVRMLRock);
	g_hsprAuraVRML = LoadSprite("sprites/auraVRML.spr");
	g_hsprAuraWhiteVRML = LoadSprite("sprites/grey.spr");
	g_hsprLighting = LoadSprite("sprites/lgtning.spr");
	g_hsprRockVRML = LoadSprite("sprites/rockVRML.spr");
	return 1;
}

// -----------------
//  Event Managment
// -----------------

void CHudTransformFX::AddEvent( trans_event_manager *pTransFx, int iFlag, float flTimeStart, float flDurration )
{	// Entering data for events...
	trans_event *pNewEvent = new trans_event;

	pNewEvent->iFlag = iFlag;
	pNewEvent->flTimeStart = flTimeStart;
	pNewEvent->flTimeEnd = pTransFx->flTimeStart + flDurration;
	pNewEvent->iIndex = pTransFx->iIndex;
	strcpy(pNewEvent->szSound,"");
	pNewEvent->pNext = NULL;

	// First in list? If so, place it here
	
	if(!pTransFx->pEvents)
	{	pTransFx->pEvents = pNewEvent;
	}
	// Search!
	else
	{	trans_event *pTemp = pTransFx->pEvents;
		while(pTemp->pNext)
		{
			pTemp = pTemp->pNext;
		}
		pTemp->pNext = pNewEvent;
	}

	// Note - Most of these particle systems will allocate extra memory when needed, thus the low settings
	// Init Particle system
	switch (iFlag)
	{
	case ROTATE_LGHTING_SPHERE:
	case PURPLE_LGHTING_SPHERE:
	case PINK_SOLID_SPHERE:
	case FLASHY_AURA:
	case FLASHY_WHITE_AURA:
	case WHITE_SPHERE:
	case EXPLOSION_SPHERE:
	case SHOCKWAVE_CORE:
	case SHOCKWAVE_CORE_INVERSE:
	case HARD_INNDER_SPHERE:
		Partsys.CreateParticleSystem( 1, pTransFx->iCharacter, pNewEvent );
		break;
	case LIGHTING:
		Partsys.CreateParticleSystem( 6, pNewEvent );
		break;
	case FLOATING_ROCKS:
	case DUST:
	case COLUMN_DUST:
	case ROTATING_DUST:
	case EXPANDED_DUST:
	case STEAM:
	case STEAM_HEAD:
		Partsys.CreateParticleSystem( 10, pNewEvent );
		break;
	case SCREAM:
	case SCREAM2:
	case PSCREAM:
		{
			cl_entity_t *pClient = gEngfuncs.GetEntityByIndex(pTransFx->iIndex);
			char szSound[256];

			// Copy Player Name to string
			sprintf( szSound,"%s", sLocalisedClasses[g_PlayerExtraInfo[pNewEvent->iIndex].playerclass]);

			// Move every character back one ( To remove the # infront of the player names )
			for(unsigned int i = 0; i < strlen(szSound); i++)
			{	szSound[i] = szSound[i+1];
			}

			// Use the right type of scream
			if(iFlag == SCREAM)
			{	sprintf ( pNewEvent->szSound,"%s/scream.wav", szSound);
			}
			else if(iFlag == SCREAM2)
			{	sprintf ( pNewEvent->szSound,"%s/scream2.wav", szSound);
			}
			else
			{	sprintf ( pNewEvent->szSound,"%s/pscream.wav", szSound);
			}

			break;
		}
	}
}

// ------------------------
//  Character Trans Events
// ------------------------

void CHudTransformFX::GokuTrans( trans_event_manager *pTransFx )
{
	// Player Pointer
	cl_entity_t *pClient = gEngfuncs.GetEntityByIndex(pTransFx->iIndex);

	float flDurration = pTransFx->flDurration;
	float flTotalTime = pTransFx->flTimeStart + flDurration;

	// Event 1
	// If Over 9.0 seconds, lighting. Else, Flash Aura + dust
	if( flDurration >= DRAMATIC_TRANSFX )
	{	gEngfuncs.pEventAPI->EV_PlaySound( pClient->index, pClient->origin, CHAN_ITEM, "goku/Trans.wav", 1, ATTN_NORM, 0, PITCH_NORM );
		// Add scream sound event
		AddEvent( pTransFx, SCREAM, flTotalTime-1.25, flDurration );
		// Lighting
		AddEvent( pTransFx, LIGHTING, pTransFx->flTimeStart, flDurration );
		// Add shockwave explosions
		AddEvent( pTransFx, EXPLOSION_SPHERE, pTransFx->flTimeStart+2.3, flDurration );
		AddEvent( pTransFx, EXPLOSION_SPHERE, pTransFx->flTimeStart+2.8, flDurration );
		AddEvent( pTransFx, EXPLOSION_SPHERE, pTransFx->flTimeStart+3.3, flDurration );
		// Add Floating rocks
		AddEvent( pTransFx, FLOATING_ROCKS, pTransFx->flTimeStart+4.5, flDurration );

		// Add Ending Aura
		AddEvent( pTransFx, FLASHY_AURA, flTotalTime-0.9, flDurration );
	}
	else
	{	
		// Grunts for short transform
		if(flDurration >= 1.5)
			gEngfuncs.pEventAPI->EV_PlaySound( pClient->index, pClient->origin, CHAN_ITEM, "goku/Trans2.wav", 1, ATTN_NORM, 0, PITCH_NORM );
		// Add scream sound event
		AddEvent( pTransFx, SCREAM2, flTotalTime-1, flDurration );

		// Flashy Aura
		AddEvent( pTransFx, FLASHY_AURA, pTransFx->flTimeStart, flDurration - 0.675 );

		// Dust
		AddEvent( pTransFx, DUST, pTransFx->flTimeStart, flDurration - 0.675 );

		if( flDurration >= 2.0 )
		{	// Floating Rocks
			AddEvent( pTransFx, FLOATING_ROCKS, pTransFx->flTimeStart, flDurration - 0.675 );
		}

		AddEvent( pTransFx, EXPLOSION_SPHERE, pTransFx->flTimeStart + flDurration - 0.675, flDurration );
	}
}

void CHudTransformFX::VegetaTrans( trans_event_manager *pTransFx )
{
	// Player Pointer
	cl_entity_t *pClient = gEngfuncs.GetEntityByIndex(pTransFx->iIndex);

	float flDurration = pTransFx->flDurration;
	float flTotalTime = pTransFx->flTimeStart + flDurration;

	// Over 9 seconds
	if( flDurration >= DRAMATIC_TRANSFX )
	{
		// Music
		gEngfuncs.pEventAPI->EV_PlaySound( pClient->index, pClient->origin, CHAN_ITEM, "vegeta/Trans.wav", 1, ATTN_NORM, 0, PITCH_NORM );
		// Add scream sound event
		AddEvent( pTransFx, SCREAM, flTotalTime-1, flDurration );
		// Flash Aura
		AddEvent( pTransFx, FLASHY_AURA, pTransFx->flTimeStart + 2.55, flDurration-1 );
		// Floating Rocks
		AddEvent( pTransFx, FLOATING_ROCKS, pTransFx->flTimeStart+4.5, flDurration-1 );
		// Dust
		AddEvent( pTransFx, DUST, pTransFx->flTimeStart+6.5, flDurration-1 );
	}
	// Under
	else
	{
		// Grunts for short transform
		if(flDurration >= 1.5)
			gEngfuncs.pEventAPI->EV_PlaySound( pClient->index, pClient->origin, CHAN_ITEM, "Vegeta/Trans2.wav", 1, ATTN_NORM, 0, PITCH_NORM );
		// Add scream sound event
		AddEvent( pTransFx, SCREAM2, flTotalTime-1, flDurration );
		// Flash Aura
		AddEvent( pTransFx, FLASHY_AURA, pTransFx->flTimeStart, flDurration-1 );
		// Dust
		AddEvent( pTransFx, DUST, pTransFx->flTimeStart, flDurration-1 );
	}
	
	// Ending Shockwave
	AddEvent( pTransFx, EXPLOSION_SPHERE, flTotalTime-1, flDurration );
}

void CHudTransformFX::GohanTrans( trans_event_manager *pTransFx )
{
	// Player Pointer
	cl_entity_t *pClient = gEngfuncs.GetEntityByIndex(pTransFx->iIndex);

	float flDurration = pTransFx->flDurration;
	float flTotalTime = pTransFx->flTimeStart + flDurration;

	// Event 1
	if( flDurration >= DRAMATIC_TRANSFX )
	{
		// Music
		gEngfuncs.pEventAPI->EV_PlaySound( pClient->index, pClient->origin, CHAN_ITEM, "gohan/Trans.wav", 1, ATTN_NORM, 0, PITCH_NORM );
		// Add scream sound event
		AddEvent( pTransFx, SCREAM, flTotalTime-1, flDurration );
		// Flashy Aura
		AddEvent( pTransFx, FLASHY_AURA, pTransFx->flTimeStart+4.9, flDurration-0.3 );
		// Dust
		AddEvent( pTransFx, DUST, pTransFx->flTimeStart+4.9, flDurration-0.3 );
		// Add shockwave explosion
		AddEvent( pTransFx, EXPLOSION_SPHERE, pTransFx->flTimeStart+4.6, flDurration );
		// Add shockwave explosion 2
		AddEvent( pTransFx, EXPLOSION_SPHERE, pTransFx->flTimeStart+3.2, flDurration );
		// Add shockwave explosion 3
		AddEvent( pTransFx, EXPLOSION_SPHERE, flTotalTime-0.3, flDurration );
	}
	else
	{
		// Grunts for short transform
		if(flDurration >= 1.5)
			gEngfuncs.pEventAPI->EV_PlaySound( pClient->index, pClient->origin, CHAN_ITEM, "gohan/Trans2.wav", 1, ATTN_NORM, 0, PITCH_NORM );
		// Add scream sound event
		AddEvent( pTransFx, SCREAM2, flTotalTime-1, flDurration );
		// Flash Aura
		AddEvent( pTransFx, FLASHY_AURA, pTransFx->flTimeStart, flDurration-0.3 );
		// Dust
		AddEvent( pTransFx, DUST, pTransFx->flTimeStart, flDurration-0.3 );
		// Add shockwave explosion
		AddEvent( pTransFx, EXPLOSION_SPHERE, flTotalTime-0.3, flDurration );
	}

	if( flDurration >= 2.0 )
	{	// Floating Rocks
		AddEvent( pTransFx, FLOATING_ROCKS, pTransFx->flTimeStart, flDurration );
	}

}

void CHudTransformFX::TrunksTrans( trans_event_manager *pTransFx )
{
	// Player Pointer
	cl_entity_t *pClient = gEngfuncs.GetEntityByIndex(pTransFx->iIndex);

	float flDurration = pTransFx->flDurration;
	float flTotalTime = pTransFx->flTimeStart + flDurration;

	// If Over 9.0 seconds, Scream
	if( flDurration >= DRAMATIC_TRANSFX )
	{
		gEngfuncs.pEventAPI->EV_PlaySound( pClient->index, pClient->origin, CHAN_ITEM, "trunks/Trans.wav", 1, ATTN_NORM, 0, PITCH_NORM );
		// Add scream sound event
		AddEvent( pTransFx, SCREAM, flTotalTime-1, flDurration  );
		// Flashy Aura
		AddEvent( pTransFx, FLASHY_AURA, pTransFx->flTimeStart+2.5, flDurration-0.4 );
		// Rocks
		AddEvent( pTransFx, FLOATING_ROCKS, pTransFx->flTimeStart+5.25, flDurration-0.4 );
		// Shockwave
		AddEvent( pTransFx, EXPLOSION_SPHERE, pTransFx->flTimeStart+5.25, flDurration );
		// Dust
		AddEvent( pTransFx, DUST, pTransFx->flTimeStart+5.25, flDurration-0.4 );
		// Shockwave
		AddEvent( pTransFx, EXPLOSION_SPHERE, flTotalTime-0.4, flDurration );
	}
	else
	{
		// Grunts for short transform
		if(flDurration >= 1.5)
			gEngfuncs.pEventAPI->EV_PlaySound( pClient->index, pClient->origin, CHAN_ITEM, "trunks/Trans2.wav", 1, ATTN_NORM, 0, PITCH_NORM );
		// Add scream sound event
		AddEvent( pTransFx, SCREAM2, flTotalTime-1, flDurration );
		// Flashy Aura
		AddEvent( pTransFx, FLASHY_AURA, pTransFx->flTimeStart, flDurration-0.4 );
		// Rocks
		AddEvent( pTransFx, FLOATING_ROCKS, pTransFx->flTimeStart, flDurration-0.4 );
		// Shockwave
		AddEvent( pTransFx, EXPLOSION_SPHERE, flTotalTime-0.4, flDurration );
	}
}
void CHudTransformFX::CellTrans( trans_event_manager *pTransFx )
{
	// Player Pointer
	cl_entity_t *pClient = gEngfuncs.GetEntityByIndex(pTransFx->iIndex);

	float flDurration = pTransFx->flDurration;
	float flTotalTime = pTransFx->flTimeStart + flDurration;

	// Event 1
	// If Over 9.0 seconds, lighting. Else, Flash Aura + dust
/*	if( flDurration >= DRAMATIC_TRANSFX )
	{*/

	gEngfuncs.pEventAPI->EV_PlaySound( pClient->index, pClient->origin, CHAN_ITEM, "cell/Trans.wav", 1, ATTN_NORM, 0, PITCH_NORM );
	// Add scream sound event
	AddEvent( pTransFx, SCREAM, pTransFx->flTimeStart+flDurration-1, flDurration );
	// FX list
	AddEvent( pTransFx, FLOATING_ROCKS, pTransFx->flTimeStart, flDurration );
	AddEvent( pTransFx, ROTATING_DUST, pTransFx->flTimeStart+0.5, flDurration - 1.5 );
	AddEvent( pTransFx, EXPANDED_DUST, pTransFx->flTimeStart+0.5, flDurration - 1 );
	AddEvent( pTransFx, WHITE_SPHERE, pTransFx->flTimeStart+0.5, flDurration - 1 );
	AddEvent( pTransFx, EXPLOSION_SPHERE, flTotalTime-1, flDurration );
	AddEvent( pTransFx, DUST, flTotalTime-1, flDurration );
	AddEvent( pTransFx, FLASHY_WHITE_AURA, flTotalTime-1, flDurration );

/*	}
	else
	{
		// Grunts for short transform
		gEngfuncs.pEventAPI->EV_PlaySound( pClient->index, pClient->origin, CHAN_ITEM, "cell/Trans2.wav", 1, ATTN_NORM, 0, PITCH_NORM );
		// Add scream sound event
		AddEvent( pTransFx, SCREAM2, flTotalTime-1, flDurration );
		// White Shockwave Sphere, emitting colored shockwaves
		AddEvent( pTransFx, SHOCKWAVE_CORE, pTransFx->flTimeStart, flDurration-0.5 );
		// Explosnig sphere
		AddEvent( pTransFx, EXPLOSION_SPHERE, flTotalTime-0.5, flDurration );
		// Floating Rocks
		AddEvent( pTransFx, FLOATING_ROCKS, pTransFx->flTimeStart+2, flDurration );
	}*/
}

void CHudTransformFX::FriezaTrans( trans_event_manager *pTransFx )
{
	// Player Pointer
	cl_entity_t *pClient = gEngfuncs.GetEntityByIndex(pTransFx->iIndex);

	float flDurration = pTransFx->flDurration;
	float flTotalTime = pTransFx->flTimeStart + flDurration;

	// Event 1
	// If Over 9.0 seconds, lighting. Else, Flash Aura + dust
	if( flDurration >= DRAMATIC_TRANSFX )
	{
		gEngfuncs.pEventAPI->EV_PlaySound( pClient->index, pClient->origin, CHAN_ITEM, "frieza/Trans.wav", 1, ATTN_NORM, 0, PITCH_NORM );
		// Add scream sound event
		AddEvent( pTransFx, SCREAM, pTransFx->flTimeStart+flDurration-1, flDurration );
		// Shockwave emitting spheres
		AddEvent( pTransFx, SHOCKWAVE_CORE_INVERSE, pTransFx->flTimeStart, flDurration-8.3 );
		AddEvent( pTransFx, SHOCKWAVE_CORE, pTransFx->flTimeStart+1.8, flDurration-0.95 );
		// Shockwave
		AddEvent( pTransFx, EXPLOSION_SPHERE, flTotalTime-0.9, flDurration );
		// Floating Rocks
		AddEvent( pTransFx, FLOATING_ROCKS, pTransFx->flTimeStart+3.75, flDurration );
	}
	else
	{
		// Grunts for short transform
		if(flDurration >= 1.5)
			gEngfuncs.pEventAPI->EV_PlaySound( pClient->index, pClient->origin, CHAN_ITEM, "frieza/Trans2.wav", 1, ATTN_NORM, 0, PITCH_NORM );
		// Add scream sound event
		AddEvent( pTransFx, SCREAM2, flTotalTime-1, flDurration );
		// White Shockwave Sphere, emitting colored inversed shockwaves
		AddEvent( pTransFx, SHOCKWAVE_CORE_INVERSE, pTransFx->flTimeStart, flDurration-0.9 );
		// Shockwave
		AddEvent( pTransFx, EXPLOSION_SPHERE, flTotalTime-0.9, flDurration );
	}

	if( flDurration >= 2.0 )
	{	// Floating Rocks
		AddEvent( pTransFx, FLOATING_ROCKS, pTransFx->flTimeStart, flDurration );
	}
}

void CHudTransformFX::BuuTrans( trans_event_manager *pTransFx )
{
	// Player Pointer
	cl_entity_t *pClient = gEngfuncs.GetEntityByIndex(pTransFx->iIndex);

	float flDurration = pTransFx->flDurration;
	float flTotalTime = pTransFx->flTimeStart + flDurration;

	// Event 1
	// If Over 9.0 seconds, lighting. Else, Flash Aura + dust
/*	if( flDurration >= DRAMATIC_TRANSFX )
	{*/
	gEngfuncs.pEventAPI->EV_PlaySound( pClient->index, pClient->origin, CHAN_ITEM, "fatbuu/Trans.wav", 1, ATTN_NORM, 0, PITCH_NORM );
	// Add scream sound event
	AddEvent( pTransFx, SCREAM, pTransFx->flTimeStart+flDurration-1, flDurration );
	// Steam comming out of head
	AddEvent( pTransFx, STEAM_HEAD, pTransFx->flTimeStart+2, flDurration-2 );
	// Steam forming around body
	AddEvent( pTransFx, STEAM, pTransFx->flTimeStart+3.5, flDurration-0.9 );
	// Shockwave to top things off
	AddEvent( pTransFx, EXPLOSION_SPHERE, flTotalTime-0.9, flDurration );
	// Flashy White aura
	AddEvent( pTransFx, FLASHY_WHITE_AURA, flTotalTime-0.9, flDurration );
/*	}
	else
	{
		// Grunts for short transform
		gEngfuncs.pEventAPI->EV_PlaySound( pClient->index, pClient->origin, CHAN_ITEM, "buu/Trans2.wav", 1, ATTN_NORM, 0, PITCH_NORM );
		// Add scream sound event
		AddEvent( pTransFx, SCREAM2, flTotalTime-1, flDurration );
	}*/
}

void CHudTransformFX::KrillinTrans ( trans_event_manager *pTransFx )
{	
	// Player Pointer
	cl_entity_t *pClient = gEngfuncs.GetEntityByIndex(pTransFx->iIndex);

	float flDurration = pTransFx->flDurration;
	float flTotalTime = pTransFx->flTimeStart + flDurration;

	// Event 1
	// If Over 9.0 seconds, lighting. Else, Flash Aura + dust
/*	if( flDurration >= DRAMATIC_TRANSFX )
	{*/
	gEngfuncs.pEventAPI->EV_PlaySound( pClient->index, pClient->origin, CHAN_ITEM, "krillin/Trans.wav", 1, ATTN_NORM, 0, PITCH_NORM );
	// Add scream sound event
	AddEvent( pTransFx, SCREAM, flTotalTime-1, flDurration );
	AddEvent( pTransFx, EXPLOSION_SPHERE, pTransFx->flTimeStart+1, flDurration );
	AddEvent( pTransFx, COLUMN_DUST, pTransFx->flTimeStart+1, flDurration-0.9 );
	AddEvent( pTransFx, EXPLOSION_SPHERE, pTransFx->flTimeStart+1, flDurration-0.9 );
	AddEvent( pTransFx, FLASHY_WHITE_AURA, pTransFx->flTimeStart+1, flDurration-0.9 );
	AddEvent( pTransFx, DUST, flTotalTime - 0.9, flDurration );
/*	}
	else
	{
		// Grunts for short transform
		gEngfuncs.pEventAPI->EV_PlaySound( pClient->index, pClient->origin, CHAN_ITEM, "krillin/Trans2.wav", 1, ATTN_NORM, 0, PITCH_NORM );
		// Add scream sound event
		AddEvent( pTransFx, SCREAM2, flTotalTime-1, flDurration );
	}*/
}

void CHudTransformFX::PiccoloTrans( trans_event_manager *pTransFx )
{
	// Player Pointer
	cl_entity_t *pClient = gEngfuncs.GetEntityByIndex(pTransFx->iIndex);

	float flDurration = pTransFx->flDurration;
	float flTotalTime = pTransFx->flTimeStart + flDurration;

	// Event 1
	// If Over 9.0 seconds, lighting. Else, Flash Aura + dust
	if( flDurration >= DRAMATIC_TRANSFX )
	{
		gEngfuncs.pEventAPI->EV_PlaySound( pClient->index, pClient->origin, CHAN_ITEM, "piccolo/Trans.wav", 1, ATTN_NORM, 0, PITCH_NORM );
		// Add scream sound event
		AddEvent( pTransFx, SCREAM, pTransFx->flTimeStart+flDurration-1, flDurration );
		// Add FX events
		AddEvent( pTransFx, EXPLOSION_SPHERE, pTransFx->flTimeStart+2, flDurration );
		AddEvent( pTransFx, FLASHY_WHITE_AURA, pTransFx->flTimeStart+2.2, flDurration-1 );
		AddEvent( pTransFx, COLUMN_DUST, pTransFx->flTimeStart+2.85, flDurration-1.3 );
		AddEvent( pTransFx, EXPLOSION_SPHERE, flTotalTime-1, flDurration );
		AddEvent( pTransFx, DUST, flTotalTime-1, flDurration );
	}
	else
	{
		// Grunts for short transform
		if(flDurration >= 1.5)
			gEngfuncs.pEventAPI->EV_PlaySound( pClient->index, pClient->origin, CHAN_ITEM, "piccolo/Trans2.wav", 1, ATTN_NORM, 0, PITCH_NORM );
		// Add scream sound event
		AddEvent( pTransFx, SCREAM2, flTotalTime-1, flDurration );
		// Add FX events
		AddEvent( pTransFx, SHOCKWAVE_CORE_INVERSE, pTransFx->flTimeStart, flDurration-1 );
		AddEvent( pTransFx, FLOATING_ROCKS, pTransFx->flTimeStart, flDurration-1 );
		AddEvent( pTransFx, EXPLOSION_SPHERE, flTotalTime-1, flDurration );
		AddEvent( pTransFx, DUST, flTotalTime-1, flDurration );
	}
}


void CHudTransformFX::PerfectTransform( trans_event_manager *pTransFx )
{	AddEvent( pTransFx, EXPLOSION_SPHERE, pTransFx->flTimeStart, 1 );
	AddEvent( pTransFx, PSCREAM, pTransFx->flTimeStart, 1 );
}

// -----------------------
//  Add Transforms/Events
// -----------------------

void CHudTransformFX::AddEvents( trans_event_manager *pTransFx )
{	
	// Perfect Transform
	if(pTransFx->flDurration == -1)
	{	PerfectTransform(pTransFx);
		return;
	}

	// set it up differently depending on Char
	switch( pTransFx->iCharacter )
	{
	case CLASS_BUU:
		BuuTrans( pTransFx );
		break;

	case CLASS_GOKU:
		GokuTrans( pTransFx );
		break;

	case CLASS_GOHAN:
		GohanTrans( pTransFx );
		break;

	case CLASS_TRUNKS:
		TrunksTrans( pTransFx );
		break;

	case CLASS_VEGETA:
		VegetaTrans( pTransFx );
		break;

	case CLASS_KRILLIN:
		KrillinTrans( pTransFx );
		break;

	case CLASS_FRIEZA:
		FriezaTrans( pTransFx );
		break;

	case CLASS_PICCOLO:
		PiccoloTrans( pTransFx );
		break;

	case CLASS_CELL:
		CellTrans( pTransFx );
		break;
	}
}

// -----------------
//  Transform Stuff
// -----------------

void CHudTransformFX::AddTransform( int iIndex, int iCharacter, float flAcendTime )
{
	trans_event_manager *pNewTrans = new trans_event_manager;

	pNewTrans->iIndex = iIndex;
	pNewTrans->iCharacter = iCharacter;
	pNewTrans->flDurration = flAcendTime;
	pNewTrans->flTimeStart = m_flTime;
	pNewTrans->pNext = NULL;
	pNewTrans->pEvents = NULL;

	AddEvents( pNewTrans );

	if(flAcendTime == -1)
	{	pNewTrans->flDurration = 1;
	}
	 
	// Player Pointer
	cl_entity_t *pClient = gEngfuncs.GetLocalPlayer();

	// pause the mp3 player if its your transformation
	if( iIndex == pClient->index && gHUD.m_Mp3Player.m_eStatus == gHUD.m_Mp3Player.MP3_PLAY )
	{	// Only pause music when we do a dramatic transformation w/ music
		if(flAcendTime >= DRAMATIC_TRANSFX)
		{	gHUD.m_Mp3Player.Pause();
			m_blMp3Pause = true;
		}
	}

	// First, lets see if you already own an event with your name on it. If so, delete it.
	trans_event_manager *pTransFx = FindTrans( iIndex );
	while(pTransFx)
	{
		DeleteTransFx( pTransFx );
		pTransFx = FindTrans( iIndex );
	}

	// Lets add it on the list
	// Is the first spot taken? If so, search for an empty slot
	if(!pTrans)
	{	pTrans = pNewTrans;
	}
	else
	{
		// Add the exp to the end
		trans_event_manager *pCurrent = pTrans;

		while(pCurrent->pNext)
		{	pCurrent = pCurrent->pNext;
		}
		pCurrent->pNext = pNewTrans;
	}
}

trans_event_manager *CHudTransformFX::FindPrevTrans( int iIndex )
{
	trans_event_manager *pTransFx = pTrans;

	// Lets search through everything... Return null if it doesnt exist
	while(pTransFx)
	{	
		if(pTransFx->pNext)
		{
			if(pTransFx->pNext->iIndex == iIndex)
			{	return pTransFx;
			}
			else
			{	pTransFx = pTransFx->pNext;
			}
		}
		else
		{	break;
		}
	}

	return NULL;
}

trans_event_manager *CHudTransformFX::FindTrans( int iIndex )
{
	trans_event_manager *pTransFx = pTrans;

	// Lets search through everything... Return null if it doesnt exist
	while(pTransFx)
	{	
		if(pTransFx->iIndex == iIndex)
		{	return pTransFx;
		}
		else
		{	pTransFx = pTransFx->pNext;
		}
	}

	return NULL;
}

trans_event *CHudTransformFX::FindPrevEvent( trans_event *pEvent, trans_event *pStart )
{
	trans_event *pCurrent = pStart;

	// Lets search through everything... Return null if it doesnt exist
	while(pCurrent)
	{	
		if(pCurrent->pNext)
		{
			if(pCurrent->pNext == pEvent)
			{	return pCurrent;
			}
			else
			{	pCurrent = pCurrent->pNext;
			}
		}
		else
		{	break;
		}
	}

	return NULL;

}


trans_event *CHudTransformFX::DeleteEvent( trans_event *pEvent, trans_event_manager *pManager )
{

	// Shouldnt happen...
	if(!pEvent || !pManager->pEvents )
	{
		return NULL;
	}

	trans_event *pStartEvent = pManager->pEvents;

	// First one in the list, take it out right away
	if(pEvent == pStartEvent)
	{
		pStartEvent = pStartEvent->pNext;
		delete pEvent;
		pEvent = NULL;
		// Copy current event over start event
		pManager->pEvents = pStartEvent;
		return pStartEvent;
	}

	// Search..
	trans_event *pPrev = FindPrevEvent(pEvent, pStartEvent);

	// Make sure we found it
	if(!pPrev)
	{	return NULL;
	}

	// Delete the trans FX struct
	trans_event *pNext = pEvent->pNext;
	delete pEvent;
	pEvent = NULL;
	pPrev->pNext = pNext;
	return pNext;

}

trans_event_manager *CHudTransformFX::DeleteTransFx( trans_event_manager *pTransFx )
{
	// Lets make sure what we are deleting is valid
	if(!pTransFx)
	{	return NULL;
	}

	// First, lets delete all of the events.
	trans_event *pEvent = pTransFx->pEvents;
	while(pEvent)
	{	trans_event *pNext = pEvent->pNext;
		delete pEvent;
		pEvent = pNext;
	//	ConsolePrint("Delete Event\n");
	}

	// Delete Trans FX struct
	// Lets find the one before the one we want to delete

	// First one in the list, take it out right away
	if(pTransFx == pTrans)
	{
		pTransFx = pTransFx->pNext;
		delete pTrans;
		pTrans = pTransFx;
	//	ConsolePrint("Delete TransFx\n");
		return pTransFx;
	}

	// Search...
	trans_event_manager * pPrev = FindPrevTrans( pTransFx->iIndex );

	// Make sure we found it
	if(!pPrev)
	{	return NULL;
	}

	// Delete the trans FX struct
	trans_event_manager *pNext = pTransFx->pNext;
	delete pTransFx;
	pPrev->pNext = pNext;
	return pNext;
}

// ---------
//  Draw FX
// ---------

int CHudTransformFX::Draw(float flTime)
{	m_flTime = flTime;

	// Set Time Difference
	SetTimeDifference( flTime );
	
	// Go through events...
	// This shouldnt happen, but if a stray transformation FX was laying around for a long time,delete it
	trans_event_manager *pCurrent = pTrans;
	while(pCurrent)
	{
		// Go through events, and see if we have any sound events. If so, play it!
		trans_event *pEvent = pCurrent->pEvents;
		while(pEvent)
		{
			if(pEvent->iFlag == SCREAM || pEvent->iFlag == SCREAM2 || pEvent->iFlag == PSCREAM)
			{
				// Lets play the sound
				if(pEvent->flTimeStart <= flTime)
				{
					cl_entity_t *pClient = gEngfuncs.GetEntityByIndex(pEvent->iIndex);
					gEngfuncs.pEventAPI->EV_PlaySound( pEvent->iIndex, pClient->origin, CHAN_WEAPON, pEvent->szSound, 1, ATTN_NORM, 0, PITCH_NORM );
					// Delete Event
					pEvent = DeleteEvent(pEvent, pCurrent);
					continue;
				}
			}
			pEvent = pEvent->pNext;
		}

		// Delete managers that are done
		if(flTime - (pCurrent->flTimeStart + pCurrent->flDurration) > 1)
		{
			pCurrent = DeleteTransFx(pCurrent);
			continue;
		}
		else
		{
			pCurrent = pCurrent->pNext;
		}
	}

	// Dont allow software mode to run transformation FX
/*	if(IEngineStudio.IsHardware())*/
		Partsys.Draw( flTime, m_flTimeDifference );

	// Reset Time difference for next loop
	ResetTimeDifference( flTime );

	return 1;
}

int CHudTransformFX::MsgFunc_TransformFX(const char *pszName, int iSize, void *pbuf)
{	BEGIN_READ( pbuf, iSize );

//	ConsolePrint("Start Transformation\n");

	int iIndex = READ_BYTE();								// Index
	float flAcendTime = READ_COORD();						// How Long will it take for transformation?
	int iCharacter = g_PlayerExtraInfo[iIndex].playerclass;	// Player Class

	// Dont bother with no-time transforms
	if(flAcendTime<=0 && flAcendTime != -1)
		return 1;

	// Enable FX system(s) for specified player
	AddTransform( iIndex, iCharacter, flAcendTime );

	return 1;
}

int CHudTransformFX::MsgFunc_StopTransFX(const char *pszName, int iSize, void *pbuf)
{	BEGIN_READ( pbuf, iSize );

//	ConsolePrint("End Transformation\n");

	int iIndex = READ_BYTE();		// Index of player

	trans_event_manager *pTransFx = FindTrans( iIndex );

	// Only delete it if you can find it
	if( pTransFx )
	{
		// Mute tranny music
		// Player Pointer
		cl_entity_t *pClient = gEngfuncs.GetEntityByIndex(iIndex);

		gEngfuncs.pEventAPI->EV_PlaySound( iIndex, pClient->origin, CHAN_ITEM, "common/null.wav", 1, ATTN_NORM, 0, PITCH_NORM );
	
		// Player Pointer
		cl_entity_t *pClientLocal = gEngfuncs.GetLocalPlayer();

		// Resume mp3 player
		if( iIndex == pClientLocal->index && gHUD.m_Mp3Player.m_eStatus == gHUD.m_Mp3Player.MP3_PAUSE )
		{
			if(m_blMp3Pause)
			{
				gHUD.m_Mp3Player.Pause();
				m_blMp3Pause = false;
			}
		}
		DeleteTransFx( pTransFx );
		// Lets see if there are any other fx events with our name on it. If so, delete it
		pTransFx = FindTrans( iIndex );
		while(pTransFx)
		{
			DeleteTransFx( pTransFx );
			pTransFx = FindTrans( iIndex );
		}
	}

	// Lets Disable the particle system(s) linked to this player
	part_manager_s *pCurrent = pPartJobs;
	while(pCurrent)
	{
		// Linked to the player
		if(pCurrent->m_iIndex == iIndex)
		{
			// Dont delete Explosion spheres, they delete themselfs
			if((pCurrent->m_iFlag == EXPLOSION_SPHERE || pCurrent->m_iFlag == SHOCKWAVE_FROM_CORE
				|| pCurrent->m_iFlag == SHOCKWAVE_FROM_CORE_INVERSE) && pCurrent->flTimeStart < m_flTime)
			{
				pCurrent = pCurrent->pNext;
				continue;
			}

			// Delete some other tranny FX the player has a single particle( usually a model )
			if((pCurrent->pParticle && pCurrent->flDieTime == -1) || (!pCurrent->pParticle && !pCurrent->pPartSys))
			{
				pCurrent = Partsys.RemoveSystem( pCurrent );
				continue;
			}
			else
			{	
				if(pCurrent->flDieTime == -1)
				{
					// Kill it slowly
					Partsys.KillSystem(m_flTime + 5, pCurrent);
				}
			}
		}
		pCurrent = pCurrent->pNext;
	}
	return 1;
}