/*
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.

*/
// g_local.h -- local definitions for game module
#include "q_shared.h"
#include "../gameshared/gs_public.h"
#include "g_public.h"
#include "g_syscalls.h"
#include "g_pmodels.h"

//==================================================================
// round(x)==floor(x+0.5f)
#define HEALTH_TO_INT(x)	( (x) < 1.0f ? (int)ceil((x)) : (int)floor((x)+0.5f) )
#define ARMOR_TO_INT(x)		( (x) < 1.0f ? (int)ceil((x)) : (int)floor((x)+0.5f) )

#define G_IsDead(ent)		(HEALTH_TO_INT(ent->health) <= 0)

// Quad scale for damage and knockback
#define QUAD_DAMAGE_SCALE 4
#define QUAD_KNOCKBACK_SCALE 4

// view pitching times
#define DAMAGE_TIME		0.5
#define	FALL_TIME		0.3

#ifdef UNBALANCED_ARMORS
#ifdef ARMOR_SYSTEM_OF_THE_DAY
#define	ARMOR_DEGRADATION 0.66 //0.66
#else
#define	ARMOR_DEGRADATION 0.50 // 50 if max RA is 150, 75 if max RA is 200
#endif
#endif 

#define G_INSTAGIB_NEGATE_ITEMMASK (IT_WEAPON|IT_AMMO|IT_ARMOR|IT_POWERUP|IT_HEALTH)

// edict->spawnflags
// these are set with checkboxes on each entity in the map editor
#define	SPAWNFLAG_NOT_EASY			0x00000100
#define	SPAWNFLAG_NOT_MEDIUM		0x00000200
#define	SPAWNFLAG_NOT_HARD			0x00000400
#define	SPAWNFLAG_NOT_DEATHMATCH	0x00000800

// edict->flags
#define	FL_FLY					0x00000001
#define	FL_SWIM					0x00000002	// implied immunity to drowining
#define FL_IMMUNE_LASER			0x00000004
#define	FL_INWATER				0x00000008
#define	FL_GODMODE				0x00000010
#define	FL_NOTARGET				0x00000020
#define FL_IMMUNE_SLIME			0x00000040
#define FL_IMMUNE_LAVA			0x00000080
#define	FL_PARTIALGROUND		0x00000100	// not all corners are valid
#define	FL_WATERJUMP			0x00000200	// player jumping out of water
#define	FL_TEAMSLAVE			0x00000400	// not the first on the team
#define FL_NO_KNOCKBACK			0x00000800
#define FL_RESPAWN				0x80000000	// used for item respawning

#define FRAMETIME (game.frametime)
#define G_FRAMETIME (game.framemsec)

// memory tags to allow dynamic memory to be cleaned up
#define	TAG_GAME	765		// clear when unloading the dll
#define	TAG_LEVEL	766		// clear when loading a new level


#define MELEE_DISTANCE	80

#define BODY_QUEUE_SIZE		8

typedef enum
{
	DAMAGE_NO,
	DAMAGE_YES,			// will take damage if hit
	DAMAGE_AIM			// auto targeting recognizes this
} damage_t;

typedef enum 
{
	WEAPON_READY, 
	WEAPON_ACTIVATING,
	WEAPON_DROPPING,
	WEAPON_POWERING,
	WEAPON_FIRING,
	WEAPON_RELOADING,
	WEAPON_COOLDOWN
} weaponstate_t;


// deadflag
#define DEAD_NO					0
#define DEAD_DYING				1
#define DEAD_DEAD				2
#define DEAD_RESPAWNABLE		3

// range
#define RANGE_MELEE				0
#define RANGE_NEAR				1
#define RANGE_MID				2
#define RANGE_FAR				3

// gib types
#define GIB_ORGANIC				0
#define GIB_METALLIC			1

// monster ai flags
#define AI_STAND_GROUND			0x00000001
#define AI_TEMP_STAND_GROUND	0x00000002
#define AI_SOUND_TARGET			0x00000004
#define AI_LOST_SIGHT			0x00000008
#define AI_PURSUIT_LAST_SEEN	0x00000010
#define AI_PURSUE_NEXT			0x00000020
#define AI_PURSUE_TEMP			0x00000040
#define AI_HOLD_FRAME			0x00000080
#define AI_GOOD_GUY				0x00000100
#define AI_BRUTAL				0x00000200
#define AI_NOSTEP				0x00000400
#define AI_DUCKED				0x00000800
#define AI_COMBAT_POINT			0x00001000
#define AI_MEDIC				0x00002000
#define AI_RESURRECTING			0x00004000

// monster attack state
#define AS_STRAIGHT				1
#define AS_SLIDING				2
#define	AS_MELEE				3
#define	AS_MISSILE				4


// game.serverflags values
#define SFL_CROSS_TRIGGER_1		0x00000001
#define SFL_CROSS_TRIGGER_2		0x00000002
#define SFL_CROSS_TRIGGER_3		0x00000004
#define SFL_CROSS_TRIGGER_4		0x00000008
#define SFL_CROSS_TRIGGER_5		0x00000010
#define SFL_CROSS_TRIGGER_6		0x00000020
#define SFL_CROSS_TRIGGER_7		0x00000040
#define SFL_CROSS_TRIGGER_8		0x00000080
#define SFL_CROSS_TRIGGER_MASK	0x000000ff


