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

//==================================================================
// 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 ) )

// FIXME: Medar: Remove the spectator test and just make sure they always have health
#define G_IsDead( ent )	      ( ( !ent->r.client || ent->s.team != TEAM_SPECTATOR ) && HEALTH_TO_INT( ent->health ) <= 0 )

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

#define	ARMOR_DEGRADATION 0.66 // the smaller the stronger

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

// 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 ( (float)game.frametime * 0.001f )

#define BODY_QUEUE_SIZE	    8

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

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

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

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

// milliseconds before allowing fire after respawn
#define WEAPON_RESPAWN_DELAY		    350

// edict->movetype values
typedef enum
{
	MOVETYPE_NONE,      // never moves
	MOVETYPE_PLAYER,    // never moves (but is moved by pmove)
	MOVETYPE_NOCLIP,    // like MOVETYPE_PLAYER, but not clipped
	MOVETYPE_PUSH,      // no clip to world, push on box contact
	MOVETYPE_STOP,      // no clip to world, stops on box contact
	MOVETYPE_FLY,
	MOVETYPE_TOSS,      // gravity
	MOVETYPE_LINEARPROJECTILE, // extra size to monsters
	MOVETYPE_BOUNCE,
	MOVETYPE_BOUNCEGRENADE
} movetype_t;

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;

#define MAX_RACE_CHECKPOINTS	32

//
// 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;     // string containing the unparsed entities

	char *map_parsed_ents;      // string used for storing parsed key values
	size_t map_parsed_len;
	int protocol;

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

	// cross level triggers
	int serverflags;

	int frametime;                  // in milliseconds
	int snapFrameTime;              // in milliseconds
	unsigned int realtime;          // actual time, set with Sys_Milliseconds every frame
	unsigned int serverTime;        // actual time in the server

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

	int gametype;    //newgametypes

	qboolean lock_teams;
	int numBots;

	unsigned int race_record;
	unsigned int race_record_checkpoint_times[MAX_RACE_CHECKPOINTS];
} 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
{
	unsigned int framenum;
	unsigned int time; // time in milliseconds
	unsigned int spawnedTimeStamp; // time when map was restarted

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

	// intermission state
	qboolean exitNow;
	qboolean hardReset;

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

	int numCheckpoints;

	char *locationNames[MAX_LOCATIONS];
	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
	float fov;
	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;

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

	int gameteam;

	int weight;    //MBotGame
	float scale;
} spawn_temp_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_operator_password;

extern cvar_t *g_gravity;
extern cvar_t *g_maxvelocity;

extern cvar_t *sv_cheats;

extern cvar_t *g_floodprotection_messages;
extern cvar_t *g_floodprotection_team;
extern cvar_t *g_floodprotection_seconds;
extern cvar_t *g_floodprotection_penalty;

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_self_knockback;
extern cvar_t *g_ammo_respawn;
extern cvar_t *g_weapon_respawn;
extern cvar_t *g_health_respawn;
extern cvar_t *g_armor_respawn;
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_antilag_timenudge;
extern cvar_t *g_antilag_maxtimedelta;

extern cvar_t *g_teams_maxplayers;
extern cvar_t *g_teams_allow_uneven;

extern cvar_t *g_autorecord;
extern cvar_t *g_autorecord_maxdemos;

//game switches
extern cvar_t *g_ctf_timer;

#ifdef WSW_CTF_CVARS
extern cvar_t *g_ctf_capture_time;
extern cvar_t *g_ctf_unlock_time;
extern cvar_t *g_ctf_freeze_time;
#endif
extern cvar_t *g_itdm_capture_time;
extern cvar_t *g_itdm_points_time;
extern cvar_t *g_allow_spectator_voting;
extern cvar_t *g_instagib;
extern cvar_t *g_instajump;

