//
// capture the dragonballs gamerules
//
#include	"extdll.h"
#include	"util.h"
#include	"cbase.h"
#include	"effects.h"
#include	"aura.h"
#include	"classes.h"
#include	"magicattack.h"
#include	"explodingattack.h"
#include	"player.h"
#include	"weapons.h"
#include	"gamerules.h"
#include	"dragonball.h"
#include	"shenlong.h"
#include	"teamplay_gamerules.h"
#include	"capturethedragonballs_gamerules.h"
#include	"game.h"

#define		MAX_DRAGONBALLDISTANCE	100
#define		MAX_WISHDISTANCE		100

extern int gmsgVGUIMenu;
extern int gmsgScoreInfo;
extern int gmsgDragonBallEnt;
extern cvar_t	wishlimit;
extern DLL_GLOBAL BOOL	g_fGameOver;

//added by Rick
#include	"../bot/bot.h"
extern CBotManager BotManager;
extern CBotDBManager BotDBManager;
// end add by Rick

CHalfLifeCaptureTheDragonBalls::CHalfLifeCaptureTheDragonBalls() : CHalfLifeTeamplay()
{	m_fSpawnedBalls = false;
	m_fDragonBallsGathered = false;
	m_fRespawnBalls = false;
	m_fTeamPlayOnly = false;
	m_fCanWish = false;
	m_flRespawnBallsTime = gpGlobals->time;
	m_pShenlong = NULL;
	for (int i = 0;i<7;i++)
	{	m_pDragonBalls[i] = NULL;
	}

	// Added by Rick: let bots know that we're playing cptdb mode
	BotManager.SetDBMode();
}

void CHalfLifeCaptureTheDragonBalls :: Think()
{	if (!m_fSpawnedBalls && !m_fTeamPlayOnly )
	{	if (!m_fRespawnBalls || m_flRespawnBallsTime < gpGlobals->time)
		{	SpawnDragonBalls();
			m_fCanWish = true;		
		}
	}
	else
	{	if (DragonBallsGathered())
		{	if(!m_fDragonBallsGathered)
			{	m_fDragonBallsGathered = true;
				for (int n=0;n<7;n++)
				{	m_pDragonBalls[n]->Glow();
				}
			}
		}
		else
		{	if (m_fDragonBallsGathered)
			{	m_fDragonBallsGathered = false;
				for (int n=0;n<7;n++)
				{	if (m_pDragonBalls[n])
					{	m_pDragonBalls[n]->UnGlow();
					}
				}
				//remove shenlong
				UTIL_Remove(m_pShenlong);
				m_pShenlong = NULL;
			}
		}
	

		float flWishLimit = wishlimit.value;

		//go to intermission if one of the teams has passed the wish limit
		if ( flWishLimit && !g_fGameOver )
		{				
			int iTeamWishes[MAX_TEAMS];
			int i; //stupid visual C++ scope bug
			for (i=0;i<MAX_TEAMS;i++)
			{	iTeamWishes[i]=0;
			}

			// count team wishes
			for ( i = 1; i <= gpGlobals->maxClients; i++ )
			{	CBaseEntity *pEnt = UTIL_PlayerByIndex( i );
				if (pEnt)
				{	if (pEnt->IsPlayer())
					{	CBasePlayer *pPlayer = (CBasePlayer *)pEnt;
						int iTeam = GetTeamIndex( pPlayer->m_szTeamName ) + 1;
						if (iTeam)
						{	iTeamWishes[iTeam]+=pPlayer->m_iWishes;
						}
					}
				}
			}

			//check if one of the teams has passed the wish limit
			for ( i=1;i<MAX_TEAMS;i++)
			{	if (iTeamWishes[i]>=flWishLimit)
				{	GoToIntermission();
					return;
				}
			}
		}
	}
	CHalfLifeTeamplay :: Think();
}

BOOL CHalfLifeCaptureTheDragonBalls ::PlayerUses(CBasePlayer *pl)
{	if (m_fDragonBallsGathered && pl->IsAlive() && m_fCanWish)
	{	for (int n=0; n<7; n++)
		{	if( (pl->pev->origin - m_pDragonBalls[n]->pev->origin).Length() < MAX_WISHDISTANCE)
			{	pl->m_fWishing = true;

				//open wish menu
				MESSAGE_BEGIN( MSG_ONE, gmsgVGUIMenu, NULL, pl->pev );
					WRITE_BYTE( 31 );	// This is the menu number that needs to be sent
				MESSAGE_END();

				//show shenlong if he isn't there yet
				if (!m_pShenlong)
				{	Vector vecDir = pl->pev->origin - m_pDragonBalls[0]->pev->origin;
					vecDir.z = 0;//always face up
					m_pShenlong = CShenlong::CreateShenlong(m_pDragonBalls[0]->pev->origin + Vector(0,0,50), vecDir, m_pDragonBalls);
				}
				return true;
			}
		}
	}
	return false;
}