// handedness values
#define RIGHT_HANDED			0
#define LEFT_HANDED				1
#define CENTER_HANDED			2

// edict->movetype values
typedef enum
{
	MOVETYPE_NONE,			// never moves
	MOVETYPE_NOCLIP,		// origin and angles change with no interaction
	MOVETYPE_PUSH,			// no clip to world, push on box contact
	MOVETYPE_STOP,			// no clip to world, stops on box contact

	MOVETYPE_WALK,			// gravity
	MOVETYPE_FLY,
	MOVETYPE_TOSS,			// gravity
	MOVETYPE_FLYMISSILE,	// extra size to monsters
	MOVETYPE_BOUNCE,
	MOVETYPE_BOUNCEGRENADE
} movetype_t;



typedef struct firedef_s
{
	//ammo def
	char	*name;
	void	(*fire)(edict_t *ent);
	int		fire_mode;
	int		ammo_id;
	int		usage_count;
	int		projectile_count;

	// timings
	int		weaponup_time;
	int		weapondown_time;
	int		reload_time;
	int		cooldown_time;
	int		powering_time;
	int		timeout;
	
	// damages
	int		damage;
	int		knockback;
	int		splash_radius;
	int		splash_min_damage;

	// projectile def
	float	speed;
	int		h_spread;
	int		v_spread;

	// ammo amounts
	int		ammo_pickup;
	int		ammo_max;

}firedef_t;

typedef struct weapon_info_s
{
	char	*name;
	int		weapon_id;
	
	firedef_t	*firedef;
	firedef_t	*firedef_weak;

}weapon_info_t;

extern weapon_info_t g_weaponInfos[WEAP_TOTAL];

typedef struct
{
	int		base_count;
	int		max_count;
	float	protection;	//jal: make armor saving the save damage to every weapon
	int		armor;
} gitem_armor_t;

#define TIMEOUT_TIME	180000
#define TIMEIN_TIME		5000

typedef struct
{
	qboolean	active;
	int			time;
	int			endtime;
	int			caller;
	int			used[MAX_CLIENTS];
} timeout_t;

extern timeout_t gtimeout;

//
// this structure is left intact through an entire game
// it should be initialized at dll load time, and read/written to
// the server.ssv file for savegames
//
typedef struct
{
	edict_t		*edicts;		// [maxentities]
	gclient_t	*clients;		// [maxclients]
	char		*map_entities;	// raw string containing the unparsed entities

	// can't store spawnpoint in level, because
	// it would get overwritten by the savegame restore
	char		spawnpoint[512];	// needed for coop respawns

	// store latched cvars here that we want to get at often
	int			maxclients;
	int			maxentities;
	int			numentities;

	// cross level triggers
	int			serverflags;

	int			framemsec;
	float		frametime;

	unsigned int	realtime;			// actual time, set with Sys_Milliseconds every frame

	// items
	gitem_t		*items[MAX_ITEMS];	//jal: item pointers sorted by tags
	int			numItems;			//count of sorted items

	qboolean	autosaved;

	int			gametype;//newgametypes
	float		besttime;

	int			numBots;
} game_locals_t;

//
// this structure is cleared as each map is entered
// it is read/written to the level.sav file for savegames
//
typedef struct
{
	int			framenum;
	float		time;
	unsigned int	timemsec;
	unsigned int	maptime; // time since G_NewMap was called (map was restarted)

	char		level_name[MAX_QPATH];	// the descriptive name (Outer Base, etc)
	char		mapname[MAX_QPATH];		// the server name (q3dm0, etc)
	char		nextmap[MAX_QPATH];		// go here when match is finished
	char		forcemap[MAX_QPATH];	// go here

	// intermission state
	char		*changemap;
	int			exitnow;

	int			pic_health;

	int			total_secrets;
	int			found_secrets;

	int			total_goals;
	int			found_goals;

	edict_t		*current_entity;	// entity running from G_RunFrame
	int			body_que;			// dead bodies

	int         nbcheckpoint;

	char		locationNames[MAX_LOCATIONS][MAX_STRING_CHARS];
	int			numLocations;
} level_locals_t;


// spawn_temp_t is only used to hold entity field values that
// can be set from the editor, but aren't actualy present
// in edict_t during gameplay
typedef struct
{
	// world vars
	char		*sky;
	float		skyrotate;
	vec3_t		skyaxis;
	char		*nextmap;

	char		*music;

	int			lip;
	int			distance;
	int			height;
	float		roll;
	float		radius;
	float		phase;
	char		*noise;
	char		*noise_start;
	char		*noise_stop;
	float		pausetime;
	char		*item;
	char		*gravity;

	float		minyaw;
	float		maxyaw;
	float		minpitch;
	float		maxpitch;

	int			notsingle;
	int			notteam;
	int			notfree;
	int			notduel;
	int			notctf;
	int			notffa;

	int			gameteam;

	int			weight;//MBotGame
} spawn_temp_t;