#define G_CTF_TIMER	( ( g_instagib->integer ) ? 0.0 : g_ctf_timer->value ) // Should be used instead of g_ctf_timer->integer
// KoFFiE: Added these for the new CTF gametypes
// Ignore all timers when in instagib mode...
#ifndef WSW_CTF_CVARS
#define WSW_CTF_UNLOCKTIME ( (unsigned int)( ( g_instagib->integer ) ? 0 : ( WSW_CTF_CAPTURE_TIME_DEFAULT * 1000 ) ) ) // 2 seconds unlock time by default?
#define WSW_CTF_CAPTURETIME    ( (unsigned int)( ( g_instagib->integer ) ? 0 : ( WSW_CTF_UNLOCK_TIME_DEFAULT  * 1000 ) ) ) // 10 seconds capture time by default?
#define WSW_CTF_FREEZETIME    ( (unsigned int)( ( g_instagib->integer ) ? 0 : ( WSW_CTF_FREEZE_TIME_DEFAULT ) ) )
#else
#define WSW_CTF_UNLOCKTIME ( (unsigned int)( ( g_instagib->integer ) ? 0 : ( g_ctf_unlock_time->value * 1000 ) ) )
#define WSW_CTF_CAPTURETIME    ( (unsigned int)( ( g_instagib->integer ) ? 0 : ( g_ctf_capture_time->value * 1000 ) ) )
#define WSW_CTF_FREEZETIME    ( (unsigned int)( ( g_instagib->integer ) ? 0 : ( g_ctf_freeze_time->integer ) ) )
#endif
#define VALID_TIMER( lasttouch )  ( ( lasttouch + 150 ) > level.time )

extern cvar_t *g_ca_health;
extern cvar_t *g_ca_armor;
extern cvar_t *g_ca_weapons;
extern cvar_t *g_ca_weak_ammo;
extern cvar_t *g_ca_strong_ammo;
extern cvar_t *g_ca_roundlimit;
extern cvar_t *g_ca_allow_selfdamage;
extern cvar_t *g_ca_allow_teamdamage;
extern cvar_t *g_ca_competitionmode;
#ifndef WSW_RELEASE
extern cvar_t *g_ca_classmode;
#endif

edict_t *G_Teams_BestInChallengersQueue( unsigned int lastTimeStamp, edict_t *ignore );
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_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 Cmd_Say_f( edict_t *ent, qboolean arg0, qboolean checkflood );
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_ToggleReady( 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 );
float G_Gametype_ItemRespawnDelay( gitem_t *item );
qboolean G_Gametype_CanDropItem( gitem_t *item, qboolean ignoreMatchState );
qboolean G_Gametype_CanFallDamage( void );
qboolean G_Gametype_CanTeamDamage( int damageflags );
float G_Gametype_RespawnTimeForItem( gitem_t *item );
int G_Gametype_SpawnPointRadius( void );
int G_Gametype_DroppedItemTimeout( gitem_t *item );
qboolean G_Gametype_ClientRespawn( edict_t *self );
void G_Gametypes_ClienBegin( edict_t *ent );
qboolean 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( void );


//
// g_gametype_tdm.c
//
extern char *capture_items[];

//
// 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_CheckHurtCarrier( edict_t *targ, edict_t *attacker );
void G_Gametype_CTF_Effects( edict_t *player );

edict_t *G_Gametype_CTF_SelectSpawnPoint( edict_t *ent );
void G_Gametype_CTF_CleanUpPlayerStats( edict_t *ent );

void SP_team_CTF_alphaspawn( edict_t *self );
void SP_team_CTF_betaspawn( edict_t *self );
void SP_team_CTF_deltaspawn( edict_t *self );
void SP_team_CTF_gammaspawn( edict_t *self );

void SP_team_CTF_alphaplayer( edict_t *self );
void SP_team_CTF_betaplayer( edict_t *self );
void SP_team_CTF_deltaplayer( edict_t *self );
void SP_team_CTF_gammaplayer( edict_t *self );

void SP_team_CTF_redspawn( edict_t *self );
void SP_team_CTF_bluespawn( edict_t *self );
void SP_team_CTF_redplayer( edict_t *self );
void SP_team_CTF_blueplayer( edict_t *self );

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

//
// g_gametype_ca.c
//
edict_t *G_Gametype_CA_SelectSpawnPoint( edict_t *ent );