BOOL CHalfLifeCaptureTheDragonBalls :: ClientCommand( CBasePlayer *pPlayer, const char *pcmd )
{	if ( FStrEq( pcmd, "immortality" ) )
	{	if (m_fCanWish && pPlayer->m_fWishing && m_fDragonBallsGathered)
		{	pPlayer->m_fInvulnerable = true;
			pPlayer->m_flInvulnerableTime = gpGlobals->time + 45;
			FinishWish(pPlayer,1);
		}
		return true;
	}
	else if ( FStrEq( pcmd, "strength" ) )
	{	if (m_fCanWish && pPlayer->m_fWishing && m_fDragonBallsGathered)
		{	pPlayer->IncreasePL(1000000);
			UpdatePlayerStats();
			FinishWish(pPlayer,1);
		}
		return true;
	}
	else if ( FStrEq( pcmd, "wishpoint" ) )
	{	if (m_fCanWish && pPlayer->m_fWishing && m_fDragonBallsGathered)
		{	FinishWish(pPlayer,2);
		}
		return true;
	}
	return CHalfLifeTeamplay :: ClientCommand( pPlayer, pcmd );
}

void CHalfLifeCaptureTheDragonBalls :: InitHUD( CBasePlayer *pl )
{	int n; //stupid visual studio scope bug
	for (n=0;n<7;n++)
	{	if (m_pDragonBalls[n])
		{	MESSAGE_BEGIN(MSG_ONE, gmsgDragonBallEnt, NULL, pl->edict());
				WRITE_BYTE( n );
				WRITE_SHORT( m_pDragonBalls[n]->entindex());
			MESSAGE_END();
		}
	}
	for ( n = 1; n <= gpGlobals->maxClients; n++ )
	{	CBaseEntity *pEnt = UTIL_PlayerByIndex( n );
		CBasePlayer *pPlayer;
		if ( pEnt )
		{	if (pEnt->IsPlayer())
			{	pPlayer = (CBasePlayer*)pEnt;
				if(pPlayer->m_iDragonball)
				{	MESSAGE_BEGIN(MSG_ONE, gmsgDragonBallEnt, NULL, pl->edict());
						WRITE_BYTE( pPlayer->m_iDragonball - 1);
						WRITE_SHORT( pPlayer->entindex());
					MESSAGE_END();
				}
			}
		}
	}
	CHalfLifeTeamplay ::InitHUD(pl);
}

void CHalfLifeCaptureTheDragonBalls :: SpawnDragonBalls()
{	//find item_dragonball spots on the map
	edict_t *pSpot[100];
	int nr_of_balls = 0;
	pSpot[0] = FIND_ENTITY_BY_CLASSNAME( NULL, "item_dragonball");

	while( nr_of_balls<100 && !FNullEnt(pSpot[nr_of_balls]))
	{	nr_of_balls++;
		pSpot[nr_of_balls] = FIND_ENTITY_BY_CLASSNAME( pSpot[nr_of_balls-1], "item_dragonball");
	}
		
	//enough dragonball spots found?
	if (nr_of_balls<7)
	{	//not enough dragonballs... doing teamplay now
		ALERT(at_console,"not enough dragonballs in this map\n");
		m_fTeamPlayOnly = true;
		return;
	}

	//randomly find 7 dragonball indices
	int spots[7];
	int i,n;
	int newspot;
	for (n=0;n<7;n++)
	{	do 
		{	i = RANDOM_LONG(0,nr_of_balls-1);
			newspot=true;
			for(int m=0;m<n;m++)
			{	if (spots[m] == i)
				{	newspot = false;
				}
			}
		}
		while(!newspot);
		spots[n]=i;
	}

	for (n=0;n<7;n++)
	{	m_pDragonBalls[n] = CDragonBall::CreateDragonBall(pSpot[spots[n]]->v.origin, n+1);
		//invalid spawn point
		if(!m_pDragonBalls[n])
		{	return;
		}		
	}

	
	if (m_fRespawnBalls)
	{	m_fRespawnBalls = false;
		for (int n = 0;n<7;n++)
		{	//send dragonball info to clients
			MESSAGE_BEGIN(MSG_ALL, gmsgDragonBallEnt);
				WRITE_BYTE( n );
				WRITE_SHORT( m_pDragonBalls[n]->entindex());
			MESSAGE_END();
			//turn all dragonballs into stone
			m_pDragonBalls[n]->Stonify();
		}
	}
	m_fSpawnedBalls = true;	
}