typedef struct
{
	// fixed data
	vec3_t		start_origin;
	vec3_t		start_angles;
	vec3_t		end_origin;
	vec3_t		end_angles;

	int			sound_start;
	int			sound_middle;
	int			sound_end;

	float		accel;
	float		speed;
	float		decel;
	float		distance;

	float		wait;

	float		phase;

	// state data
	int			state;
	vec3_t		dir;
	float		current_speed;
	float		move_speed;
	float		next_speed;
	float		remaining_distance;
	float		decel_distance;
	void		(*endfunc)(edict_t *);
} moveinfo_t;



extern	game_locals_t	game;
extern	level_locals_t	level;
extern	spawn_temp_t	st;

extern	int	meansOfDeath;


#define	FOFS(x) (size_t)&(((edict_t *)0)->x)
#define	STOFS(x) (size_t)&(((spawn_temp_t *)0)->x)
#define	LLOFS(x) (size_t)&(((level_locals_t *)0)->x)
#define	CLOFS(x) (size_t)&(((gclient_t *)0)->x)

//extern	cvar_t	*maxentities;
//newgametypes		extern	cvar_t	*deathmatch;
extern	cvar_t	*dmflags;

extern	cvar_t	*password;
extern	cvar_t	*g_select_empty;
extern	cvar_t	*dedicated;
extern	cvar_t	*developer;

extern	cvar_t	*filterban;

extern	cvar_t	*g_gravity;
extern	cvar_t	*g_maxvelocity;

extern	cvar_t	*sv_cheats;
#ifdef BATTLEYE
extern	cvar_t	*sv_battleye;
#endif

extern	cvar_t	*flood_msgs;
extern	cvar_t	*flood_persecond;
extern	cvar_t	*flood_waitdelay;

extern	cvar_t	*g_maplist;
extern	cvar_t	*g_maprotation;

//newgametypes[start]

extern	cvar_t	*g_maxteams;
extern	cvar_t	*g_scorelimit;
extern	cvar_t	*g_timelimit;

extern	cvar_t	*g_projectile_touch_owner;
extern	cvar_t	*g_projectile_prestep;
extern	cvar_t	*g_numbots;
extern	cvar_t	*g_maxtimeouts;

extern	cvar_t	*g_respawn_delay_min;
extern	cvar_t	*g_respawn_delay_max;
extern	cvar_t	*g_deadbody_followkiller;
extern	cvar_t	*g_deadbody_filter;
extern	cvar_t	*g_challengers_queue;

extern	cvar_t	*g_teams_maxplayers;
extern	cvar_t	*g_teams_lock;

//game switches
extern	cvar_t	*g_tctf;
extern	cvar_t	*g_instagib;

void G_Teams_Join_Cmd( edict_t *ent );
void G_Teams_AssignTeamSkin(edict_t *ent, char *s);
qboolean G_Teams_JoinTeam( edict_t *ent, int team );
void G_Teams_UnInvitePlayer( int team, edict_t *ent );
void G_Teams_RemoveInvites( void );
qboolean G_Teams_TeamIsLocked( int team );
void G_Teams_LockTeam( int team );
void G_Teams_UnLockTeam( int team );
void G_Teams_Lock_f( edict_t *ent );
void G_Teams_UnLock_f( edict_t *ent );
void G_Teams_Invite_f( edict_t *ent );
void G_Teams_UpdateMembersList( void );
qboolean G_Teams_JoinAnyTeam( edict_t *ent, qboolean silent );
void G_Teams_SetTeam( edict_t *ent, int team );
void G_RegisterMapLocationName( char *name );

void G_Say_Team(edict_t *who, char *msg, qboolean checkflood);

void G_Match_Ready(edict_t *ent);
void G_Match_NotReady(edict_t *ent);
void G_Match_CheckReadys( void );
void G_Match_NewMap( void );
qboolean G_Match_RestartLevel(void);
void G_EndMatch (void);

void G_Teams_JoinChallengersQueue( edict_t *ent );
void G_Teams_LeaveChallengersQueue( edict_t *ent );

void G_MoveClientToPostMatchScoreBoards (edict_t *ent, edict_t *spawnpoint);
void G_Gametype_Init (void);
void G_Gametype_Update(void);
qboolean G_Gametype_IsVotable( int type );
void G_GametypeCheckRules (void);
qboolean G_Gametype_CanPickUpItem( gitem_t *item );
qboolean G_Gametype_CanSpawnItem( gitem_t *item );
qboolean G_Gametype_CanRespawnItem( gitem_t *item );
qboolean G_Gametype_CanDropItem( gitem_t *item );
qboolean G_Gametype_CanFallDamage( void );
qboolean G_Gametype_CanTeamDamage( int damageflags );
float G_Gametype_RespawnTimeForItem( gitem_t *item );
int G_Gametype_DroppedItemTimeout( gitem_t *item );
int G_Gametype_ClientRespawn( edict_t *self);
void G_Gametypes_ClienBegin( edict_t *ent );
int ClientRespawn( edict_t *self );
qboolean G_Gametype_Killed (edict_t *targ, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point, int mod);
char *G_Gametype_ScoreboardMessage (edict_t *ent, edict_t *killer);

