/*
   Copyright (C) 1997-2001 Id Software, Inc.

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License
   as published by the Free Software Foundation; either version 2
   of the License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

   See the GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

 */

// gs_weapondefs.c	-	hard coded weapon definitions

#include "../game/q_shared.h"
#include "gs_public.h"

#ifndef WSW_RELEASE
#define ALLOW_WEAPONDEFS_READED_FROM_DISK
#endif

#define INSTANT 0

firedef_t ammoFireDefs[] =
{
	{
		WEAP_GUNBLADE,
		FIRE_MODE_STRONG,
		AMMO_CELLS,
		1,              // ammo usage per shot
		1,              // projectiles fired each shot

		//timings (in msecs)
		50,             // weapon up frametime
		50,             // weapon down frametime
		400,                // reload frametime
		0,              // cooldown frametime
		5000,               // projectile timeout

		//damages
		40,             // damage
		0.5,  // selfdamage ratio
		90,             // knockback
		80,                // splash radius
		8,              // splash minimum damage

		//projectile def
		3000,               // speed
		0,              // spread

		//ammo
		2,         // pickup amount
		10         // max amount
	},

	{
		WEAP_GUNBLADE,
		FIRE_MODE_WEAK,
		AMMO_WEAK_GUNBLADE,
		0,          // ammo usage per shot
		0,          // projectiles fired each shot

		//timings (in msecs)
		50,         // weapon up frametime
		50,         // weapon down frametime
		800,            // reload frametime
		0,          // cooldown frametime
		64,         // projectile timeout  / projectile range for instant weapons

		//damages
		45,         // damage
		0.5, // selfdamage ratio
		50,         // knockback
		0,          // splash radius
		0,          // splash minimum damage

		//projectile def
		0,          // speed
		0,          // spread

		//ammo
		0,          // pickup amount
		0           // max amount
	},

	{
		WEAP_SHOCKWAVE,
		FIRE_MODE_STRONG,
		AMMO_WAVES,
		1,          // ammo usage per shot
		1,          // projectiles fired each shot

		//timings (in msecs)
		50,         // weapon up frametime
		50,         // weapon down frametime
		1000,           // reload frametime
		0,          // cooldown frametime
		3000,           // projectile timeout

		//damages
		0,          // damage
		0,  // selfdamage ratio
		0,          // knockback
		50,         // splash radius
		0,          // splash minimum damage

		//projectile def
		1000,           // speed
		0,          // spread

		//ammo
		5,          // pickup amount
		5           // max amount
	},

	{
		WEAP_SHOCKWAVE,
		FIRE_MODE_WEAK,
		AMMO_WEAK_WAVES,
		1,          // ammo usage per shot
		1,          // projectiles fired each shot

		//timings (in msecs)
		50,         // weapon up frametime
		50,         // weapon down frametime
		1000,       // reload frametime
		0,          // cooldown frametime
		3000,       // projectile timeout

		//damages
		0,          // damage
		0,  // selfdamage ratio
		0,          // knockback
		50,         // splash radius
		0,          // splash minimum damage

		//projectile def
		1000,       // speed
		0,          // spread

		//ammo
		10,         // pickup amount
		10          // max amount
	},

	{
		WEAP_RIOTGUN,
		FIRE_MODE_STRONG,
		AMMO_SHELLS,
		1,          // ammo usage per shot
		22, //20*5=100	// projectiles fired each shot

		//timings (in msecs)
		50,         // weapon up frametime
		50,         // weapon down frametime
		850,            // reload frametime
		0,          // cooldown frametime
		8192,       // projectile timeout / projectile range for instant weapons

		//damages
		5,          // damage
		0,  // selfdamage ratio (rg cant selfdamage)
		8,         // knockback
		0,          // splash radius
		0,          // splash minimum damage

		//projectile def
		INSTANT,        // speed
		95,           // spread

		//ammo
		5,          // pickup amount
		10          // max amount
	},

	{
		WEAP_RIOTGUN,
		FIRE_MODE_WEAK,
		AMMO_WEAK_SHELLS,
		1,          // ammo usage per shot
		17, //15*5=75	// projectiles fired each shot

		//timings (in msecs)
		50,         // weapon up frametime
		50,         // weapon down frametime
		850,            // reload frametime
		0,          // cooldown frametime
		8192,       // projectile timeout / projectile range for instant weapons

		//damages
		5,          // damage
		0,  // selfdamage ratio (rg cant selfdamage)
		6,         // knockback
		0,          // splash radius
		0,          // splash minimum damage

		//projectile def
		INSTANT,        // speed
		130,           // spread

		//ammo
		10,         // pickup amount
		25          // max amount
	},

	{
		WEAP_GRENADELAUNCHER,
		FIRE_MODE_STRONG,
		AMMO_GRENADES,
		1,          // ammo usage per shot
		1,          // projectiles fired each shot

		//timings (in msecs)
		50,         // weapon up frametime
		50,         // weapon down frametime
		800,            // reload frametime
		0,          // cooldown frametime
		2000,           // projectile timeout

		//damages
		90,            // damage
		0.5,  // selfdamage ratio
		100,            // knockback
		80,            // splash radius
		20,         // splash minimum damage

		//projectile def
		900,           // speed
		0,          // spread

		//ammo
		5,          // pickup amount
		10          // max amount
	},

	{
		WEAP_GRENADELAUNCHER,
		FIRE_MODE_WEAK,
		AMMO_WEAK_GRENADES,
		1,          // ammo usage per shot
		1,          // projectiles fired each shot

		//timings (in msecs)
		50,         // weapon up frametime
		50,         // weapon down frametime
		800,            // reload frametime
		0,          // cooldown frametime
		2000,           // projectile timeout

		//damages
		100,            // damage
		0.5,  // selfdamage ratio
		80,         // knockback
		150,            // splash radius
		5,          // splash minimum damage

		//projectile def
		800,           // speed
		0,          // spread

		//ammo
		10,         // pickup amount
		15          // max amount
	},

	{
		WEAP_ROCKETLAUNCHER,
		FIRE_MODE_STRONG,
		AMMO_ROCKETS,
		1,                      // ammo usage per shot
		1,                      // projectiles fired each shot

		//timings (in msecs)
		50,                     // weapon up frametime
		50,                     // weapon down frametime
		850,                        // reload frametime
		0,                      // cooldown frametime
		10000,                      // projectile timeout

		//damages
		90,                        // damage
		0.75,        // selfdamage ratio
		100,                        // knockback
		120,                        // splash radius
		15,                     // splash minimum damage

		//projectile def
		1000,                       // speed
		0,                      // spread

		//ammo
		5,          // pickup amount
		5           // max amount
	},

	{
		WEAP_ROCKETLAUNCHER,
		FIRE_MODE_WEAK,
		AMMO_WEAK_ROCKETS,
		1,                      // ammo usage per shot
		1,                      // projectiles fired each shot

		//timings (in msecs)
		50,                     // weapon up frametime
		50,                     // weapon down frametime
		850,                        // reload frametime
		0,                      // cooldown frametime
		10000,      // projectile timeout

		//damages
		80,                     // damage
		0.75,      // selfdamage ratio
		95,                     // knockback
		120,                        // splash radius
		8,                     // splash minimum damage

		//projectile def
		1000,                       // speed
		0,                      // spread

		//ammo
		10,         // pickup amount
		25          // max amount
	},

	{
		WEAP_PLASMAGUN,
		FIRE_MODE_STRONG,
		AMMO_PLASMA,
		1,          // ammo usage per shot
		1,          // projectiles fired each shot

		//timings (in msecs)
		50,         // weapon up frametime
		50,         // weapon down frametime
		100,            // reload frametime
		0,          // cooldown frametime
		5000,           // projectile timeout

		//damages
		15,         // damage
		0.5, // selfdamage ratio
		28,         // knockback
		40,         // splash radius
		5,          // splash minimum damage

		//projectile def
		1700,           // speed
		0,          // spread

		//ammo
		25,         // pickup amount
		50          // max amount
	},

	{
		WEAP_PLASMAGUN,
		FIRE_MODE_WEAK,
		AMMO_WEAK_PLASMA,
		1,          // ammo usage per shot
		1,          // projectiles fired each shot

		//timings (in msecs)
		50,         // weapon up frametime
		50,         // weapon down frametime
		100,            // reload frametime
		0,          // cooldown frametime
		5000,           // projectile timeout

		//damages
		12,         // damage
		0.5, // selfdamage ratio
		19,         // knockback
		20,         // splash radius
		1,          // splash minimum damage

		//projectile def
		1700,           // speed
		0,          // spread

		//ammo
		50,         // pickup amount
		75          // max amount
	},

	{
		WEAP_LASERGUN,
		FIRE_MODE_STRONG,
		AMMO_LASERS,
		1,              // ammo usage per shot
		1,              // projectiles fired each shot

		//timings (in msecs)
		50,             // weapon up frametime
		50,             // weapon down frametime
		50,             // reload frametime
		0,              // cooldown frametime
		590,                // projectile timeout / projectile range for instant weapons

		//damages
		7,              // damage
		0,    // selfdamage ratio (lg cant damage)
		10,              // knockback
		0,              // splash radius
		0,              // splash minimum damage

		//projectile def
		INSTANT,            // speed
		0,              // spread

		//ammo
		40,         // pickup amount
		120         // max amount
	},

	{
		WEAP_LASERGUN,
		FIRE_MODE_WEAK,
		AMMO_WEAK_LASERS,
		1,          // ammo usage per shot
		1,          // projectiles fired each shot

		//timings (in msecs)
		50,         // weapon up frametime
		50,         // weapon down frametime
		50,         // reload frametime
		0,          // cooldown frametime
		590,            // projectile timeout / projectile range for instant weapons

		//damages
		7,          // damage
		0,  // selfdamage ratio (lg cant damage)
		10,          // knockback
		0,          // splash radius
		0,          // splash minimum damage

		//projectile def
		INSTANT,        // speed
		0,          // spread

		//ammo
		80,         // pickup amount
		120         // max amount
	},

	{
		WEAP_ELECTROBOLT,
		FIRE_MODE_STRONG,
		AMMO_BOLTS,
		1,          // ammo usage per shot
		1,          // projectiles fired each shot

		//timings (in msecs)
		50,         // weapon up frametime
		50,         // weapon down frametime
		1300,           // reload frametime
		0,          // cooldown frametime
		1024,           // instant block range (weak def timeout for projectile part).

		//damages
		65,         // damage
		0,  // selfdamage ratio (eb cant selfdamage)
		120,        // knockback
		0,          // splash radius
		0,          // splash minimum damage

		//projectile def
		INSTANT,        // speed
		0,          // spread

		//ammo
		5,          // pickup amount
		5           // max amount
	},

	{
		WEAP_ELECTROBOLT,
		FIRE_MODE_WEAK,
		AMMO_WEAK_BOLTS,
		1,          // ammo usage per shot
		1,          // projectiles fired each shot

		//timings (in msecs)
		50,         // weapon up frametime
		50,         // weapon down frametime
		1300,           // reload frametime
		0,          // cooldown frametime
		5000,           // projectile timeout

		//damages
		65,         // damage
		0,  // selfdamage ratio (eb cant selfdamage)
		115,        // knockback
		0,          // splash radius
		0,          // splash minimum damage

		//projectile def
		6000,           // speed
		0,          // spread

		//ammo
		5,          // pickup amount
		15          // max amount
	},

	{
		WEAP_INSTAGUN,
		FIRE_MODE_STRONG,
		AMMO_INSTAS,
		1,          // ammo usage per shot
		1,          // projectiles fired each shot

		//timings (in msecs)
		50,         // weapon up frametime
		50,         // weapon down frametime
		1300,           // reload frametime
		0,          // cooldown frametime
		1024,           // instant block range (weak def timeout for projectile part).

		//damages
		65,         // damage
		0.5,  // selfdamage ratio (ig cant damage)
		90,        // knockback
		80,          // splash radius
		0,          // splash minimum damage

		//projectile def
		INSTANT,        // speed
		0,          // spread

		//ammo
		5,          // pickup amount
		5           // max amount
	},

	{
		WEAP_INSTAGUN,
		FIRE_MODE_WEAK,
		AMMO_WEAK_INSTAS,
		1,          // ammo usage per shot
		1,          // projectiles fired each shot

		//timings (in msecs)
		50,         // weapon up frametime
		50,         // weapon down frametime
		1300,           // reload frametime
		0,          // cooldown frametime
		5000,           // projectile timeout

		//damages
		65,         // damage
		0,  // selfdamage ratio (ig cant damage)
		115,        // knockback
		0,          // splash radius
		0,          // splash minimum damage

		//projectile def
		6000,           // speed
		0,          // spread

		//ammo
		5,          // pickup amount
		10          // max amount
	},
	{ 0 }
};