//
// g_spawnpoints.c
//
edict_t *SelectDeathmatchSpawnPoint( edict_t *ent );
void SelectSpawnPoint( edict_t *ent, edict_t **spawnpoint, vec3_t origin, vec3_t angles, int radius );
edict_t *G_SelectIntermissionSpawnPoint( void );
//newgametypes[end]
float PlayersRangeFromSpot( edict_t *spot, int ignore_team );

void SP_info_player_start( edict_t *ent );
void SP_info_player_deathmatch( edict_t *ent );
void SP_info_player_intermission( edict_t *ent );

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

void SP_func_plat( edict_t *ent );
void SP_func_rotating( edict_t *ent );
void SP_func_button( edict_t *ent );
void SP_func_door( edict_t *ent );
void SP_func_door_rotating( edict_t *ent );
void SP_func_train( edict_t *ent );
void SP_func_conveyor( edict_t *self );
void SP_func_wall( edict_t *self );
void SP_func_object( edict_t *self );
void SP_func_explosive( edict_t *self );
void SP_func_killbox( edict_t *ent );
void SP_func_static( edict_t *ent );
void SP_func_bobbing( edict_t *ent );
void SP_func_pendulum( edict_t *ent );

#define world	( (edict_t *)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
//
#define FFL_SPAWNTEMP	    1

typedef enum
{
	F_INT,
	F_FLOAT,
	F_LSTRING,      // string on disk, pointer in memory, TAG_LEVEL
	F_VECTOR,
	F_ANGLEHACK,
	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
//
char *G_StatsMessage( edict_t *ent );
qboolean CheckFlood( edict_t *ent, qboolean teamonly );
void G_InitGameCommands( void );
void G_AddCommand( char *name, void *cmdfunc );
void G_BOTvsay_f( edict_t *ent, char *msg, qboolean team );

//
// g_items.c
//
void	    DoRespawn( edict_t *ent );
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 msec );
void	    MegaHealth_think( edict_t *self );
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 );
qboolean    Add_Armor( edict_t *ent, edict_t *other, qboolean pick_it );
int	    G_ItemRespawnTimer( char *class_name );

//
// g_utils.c
//
#define	    G_LEVEL_DEFAULT_POOL_SIZE	128 * 1024

qboolean    KillBox( edict_t *ent );
float	    LookAtKillerYAW( edict_t *self, edict_t *inflictor, edict_t *attacker );
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_LevelInitPool( size_t size );
void *_G_LevelMalloc( size_t size, const char *filename, int fileline );
void	    _G_LevelFree( void *data, const char *filename, int fileline );
char *_G_LevelCopyString( const char *in, const char *filename, int fileline );

char *_G_CopyString( const char *in, const char *filename, int fileline );
#define	    G_CopyString( in ) _G_CopyString( in, __FILE__, __LINE__ )

void	G_ProjectSource( 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, const char *format, ... );
void	G_ChatMsg( edict_t *ent, const char *format, ... );
void	G_CenterPrintMsg( edict_t *ent, const char *format, ... );
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 );
float vectoyaw( vec3_t vec );

void	G_PureSound( const char *sound );
void	G_PureModel( const char *model );

//more warsow utils
extern game_locals_t game;
#define ENTNUM( x ) ( ( x ) - game.edicts )

#define PLAYERNUM( x ) ( ( x ) - game.edicts - 1 )
#define PLAYERENT( x ) ( game.edicts + ( x ) + 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_ReleaseClientPSEvent( gclient_t *client );
void	G_AddPlayerStateEvent( gclient_t *client, int event, int parm );
void	G_ClearPlayerStateEvents( gclient_t *client );
// announcer events
void	G_AnnouncerSound( edict_t *targ, int soundindex, int team, qboolean queued );
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 );
void SP_trigger_always( edict_t *ent );
void SP_trigger_once( edict_t *ent );
void SP_trigger_multiple( edict_t *ent );
void SP_trigger_relay( edict_t *ent );
void SP_trigger_push( edict_t *ent );
void SP_trigger_hurt( edict_t *ent );
void SP_trigger_key( edict_t *ent );
void SP_trigger_counter( edict_t *ent );
void SP_trigger_elevator( edict_t *ent );
void SP_trigger_gravity( edict_t *ent );

//
// g_clip.c
//