//
// g_gametype_ctf.c
//
void G_Gametype_CTF_ResetFlag( int team );
void G_Gametype_CTF_ResetFlags( void );
void G_Gametype_CTF_ResetClientFlag( edict_t *ent );
void G_Gametype_CTF_DeadDropFlag( edict_t *self);
void G_Gametype_CTF_FlagSetup( edict_t *ent );
qboolean G_Gametype_CTF_Pickup_Flag( edict_t *ent, edict_t *other );
void G_Gametype_CTF_Drop_Flag( edict_t *ent, gitem_t *item );
qboolean G_Gametype_CTF_HasFlag( edict_t *ent, int team );
gitem_t *G_Gametype_CTF_FlagItem( int team );

void G_Gametype_CTF_SetPowerUpEffect( edict_t *ent );
void G_Gametype_CTF_CheckHurtCarrier( edict_t *targ, edict_t *attacker );
void G_Gametype_CTF_Effects( edict_t *player );

edict_t *G_Gametype_CTF_SelectSpawnPoint ( edict_t *ent );

//
// g_gametype_race.c
//
void UpdateClientRaceStats( edict_t *ent );

//
// g_spawnpoints.c
//
edict_t *SelectDeathmatchSpawnPoint( edict_t *ent );
void SelectSpawnPoint( edict_t *ent, vec3_t origin, vec3_t angles );
edict_t *G_SelectIntermissionSpawnPoint( void );
//newgametypes[end]

//
// g_func.c
//
void G_AssignMoverSounds( edict_t *ent, char *start, char *move, char *stop );

#define world	(game.edicts)

// item spawnflags
#define ITEM_TRIGGER_SPAWN		0x00000001
#define ITEM_NO_TOUCH			0x00000002
// 6 bits reserved for editor flags
// 8 bits used as power cube id bits for coop games
#define DROPPED_ITEM			0x00010000
#define	DROPPED_PLAYER_ITEM		0x00020000
#define ITEM_TARGETS_USED		0x00040000

//
// fields are needed for spawning from the entity string
// and saving / loading games
//
#define FFL_SPAWNTEMP		1

typedef enum {
	F_INT, 
	F_FLOAT,
	F_LSTRING,			// string on disk, pointer in memory, TAG_LEVEL
	F_GSTRING,			// string on disk, pointer in memory, TAG_GAME
	F_VECTOR,
	F_ANGLEHACK,
	F_EDICT,			// index on disk, pointer in memory
	F_ITEM,				// index on disk, pointer in memory
	F_CLIENT,			// index on disk, pointer in memory
	F_FUNCTION,
	F_IGNORE
} fieldtype_t;

typedef struct
{
	const char	*name;
	size_t	ofs;
	fieldtype_t	type;
	int		flags;
} field_t;


extern	const field_t fields[];


//
// g_cmds.c
//
qboolean CheckFlood(edict_t *ent);
// wsw : jal : gamecommandscompletion
void G_InitGameCommands( void );
void G_AddCommand( char *name, void *cmdfunc );

//
// g_items.c
//
void PrecacheItem (gitem_t *it);
void InitItems (void);
void SetItemNames (void);
edict_t *Drop_Item (edict_t *ent, gitem_t *item);
void SetRespawn (edict_t *ent, float delay);
void ChangeWeapon (edict_t *ent);
void SpawnItem (edict_t *ent, gitem_t *item);
void Think_Weapon (edict_t *ent);
int PowerArmorType (edict_t *ent);
gitem_t	*GetItemByTag (int tag);	//wsw
qboolean Add_Ammo (edict_t *ent, gitem_t *item, int count, qboolean add_it );
void Touch_Item (edict_t *ent, edict_t *other, cplane_t *plane, int surfFlags);
qboolean	G_PickupItem( struct edict_s *ent, struct edict_s *other );
void		G_UseItem( struct edict_s *ent, struct gitem_s *item );
void		G_DropItem( struct edict_s *ent, struct gitem_s *item );

//
// g_utils.c
//
qboolean	KillBox (edict_t *ent);
edict_t *G_Find (edict_t *from, size_t fieldofs, char *match);
edict_t *findradius (edict_t *from, vec3_t org, float rad);
edict_t *G_FindBoxInRadius( edict_t *from, vec3_t org, float rad );
edict_t *G_PickTarget (char *targetname);
void	G_UseTargets (edict_t *ent, edict_t *activator);
void	G_SetMovedir (vec3_t angles, vec3_t movedir);
void	G_InitMover ( edict_t *ent );
void	G_DropSpawnpointToFloor( edict_t *ent );

void	G_InitEdict (edict_t *e);
edict_t	*G_Spawn (void);
void	G_FreeEdict (edict_t *e);

void	G_TouchTriggers (edict_t *ent);
void	G_TouchSolids (edict_t *ent);

char	*G_CopyString (char *in);

void	G_ProjectSource ( vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result );
void	P_ProjectSource ( gclient_t *client, vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result );

