#include "g_local.h"
#include "w_saber.h"
#include "ai_main.h"
#include "..\ghoul2\g2.h"

#define METROID_JUMP 1

extern bot_state_t *botstates[MAX_CLIENTS];

int speedLoopSound = 0;
 
int rageLoopSound = 0;

int protectLoopSound = 0;

int absorbLoopSound = 0;

int seeLoopSound = 0;

int	ysalamiriLoopSound = 0;

#define FORCE_VELOCITY_DAMAGE 0

int ForceShootDrain( gentity_t *self );

gentity_t *G_PreDefSound(vec3_t org, int pdSound)
{
	gentity_t	*te;

	te = G_TempEntity( org, EV_PREDEFSOUND );
	te->s.eventParm = pdSound;
	VectorCopy(org, te->s.origin);

	return te;
}

qboolean InFront( vec3_t spot, vec3_t from, vec3_t fromAngles, float threshHold )
{
	vec3_t	dir, forward, angles;
	float	dot;

	VectorSubtract( spot, from, dir );
	dir[2] = 0;
	VectorNormalize( dir );

	VectorCopy( fromAngles, angles );
	angles[0] = 0;
	AngleVectors( angles, forward, NULL, NULL );

	dot = DotProduct( dir, forward );

	return (dot > threshHold);
}

int forcePowerMinRank[NUM_FORCE_POWER_LEVELS][NUM_FORCE_POWERS] = //0 == neutral
{
	{
		999,//FP_HEAL,//instant
		999,//FP_LEVITATION,//hold/duration
		999,//FP_SPEED,//duration
		999,//FP_PUSH,//hold/duration
		999,//FP_PULL,//hold/duration
		999,//FP_TELEPATHY,//instant
		999,//FP_GRIP,//hold/duration
		999,//FP_LIGHTNING,//hold/duration
		999,//FP_RAGE,//duration
		999,//FP_PROTECT,//duration
		999,//FP_ABSORB,//duration
		999,//FP_TEAM_HEAL,//instant
		999,//FP_TEAM_FORCE,//instant
		999,//FP_DRAIN,//hold/duration
		999,//FP_SEE,//duration
		999,//FP_SABERATTACK,
		999,//FP_SABERDEFEND,
		999//FP_SABERTHROW,
		//NUM_FORCE_POWERS
	},
	{
		10,//FP_HEAL,//instant
		0,//FP_LEVITATION,//hold/duration
		0,//FP_SPEED,//duration
		0,//FP_PUSH,//hold/duration
		0,//FP_PULL,//hold/duration
		10,//FP_TELEPATHY,//instant
		15,//FP_GRIP,//hold/duration
		10,//FP_LIGHTNING,//hold/duration
		15,//FP_RAGE,//duration
		15,//FP_PROTECT,//duration
		15,//FP_ABSORB,//duration
		10,//FP_TEAM_HEAL,//instant
		10,//FP_TEAM_FORCE,//instant
		10,//FP_DRAIN,//hold/duration
		5,//FP_SEE,//duration
		0,//FP_SABERATTACK,
		0,//FP_SABERDEFEND,
		0//FP_SABERTHROW,
		//NUM_FORCE_POWERS
	},
	{
		10,//FP_HEAL,//instant
		0,//FP_LEVITATION,//hold/duration
		0,//FP_SPEED,//duration
		0,//FP_PUSH,//hold/duration
		0,//FP_PULL,//hold/duration
		10,//FP_TELEPATHY,//instant
		15,//FP_GRIP,//hold/duration
		10,//FP_LIGHTNING,//hold/duration
		15,//FP_RAGE,//duration
		15,//FP_PROTECT,//duration
		15,//FP_ABSORB,//duration
		10,//FP_TEAM_HEAL,//instant
		10,//FP_TEAM_FORCE,//instant
		10,//FP_DRAIN,//hold/duration
		5,//FP_SEE,//duration
		5,//FP_SABERATTACK,
		5,//FP_SABERDEFEND,
		5//FP_SABERTHROW,
		//NUM_FORCE_POWERS
	},
	{
		10,//FP_HEAL,//instant
		0,//FP_LEVITATION,//hold/duration
		0,//FP_SPEED,//duration
		0,//FP_PUSH,//hold/duration
		0,//FP_PULL,//hold/duration
		10,//FP_TELEPATHY,//instant
		15,//FP_GRIP,//hold/duration
		10,//FP_LIGHTNING,//hold/duration
		15,//FP_RAGE,//duration
		15,//FP_PROTECT,//duration
		15,//FP_ABSORB,//duration
		10,//FP_TEAM_HEAL,//instant
		10,//FP_TEAM_FORCE,//instant
		10,//FP_DRAIN,//hold/duration
		5,//FP_SEE,//duration
		10,//FP_SABERATTACK,
		10,//FP_SABERDEFEND,
		10//FP_SABERTHROW,
		//NUM_FORCE_POWERS
	}
};     
/*
 * Gamall Wednesday Ida
 * Workaround Force crash
 * License GPL.
 *
 * Version modified to allow 'tweaked" settings
 * like "g_maxforcerank 200".
 */