int	G_PointContents( vec3_t p );
void	G_Trace( trace_t *tr, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *passedict, int contentmask );
int G_PointContents4D( vec3_t p, int timeDelta );
void G_Trace4D( trace_t *tr, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *passedict, int contentmask, int timeDelta );
void GClip_BackUpCollisionFrame( void );
edict_t *GClip_FindBoxInRadius4D( edict_t *from, vec3_t org, float rad, int timeDelta );
float G_KnockbackPushFrac4D( vec3_t pushorigin, int entNum, vec3_t pushdir, float pushradius, int timeDelta );
void	GClip_ClearWorld( void );
void	GClip_SetBrushModel( edict_t *ent, char *name );
void	GClip_SetAreaPortalState( edict_t *ent, qboolean open );
void	GClip_LinkEntity( edict_t *ent );
void	GClip_UnlinkEntity( edict_t *ent );
void	GClip_TouchTriggers( edict_t *ent );
void G_PMoveTouchTriggers( pmove_t *pm );



//
// g_combat.c
//
void Killed( edict_t *targ, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point, int mod );
int G_ModToAmmo( int mod );
qboolean G_IsTeamDamage( edict_t *targ, edict_t *attacker );
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 );
void BecomeExplosion1( edict_t *self );

void SP_light( edict_t *self );
void SP_light_mine( edict_t *ent );
void SP_info_null( edict_t *self );
void SP_info_notnull( edict_t *self );
void SP_info_camp( edict_t *self );
void SP_path_corner( edict_t *self );

void SP_misc_teleporter_dest( edict_t *self );
void SP_misc_model( edict_t *ent );
void SP_misc_portal_surface( edict_t *ent );
void SP_misc_portal_camera( edict_t *ent );
void SP_skyportal( edict_t *ent );
void SP_capture_area( edict_t *ent );
void SP_capture_area_indicator( edict_t *ent );
edict_t *G_Gametype_TDM_SelectSpawnPoint( edict_t *ent );

//
// 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 G_HideLaser( edict_t *ent );

void W_Fire_Blade( edict_t *self, int range, vec3_t start, vec3_t dir, int damage, int kick, int mod, int timeDelta );
void W_Fire_Gunblade_Bullet( edict_t *self, vec3_t start, vec3_t dir, int damage, int knockback, int mod, int timeDelta );
edict_t *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, int timeDelta );
edict_t *W_Fire_Shockwave( edict_t *self, vec3_t start, vec3_t dir, float speed, int radius, int timeout, int timeDelta );
void W_Fire_Riotgun( edict_t *self, vec3_t start, vec3_t dir, int damage, int knockback, int spread, int count, int dflags, int mod, int timeDelta );
edict_t *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, int timeDelta );
edict_t *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, int timeDelta );
edict_t *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, int timeDelta );
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, int timeDelta );
edict_t *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, int timeDelta );
void W_Fire_Lasergun( edict_t *self, vec3_t start, vec3_t aimdir, int damage, int knockback, int timeout, int dflags, int mod, int timeDelta );
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, int timeDelta );
void G_HideClientLaser( edict_t *ent );
void W_Fire_Instagun_Strong( edict_t *self, vec3_t start, vec3_t aimdir, float speed, int damage, int knockback, int radius, int range, int dflags, int mod, int timeDelta );
edict_t *W_Fire_Instagun_Weak( edict_t *self, vec3_t start, vec3_t aimdir, float speed, int damage, int knockback, int timeout, int dflags, int mod, int timeDelta );

qboolean Pickup_Weapon( edict_t *ent, edict_t *other );
void Drop_Weapon( edict_t *ent, gitem_t *item );
void Use_Weapon( edict_t *ent, gitem_t *item );
firedef_t *Player_GetCurrentWeaponFiredef( edict_t *ent );