void	G_AddEvent ( edict_t *ent, int event, int parm, qboolean highPriority );
edict_t *G_SpawnEvent ( int event, int parm, vec3_t origin );
void	G_TurnEntityIntoEvent ( edict_t *ent, int event, int parm );

int		G_PlayerGender (edict_t *player);

void	G_PrintMsg ( edict_t *ent, char *fmt, ... );
void	G_ChatMsg( edict_t *ent, char *fmt, ... );
void	G_CenterPrintMsg ( edict_t *ent, char *fmt, ... );
void	G_UpdatePlayerMatchMsg ( edict_t *ent );
void	G_UpdatePlayersMatchMsgs ( void );
void	G_Obituary ( edict_t *victim, edict_t *attacker, int mod );

void	G_Sound ( edict_t *ent, int channel, int soundindex, float volume, float attenuation );
void	G_PositionedSound ( vec3_t origin, edict_t *ent, int channel, int soundindex, float volume, float attenuation );
void	G_GlobalSound ( int channel, int soundindex );

// announcer events
void G_AnnouncerSound( edict_t *targ, int soundindex, int team, qboolean queued );

float vectoyaw (vec3_t vec);

//more warsow miscelanea utils (newgametypes)
extern game_locals_t game;
#define ENTNUM(x) ((x) - game.edicts)
#define PLAYERNUM(x) ((x) - game.edicts - 1)
void G_SpawnTeleportEffect( edict_t *ent );
qboolean G_Visible (edict_t *self, edict_t *other);
qboolean G_InFront (edict_t *self, edict_t *other);
void G_DropToFloor (edict_t *ent);
int G_SolidMaskForEnt( edict_t *ent );
void G_CheckGround (edict_t *ent);
void G_CategorizePosition (edict_t *ent);
qboolean G_CheckBottom (edict_t *ent);
void G_AddPlayerStateEvent ( gclient_t *client, int event, int parm );
void G_ClearPlayerStateEvents( gclient_t *client );

edict_t *G_PlayerForText( const char *text );

//
// g_trigger.c
//
void SP_trigger_teleport (edict_t *ent);
void SP_info_teleport_destination (edict_t *ent);

//
// g_combat.c
//
int G_ModToAmmo( int mod );
qboolean G_IsTeamDamage( edict_t *targ, edict_t *attacker );
qboolean OnSameTeam (edict_t *ent1, edict_t *ent2);
qboolean CanDamage (edict_t *targ, edict_t *inflictor);
qboolean CheckTeamDamage (edict_t *targ, edict_t *attacker);
float G_KnockbackPushFrac( vec3_t pushorigin, vec3_t origin, vec3_t mins, vec3_t maxs, vec3_t pushdir, float pushradius );
void T_Damage (edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t dir, vec3_t point, vec3_t normal, float damage, float knockback, int dflags, int mod);
void T_RadiusDamage (edict_t *inflictor, edict_t *attacker, cplane_t *plane, float maxdamage, float knockback, float mindamage, edict_t *ignore, float radius, int mod);

// damage flags
#define DAMAGE_RADIUS			0x00000001	// damage was indirect
#define DAMAGE_NO_ARMOR			0x00000002	// armour does not protect from this damage
#define DAMAGE_ENERGY			0x00000004	// damage is from an energy based weapon
#define DAMAGE_NO_KNOCKBACK		0x00000008	// do not affect velocity, just view angles
#define DAMAGE_BULLET			0x00000010  // damage is from a bullet (used for ricochets)
#define DAMAGE_BLADE			0x00000020  // damage is from a gunblade
#define DAMAGE_SHELL			0x00000040  // damage is from a weak riotgun shell (used for ricochets)
#define DAMAGE_DOUBLE_SHELL		0x00000080  // damage is from a strong riotgun shell (used for ricochets)
#define DAMAGE_BOLT_WEAK		0x00000100	// damage is from from eb - 25/75
#define DAMAGE_NO_PROTECTION	0x00000200  // armor, shields, invulnerability, and godmode have no effect

#define	GIB_HEALTH				-70


//
// g_misc.c
//
void ThrowClientHead (edict_t *self, int damage);
void ThrowSmallPileOfGibs ( edict_t *self, int count, int damage );//splitmodels (debrisbounce)
void BecomeExplosion1(edict_t *self);

//
// g_weapon.c
//
void ThrowDebris (edict_t *self, char *modelname, float speed, vec3_t origin);
qboolean fire_hit (edict_t *self, vec3_t aim, int damage, int kick);