//JediDog: I used Gamall's Force Crash fix because it's just easier since it's open source.

char  *gaGENERIC_FORCE    = "7-1-033330000000000333";
char  *gaFORCE_LOWER     = "-1-000000000000000000";
char  *gaFORCE_UPPER     = "-2-333333333333333333";


char* gaCheckForceStringTail(char* s, char* S) {
    char *p = s, *pu = gaFORCE_UPPER, *pl = gaFORCE_LOWER;
    if (!s || strlen(s) != 21) return gaGENERIC_FORCE;
    while(*p) {if (*p > *pu++ || *p++ < *pl++) {return gaGENERIC_FORCE;}}
    return S;    
}

char* gaCheckForceString(char* S) {
    int i, l; char *p = S;
    if (!S || (l = strlen(S)) > 24 || l < 22  || *S < '\0' || *S > '9') return gaGENERIC_FORCE;
    for(i = 1 ; i <= 3 ; i++) {
        if (S[i] == '-') return gaCheckForceStringTail(S+i, S);
        if (S[i] < '\0' || S[i] > '9') break;
    } return gaGENERIC_FORCE;
}

// GWI: End Force Crash workaround.

void WP_InitForcePowers( gentity_t *ent )
{
	int i;
	int i_r;
	int maxRank = g_maxForceRank.integer;
	qboolean warnClient = qfalse;
	qboolean warnClientLimit = qfalse;
	char userinfo[MAX_INFO_STRING];
	char forcePowers[256];
	char readBuf[256];
	int lastFPKnown = -1;
	qboolean didEvent = qfalse;
	// GWI: force crash
    char* temp;

	if (!maxRank)
	{ //if server has no max rank, default to max (50)
		maxRank = FORCE_MASTERY_JEDI_MASTER;
	}

	/*
	if (g_forcePowerDisable.integer)
	{
		maxRank = FORCE_MASTERY_UNINITIATED;
	}
	*/
	//rww - don't do this

	if ( !ent || !ent->client )
	{
		return;
	}

	ent->client->ps.fd.saberAnimLevel = ent->client->sess.saberLevel;

	if (ent->client->ps.fd.saberAnimLevel < FORCE_LEVEL_1 ||
		ent->client->ps.fd.saberAnimLevel > FORCE_LEVEL_3)
	{
		ent->client->ps.fd.saberAnimLevel = FORCE_LEVEL_1;
	}

	if (!speedLoopSound)
	{ //so that the client configstring is already modified with this when we need it
		speedLoopSound = G_SoundIndex("sound/weapons/force/speedloop.wav");
	}

	if (!rageLoopSound)
	{
		rageLoopSound = G_SoundIndex("sound/weapons/force/rageloop.wav");
	}

	if (!absorbLoopSound)
	{
		absorbLoopSound = G_SoundIndex("sound/weapons/force/absorbloop.wav");
	}

	if (!protectLoopSound)
	{
		protectLoopSound = G_SoundIndex("sound/weapons/force/protectloop.wav");
	}

	if (!seeLoopSound)
	{
		seeLoopSound = G_SoundIndex("sound/weapons/force/seeloop.wav");
	}

	if (!ysalamiriLoopSound)
	{
		ysalamiriLoopSound = G_SoundIndex("sound/player/nullifyloop.wav");
	}

	i = 0;
	while (i < NUM_FORCE_POWERS)
	{
		ent->client->ps.fd.forcePowerLevel[i] = 0;
		ent->client->ps.fd.forcePowersKnown &= ~(1 << i);
		i++;
	}

	ent->client->ps.fd.forcePowerSelected = -1;

	ent->client->ps.fd.forceSide = 0;

	trap_GetUserinfo( ent->s.number, userinfo, sizeof( userinfo ) );

	Q_strncpyz( forcePowers, Info_ValueForKey (userinfo, "forcepowers"), sizeof( forcePowers ) );
	// GWI: Force crash
    temp = gaCheckForceString(forcePowers);
    if (temp != forcePowers) {
		trap_SendServerCommand(ent->s.clientNum, 
			va("print \"^1Incorrect force string '%s'. Replaced by default.\n\"", forcePowers));
		G_LogPrintf("FORCE CRASH: Client num %d tried to take incorrect forcestring '%s'.",
			ent->s.clientNum, forcePowers);
         Q_strncpyz( forcePowers, temp, sizeof( forcePowers ) );
	} // End force crash workaround

	if ( ent->r.svFlags & SVF_BOT && botstates[ent->s.number] )
	{ //if it's a bot just copy the info directly from its personality
		Com_sprintf(forcePowers, sizeof(forcePowers), "%s\0", botstates[ent->s.number]->forceinfo);
	}

	//rww - parse through the string manually and eat out all the appropriate data
	i = 0;