//
// g_chasecam	//newgametypes
//
void G_SpectatorMode( edict_t *ent );
void G_ChasePlayer( edict_t *ent, char *name, qboolean teamonly, int followmode );
void G_ChaseStep( edict_t *ent, int step );
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 InitClientPersistant( gclient_t *client );
void InitClientResp( gclient_t *client );
void InitClientTeamChange( gclient_t *client );
void G_InitBodyQueue( void );
void ClientUserinfoChanged( edict_t *ent, char *userinfo );
qboolean ClientMultiviewChanged( edict_t *ent, qboolean multiview );
void ClientThink( edict_t *ent, usercmd_t *cmd, int timeDelta );
qboolean ClientConnect( edict_t *ent, char *userinfo, qboolean fakeClient, qboolean tvClient );
void ClientDisconnect( edict_t *ent, const char *reason );
void ClientBegin( edict_t *ent );
void ClientCommand( edict_t *ent );
void G_PredictedEvent( int entNum, int ev, int parm );

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

void G_DropClientBackPack( edict_t *self );
void TossClientWeapon( edict_t *self );

//
// 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 );
void player_think( edict_t *self );

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

void SP_target_temp_entity( edict_t *ent );
void SP_target_speaker( edict_t *ent );
void SP_target_explosion( edict_t *ent );
void SP_target_spawner( edict_t *ent );
void SP_target_crosslevel_trigger( edict_t *ent );
void SP_target_crosslevel_target( edict_t *ent );
void SP_target_laser( edict_t *self );
void SP_target_lightramp( edict_t *self );
void SP_target_earthquake( edict_t *ent );
void SP_target_string( edict_t *ent );
void SP_target_location( edict_t *self );
void SP_target_position( edict_t *self );
void SP_target_print( edict_t *self );
void SP_target_starttimer( edict_t *self );
void SP_target_stoptimer( edict_t *self );
void SP_target_checkpoint( edict_t *self );
void SP_target_give( edict_t *self );
void SP_target_reset_flag_countdown( edict_t *self );
void SP_target_freeze_flag_countdown( edict_t *self );
void SP_target_init( edict_t *self );

//
// g_svcmds.c
//
void SV_ResetPacketFiltersTimeouts( void );
qboolean SV_FilterPacket( char *from );
void G_AddCommands( void );
void G_RemoveCommands( void );
void SV_ReadIPList( void );
void SV_WriteIPList( void );

//
// p_view.c
//
void G_ClientEndSnapFrame( edict_t *ent );
void G_ClientDamageFeedback( edict_t *ent );
void G_CheckClientRespawnClick( edict_t *ent );
qboolean G_ClientIsZoom( edict_t *ent );

//
// p_hud.c
//

//scoreboards string
extern char scoreboardString[MAX_STRING_CHARS];
extern const unsigned int scoreboardInterval;
#define SCOREBOARD_MSG_MAXSIZE ( MAX_STRING_CHARS-8 ) //I know, I know, doesn't make sense having a bigger string than the maxsize value

void MoveClientToIntermission( edict_t *client );
void G_SetClientStats( edict_t *ent );
void ValidateSelectedItem( edict_t *ent );
void G_Snap_UpdateWeaponListMessages( void );
void G_ScoreboardMessage_AddSpectators( void );
void G_UpdateScoreBoardMessages( void );

//
// g_phys.c
//
void SV_Impact( edict_t *e1, trace_t *trace );
void G_RunEntity( edict_t *ent );
int G_BoxSlideMove( edict_t *ent, float time, int contentmask, float slideBounce );

//
// g_main.c
//

// memory management
#define G_Malloc( size ) trap_MemAlloc( size, __FILE__, __LINE__ )
#define G_Free( mem ) trap_MemFree( mem, __FILE__, __LINE__ )

#define	G_LevelMalloc( size ) _G_LevelMalloc( ( size ), __FILE__, __LINE__ )
#define	G_LevelFree( data ) _G_LevelFree( ( data ), __FILE__, __LINE__ )
#define	G_LevelCopyString( in ) _G_LevelCopyString( ( in ), __FILE__, __LINE__ )

int	G_API( void );
void	G_Error( const char *format, ... );
void	G_Printf( const char *format, ... );
void	G_Init( unsigned int seed, unsigned int maxclients, unsigned int framemsec, int protocol );
void	G_Shutdown( void );
void	G_ExitLevel( void );
void	G_GetMatchState( match_state_t *matchstate );
void	G_Timeout_Reset( void );

qboolean    G_AllowDownload( edict_t *ent, const char *requestname, const char *uploadname );