void W_Fire_Blade( edict_t *self, int range, vec3_t start, vec3_t dir, int damage, int kick, int mod );
void W_Fire_Gunblade_Bullet( edict_t *self, vec3_t start, vec3_t dir, int damage, int knockback, int mod );
void W_Fire_GunbladeBlast( edict_t *self, vec3_t start, vec3_t dir, int damage, int knockback, int radius_damage, int radius, int speed, int timeout, int mod );
void W_Fire_Shockwave( edict_t *self, vec3_t start, vec3_t dir, float speed, int radius, int timeout );
void W_Fire_Riotgun( edict_t *self, vec3_t start, vec3_t dir, int damage, int knockback, int hspread, int vspread, int count, int dflags, int mod );
void W_Fire_Grenade( edict_t *self, vec3_t start, vec3_t dir, int speed, int damage, int knockback, int radius_damage, float damage_radius, int timeout, int mod );
void W_Fire_Rocket( edict_t *self, vec3_t start, vec3_t dir, int speed, int damage, int knockback, int radius_damage, int radius, int timeout, int mod );
void W_Fire_Plasma( edict_t *self, vec3_t start, vec3_t dir, int damage, int knockback, int radius_damage, int radius, int speed, int timeout, int mod );
void W_Fire_Electrobolt_Strong( edict_t *self, vec3_t start, vec3_t aimdir, float speed, int damage, int knockback, int range, int dflags, int mod );
void W_Fire_Electrobolt_Weak( edict_t *self, vec3_t start, vec3_t aimdir, float speed, int damage, int knockback, int timeout, int dflags, int mod );
void W_Fire_Lasergun( edict_t *self, vec3_t start, vec3_t aimdir, int damage, int knockback, int timeout, int dflags, int mod );
void W_Fire_Lasergun_Weak( edict_t *self, vec3_t start, vec3_t end, vec3_t aimdir, int damage, int knockback, int timeout, int dflags, int mod );

//
// p_weapon.c
//
firedef_t *G_FiredefForAmmo( int tag );
weapon_info_t *G_FiredefForWeapon( int tag );

//
// g_chasecam	//newgametypes
//
void ChaseNext(edict_t *ent);
void ChasePrev(edict_t *ent);
void G_ChaseCamMode( edict_t *ent );
void G_SpectatorMode( edict_t *ent );
void Cmd_SwitchChaseCamMode_f( edict_t *ent );
void Cmd_ChaseCam_f(edict_t *ent);
void Cmd_Spec_f( edict_t *ent );
void G_EndServerFrames_UpdateChaseCam (void);

//
// g_client.c
//
void respawn (edict_t *ent);
//void BeginIntermission (edict_t *targ);
void PutClientInServer (edict_t *ent);
void InitClientPersistant (gclient_t *client);
void InitClientResp (gclient_t *client);
void InitClientTeamChange(gclient_t *client);
void InitBodyQue (void);
void ClientBeginServerFrame (edict_t *ent);
void ClientUserinfoChanged (edict_t *ent, char *userinfo);
void ClientThink (edict_t *ent, usercmd_t *cmd);
qboolean ClientConnect (edict_t *ent, char *userinfo, qboolean fakeClient);
void ClientDisconnect (edict_t *ent);
void ClientBegin (edict_t *ent);
void ClientCommand (edict_t *ent);

//newgametypes
void ClientBeginMultiplayerGame (edict_t *ent);
void ClientBeginSingleplayerGame (edict_t *ent);

//
// g_player.c
//
void player_pain (edict_t *self, edict_t *other, float kick, int damage);
void player_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point);

//
// g_target.c
//
void target_laser_start (edict_t *self);

//
// g_svcmds.c
//
void	ServerCommand (void);

//
// p_view.c
//
void ClientEndServerFrame (edict_t *ent);

//
// p_hud.c
//
void G_ScoreboardEvent();
void MoveClientToIntermission (edict_t *client);
void G_SetStats (edict_t *ent);
void ValidateSelectedItem (edict_t *ent);
//newgametypes
void ClientEndServerFrames_UpdateScoreBoardMessages( void );
void G_ScoreboardMessage_AddSpectators( void );
void ClientEndServerFrames_UpdateWeaponListMessages( void );
void G_ScoreboardMessage_AddPlayerStats( edict_t *ent);

//
// g_phys.c
//
void G_RunEntity (edict_t *ent);

//
// g_main.c
//

// memory management
// G_GameMalloc and G_LevelMalloc are only used during loadtime
// note that G_Malloc and G_Free exist for simplified temporary memory allocation\freeing
// the coder should not care about G_Malloc actually using levelpool
extern struct mempool_s *gamepool;
extern struct mempool_s *levelpool;

#define G_MemAlloc(pool,size) trap_MemAlloc(pool, size, __FILE__, __LINE__)
#define G_MemFree(mem) trap_MemFree(mem, __FILE__, __LINE__)
#define G_MemAllocPool(name) trap_MemAllocPool(name, __FILE__, __LINE__)
#define G_MemFreePool(pool) trap_MemFreePool(pool, __FILE__, __LINE__)
#define G_MemEmptyPool(pool) trap_MemEmptyPool(pool, __FILE__, __LINE__)

#define G_GameMalloc(size) G_MemAlloc(gamepool,size)
#define G_EmptyGamePool() G_MemEmptyPool(gamepool)
#define G_GameFree(data) G_MemFree(data)

#define G_LevelMalloc(size) G_MemAlloc(levelpool,size)
#define G_EmptyLevelPool() G_MemEmptyPool(levelpool)
#define G_LevelFree(data) G_MemFree(data)

#define G_Malloc(size) G_MemAlloc(levelpool,size)
#define G_Free(data) G_MemFree(data)