weapon_info_t gs_weaponInfos[WEAP_TOTAL];

firedef_t noweaponFireDef =
{
	WEAP_NONE,                      // weapon name
	0,                              // fire mode
	AMMO_NONE,                      // ammo tag
	0,                              // ammo usage per shot
	0,                              // projectiles fired each shot

	//timings (in msecs)
	100,                            // weapon up frametime
	100,                            // weapon down frametime
	0,                              // reload frametime
	0,                              // cooldown frametime
	0,                              // projectile timeout

	//damages
	0,                              // damage
	0,              // selfdamage ratio
	0,                              // knockback
	0,                              // splash radius
	0,                              // splash minimum damage

	//projectile def
	0,                              // speed
	0,                              // spread

	//ammo
	0,                              // pickup amount
	0                               // max amount
};

#ifdef ALLOW_WEAPONDEFS_READED_FROM_DISK

static qbyte *GS_LoadWeaponDefFile( char *defname )
{
	int length, filenum;
	qbyte *data;
	char filename[MAX_QPATH];

	Q_snprintfz( filename, sizeof( filename ), "weapondefs/%s.def", defname );
	length = GS_FS_FOpenFile( filename, &filenum, FS_READ );

	if( length == -1 )
	{
		GS_Printf( "Couldn't find script: %s.\n", filename );
		return NULL;
	}

	if( !length )
	{
		GS_Printf( "Found empty script: %s.\n", filename );
		GS_FS_FCloseFile( filenum );
		return NULL;
	}

	//load the script data into memory
	data = GS_Malloc( length + 1 );
	GS_FS_Read( data, length, filenum );
	GS_FS_FCloseFile( filenum );

	if( !data[0] )
	{
		GS_Printf( "Found empty script: %s.\n", filename );
		return NULL;
	}

	return data;
}