//
// g_frame.c
//
void G_RunFrame( unsigned int msec, unsigned int serverTime );
void G_SnapClients( void );
void G_ClearSnap( void );
void G_SnapFrame( void );


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

//
// g_awards.c
//
void G_AwardPlayerHit( edict_t *targ, edict_t *attacker, int mod );
void G_AwardPlayerMissedElectrobolt( edict_t *self, int mod );
void G_AwardPlayerMissedLasergun( edict_t *self, int mod );
void G_AwardPlayerKilled( edict_t *self, edict_t *inflictor, edict_t *attacker, int mod );
void G_AwardPlayerPickup( edict_t *self, edict_t *item );
void G_AwardResetPlayerComboStats( edict_t *ent );
void G_AwardRaceRecord( edict_t *self );
void G_AwardCapture( edict_t *ent );
void G_AwardCTFRecovery( edict_t *ent );
void G_AwardCaptureArea( edict_t *ent );
void G_AwardAllCaptureAreas( edict_t *ent );
void G_AwardFragFlagCarrier( edict_t *ent );
void G_AwardDefendFlagCarrier( edict_t *ent );
void G_AwardDefendFlagBase( edict_t *ent );

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

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

typedef struct
{
	qboolean active;
	int target;
	int mode;                   //3rd or 1st person
	int range;
	qboolean teamonly;
	unsigned int timeout;           //delay after loosing target
	int followmode;
} chasecam_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;

	vec3_t movedir;  // direction defined in the bsp

	float speed;
	float distance;    // used by binary movers

	float wait;

	float phase;

	// state data
	int state;
	vec3_t dir;             // used by func_bobbing and func_pendulum
	float current_speed;    // used by func_rotating

	void ( *endfunc )( edict_t * );
	void ( *blocked )( edict_t *self, edict_t *other );

	vec3_t dest;
	vec3_t destangles;
} moveinfo_t;

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

	char ip[MAX_INFO_VALUE];
	char socket[MAX_INFO_VALUE];

	int hand;
	int fov;
	int movestyle;
	int movestyle_latched;
	int zoomfov;
	byte_vec4_t color;

#ifdef UCMDTIMENUDGE
	int ucmdTimeNudge;
#endif

	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

	qboolean isoperator;		// this client has the gameadmin password

	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

	qboolean multiview, tv;
} client_persistant_t;

#define MAX_FLOOD_MESSAGES 32

// client data that stays across deathmatch respawns
// reseted on connect, match start, map change, but NOT on team change, respawns
typedef struct
{
	// for race
	unsigned int race_record;
	unsigned int race_record_checkpoint_times[MAX_RACE_CHECKPOINTS];

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

	// flood protection
	float flood_locktill;           // locked from talking
	float flood_when[MAX_FLOOD_MESSAGES];           // when messages were said
	int flood_whenhead;             // head pointer for when said
	// team only
	float flood_team_when[MAX_FLOOD_MESSAGES];              // when messages were said
	int flood_team_whenhead;                // head pointer for when said

	matchmessage_t matchmessage;
} client_teamchange_t;

// client data that stays across deathmatch respawns
// reset 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];
	int total_damage_given;
	int total_damage_received;
	int health_taken;
	int armor_taken;

	// for race
	// what is set/reset at race start or end
	qboolean race_active;
	unsigned int race_time;
	unsigned int race_checkpoint_times[MAX_RACE_CHECKPOINTS];

	// survive respawn
	unsigned int race_last;
} client_respawn_t;

typedef struct
{
	int ebhit_count;
	int directrocket_count;
	int directgrenade_count;
	int multifrag_timer;
	int multifrag_count;
	int frag_count;

	int accuracy_award;
	int directrocket_award;
	int directgrenade_award;
	int multifrag_award;
	int spree_award;
	int gl_midair_award;
	int rl_midair_award;

	int mh_control_award;
	int ra_control_award;

	qbyte combo[MAX_CLIENTS]; // combo management for award
	edict_t *lasthit;
	unsigned int lasthit_time;
} award_info_t;

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

#define MAX_CLIENT_EVENTS   16
#define MAX_CLIENT_EVENTS_MASK ( MAX_CLIENT_EVENTS - 1 )