int G_API(void);
void G_Error( char *fmt, ... );
void G_Printf( char *fmt, ... );
void G_Init( unsigned int seed, unsigned int maxclients, unsigned int framemsec );
void G_Shutdown( void );
void G_RunFrame( unsigned int msec );
void	G_GetMatchState( match_state_t *matchstate );
void	G_Timeout_Reset( void );

//
// g_svcmds.c
//
qboolean SV_FilterPacket (char *from);

//
// g_save.c
//
void WriteGame (char *filename, qboolean autosave);
void ReadGame (char *filename);
void WriteLevel (char *filename);
void ReadLevel (char *filename);

//
// g_spawn.c
//
void G_CallSpawn (edict_t *ent);
void G_SpawnMapEntities( qboolean worldspawn );
void SpawnEntities (char *mapname, char *entities, int len, char *spawnpoint);

//============================================================================
#define MAX_RACE_CHECKPOINT 16

#include "ai/ai.h"//MbotGame

// client data that stays across multiple level loads
// reseted only on connect
typedef struct
{
	char		userinfo[MAX_INFO_STRING];
	char		netname[MAX_INFO_VALUE]; // maximum name length is characters without counting color tokens
                                         // is controlled by MAX_NAME_CHARS constant
	int			hand;
	int			fov;
	byte_vec4_t	color;

	qboolean	connected;			// a loadgame will leave valid entities that just don't have a connection yet
	qboolean	connecting;		// so whe know when a player is in the process of connecting for scoreboard prints

	short		cmd_angles[3];			// angles sent over in the last command

	unsigned int queueTimeStamp;
	int			team;

	unsigned int	readyUpWarningNext; // (timer) warn people to ready up 
	int				readyUpWarningCount; 

	int			muted; // & 1 = chat disabled, & 2 = vsay disabled

#ifdef BATTLEYE
	qboolean	battleye;
#endif
} client_persistant_t;


// client data that stays across deathmatch respawns
// reseted on connect, match start, map change, but NOT on team change, respawns
typedef struct
{
	// for race
	float race_best_lap_time;
	float race_checkpoint_time[MAX_RACE_CHECKPOINT];

	// for position command
	qboolean		position_saved;
	vec3_t			position_origin;
	vec3_t			position_angles;
	unsigned int	position_lastcmd;
} client_teamchange_t;

// client data that stays across deathmatch respawns
// reseted on connect, map change, team change, but NOT on respawns
typedef struct
{
	unsigned int	respawnCount;

	gitem_t		*last_drop_item;
	vec3_t		last_drop_location;

	edict_t		*last_pickup;

	int			accuracy_shots[AMMO_TOTAL-AMMO_CELLS];
	int			accuracy_hits[AMMO_TOTAL-AMMO_CELLS];
	int			accuracy_hits_direct[AMMO_TOTAL-AMMO_CELLS];
	int			accuracy_damage[AMMO_TOTAL-AMMO_CELLS];

	// for race
	// what is set/reset at race start or end
	qboolean race_in_race;             
	qboolean race_checkpoint_used[MAX_RACE_CHECKPOINT]; // did the player already used that checkpoint
	float race_start_time;             
	int race_current_checkpoint;

	// survive respawn
	float race_last_lap_time;
} client_respawn_t;

#define	LASERGUN_WEAK_TRAIL_BACKUP	32	// always power of 2
#define	LASERGUN_WEAK_TRAIL_MASK		(LASERGUN_WEAK_TRAIL_BACKUP-1)

// this structure is cleared on each PutClientInServer(),
// except for 'client->pers'
struct gclient_s
{
	// known to server
	player_state_t	ps;				// communicated by server to clients
	client_shared_t	r;

	// DO NOT MODIFY ANYTHING ABOVE THIS, THE SERVER
	// EXPECTS THE FIELDS IN THAT ORDER!

	//================================

	// private to game
	client_persistant_t	pers;	    // cleared on connect
	client_teamchange_t	teamchange;	// cleared on connect, map change but NOT on team change, respawns
	client_respawn_t	resp;	    // cleared on connect, match start, map change, team change, but NOT on respawns

	pmove_state_t		old_pmove;	// for detecting out-of-pmove changes

	qboolean	showscores;			// set layout stat
	qboolean	showinventory;		// set layout stat

	int			selected_item;
	int			inventory[MAX_ITEMS];

	float		armor;
	int			armortag;

	int			buttons;
	int			oldbuttons;
	int			latched_buttons;

	qboolean	walljumped;			// needed for sending walljump event only once

	qboolean	weapon_thunk;

	float		killer_yaw;			// when dead, look at killer

	weaponstate_t	weaponstate;
	
	float		fall_value;			// for fall damage
	qboolean	fall_fatal;			// for falling to void etc.

	vec3_t		v_angle;			// aiming direction

	vec3_t		oldviewangles;
	vec3_t		oldvelocity;

	float		next_drown_time;
	int			old_waterlevel;
	int			old_watertype;
	int			breather_sound;

	// powerup timers
	float		quad_timeout;

	qboolean	grenade_blew_up;
	float		grenade_time;
	int			silencer_shots;
	int			weapon_sound;
	qboolean	weapon_missed;