#define WEAPONDEF_NUMPARMS 16
static qboolean GS_ParseFiredefFile( qbyte *buf, firedef_t *firedef )
{
	char *ptr, *token;
	int count = 0;
	float parm[WEAPONDEF_NUMPARMS];

	// jal: this is quite ugly.
	ptr = ( char * )buf;
	while( ptr )
	{
		token = COM_ParseExt( &ptr, qtrue );
		if( !token[0] )
			break;

		//ignore spacing tokens
		if( !Q_stricmp( token, "," ) ||
		   !Q_stricmp( token, "{" ) ||
		   !Q_stricmp( token, "}" ) )
			continue;

		//some token sanity checks
		if( token[strlen( token )-1] == ',' )
			token[strlen( token )-1] = 0;
		if( token[strlen( token )-1] == '}' )
			token[strlen( token )-1] = 0;
		//(I don't fix these ones, but show the error)
		if( token[0] == ',' )
		{
			GS_Printf( "ERROR in script. Comma must be followed by space or newline\n" );
			return qfalse;
		}
		if( token[0] == '{' || token[0] == '}' )
		{
			GS_Printf( "ERROR in script. Scorches must be followed by space or newline\n" );
			return qfalse;
		}

		if( count > WEAPONDEF_NUMPARMS )
			return qfalse;

		if( !Q_stricmp( token, "instant" ) )
			parm[count] = 0;
		else
			parm[count] = atof( token );

		if( parm[count] < 0 )
			return qfalse;

		count++;
	}

	// incomplete or wrong file
	if( count < WEAPONDEF_NUMPARMS )
		return qfalse;

	// validate

	// 2 and 3 are weapon switches. They MUST be game.frametime msecs at least
	/*if( parm[2] < game.frametime )
	    parm[2] = game.frametime;

	   if( parm[3] < game.frametime )
	    parm[3] = game.frametime;*/

	count = 0;
	// put the data into the firedef
	firedef->usage_count = parm[count++];
	firedef->projectile_count = parm[count++];

	firedef->weaponup_time = parm[count++];
	firedef->weapondown_time = parm[count++];
	firedef->reload_time = parm[count++];
	firedef->cooldown_time = parm[count++];
	firedef->timeout = parm[count++];

	firedef->damage = parm[count++];
	firedef->selfdamage = parm[count++];
	firedef->knockback = parm[count++];
	firedef->splash_radius = parm[count++];
	firedef->splash_min_damage = parm[count++];

	firedef->speed = parm[count++];
	firedef->spread = parm[count++];

	firedef->ammo_pickup = parm[count++];
	firedef->ammo_max = parm[count++];

	return qtrue;
}