#define G_MAX_TIME_DELTAS   8
#define G_MAX_TIME_DELTAS_MASK ( G_MAX_TIME_DELTAS - 1 )

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

	int timeDelta;              // time offset to adjust for shots collision (antilag)
	int timeDeltas[G_MAX_TIME_DELTAS];
	int timeDeltasHead;

	qboolean showscores;        // set layout stat

	int selected_item;
	int inventory[MAX_ITEMS];

	float armor;
	int armortag;

	int buttons;

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

	float killer_yaw;           // when dead, look at killer

	weapon_state_t weaponstate;

	unsigned int next_drown_time;
	int old_waterlevel;
	int old_watertype;
	int breather_sound;

	// powerup timers
	unsigned int quad_timeout;
	unsigned int shell_timeout;

	int weapon_sound;
	qboolean weapon_missed;

	unsigned int pickup_msg_time;

	unsigned int scoreboard_time; // when scoreboard was last sent

	unsigned int last_vsay;         // time when last vsay was said

	unsigned int respawn_timestamp;     // timemsec when it was respawned

	chasecam_t chase;

	qbyte plrkeys; // used for displaying key icons

	//weapons stuff
	int latched_weapon;

	int ammo_index;
	int ammo_weak_index;

	vec3_t lasergunTrail[LASERGUN_WEAK_TRAIL_BACKUP];
	unsigned int lasergunTrailTimes[LASERGUN_WEAK_TRAIL_BACKUP];

	// player_state_t event
	int events[MAX_CLIENT_EVENTS];                  // psEvents buffer
	unsigned int eventsCurrent;
	unsigned int eventsHead;

	award_info_t awardInfo; // award management

	unsigned int gunblade_charge_waitingtime;

	qboolean is_coach;
};

typedef struct snap_edict_s
{
	int buttons;

	// whether we have killed anyone this snap
	qboolean kill;
	qboolean teamkill;

	// ents can accumulate damage along the frame, so they spawn less events
	float damage_taken;
	float damage_saved;         // saved by the armor.
	vec3_t damage_dir;
	vec3_t damage_at;
	float damage_given;             // for hitsounds
	float damageteam_given;
	float damage_fall;
} snap_edict_t;

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!

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

	entity_state_t olds; // state in the last sent frame snap

	int movetype;
	int flags;

	char *model;
	char *model2;
	unsigned int freetime;          // time when the object was freed

	int numEvents;
	qboolean eventPriority[2];

	//
	// only used locally in game, not by server
	//

	char *classname;
	int spawnflags;

	unsigned int nextthink;

	void ( *think )( edict_t *self );
	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 );

	char *target;
	char *targetname;
	char *killtarget;
	char *team;
	char *pathtarget;
	edict_t	*target_ent;

	vec3_t velocity;
	vec3_t avelocity;

	float angle;                // set in qe3, -1 = up, -2 = down
	float speed;
	float accel, decel;         // usef for func_rotating (and shockwave)

	unsigned int timeStamp;
	unsigned int deathTimeStamp;
	int timeDelta;              // SVF_PROJECTILE only. Used for 4D collision detection

	int dmg_knockback;          // SVF_PROJECTILE only. knockbacks.

	char *message;
	int mass;
	unsigned int 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;

	unsigned int pain_debounce_time;

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

	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;

	char *capture_arealetter;   // added by will
	int capture_areano;   // added by will

	unsigned int timeout; // for SW and fat PG

	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

	int watertype;
	int waterlevel;

	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;        // func movers movement

	ai_handle_t ai;     //MbotGame

	snap_edict_t snap; // information that is cleared each frame snap

	qboolean fall_fatal;        // for falling to void etc.

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

	edict_t	*trigger_entity;
	unsigned int trigger_timeout;

	qboolean linked;
};

// matchmaker

typedef enum
{
	MM_UNREADY,
	MM_RESTART,
	MM_READY
} mm_state_t;

void G_SetupMM( int maxclients, int gametype, const char *pass, int scorelimit, float timelimit, qboolean falldamage );
void G_CheckMM( void );
void G_SetMMReadyState( void );