void CHalfLifeCaptureTheDragonBalls :: DragonBallPickUp(int nr, int playerIndex)
{	if (nr<1 || nr>7)
	{	return;
	}
	m_pDragonBalls[nr-1] = NULL;
	MESSAGE_BEGIN(MSG_ALL, gmsgDragonBallEnt);
		WRITE_BYTE( nr-1 );
		WRITE_SHORT(playerIndex);
	MESSAGE_END();
}

void CHalfLifeCaptureTheDragonBalls :: DragonBallDrop(int nr, CDragonBall *ball)
{	if (nr<1 || nr>7)
	{	return;
	}
	m_pDragonBalls[nr-1] = ball;
	MESSAGE_BEGIN(MSG_ALL, gmsgDragonBallEnt);
		WRITE_BYTE( nr-1 );
		WRITE_SHORT( m_pDragonBalls[nr-1]->entindex());
	MESSAGE_END();
}

void CHalfLifeCaptureTheDragonBalls :: FinishWish(CBasePlayer *pl, int wishpoints)
{	
	pl->m_fWishing=false;
	
	m_fCanWish = false;
	//send wish points to scoreboard
	pl->m_iWishes += wishpoints;
	MESSAGE_BEGIN( MSG_ALL, gmsgScoreInfo );
		WRITE_BYTE( pl->entindex());
		WRITE_SHORT( (int)pl->pev->frags );
		WRITE_SHORT( pl->m_iDeaths );
		WRITE_SHORT( pl->m_iWishes );
		WRITE_SHORT( pl->pev->playerclass );
		WRITE_SHORT( GetTeamIndex( pl->m_szTeamName ) + 1 );
		WRITE_SHORT(pl->m_pClass->ScoreboardName());
	MESSAGE_END();

	//remove shenlong and spread dragonballs
	m_pShenlong->GrantWish();
	m_pShenlong = NULL;

	//remove dragonballs from da radar
	for (int n = 0;n<7;n++)
	{	MESSAGE_BEGIN(MSG_ALL, gmsgDragonBallEnt);
			WRITE_BYTE( n );
			WRITE_SHORT(0);
		MESSAGE_END();
	}

	//respawn dragonballs after a while
	m_fRespawnBalls = true;
	m_fSpawnedBalls = false;
	m_flRespawnBallsTime = gpGlobals->time + 45;
	
	// Added by Rick: Let bots know someone just wished
	BotDBManager.FinishWish();
	// end add by Rick
}

BOOL CHalfLifeCaptureTheDragonBalls ::DragonBallsGathered()
{	for(int ball=0;ball<6;ball++)
	{	if (!m_pDragonBalls[ball])
		{	return false;
		}
		
		//Shenlong doesn't fit in a cave, you doofus
		Vector vecUp = m_pDragonBalls[ball]->pev->origin + Vector(0,0,300);
		TraceResult tr;
		UTIL_TraceLine(m_pDragonBalls[ball]->pev->origin,vecUp,ignore_monsters,ENT(m_pDragonBalls[ball]->pev),&tr);
		if (tr.flFraction<1)
			return false;

		//wish already done
		if (m_pDragonBalls[ball]->m_fSpreading)
		{	return false;
		}

		for(int n=ball+1;n<7;n++)
		{	if (!m_pDragonBalls[n])
			{	return false;
			}
			if ( (m_pDragonBalls[ball]->pev->origin-m_pDragonBalls[n]->pev->origin).Length() > MAX_DRAGONBALLDISTANCE)
			{	return false;
			}
		}
	}
	return true;
}

/**
* DragonBallPoint class, spawnpoints for dragonballs
* @version 19-9-2001
* @author Herwin 'harSens' van Welbergen
*/
class CDragonBallPoint:public CPointEntity
{	void Spawn( void );		
};

void CDragonBallPoint::Spawn( void )
{	UTIL_SetOrigin( pev, pev->origin );
	pev->solid = SOLID_NOT;
	pev->effects = EF_NODRAW;
	pev->v_angle = g_vecZero;
}
LINK_ENTITY_TO_CLASS( item_dragonball, CDragonBallPoint);