static qboolean GS_LoadFiredefFromFile( firedef_t *firedef )
{
	char filename[MAX_QPATH];
	qbyte *data;

	if( !firedef || !firedef->weapon_id )
		return qfalse;

	Q_snprintfz( filename, sizeof( filename ), "%s %s", GS_FindItemByTag( firedef->weapon_id )->pickup_name,
	             ( firedef->fire_mode == FIRE_MODE_STRONG ) ? "strong" : "weak" );

	data = GS_LoadWeaponDefFile( filename );
	if( !data )
		return qfalse;

	//parse the file updating the firedef
	if( !GS_ParseFiredefFile( data, firedef ) )
	{
		GS_Printf( "'InitWeapons': Error in definition file %s\n", filename );
		GS_Free( data );
		return qfalse;
	}

	GS_Free( data );
	return qtrue;
}
#endif //ALLOW_WEAPONDEFS_READED_FROM_DISK

//=================
//GS_FiredefForAmmo
//=================
firedef_t *GS_FiredefForAmmo( int tag )
{
	gitem_t *item = GS_FindItemByTag( tag );

	if( item->type == IT_AMMO )
		return (firedef_t *)item->info;
	else
		return NULL;
}

//=================
//GS_FiredefForWeapon
//=================
weapon_info_t *GS_FiredefForWeapon( int tag )
{
	gitem_t *item = GS_FindItemByTag( tag );

	if( item->type == IT_WEAPON )
		return (weapon_info_t *)item->info;
	else
		return NULL;
}