	float		pickup_msg_time;

	float		flood_locktill;		// locked from talking
	float		flood_when[10];		// when messages were said
	int			flood_whenhead;		// head pointer for when said

	unsigned int	scoreboard_time; // when scoreboard was last sent

#ifdef VSAYS
	unsigned int	last_vsay;			// time when last vsay was said
#endif

	unsigned int	respawn_timestamp;		// timemsec when it was respawned

	chasecam_t	chase;				//splitmodels & CHASEHACKv2

	float		jumppad_time;
	
	//weapons stuff
	int			latched_weapon;

	int			ammo_index;
	int			ammo_weak_index;

	vec3_t		lasergunTrail[LASERGUN_WEAK_TRAIL_BACKUP];

	//generic weapon timing
	int				weapon_state;
	unsigned int	weapon_nexttime;	//in msecs
	int				weapon_powered;		//in msecs

	float			damage_taken;
	float			damage_saved;
	float			damage_given;
	float			damageteam_given;

	// player_state_t event
	unsigned int	events[16];			// psEvents buffer
};


struct edict_s
{
	entity_state_t	s;
	entity_shared_t	r;

	// DO NOT MODIFY ANYTHING ABOVE THIS, THE SERVER
	// EXPECTS THE FIELDS IN THAT ORDER!

	//================================
	//spawn_temp_t	*st;

	int			movetype;
	int			flags;

	char		*model;
	char		*model2;
	float		freetime;			// sv.time when the object was freed

	int			numEvents;
	qboolean	eventPriority[2];
	qboolean	freeAfterEvent;

	//
	// only used locally in game, not by server
	//
	char		*message;
	char		*classname;
	int			spawnflags;

	float		timestamp;
	unsigned int deathtimestamp;

	float		angle;			// set in qe3, -1 = up, -2 = down
	char		*target;
	char		*targetname;
	char		*killtarget;
	char		*team;
	char		*pathtarget;
	edict_t		*target_ent;

	float		speed, accel, decel;
	vec3_t		movedir;
	vec3_t		pos1, pos2;

	vec3_t		velocity;
	vec3_t		avelocity;
	int			mass;
	float		air_finished;
	float		gravity;		// per entity gravity multiplier (1.0 is normal)
								// use for lowgrav artifact, flares

	edict_t		*goalentity;
	edict_t		*movetarget;
	float		yaw_speed;
	float		ideal_yaw;

	unsigned int	nextthink; // make think function msec based

	void		(*prethink) (edict_t *ent);
	void		(*think)(edict_t *self);
	void		(*blocked)(edict_t *self, edict_t *other);	//move to moveinfo?
	void		(*touch)(edict_t *self, edict_t *other, cplane_t *plane, int surfFlags);
	void		(*use)(edict_t *self, edict_t *other, edict_t *activator);
	void		(*pain)(edict_t *self, edict_t *other, float kick, int damage);
	void		(*die)(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point);

	float		touch_debounce_time;		// are all these legit?  do we need more/less of them?
	float		pain_debounce_time;
	float		damage_debounce_time;
	float		last_move_time;

	float		health;
	int			max_health;
	int			gib_health;
	int			deadflag;
	float		show_hostile;

	float		powerarmor_time;

	char		*map;			// target_changelevel

	int			viewheight;		// height above origin where eyesight is determined
	int			takedamage;
	int			dmg;
	int			radius_dmg;
	float		dmg_radius;
	char		*sounds;			//make this a spawntemp var?
	int			count;

	float		timeout; // for SW

	edict_t		*chain;
	edict_t		*enemy;
	edict_t		*oldenemy;
	edict_t		*activator;
	edict_t		*groundentity;
	int			groundentity_linkcount;
	edict_t		*teamchain;
	edict_t		*teammaster;
	int			noise_index;
	int			noise_index2;
	float		volume;
	float		attenuation;

	// timing variables
	float		wait;
	float		delay;			// before firing targets
	float		random;

	float		teleport_time;

	int			watertype;
	int			waterlevel;

	vec3_t		move_origin;
	vec3_t		move_angles;

	// move this to clientinfo?
	int			light_level;

	int			style;			// also used as areaportal number

	float		light;
	vec3_t		color;

	gitem_t		*item;			// for bonus items
	int			invpak[AMMO_TOTAL]; //small inventory-like for dropped backpacks. Handles weapons and ammos of both types

	// common data blocks
	moveinfo_t		moveinfo;

	pmanim_t	pmAnim;				//splitmodels animation stuff

	//newgametypes
	ai_handle_t		ai;		//MbotGame

	// ents can accumulate damage along the frame, so they spawn less events
	float			frame_damage_taken;
	float			frame_damage_saved;	//saved by the armor.
	vec3_t			frame_damage_dir;
	vec3_t			frame_damage_at;

	//JALFIXME
	qboolean		is_swim;
	qboolean		is_step;
	qboolean		is_ladder;
	qboolean		was_swim;
	qboolean		was_step;

	int				dmg_knockback; //jal: only used for projectile knockbacks. I'll try to clean it later
};