//=================
//GS_InitWeapons
//=================
void GS_InitWeapons( void )
{
	int i;
	gitem_t *item;
	firedef_t *firedef;

	//GS_Printf( "Initializing weapons\n" );

	//set up no weapon with no fires (not totally correct. I should not use item->info)
	gs_weaponInfos[WEAP_NONE].firedef = &noweaponFireDef;
	gs_weaponInfos[WEAP_NONE].firedef_weak = &noweaponFireDef;

	//assign the actual weapons
	for( i = WEAP_GUNBLADE; i < WEAP_TOTAL; i++ )
	{
		item = GS_FindItemByTag( i );
		gs_weaponInfos[i].firedef = gs_weaponInfos[i].firedef_weak = NULL; //start clean

		//find predefined firedefs for this weapon
		for( firedef = &ammoFireDefs[0]; firedef->weapon_id; firedef++ )
		{
			if( firedef->weapon_id == i )
			{
				if( firedef->ammo_id < AMMO_WEAK_GUNBLADE )
				{
					assert( firedef->fire_mode == FIRE_MODE_STRONG );
					gs_weaponInfos[i].firedef = firedef;
				}
				else
				{
					assert( firedef->fire_mode == FIRE_MODE_WEAK );
					gs_weaponInfos[i].firedef_weak = firedef;
				}
			}
		}
	}

#ifdef ALLOW_WEAPONDEFS_READED_FROM_DISK
	// ok, we assigned the default ones, but meanwhile we are designing the
	// game we will load replacements from text files
	for( i = WEAP_GUNBLADE; i < WEAP_TOTAL; i++ )
	{
		GS_LoadFiredefFromFile( gs_weaponInfos[i].firedef );
		GS_LoadFiredefFromFile( gs_weaponInfos[i].firedef_weak );
	}
#endif //ALLOW_WEAPONDEFS_READED_FROM_DISK

	for( i = WEAP_GUNBLADE; i < WEAP_TOTAL; i++ )
	{
		item = GS_FindItemByTag( i );
		assert( gs_weaponInfos[i].firedef );
		assert( gs_weaponInfos[i].firedef_weak );

		//link here too, but use gs_weaponInfos better
		item->info = (weapon_info_t *)&gs_weaponInfos[i];
		if( GS_FindItemByTag( item->weakammo_tag ) )
		{
			GS_FindItemByTag( item->weakammo_tag )->info = gs_weaponInfos[i].firedef_weak;
			GS_FindItemByTag( item->weakammo_tag )->quantity = gs_weaponInfos[i].firedef_weak->ammo_pickup;
		}
		if( GS_FindItemByTag( item->ammo_tag ) )
		{
			GS_FindItemByTag( item->ammo_tag )->info = gs_weaponInfos[i].firedef;
			GS_FindItemByTag( item->ammo_tag )->quantity = gs_weaponInfos[i].firedef->ammo_pickup;
		}
	}
}
