// Copyright (C) 1999-2000 Id Software, Inc.
//

#include "g_local.h"
#include "g_groups.h"

//extern qboolean BG_BorgTransporting( playerState_t *ps );
extern void BG_LoadItemNames(void);

extern qboolean BG_ParseRankNames ( char* fileName, rankNames_t rankNames[] );

qboolean G_LoadMapConfigurations( void );

//RPG-X: RedTechie
//int shaketimer; //Global shake timer varible //TiM: NOT NECESSARY
int RPGEntityCount; //Global entity count varible
//int lastTimedMessage; //The last timed message that was displayed //TiM: Not necessary here

level_locals_t	level;
extern char	races[256];	//this is evil!
extern qboolean levelExiting;

group_list_t	group_list[MAX_GROUP_MEMBERS];
int 			group_count;
int numKilled;

typedef struct {
	vmCvar_t	*vmCvar;
	char		*cvarName;
	char		*defaultString;
	int			cvarFlags;
	int			modificationCount;  // for tracking changes
	qboolean	trackChange;	// track this variable, and announce if changed
} cvarTable_t;

gentity_t	g_entities[MAX_GENTITIES];
gclient_t	g_clients[MAX_CLIENTS];

rankNames_t g_rankNames[MAX_RANKS];

g_classData_t	g_classData[MAX_CLASSES];

vmCvar_t	g_pModAssimilation;
vmCvar_t	g_pModDisintegration;
vmCvar_t	g_pModActionHero;
vmCvar_t	g_pModSpecialties;
vmCvar_t	g_pModElimination;

vmCvar_t	g_gametype;
vmCvar_t	g_dmflags;
vmCvar_t	g_fraglimit;
vmCvar_t	g_timelimit;
vmCvar_t	g_timelimitWinningTeam;
vmCvar_t	g_capturelimit;
vmCvar_t	g_friendlyFire;
vmCvar_t	g_password;
vmCvar_t	g_needpass;
vmCvar_t	g_maxclients;
vmCvar_t	g_maxGameClients;
vmCvar_t	g_dedicated;
vmCvar_t	g_speed;
vmCvar_t	g_gravity;
vmCvar_t	g_cheats;
vmCvar_t	g_knockback;
vmCvar_t	g_dmgmult;
vmCvar_t	g_forcerespawn;
vmCvar_t	g_inactivity;
vmCvar_t	g_debugMove;
vmCvar_t	g_debugDamage;
vmCvar_t	g_debugAlloc;
vmCvar_t	g_weaponRespawn;
vmCvar_t	g_adaptRespawn;
vmCvar_t	g_motd;
vmCvar_t	g_synchronousClients;
vmCvar_t	g_warmup;
vmCvar_t	g_doWarmup;
vmCvar_t	g_restarted;
vmCvar_t	g_log;
vmCvar_t	g_logSync;
vmCvar_t	g_podiumDist;
vmCvar_t	g_podiumDrop;
vmCvar_t	g_allowVote;
vmCvar_t	g_teamAutoJoin;
vmCvar_t	g_teamForceBalance;
vmCvar_t	g_banIPs;
vmCvar_t	g_filterBan;
vmCvar_t	g_banIDs;	//TiM - Security ban system
vmCvar_t	g_debugForward;
vmCvar_t	g_debugRight;
vmCvar_t	g_debugUp;
vmCvar_t	g_language;
vmCvar_t	g_holoIntro;
//vmCvar_t	g_ghostRespawn;
vmCvar_t	g_intermissionTime;
vmCvar_t	g_team_group_red;
vmCvar_t	g_team_group_blue;
vmCvar_t	g_random_skin_limit;
vmCvar_t	g_classChangeDebounceTime;
//vmCvar_t	ui_playerclass;

//RPG-X: - RedTechie More CVAR INFO
vmCvar_t	rpg_allowvote;
vmCvar_t	rpg_chatsallowed;
vmCvar_t	rpg_allowsuicide;
vmCvar_t	rpg_selfdamage;
vmCvar_t	rpg_rpg;
vmCvar_t	rpg_kickspammers;				//!< Specifies whether player that spam get kicked automatically.
vmCvar_t	rpg_kicksuiciders;				//!< Specifies whether player that sucide get kicked automatically.
vmCvar_t	rpg_allowspmaps;				//!< Specifies whether singleplayer maps can be loaded
vmCvar_t	rpg_rangetricorder;				//!< Maximum range the Tricorder can scan.
vmCvar_t	rpg_rangehypo;					//!< Maximum range of the Hypospray.
vmCvar_t	rpg_norpgclasses;
vmCvar_t	rpg_forceclasscolor;			//!< Specifies whether class colors specified in the *.class file are enforced.
vmCvar_t	rpg_nosecurity;
vmCvar_t	rpg_nomarine;
vmCvar_t	rpg_nomedical;
vmCvar_t	rpg_noscience;
vmCvar_t	rpg_nocommand;
vmCvar_t	rpg_noengineer;
vmCvar_t	rpg_noalien;
vmCvar_t	rpg_nomaker;
vmCvar_t	rpg_non00b;
vmCvar_t	rpg_nocloak;					//!< Can be used to disable the admin cloaking device.
vmCvar_t	rpg_noflight;					//!< Can be used to disable the admin flight mode.
vmCvar_t	rpg_phaserdmg;					//!< Specifies whether the phaser damges players.
vmCvar_t	rpg_rifledmg;					//!< Specifies whether the phaser rifle damages players.
vmCvar_t	rpg_stasisdmg;					//!< Specifies whether the disruptor damages rifles.
vmCvar_t	rpg_imoddmg;					
vmCvar_t	rpg_noweapons;					//!< Can be used to disable all weapons.
//vmCvar_t	rpg_marinepass;
//vmCvar_t	rpg_securitypass;
//vmCvar_t	rpg_adminpass;
//vmCvar_t	rpg_medicalpass;
//vmCvar_t	rpg_sciencepass;
//vmCvar_t	rpg_commandpass;
//vmCvar_t	rpg_engineerpass;
//vmCvar_t	rpg_alienpass;
//vmCvar_t	rpg_n00bpass;
//vmCvar_t	rpg_alienflags;
//vmCvar_t	rpg_marineflags;
//vmCvar_t	rpg_securityflags;
//vmCvar_t	rpg_adminflags;
//vmCvar_t	rpg_medicalflags;
//vmCvar_t	rpg_scienceflags;
//vmCvar_t	rpg_commandflags;
//vmCvar_t	rpg_engineerflags;
vmCvar_t	rpg_welcomemessage;					//!< Welcome message displayed when a player joins the server.
//vmCvar_t	rpg_timedmessage;
vmCvar_t	rpg_timedmessagetime;				//!< Delay between timed mesagges
vmCvar_t	rpg_message1;						//!< Timed message
vmCvar_t	rpg_message2;						//!< Timed message
vmCvar_t	rpg_message3;						//!< Timed message
vmCvar_t	rpg_message4;						//!< Timed message
vmCvar_t	rpg_message5;						//!< Timed message
vmCvar_t	rpg_message6;						//!< Timed message
vmCvar_t	rpg_message7;						//!< Timed message
vmCvar_t	rpg_message8;						//!< Timed message
vmCvar_t	rpg_message9;						//!< Timed message
vmCvar_t	rpg_message10;						//!< Timed message
vmCvar_t	rpg_forcekillradius;				//!< Specifies whether the forcekillradius command is avaible.
vmCvar_t	rpg_forcekillradiuswaittime;		//!< forcekillradius delay
vmCvar_t	rpg_noclipspectating;				//!< Specifies whether spectators uses clipping.
vmCvar_t	rpg_chatarearange;					//!< Maximumrange for area chat.
vmCvar_t	rpg_forcefielddamage;				//!< Damage a player takes when touching an admin force field
vmCvar_t	rpg_invisibletripmines;				//!< Specifies whether invisible tripmines are enabled.
vmCvar_t	rpg_medicsrevive;					//!< Are medics allowed to revive other players
vmCvar_t	rpg_effectsgun;						//!< Can be used to enable/disable the effects gun
vmCvar_t	rpg_phaserdisintegrates;			//!< If enabled phasers disintegrate players instead ob incapacitating them.
//vmCvar_t	rpg_enabledranks;
//vmCvar_t	rpg_servershakeallclients;//RPG-X: RedTechie - Server only shake cmd used to shake clients view when set
//vmCvar_t	rpg_servershakeallclientsintensity;//RPG-X: RedTechie - Server only shake cmd used to shake clients view intensity
//! Kick player for n00bing after this ammount of kills
vmCvar_t	rpg_kickAfterXkills; //RPG-X | Phenix | 06/04/2005
vmCvar_t	rpg_rankSet;						//!< Rankset to use
vmCvar_t	rpg_passMessage;	 //RPG-X | TiM | 2/2/2006
//! If enabled the previous name of a player is displayed if the reconnects with a different one.
vmCvar_t	rpg_renamedPlayers;	 //RPG-X | TiM | For players that disconnect, reconnect with dif names to try and be sneaky...
//! If enabled only one player can have a name at the same time.
vmCvar_t	rpg_uniqueNames;	 //RPG-X | TiM | When active, only one player can have the same name on a server
//RPG-X | TiM | Cvars to make the rank system more controllable
vmCvar_t	rpg_startingRank;	 //!< The rank players will start as, regardless
vmCvar_t	rpg_maxRank;		 //!< Absolute rank players can set themselves to
vmCvar_t	rpg_changeRanks;	 //!< If players are allowed to change ranks themselves

//TiM - height paramters
vmCvar_t	rpg_maxHeight;
vmCvar_t	rpg_minHeight;
vmCvar_t	rpg_maxWeight;
vmCvar_t	rpg_minWeight;

//! Classet to use
vmCvar_t	rpg_classSet;		//TiM: current server class configuration

vmCvar_t	rpg_mapGiveFlags;

vmCvar_t	rpg_scannablePanels;	//!< Scan consoles and doors be scanned with the Tricorder

// Drop stuff
//! Enables weapon dropping
vmCvar_t    rpg_allowWeaponDrop; //RPG-X | Marcin | 03/12/2008
//! Do weapons stay in inventory when a player drops them
vmCvar_t    rpg_weaponsStay;     //RPG-X | Marcin | 04/12/2008
//! Does a player drop his weapons when he dies
vmCvar_t	rpg_dropOnDeath;	 //RPG-X | Marcin | 30/12/2008
//vmCvar_t	rpg_flushDroppedOnDisconnect; //RPG-X | GSIO01 | 08/05/2009

// Weapon speeds
//! Speed for compression riffle  projectiles
vmCvar_t    rpg_rifleSpeed;      //RPG-X | Marcin | 04/12/2008
//! Speed for disruptor projectiles
vmCvar_t    rpg_disruptorSpeed;  //RPG-X | Marcin | 04/12/2008
//! Speed for photon burst projectiles
vmCvar_t    rpg_photonSpeed;     //RPG-X | Marcin | 05/12/2008
//! Speed for altfire photon burst projectiles
vmCvar_t    rpg_altPhotonSpeed;  //RPG-X | Marcin | 06/12/2008

// Weapon delays
//! Fire delay for Compression Rifle
vmCvar_t    rpg_rifleDelay;      //RPG-X | Marcin | 06/12/2008
//! Fire delay for Disruptor
vmCvar_t    rpg_disruptorDelay;  //RPG-X | Marcin | 06/12/2008
//! Fire delay for photon burst primary fire
vmCvar_t    rpg_photonDelay;     //RPG-X | Marcin | 06/12/2008
//! Fire delay for photon burst secondary fire
vmCvar_t    rpg_altPhotonDelay;  //RPG-X | Marcin | 06/12/2008
//! Fire delay for TR116
vmCvar_t	rpg_TR116Delay;		 //RPG-X | Marcin | 30/12/2008
//! Fire delay for Tricorder alt fire
vmCvar_t	rpg_altTricorderDelay;	 //RPG-X | GSIO01 | 14/05/2009

// Motd
//! Specifies the message of the day file
vmCvar_t	rpg_motdFile;        //RPG-X | Marcin | 23/12/2008

// Privacy
//! If enabled admins can the private chat messages
vmCvar_t	rpg_respectPrivacy;  //RPG-X | Marcin | 24/12/2008

// Weaps
vmCvar_t	rpg_maxTricorders;	 //RPG-X | Marcin | 30/12/2008
vmCvar_t	rpg_maxPADDs;		 //RPG-X | Marcin | 30/12/2008
vmCvar_t	rpg_maxCups;		 //RPG-X | Marcin | 30/12/2008
vmCvar_t	rpg_maxPhasers;		 //RPG-X | Marcin | 30/12/2008
vmCvar_t	rpg_maxRifles;		 //RPG-X | Marcin | 30/12/2008
vmCvar_t	rpg_maxTR116s;		 //RPG-X | Marcin | 30/12/2008
vmCvar_t	rpg_maxAdminguns;	 //RPG-X | Marcin | 30/12/2008
vmCvar_t	rpg_maxPhotonbursts; //RPG-X | Marcin | 30/12/2008
vmCvar_t	rpg_maxDisruptors;	 //RPG-X | Marcin | 30/12/2008
vmCvar_t	rpg_maxMedkits;		 //RPG-X | Marcin | 30/12/2008
vmCvar_t	rpg_maxHyposprays;	 //RPG-X | Marcin | 30/12/2008
vmCvar_t	rpg_maxRegenerators; //RPG-X | Marcin | 30/12/2008
vmCvar_t	rpg_maxToolkits;	 //RPG-X | Marcin | 30/12/2008
vmCvar_t	rpg_maxHyperSpanners;//RPG-X | Marcin | 30/12/2008
vmCvar_t	rpg_minTricorders;	 //RPG-X | Marcin | 30/12/2008
vmCvar_t	rpg_minPADDs;		 //RPG-X | Marcin | 30/12/2008
vmCvar_t	rpg_minCups;		 //RPG-X | Marcin | 30/12/2008
vmCvar_t	rpg_minPhasers;		 //RPG-X | Marcin | 30/12/2008
vmCvar_t	rpg_minRifles;		 //RPG-X | Marcin | 30/12/2008
vmCvar_t	rpg_minTR116s;		 //RPG-X | Marcin | 30/12/2008
vmCvar_t	rpg_minAdminguns;	 //RPG-X | Marcin | 30/12/2008
vmCvar_t	rpg_minPhotonbursts; //RPG-X | Marcin | 30/12/2008
vmCvar_t	rpg_minDisruptors;	 //RPG-X | Marcin | 30/12/2008
vmCvar_t	rpg_minMedkits;		 //RPG-X | Marcin | 30/12/2008
vmCvar_t	rpg_minHyposprays;	 //RPG-X | Marcin | 30/12/2008
vmCvar_t	rpg_minRegenerators; //RPG-X | Marcin | 30/12/2008
vmCvar_t	rpg_minToolkits;	 //RPG-X | Marcin | 30/12/2008
vmCvar_t	rpg_minHyperSpanners;//RPG-X | Marcin | 30/12/2008

// respawn delay
//! Delay for respawn function
vmCvar_t	rpg_fraggerSpawnDelay; //RPG-X | Marcin | 03/01/2009

// borg adaption
//! If enabled borg get immune to weapons after some time
vmCvar_t	rpg_borgAdapt;				//RPG-X | GSIO01 | 08/05/2009
//! Borg shield plays sound if hit?
vmCvar_t	rpg_adaptUseSound;			//RPG-X | GSIO01 | 08/05/2009
//! Number of hits  before borg adapt to this weapon
vmCvar_t	rpg_adaptPhaserHits;		//RPG-X | GSIO01 | 08/05/2009
//! Number of hits  before borg adapt to this weapon
vmCvar_t	rpg_adaptPhotonHits;		//RPG-X | GSIO01 | 08/05/2009
//! Number of hits  before borg adapt to this weapon
vmCvar_t	rpg_adaptCrifleHits;		//RPG-X | GSIO01 | 08/05/2009
//! Number of hits  before borg adapt to this weapon
vmCvar_t	rpg_adaptDisruptorHits;		//RPG-X | GSIO01 | 08/05/2009
//! Number of hits  before borg adapt to this weapon
vmCvar_t	rpg_adaptTR116Hits;			//RPG-X | GSIO01 | 08/05/2009
//! Number of hits  before borg adapt to this weapon
vmCvar_t	rpg_adaptGrenadeLauncherHits; //RPG-X | GSIO01 | 08/05/2009
//! Are player allowed to remodulate their weapons
vmCvar_t	rpg_allowRemodulation;		//RPG-X | GSIO01 | 10/05/2009
//! Can borg move through admin force fields
vmCvar_t	rpg_borgMoveThroughFields;	//RPG-X | GSIO01 | 19/05/2009
//! Delay for modulation
vmCvar_t	rpg_RemodulationDelay;

// hypo melee
//! Can the hypospray be used as weapons
vmCvar_t	rpg_hypoMelee;

// repairing breakables
//! Can be used to modify repairspeed
vmCvar_t	rpg_repairModifier;	//RPG-X | GSIO01 | 09/05/2009

// force field colors
//! Current force field color
vmCvar_t	rpg_forceFieldColor; //RPG-X | GSIO01 | 09/05/2009

// modulation thingies //RPG-X | GSIO01 | 12/05/2009
vmCvar_t	rpg_forceFieldFreq;

// calc lif travel duration by dec distance
//! Calculathe the travel durration of the turbolift by the difference between the deck numbers?
vmCvar_t	rpg_calcLiftTravelDuration;
//! Can be used to modify the lift speed
vmCvar_t	rpg_liftDurationModifier;

// admin vote override
//! Admins can override votes
vmCvar_t	rpg_adminVoteOverride;

// server change
//! Enables/disables target_serverchange
vmCvar_t	rpg_serverchange;
vmCvar_t	rpg_server1;
vmCvar_t	rpg_server2;
vmCvar_t	rpg_server3;
vmCvar_t	rpg_server4;
vmCvar_t	rpg_server5;
vmCvar_t	rpg_server6;

// SP level change
//! Allow target_levelchange to change the current level?
vmCvar_t	rpg_allowSPLevelChange;

#ifdef XTRA
vmCvar_t	sql_dbName;		//!< Name of the SQL Database
vmCvar_t	sql_use;		//!< Use SQL? 1 = mysql, 2 = sqlite
vmCvar_t	sql_server;		//!< SQL server to connect to (only mysql)
vmCvar_t	sql_user;		//!< SQL user for sql_server (only mysql)
vmCvar_t	sql_password;	//!< SQL password for sql_server (only mysql)
vmCvar_t	sql_port;		//!< SQL port to use to connect to sql_server (only mysql)
vmCvar_t	sql_hash;		//!< Specifies whether passwords should be hashed and what hash to use (only mysql)
#endif

// developer tools
vmCvar_t	dev_showTriggers;

#ifdef G_LUA
// Print Lua debugging information into the game console?
vmCvar_t        g_debugLua;
vmCvar_t        lua_modules;
vmCvar_t        lua_allowedModules;
#endif

// XPERIMENTAL
//vmCvar_t	rpg_useLanguages;


static cvarTable_t		gameCvarTable[] = {
	// don't override the cheat state set by the system
	{ &g_cheats, "sv_cheats", "", 0, 0, qfalse },

	// noset vars
	{ NULL, "gamename", GAMEVERSION , CVAR_SERVERINFO | CVAR_ROM, 0, qfalse  },
	{ NULL, "gamedate", __DATE__ , CVAR_ROM, 0, qfalse  },
	{ &g_restarted, "g_restarted", "0", CVAR_ROM, 0, qfalse  },
	{ NULL, "sv_mapname", "", CVAR_SERVERINFO | CVAR_ROM, 0, qfalse  },

	// latched vars
	{ &g_gametype, "g_gametype", "0", CVAR_SERVERINFO | CVAR_LATCH | CVAR_INIT | CVAR_ROM, 0, qfalse  },
	{ &g_pModAssimilation, "g_pModAssimilation", "0", CVAR_SERVERINFO | CVAR_LATCH, 0, qfalse  },
	{ &g_pModDisintegration, "g_pModDisintegration", "0", CVAR_SERVERINFO | CVAR_LATCH, 0, qfalse  },
	{ &g_pModActionHero, "g_pModActionHero", "0", CVAR_SERVERINFO | CVAR_LATCH, 0, qfalse  },
	{ &g_pModSpecialties, "g_pModSpecialties", "0", CVAR_SERVERINFO | CVAR_LATCH, 0, qfalse  },
	{ &g_pModElimination, "g_pModElimination", "0", CVAR_SERVERINFO | CVAR_LATCH, 0, qfalse  },

	{ &g_maxclients, "sv_maxclients", "8", CVAR_SERVERINFO | CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse  },
	{ &g_maxGameClients, "g_maxGameClients", "0", CVAR_SERVERINFO | CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse  },

	// change anytime vars
	{ &g_dmflags, "dmflags", "0", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue  },
	{ &g_fraglimit, "fraglimit", "20", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },
	{ &g_timelimit, "timelimit", "0", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },
	{ &g_timelimitWinningTeam, "timelimitWinningTeam", "", CVAR_NORESTART, 0, qtrue },
	{ &g_capturelimit, "capturelimit", "8", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue },

	{ &g_synchronousClients, "g_synchronousClients", "0", CVAR_SYSTEMINFO, 0, qfalse  },

	{ &g_friendlyFire, "g_friendlyFire", "0", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue },

	{ &g_teamAutoJoin, "g_teamAutoJoin", "0", CVAR_ARCHIVE, 0, qfalse },
	{ &g_teamForceBalance, "g_teamForceBalance", "1", CVAR_ARCHIVE, 0, qfalse },

	{ &g_intermissionTime, "g_intermissionTime", "20", CVAR_ARCHIVE, 0, qtrue },
	{ &g_warmup, "g_warmup", "20", CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse },
	{ &g_doWarmup, "g_doWarmup", "0", CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse },
	{ &g_log, "g_log", "", CVAR_ARCHIVE, 0, qfalse  },
	{ &g_logSync, "g_logSync", "0", CVAR_ARCHIVE, 0, qfalse  },

	{ &g_password, "g_password", "", CVAR_USERINFO, 0, qfalse  },

	{ &g_banIPs, "g_banIPs", "", CVAR_ARCHIVE, 0, qfalse  },
	{ &g_filterBan, "g_filterBan", "1", CVAR_ARCHIVE, 0, qfalse  },

	{ &g_banIDs, "g_banIDs", "", CVAR_ARCHIVE, 0, qfalse },

	{ &g_needpass, "g_needpass", "0", CVAR_SERVERINFO | CVAR_ROM, 0, qfalse },

	{ &g_dedicated, "dedicated", "0", 0, 0, qfalse  },

	{ &g_speed, "g_speed", "250", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue  },				// Quake 3 default was 320.
	{ &g_gravity, "g_gravity", "800", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue  },
	{ &g_knockback, "g_knockback", "500", 0, 0, qtrue  },
	{ &g_dmgmult, "g_dmgmult", "1", 0, 0, qtrue  },
	{ &g_weaponRespawn, "g_weaponrespawn", "5", 0, 0, qtrue  },		// Quake 3 default (with 1 ammo weapons) was 5.
	{ &g_adaptRespawn, "g_adaptrespawn", "1", 0, 0, qtrue  },		// Make weapons respawn faster with a lot of players.
	{ &g_forcerespawn, "g_forcerespawn", "0", 0, 0, qtrue },		// Quake 3 default was 20.  This is more "user friendly".
	{ &g_inactivity, "g_inactivity", "0", 0, 0, qtrue },
	{ &g_debugMove, "g_debugMove", "0", 0, 0, qfalse },
	{ &g_debugDamage, "g_debugDamage", "0", 0, 0, qfalse },
	{ &g_debugAlloc, "g_debugAlloc", "0", 0, 0, qfalse },
	{ &g_motd, "g_motd", "", 0, 0, qfalse },

	{ &g_podiumDist, "g_podiumDist", "80", 0, 0, qfalse },
	{ &g_podiumDrop, "g_podiumDrop", "70", 0, 0, qfalse },

	{ &g_allowVote, "g_allowVote", "1", CVAR_SERVERINFO, 0, qfalse },

#if 0
	{ &g_debugForward, "g_debugForward", "0", 0, 0, qfalse },
	{ &g_debugRight, "g_debugRight", "0", 0, 0, qfalse },
	{ &g_debugUp, "g_debugUp", "0", 0, 0, qfalse },
#endif

	{ &g_language, "g_language", "", CVAR_ARCHIVE, 0, qfalse  },

	{ &g_holoIntro, "g_holoIntro", "1", CVAR_ARCHIVE, 0, qfalse},
//	{ &g_ghostRespawn, "g_ghostRespawn", "5", CVAR_ARCHIVE, 0, qfalse},		// How long the player is ghosted, in seconds.
	{ &g_team_group_red, "g_team_group_red", "", CVAR_LATCH, 0, qfalse  },		// Used to have CVAR_ARCHIVE	
	{ &g_team_group_blue, "g_team_group_blue", "", CVAR_LATCH, 0, qfalse  },		// Used to have CVAR_ARCHIVE
	{ &g_random_skin_limit, "g_random_skin_limit", "4", CVAR_ARCHIVE, 0, qfalse },
	{ &g_classChangeDebounceTime, "g_classChangeDebounceTime", "180", CVAR_ARCHIVE, 0, qfalse },
		
//	{ &ui_playerclass, "ui_playerclass", "NOCLASS", CVAR_ARCHIVE, 0, qfalse },
	
	//RPG-X: RedTechie - RPG-X CVARS....duh....just for the slow ones
	{ &rpg_allowvote, "rpg_allowVote", "1", CVAR_ARCHIVE, 0, qfalse },
	{ &rpg_chatsallowed, "rpg_chatsAllowed", "10", CVAR_ARCHIVE, 0, qfalse},
	{ &rpg_allowsuicide, "rpg_allowSuicide", "1", CVAR_ARCHIVE, 0, qfalse},
	{ &rpg_selfdamage, "rpg_selfDamage", "1", CVAR_ARCHIVE, 0, qfalse},
	{ &rpg_rpg, "rpg_rpg", "1", CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse},
	{ &rpg_kickspammers, "rpg_kickSpammers", "0", CVAR_ARCHIVE, 0, qfalse},
	{ &rpg_kicksuiciders, "rpg_kickSuiciders", "0", CVAR_ARCHIVE, 0, qfalse},
	{ &rpg_allowspmaps, "rpg_allowSPMaps", "0", CVAR_ARCHIVE, 0, qfalse},
	{ &rpg_rangetricorder, "rpg_rangeTricorder", "128", CVAR_ARCHIVE, 0, qfalse},
	{ &rpg_rangehypo, "rpg_rangeHypo", "32", CVAR_ARCHIVE, 0, qfalse},
	{ &rpg_norpgclasses, "rpg_noRPGClasses", "0", CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse},
	{ &rpg_forceclasscolor, "rpg_forceClassColor", "0", CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse},
	{ &rpg_nosecurity, "rpg_noSecurity", "0", CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse},
	{ &rpg_nomarine, "rpg_noMarine", "0", CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse},
	{ &rpg_nomedical, "rpg_noMedical", "0", CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse},
	{ &rpg_noscience, "rpg_noScience", "0", CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse},
	{ &rpg_nocommand, "rpg_noCommand", "0", CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse},
	{ &rpg_noengineer, "rpg_noEngineer", "0", CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse},
	{ &rpg_noalien, "rpg_noAlien", "0", CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse},
	{ &rpg_non00b, "rpg_non00b", "0", CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse},
	{ &rpg_nomaker, "rpg_noMaker", "0", CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse},
	{ &rpg_nocloak, "rpg_noCloak", "0", CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse},
	{ &rpg_noflight, "rpg_noFlight", "0", CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse},
	{ &rpg_phaserdmg, "rpg_phaserDmg", "1", CVAR_ARCHIVE, 0, qfalse},
	{ &rpg_rifledmg, "rpg_rifleDmg", "1", CVAR_ARCHIVE, 0, qfalse},
	{ &rpg_stasisdmg, "rpg_stasisDmg", "1", CVAR_ARCHIVE, 0, qfalse},
	{ &rpg_imoddmg, "rpg_imodDmg", "1", CVAR_ARCHIVE, 0, qfalse},
	{ &rpg_noweapons, "rpg_noWeapons", "0", CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse},
	/*{ &rpg_marinepass, "rpg_marinepass", "marine", CVAR_ARCHIVE, 0, qfalse  },
	{ &rpg_securitypass, "rpg_securityPass", "security", CVAR_ARCHIVE, 0, qfalse  },
	{ &rpg_adminpass, "rpg_adminPass", "", CVAR_ARCHIVE, 0, qfalse  },
	{ &rpg_medicalpass, "rpg_medicalPass", "medical", CVAR_ARCHIVE, 0, qfalse  },
	{ &rpg_sciencepass, "rpg_sciencePass", "science", CVAR_ARCHIVE, 0, qfalse  },
	{ &rpg_commandpass, "rpg_commandPass", "command", CVAR_ARCHIVE, 0, qfalse  },
	{ &rpg_engineerpass, "rpg_engineerPass", "engineer", CVAR_ARCHIVE, 0, qfalse  },
	{ &rpg_alienpass, "rpg_alienpass", "alien", CVAR_ARCHIVE, 0, qfalse  },
	{ &rpg_n00bpass, "rpg_n00bpass", "n00b", CVAR_ARCHIVE, 0, qfalse  },
	{ &rpg_alienflags, "rpg_alienFlags", "1026", CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse  }, //16
	//{ &rpg_marineflags, "rpg_marineflags", "8184", CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse  },
	{ &rpg_marineflags, "rpg_marineFlags", "12398", CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse  }, //111
	{ &rpg_securityflags, "rpg_securityFlags", "110", CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse  }, //15
	{ &rpg_adminflags, "rpg_adminFlags", "65534", CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse  }, //24361
	{ &rpg_medicalflags, "rpg_medicalFlags", "14382", CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse  }, //231
	{ &rpg_scienceflags, "rpg_scienceFlags", "46", CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse  }, //7
	{ &rpg_commandflags, "rpg_commandFlags", "62", CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse  }, //6
	{ &rpg_engineerflags, "rpg_engineerFlags", "49198", CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse  }, //775*/
	{ &rpg_welcomemessage, "rpg_welcomeMessage", "Welcome to the RPG-X Mod", CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse  },
//	{ &rpg_timedmessage, "rpg_timedmessage", "Server is in: Character Development Mode", CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse  },
	{ &rpg_timedmessagetime, "rpg_timedMessageTime", "5", CVAR_ARCHIVE, 0, qfalse  }, //TiM : LATCH Not necessary here.
	{ &rpg_message1, "rpg_message1", "", CVAR_ARCHIVE, 0, qfalse  },
	{ &rpg_message2, "rpg_message2", "", CVAR_ARCHIVE, 0, qfalse  },
	{ &rpg_message3, "rpg_message3", "", CVAR_ARCHIVE, 0, qfalse  },
	{ &rpg_message4, "rpg_message4", "", CVAR_ARCHIVE, 0, qfalse  },
	{ &rpg_message5, "rpg_message5", "", CVAR_ARCHIVE, 0, qfalse  },
	{ &rpg_message6, "rpg_message6", "", CVAR_ARCHIVE, 0, qfalse  },
	{ &rpg_message7, "rpg_message7", "", CVAR_ARCHIVE, 0, qfalse  },
	{ &rpg_message8, "rpg_message8", "", CVAR_ARCHIVE, 0, qfalse  },
	{ &rpg_message9, "rpg_message9", "", CVAR_ARCHIVE, 0, qfalse  },
	{ &rpg_message10, "rpg_message10", "", CVAR_ARCHIVE, 0, qfalse  },
	{ &rpg_forcekillradius, "rpg_forceKillRadius", "0", CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue},
	{ &rpg_forcekillradiuswaittime, "rpg_forceKillRadiusWaitTime", "45000", CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse},
	//{ &rpg_noclipspectating, "rpg_noclipSpectating", "1", CVAR_ARCHIVE, 0, qtrue},		//Not latched (ie doesnt need server restart)
	{ &rpg_chatarearange, "rpg_chatAreaRange", "200", CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue},	//Not latched (ie doesnt need server restart)
	{ &rpg_forcefielddamage, "rpg_forcefieldDamage", "0", CVAR_ARCHIVE, 0, qfalse},
	{ &rpg_invisibletripmines, "rpg_invisibleTripmines", "1", CVAR_ARCHIVE | CVAR_SERVERINFO, 0, qfalse},
	{ &rpg_medicsrevive, "rpg_medicsRevive", "1", CVAR_ARCHIVE | CVAR_LATCH, 0, qfalse},
	{ &rpg_effectsgun, "rpg_effectsGun", "1", CVAR_ARCHIVE | CVAR_SERVERINFO, 0, qfalse},
	{ &rpg_phaserdisintegrates, "rpg_phaserDisintegrates", "1", CVAR_ARCHIVE, 0, qfalse},
	//{ &rpg_servershakeallclients, "rpg_serverShakeAllClients", "0", CVAR_ARCHIVE | CVAR_SERVERINFO, 0, qfalse}, //RPG-X: RedTechie - SHould not be used directly this is to shake allll clients views if set on
	//{ &rpg_servershakeallclientsintensity, "rpg_serverShakeAllClientsIntensity", "2", CVAR_ARCHIVE | CVAR_SERVERINFO, 0, qfalse}, //RPG-X: RedTechie - SHould not be used directly this is to shake allll clients views itensity
	//{ &rpg_enabledranks, "rpg_enabledRanks", "65535", CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse},//RPG-X: RedTechie - This use to be CVAR_ROM jason i have no idea why you set it to read only but im setting it back to normal to fix ranks
	{ &rpg_kickAfterXkills, "rpg_kickAfterNumkills", "2", CVAR_ARCHIVE, 0, qfalse }, //RPG-X | Phenix | 06/04/2005
	{ &rpg_rankSet, "rpg_rankSet", RANKSET_DEFAULT, CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_LATCH, 0, qfalse },

	{ &rpg_passMessage, "rpg_passMessage", "", CVAR_ARCHIVE, 0, qfalse },
	{ &rpg_renamedPlayers, "rpg_renamedPlayers", "1", CVAR_ARCHIVE, 0, qfalse },
	{ &rpg_uniqueNames, "rpg_uniqueNames", "1", CVAR_ARCHIVE, 0, qfalse },
	{ &rpg_startingRank, "rpg_startingRank", "", CVAR_ARCHIVE, 0, qfalse },
	{ &rpg_maxRank,	"rpg_maxRank", "", CVAR_ARCHIVE | CVAR_SERVERINFO, 0, qfalse },
	{ &rpg_changeRanks, "rpg_changeRanks", "1", CVAR_ARCHIVE, 0, qfalse },
	{ &rpg_classSet, "rpg_classSet", "rpgx_default", CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_LATCH, 0, qfalse },

	{ &rpg_maxHeight, "rpg_maxHeight", "1.15", CVAR_ARCHIVE, 0, qfalse },
	{ &rpg_minHeight, "rpg_minHeight", "0.90", CVAR_ARCHIVE, 0, qfalse },
	{ &rpg_maxWeight, "rpg_maxWeight", "1.10", CVAR_ARCHIVE, 0, qfalse },
	{ &rpg_minWeight, "rpg_minWeight", "0.90", CVAR_ARCHIVE, 0, qfalse },

	{ &rpg_mapGiveFlags, "rpg_mapGiveFlags", "0", CVAR_ARCHIVE | CVAR_LATCH, 0, qfalse },

	//TiM - maybe we can fix it later, but for now, disable it
	{ &rpg_scannablePanels, "rpg_scannablePanels", "1", CVAR_ARCHIVE | CVAR_LATCH | CVAR_SERVERINFO, 0, qfalse },
	//{ &rpg_scannableForceField, "rpg_scannableForceField", "1", CVAR_ARCHIVE, 0, qfalse }, //RPG-X | GSIO01 | 13/05/2009
    { &rpg_allowWeaponDrop, "rpg_allowWeaponDrop", "1", CVAR_ARCHIVE, 0, qfalse }, // RPG-X | Marcin | 03/12/2008
    { &rpg_weaponsStay, "rpg_weaponsStay", "0", CVAR_ARCHIVE, 0, qfalse },         // RPG-X | Marcin | 04/12/2008
    { &rpg_rifleSpeed, "rpg_rifleSpeed", "2700", 0, 0, qtrue },        // RPG-X | Marcin | 04/12/2008
    { &rpg_disruptorSpeed, "rpg_disruptorSpeed", "3000", 0, 0, qtrue },// RPG-X | Marcin | 04/12/2008
    { &rpg_photonSpeed, "rpg_photonSpeed", "1300", 0, 0, qtrue },      // RPG-X | Marcin | 05/12/2008
    { &rpg_altPhotonSpeed, "rpg_altPhotonSpeed", "650", 0, 0, qtrue }, // RPG-X | Marcin | 06/12/2008
    { &rpg_rifleDelay, "rpg_rifleDelay", "250", 0, 0, qtrue },         // RPG-X | Marcin | 06/12/2008
    { &rpg_disruptorDelay, "rpg_disruptorDelay", "700", 0, 0, qtrue }, // RPG-X | Marcin | 06/12/2008
    { &rpg_photonDelay, "rpg_photonDelay", "1200", 0, 0, qtrue },      // RPG-X | Marcin | 06/12/2008
    { &rpg_altPhotonDelay, "rpg_altPhotonDelay", "1600", 0, 0, qtrue },// RPG-X | Marcin | 06/12/2008
	{ &rpg_TR116Delay, "rpg_TR116Delay", "500", 0, 0, qtrue },		   // RPG-X | Marcin | 30/12/2008
	{ &rpg_motdFile, "rpg_motdFile", "RPG-X_Motd.txt", CVAR_ARCHIVE | CVAR_LATCH, 0, qfalse },		// RPG-X | Marcin | 23/12/2008
	{ &rpg_respectPrivacy, "rpg_respectPrivacy", "0", CVAR_ARCHIVE | CVAR_SERVERINFO , 0, qfalse },	// RPG-X | Marcin | 24/12/2008
	{ &rpg_maxTricorders, "rpg_maxTricorders", "1", CVAR_ARCHIVE, 0, qtrue },						// RPG-X | Marcin | 30/12/2008
	{ &rpg_maxPADDs, "rpg_maxPADDs", "10", CVAR_ARCHIVE, 0, qtrue },								// RPG-X | Marcin | 30/12/2008
	{ &rpg_maxCups, "rpg_maxCups", "2", CVAR_ARCHIVE, 0, qtrue },									// RPG-X | Marcin | 30/12/2008
	{ &rpg_maxPhasers, "rpg_maxPhasers", "1", CVAR_ARCHIVE, 0, qtrue },								// RPG-X | Marcin | 30/12/2008
	{ &rpg_maxRifles, "rpg_maxRifles", "1", CVAR_ARCHIVE, 0, qtrue },								// RPG-X | Marcin | 30/12/2008
	{ &rpg_maxTR116s, "rpg_maxTR116s", "1", CVAR_ARCHIVE, 0, qtrue },								// RPG-X | Marcin | 30/12/2008
	{ &rpg_maxAdminguns, "rpg_maxAdminguns", "1", CVAR_ARCHIVE, 0, qtrue },							// RPG-X | Marcin | 30/12/2008
	{ &rpg_maxPhotonbursts, "rpg_maxPhotonbursts", "1", CVAR_ARCHIVE, 0, qtrue },					// RPG-X | Marcin | 30/12/2008
	{ &rpg_maxDisruptors, "rpg_maxDisruptors", "1", CVAR_ARCHIVE, 0, qtrue },						// RPG-X | Marcin | 30/12/2008
	{ &rpg_maxMedkits, "rpg_maxMedkits", "1", CVAR_ARCHIVE, 0, qtrue },								// RPG-X | Marcin | 30/12/2008
	{ &rpg_maxHyposprays, "rpg_maxHyposprays", "2", CVAR_ARCHIVE, 0, qtrue },						// RPG-X | Marcin | 30/12/2008
	{ &rpg_maxRegenerators, "rpg_maxRegenerators", "1", CVAR_ARCHIVE, 0, qtrue },					// RPG-X | Marcin | 30/12/2008
	{ &rpg_maxToolkits, "rpg_maxToolkits", "1", CVAR_ARCHIVE, 0, qtrue },							// RPG-X | Marcin | 30/12/2008
	{ &rpg_maxHyperSpanners, "rpg_maxHyperSpanners", "1", CVAR_ARCHIVE, 0, qtrue },					// RPG-X | Marcin | 30/12/2008
	{ &rpg_minTricorders, "rpg_minTricorders", "1", CVAR_ARCHIVE, 0, qtrue },						// RPG-X | Marcin | 30/12/2008
	{ &rpg_minPADDs, "rpg_minPADDs", "5", CVAR_ARCHIVE, 0, qtrue },									// RPG-X | Marcin | 30/12/2008
	{ &rpg_minCups, "rpg_minCups", "1", CVAR_ARCHIVE, 0, qtrue },									// RPG-X | Marcin | 30/12/2008
	{ &rpg_minPhasers, "rpg_minPhasers", "1", CVAR_ARCHIVE, 0, qtrue },								// RPG-X | Marcin | 30/12/2008
	{ &rpg_minRifles, "rpg_minRifles", "1", CVAR_ARCHIVE, 0, qtrue },								// RPG-X | Marcin | 30/12/2008
	{ &rpg_minTR116s, "rpg_minTR116s", "1", CVAR_ARCHIVE, 0, qtrue },								// RPG-X | Marcin | 30/12/2008
	{ &rpg_minAdminguns, "rpg_minAdminguns", "1", CVAR_ARCHIVE, 0, qtrue },							// RPG-X | Marcin | 30/12/2008
	{ &rpg_minPhotonbursts, "rpg_minPhotonbursts", "1", CVAR_ARCHIVE, 0, qtrue },					// RPG-X | Marcin | 30/12/2008
	{ &rpg_minDisruptors, "rpg_minDisruptors", "1", CVAR_ARCHIVE, 0, qtrue },						// RPG-X | Marcin | 30/12/2008
	{ &rpg_minMedkits, "rpg_minMedkits", "1", CVAR_ARCHIVE, 0, qtrue },								// RPG-X | Marcin | 30/12/2008
	{ &rpg_minHyposprays, "rpg_minHyposprays", "1", CVAR_ARCHIVE, 0, qtrue },						// RPG-X | Marcin | 30/12/2008
	{ &rpg_minRegenerators, "rpg_minRegenerators", "1", CVAR_ARCHIVE, 0, qtrue },					// RPG-X | Marcin | 30/12/2008
	{ &rpg_minToolkits, "rpg_minToolkits", "1", CVAR_ARCHIVE, 0, qtrue },							// RPG-X | Marcin | 30/12/2008
	{ &rpg_minHyperSpanners, "rpg_minHyperSpanners", "1", CVAR_ARCHIVE, 0, qtrue },					// RPG-X | Marcin | 30/12/2008
    { &rpg_dropOnDeath, "rpg_dropItemsOnDeath", "1", CVAR_ARCHIVE, 0, qfalse },						// RPG-X | Marcin | 30/12/2008
	{ &rpg_fraggerSpawnDelay, "rpg_fraggerSpawnDelay", "100", CVAR_ARCHIVE, 0, qfalse },
	{ &rpg_borgAdapt, "rpg_borgAdapt", "0", CVAR_ARCHIVE, 0, qfalse },
	//{ &rpg_flushDroppedOnDisconnect, "rpg_flushDroppedOnDisconnect", "1", CVAR_ARCHIVE, 0, qfalse }
	{ &rpg_hypoMelee, "rpg_hypoMelee", "0", CVAR_ARCHIVE, 0, qfalse },
	{ &rpg_adaptUseSound, "rpg_adaptUseSound", "0", CVAR_ARCHIVE, 0, qfalse },
	{ &rpg_adaptCrifleHits, "rpg_adaptCrifleHits", "6", CVAR_ARCHIVE, 0, qfalse },
	{ &rpg_adaptDisruptorHits, "rpg_adaptDisruptorHits", "6", CVAR_ARCHIVE, 0, qfalse },
	{ &rpg_adaptPhaserHits, "rpg_adaptPhaserHits", "6", CVAR_ARCHIVE, 0, qfalse },
	{ &rpg_adaptPhotonHits, "rpg_adaptPhotonHits", "6", CVAR_ARCHIVE, 0, qfalse },
	{ &rpg_adaptTR116Hits, "rpg_adaptTR116Hits", "6", CVAR_ARCHIVE, 0, qfalse },
	{ &rpg_adaptGrenadeLauncherHits, "rpg_adaptGrenadeLauncherHits", "6", CVAR_ARCHIVE, 0, qfalse },
	{ &rpg_repairModifier, "rpg_repairModifier", "1", CVAR_ARCHIVE, 0, qfalse },
	{ &rpg_forceFieldColor, "rpg_forceFieldColor", "0", CVAR_ARCHIVE, 0, qfalse },
	{ &rpg_allowRemodulation, "rpg_allowRemodulation", "1", CVAR_ARCHIVE, 0, qfalse },
	{ &rpg_forceFieldFreq, "rpg_forceFieldFreq", "0", CVAR_ARCHIVE, 0, qfalse },
	{ &rpg_calcLiftTravelDuration, "rpg_calcLiftTravelDuration", "0", CVAR_ARCHIVE, 0, qfalse },
	{ &rpg_liftDurationModifier, "rpg_liftDurationModifier" , "0.5", CVAR_ARCHIVE, 0, qfalse },
	{ &rpg_altTricorderDelay, "rpg_altTricorderDelay", "1000", CVAR_ARCHIVE, 0, qfalse },
	{ &rpg_borgMoveThroughFields, "rpg_borgMoveThroughFields", "0", CVAR_ARCHIVE, 0, qfalse },
	{ &rpg_RemodulationDelay, "rpg_RemodulationDelay", "5000", CVAR_ARCHIVE, 0, qfalse },
	{ &rpg_adminVoteOverride, "rpg_adminVoteOverride", "1", CVAR_ARCHIVE, 0, qfalse },
	{ &rpg_serverchange, "rpg_serverchange", "0", CVAR_ARCHIVE, 0, qfalse },
	{ &rpg_server1, "rpg_server1", "0", CVAR_ARCHIVE, 0, qfalse },
	{ &rpg_server2, "rpg_server2", "0", CVAR_ARCHIVE, 0, qfalse },
	{ &rpg_server3, "rpg_server3", "0", CVAR_ARCHIVE, 0, qfalse },
	{ &rpg_server4, "rpg_server4", "0", CVAR_ARCHIVE, 0, qfalse },
	{ &rpg_server5, "rpg_server5", "0", CVAR_ARCHIVE, 0, qfalse },
	{ &rpg_server6, "rpg_server6", "0", CVAR_ARCHIVE, 0, qfalse },
	{ &rpg_allowSPLevelChange, "rpg_allowSPLevelChange", "1", CVAR_ARCHIVE | CVAR_LATCH, 0, qfalse },
	//XPERIMENTAL
	//{ &rpg_useLanguages, "rpg_useLanguages", "1", CVAR_ARCHIVE, 0, qfalse }
	
	{ &dev_showTriggers, "dev_showTriggers", "0", CVAR_ARCHIVE, 0, qfalse }

#ifdef XTRA
	,
	{ &sql_dbName, "sql_dbName", "rpgx", CVAR_ARCHIVE, 0, qfalse },
	{ &sql_use, "sql_use", "0", CVAR_ARCHIVE, 0, qfalse },
	{ &sql_password, "sql_password", "", CVAR_ARCHIVE, 0, qfalse },
	{ &sql_port, "sql_port", "3306", CVAR_ARCHIVE, 0, qfalse },
	{ &sql_server, "sql_server", "", CVAR_ARCHIVE, 0, qfalse },
	{ &sql_user, "sql_user", "rpgx", CVAR_ARCHIVE, 0, qfalse },
	{ &sql_hash, "sql_hash", "0", CVAR_ARCHIVE, 0, qfalse }
#endif

#ifdef G_LUA
	,
	{ &g_debugLua, "g_debugLua", "0", 0, 0, qfalse },
	{ &lua_allowedModules, "lua_allowedModules", "", 0, 0, qfalse },
	{ &lua_modules, "lua_modules", "", 0, 0, qfalse }
#endif

};

static int	gameCvarTableSize = sizeof( gameCvarTable ) / sizeof( gameCvarTable[0] );

void G_InitGame( int levelTime, int randomSeed, int restart );
void G_RunFrame( int levelTime );
void G_ShutdownGame( int restart );
void CheckExitRules( void );

//=============================
//** begin code

/*
================
vmMain

This is the only way control passes into the module.
This MUST be the very first function compiled into the .q3vm file
================
*/
//intptr_t
intptr_t vmMain( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6 ) {
	switch ( command ) {
	case GAME_INIT:
		G_InitGame( arg0, arg1, arg2 );
		return 0;
	case GAME_SHUTDOWN:
		G_ShutdownGame( arg0 );
		return 0;
	case GAME_CLIENT_CONNECT:
		return (size_t)ClientConnect( arg0, arg1, arg2 );
	case GAME_CLIENT_THINK:
		ClientThink( arg0 );
		return 0;
	case GAME_CLIENT_USERINFO_CHANGED:
		ClientUserinfoChanged( arg0 ); //TiM - this means a user just tried to change it
		return 0;
	case GAME_CLIENT_DISCONNECT:
		ClientDisconnect( arg0 );
		return 0;
	case GAME_CLIENT_BEGIN:
		ClientBegin( arg0, qtrue, qfalse, qtrue );
		return 0;
	case GAME_CLIENT_COMMAND:
		ClientCommand( arg0 );
		return 0;
	case GAME_RUN_FRAME:
		G_RunFrame( arg0 );
		return 0;
	case GAME_CONSOLE_COMMAND:
		//RPG-X : TiM - plagiarised Red's logic from SFEFMOD here lol
		return ConsoleCommand();
		//return ConsoleCommand();
	case BOTAI_START_FRAME:
		return BotAIStartFrame( arg0 );
	}

	return -1;
}

void QDECL G_PrintfClientAll(const char *fmt, ...) {
	va_list argptr;
	char	text[1024];

	va_start (argptr, fmt);
	vsprintf (text, fmt, argptr);
	va_end	 (argptr);

	trap_SendServerCommand(-1, va("print \"%s\n\"", text));
}

void QDECL G_PrintfClient(gentity_t *ent, const char *fmt, ...) {
	va_list		argptr;
	char		text[1024];

	va_start (argptr, fmt);
	vsprintf (text, fmt, argptr);
	va_end	 (argptr);

	#ifdef G_LUA
	LuaHook_G_ClientPrint(text, ent);
	#endif
	
	trap_SendServerCommand(ent-g_entities, va("print \"%s\n\"", text));
}

void QDECL G_Printf( const char *fmt, ... ) {
	va_list		argptr;
	char		text[1024];

	va_start (argptr, fmt);
	vsprintf (text, fmt, argptr);
	va_end (argptr);

	#ifdef G_LUA
	// Lua API callbacks
	LuaHook_G_Print(text);
	#endif

	trap_Printf( text );
}

void QDECL G_Error( const char *fmt, ... ) {
	va_list		argptr;
	char		text[1024];

	va_start (argptr, fmt);
	vsprintf (text, fmt, argptr);
	va_end (argptr);

	#ifdef G_LUA
	G_LuaShutdown();
	#endif

	trap_Error( text );
}

stringID_table_t WeaponTable[] = {

	{ ENUM2STRING(WP_TRICORDER) },
	{ ENUM2STRING(WP_PADD) },
	{ ENUM2STRING(WP_COFFEE) },				

	{ ENUM2STRING(WP_PHASER) },				
	{ ENUM2STRING(WP_COMPRESSION_RIFLE) },	
	{ ENUM2STRING(WP_TR116) },

	{ ENUM2STRING(WP_GRENADE_LAUNCHER) },
	{ ENUM2STRING(WP_QUANTUM_BURST) },		
	{ ENUM2STRING(WP_DISRUPTOR) },			

	{ ENUM2STRING(WP_MEDKIT) },				
	{ ENUM2STRING(WP_VOYAGER_HYPO) },		
	{ ENUM2STRING(WP_DERMAL_REGEN) },		
	
	{ ENUM2STRING(WP_TOOLKIT) },				
	{ ENUM2STRING(WP_HYPERSPANNER) },
	{ NULL, -1 }
};

/**************************
G_LoadClassData

TiM: Loads a ".class" file
and parses the class data
for utilization on the server
and transfer to clients
**************************/
#ifdef Q3_VM
static qboolean G_LoadClassData( char* fileName )
{
	char			buffer[32000];
	char			*textPtr, *token;
	int				fileLen;
	fileHandle_t	f;
	qboolean		classValid=qfalse;
	int				classIndex=0;
	int				weapon;
	int				i;

	//Init the storage place
	memset( &g_classData, 0, sizeof ( g_classData ) );
	
	fileLen = trap_FS_FOpenFile( fileName, &f, FS_READ );

	if ( !f ) {
		G_Printf( S_COLOR_RED "ERROR: File %s not found.\n", fileName );
		return qfalse;
	}

	if ( fileLen >= sizeof( buffer ) ) {
		G_Printf( S_COLOR_RED "ERROR: File %s was way too big.\n", fileName );
		trap_FS_FCloseFile( f );
		return qfalse;
	}

	trap_FS_Read( buffer, fileLen, f );
	buffer[fileLen] = 0;
	trap_FS_FCloseFile( f );

	COM_BeginParseSession();

	textPtr = buffer;

	token = COM_Parse( &textPtr );

	if ( !token[0] ) {
		G_Printf( S_COLOR_RED "ERROR: No data was found when going to parse the file!\n" );
		return qfalse;
	}

	if ( Q_stricmpn( token, "{", 1 ) ) {
		G_Printf( S_COLOR_RED "ERROR: File did not start with a '{' symbol!\n" );
		return qfalse;
	}

	while ( 1 ) 
	{
		if ( classIndex >= MAX_CLASSES )
			break;

		if ( !Q_stricmpn( token, "{", 1 ) ) 
		{
			while ( 1 ) 
			{
				token = COM_Parse( &textPtr );
				if (!token[0]) {
					break;
				}				

				if ( !Q_stricmpn( token, "consoleName", 11 ) )
				{
					if ( COM_ParseString( &textPtr, &token ) ) 
					{
						G_Printf( S_COLOR_RED "ERROR: Invalid class console name in class index: %i.\n", classIndex );
						SkipBracedSection( &textPtr );
						continue;
					}

					Q_strncpyz( g_classData[classIndex].consoleName, token, sizeof( g_classData[classIndex].consoleName ) );
					classValid = qtrue;
					
					//G_Printf( S_COLOR_RED "%s\n", g_classData[classIndex].consoleName );

					continue;
				}

				if ( !Q_stricmpn( token, "formalName", 11 ) )
				{
					if ( COM_ParseString( &textPtr, &token ) ) 
					{
						G_Printf( S_COLOR_RED "ERROR: Invalid class formal name in class index: %i.\n", classIndex );
						SkipBracedSection( &textPtr );
						continue;
					}

					Q_strncpyz( g_classData[classIndex].formalName, token, sizeof( g_classData[classIndex].formalName ) );
					classValid = qtrue;
					
					//G_Printf( S_COLOR_RED "%s\n", g_classData[classIndex].consoleName );

					continue;
				}

				if ( !Q_stricmpn( token, "message", 7 ) ) 
				{
					if ( COM_ParseString( &textPtr, &token ) ) 
					{
						G_Printf( S_COLOR_RED "ERROR: Invalid class message in class index: %i.\n", classIndex );
						continue;
					}

					Q_strncpyz( g_classData[classIndex].message, token, sizeof( g_classData[classIndex].message ) );
					continue;					
				}

				if ( !Q_stricmpn( token, "modelSkin", 9 ) ) 
				{
					if ( COM_ParseString( &textPtr, &token ) ) 
					{
						G_Printf( S_COLOR_RED "ERROR: Invalid class skin color in class index: %i.\n", classIndex );
						continue;
					}

					Q_strncpyz( g_classData[classIndex].modelSkin, token, sizeof( g_classData[classIndex].modelSkin ) );
					continue;
				}

				if ( !Q_stricmpn( token, "weapons", 7) ) 
				{
					token = COM_Parse( &textPtr );

					if ( Q_stricmpn( token, "{", 1 ) ) 
					{
						G_Printf( S_COLOR_RED "No opening bracket found for weapons field in class: %i.\n", classIndex );
						SkipRestOfLine( &textPtr );
						continue;
					}

					//sub loop
					while ( 1 ) 
					{
						token = COM_Parse( &textPtr );

						if ( !token[0] )
							break;
						
						if ( !Q_stricmpn( token, "|", 1 ) )
							continue;

						if ( !Q_stricmpn( token, "}", 1 ) )
							break;

						if( !Q_stricmpn( token, "WP_", 3 ) ) 
						{
							weapon = GetIDForString( WeaponTable, token );

							if ( weapon >= 0 ) 
							{
								g_classData[classIndex].weaponsFlags |= ( 1 << weapon );
								continue;
							}
						}
					}

					continue;
				}

				if ( !Q_stricmpn( token, "admin", 5 ) ) 
				{
					if ( COM_ParseInt( &textPtr, &g_classData[classIndex].isAdmin ) ) 
					{
						G_Printf( S_COLOR_RED "ERROR: Class admin check for class %i was invalid.\n", classIndex );
						continue;
					}

					continue;
				}

				if ( !Q_stricmpn( token, "marine", 6 ) ) 
				{
					if ( COM_ParseInt( &textPtr, &g_classData[classIndex].isMarine ) ) 
					{
						G_Printf( S_COLOR_RED "ERROR: Class marine check for class %i was invalid.\n", classIndex );
						continue;
					}

					continue;
				}

				if ( !Q_stricmpn( token, "medical", 7 ) ) 
				{
					if ( COM_ParseInt( &textPtr, &g_classData[classIndex].isMedical ) ) 
					{
						G_Printf( S_COLOR_RED "ERROR: Class medic check for class %i was invalid.\n", classIndex );
						continue;
					}

					continue;
				}

				if( !Q_stricmpn( token, "isBorg", 6 ) )
				{
					if( COM_ParseInt( &textPtr, &g_classData[classIndex].isBorg ) )
					{
						G_Printf( S_COLOR_RED "ERROR: Class borg check for class %i was invalid.\n", classIndex );
						continue;
					}
					continue;
				}

				if ( !Q_stricmpn( token, "n00b", 4 ) ) 
				{
					if ( COM_ParseInt( &textPtr, &g_classData[classIndex].isn00b ) ) 
					{
						G_Printf( S_COLOR_RED "ERROR: Class n00b check for class %i was invalid.\n", classIndex );
						continue;
					}

					continue;
				}

				//skip the client-side specific entries since they interfere with the parsing
				if ( !Q_stricmpn( token, "radarColor", 10 ) 
					|| !Q_stricmpn( token, "iconColor", 9 ) 
					|| !Q_stricmpn( token, "hasRanks", 8 ) 
					|| !Q_stricmpn( token, "noShow", 6 )
					)
				{
					SkipRestOfLine( &textPtr );
					continue;
				}

				if ( !Q_stricmpn( token, "}", 1 ) ) 
				{
					break;
				}
			}

			
			if ( classValid ) 
			{
				classIndex++;
				classValid = qfalse;
			}
		}
		
		token = COM_Parse( &textPtr );	
		if (!token[0]) 
		{
			break;
		}
	}

	//build ourselves custom CVARs for each class
	for ( i=0; g_classData[i].consoleName[0] && i < MAX_CLASSES; i++ ) 
	{
		trap_Cvar_Register( NULL, va("rpg_%sPass", g_classData[i].consoleName ), g_classData[i].consoleName, CVAR_ARCHIVE );
		trap_Cvar_Register( NULL, va("rpg_%sFlags", g_classData[i].consoleName ), va("%i", g_classData[i].weaponsFlags), CVAR_ARCHIVE );
	}

	if ( classIndex > 0 ) 
	{
		return qtrue;
	}
	else 
	{
		G_Printf( S_COLOR_RED "ERROR: No valid classes were found.\n");
		return qfalse;
	}
}
#else
static qboolean G_LoadClassData( char* fileName )
{
	char			*buffer;
	char			*textPtr, *token;
	int				fileLen;
	fileHandle_t	f;
	qboolean		classValid=qfalse;
	int				classIndex=0;
	int				weapon;
	int				i;

	//Init the storage place
	memset( &g_classData, 0, sizeof ( g_classData ) );
	
	fileLen = trap_FS_FOpenFile( fileName, &f, FS_READ );

	if ( !f ) {
		G_Printf( S_COLOR_RED "ERROR: File %s not found.\n", fileName );
		return qfalse;
	}

	if ( fileLen >= 32000 ) {
		G_Printf( S_COLOR_RED "ERROR: File %s was way too big.\n", fileName );
		trap_FS_FCloseFile( f );
		return qfalse;
	}

	buffer = (char *)malloc(32000 * sizeof(char));

	if(!buffer) {
		G_Printf( S_COLOR_RED "ERROR: Was unable to allocate %i bytes.\n", 32000 * sizeof(char) );
		trap_FS_FCloseFile( f );
		return qfalse;
	}

	trap_FS_Read( buffer, fileLen, f );
	buffer[fileLen] = 0;
	trap_FS_FCloseFile( f );

	COM_BeginParseSession();

	textPtr = buffer;

	token = COM_Parse( &textPtr );

	if ( !token[0] ) {
		G_Printf( S_COLOR_RED "ERROR: No data was found when going to parse the file!\n" );
		free(buffer);
		return qfalse;
	}

	if ( Q_stricmpn( token, "{", 1 ) ) {
		G_Printf( S_COLOR_RED "ERROR: File did not start with a '{' symbol!\n" );
		free(buffer);
		return qfalse;
	}

	while ( 1 ) 
	{
		if ( classIndex >= MAX_CLASSES )
			break;

		if ( !Q_stricmpn( token, "{", 1 ) ) 
		{
			while ( 1 ) 
			{
				token = COM_Parse( &textPtr );
				if (!token[0]) {
					break;
				}				

				if ( !Q_stricmpn( token, "consoleName", 11 ) )
				{
					if ( COM_ParseString( &textPtr, &token ) ) 
					{
						G_Printf( S_COLOR_RED "ERROR: Invalid class console name in class index: %i.\n", classIndex );
						SkipBracedSection( &textPtr );
						continue;
					}

					Q_strncpyz( g_classData[classIndex].consoleName, token, sizeof( g_classData[classIndex].consoleName ) );
					classValid = qtrue;
					
					//G_Printf( S_COLOR_RED "%s\n", g_classData[classIndex].consoleName );

					continue;
				}

				if ( !Q_stricmpn( token, "formalName", 11 ) )
				{
					if ( COM_ParseString( &textPtr, &token ) ) 
					{
						G_Printf( S_COLOR_RED "ERROR: Invalid class formal name in class index: %i.\n", classIndex );
						SkipBracedSection( &textPtr );
						continue;
					}

					Q_strncpyz( g_classData[classIndex].formalName, token, sizeof( g_classData[classIndex].formalName ) );
					classValid = qtrue;
					
					//G_Printf( S_COLOR_RED "%s\n", g_classData[classIndex].consoleName );

					continue;
				}

				if ( !Q_stricmpn( token, "message", 7 ) ) 
				{
					if ( COM_ParseString( &textPtr, &token ) ) 
					{
						G_Printf( S_COLOR_RED "ERROR: Invalid class message in class index: %i.\n", classIndex );
						continue;
					}

					Q_strncpyz( g_classData[classIndex].message, token, sizeof( g_classData[classIndex].message ) );
					continue;					
				}

				if ( !Q_stricmpn( token, "modelSkin", 9 ) ) 
				{
					if ( COM_ParseString( &textPtr, &token ) ) 
					{
						G_Printf( S_COLOR_RED "ERROR: Invalid class skin color in class index: %i.\n", classIndex );
						continue;
					}

					Q_strncpyz( g_classData[classIndex].modelSkin, token, sizeof( g_classData[classIndex].modelSkin ) );
					continue;
				}

				if ( !Q_stricmpn( token, "weapons", 7) ) 
				{
					token = COM_Parse( &textPtr );

					if ( Q_stricmpn( token, "{", 1 ) ) 
					{
						G_Printf( S_COLOR_RED "No opening bracket found for weapons field in class: %i.\n", classIndex );
						SkipRestOfLine( &textPtr );
						continue;
					}

					//sub loop
					while ( 1 ) 
					{
						token = COM_Parse( &textPtr );

						if ( !token[0] )
							break;
						
						if ( !Q_stricmpn( token, "|", 1 ) )
							continue;

						if ( !Q_stricmpn( token, "}", 1 ) )
							break;

						if( !Q_stricmpn( token, "WP_", 3 ) ) 
						{
							weapon = GetIDForString( WeaponTable, token );

							if ( weapon >= 0 ) 
							{
								g_classData[classIndex].weaponsFlags |= ( 1 << weapon );
								continue;
							}
						}
					}

					continue;
				}

				if ( !Q_stricmpn( token, "admin", 5 ) ) 
				{
					if ( COM_ParseInt( &textPtr, &g_classData[classIndex].isAdmin ) ) 
					{
						G_Printf( S_COLOR_RED "ERROR: Class admin check for class %i was invalid.\n", classIndex );
						continue;
					}

					continue;
				}

				if ( !Q_stricmpn( token, "marine", 6 ) ) 
				{
					if ( COM_ParseInt( &textPtr, &g_classData[classIndex].isMarine ) ) 
					{
						G_Printf( S_COLOR_RED "ERROR: Class marine check for class %i was invalid.\n", classIndex );
						continue;
					}

					continue;
				}

				if ( !Q_stricmpn( token, "medical", 7 ) ) 
				{
					if ( COM_ParseInt( &textPtr, &g_classData[classIndex].isMedical ) ) 
					{
						G_Printf( S_COLOR_RED "ERROR: Class medic check for class %i was invalid.\n", classIndex );
						continue;
					}

					continue;
				}

				if( !Q_stricmpn( token, "isBorg", 6 ) )
				{
					if( COM_ParseInt( &textPtr, &g_classData[classIndex].isBorg ) )
					{
						G_Printf( S_COLOR_RED "ERROR: Class borg check for class %i was invalid.\n", classIndex );
						continue;
					}
					continue;
				}

				if ( !Q_stricmpn( token, "n00b", 4 ) ) 
				{
					if ( COM_ParseInt( &textPtr, &g_classData[classIndex].isn00b ) ) 
					{
						G_Printf( S_COLOR_RED "ERROR: Class n00b check for class %i was invalid.\n", classIndex );
						continue;
					}

					continue;
				}

				//skip the client-side specific entries since they interfere with the parsing
				if ( !Q_stricmpn( token, "radarColor", 10 ) 
					|| !Q_stricmpn( token, "iconColor", 9 ) 
					|| !Q_stricmpn( token, "hasRanks", 8 ) 
					|| !Q_stricmpn( token, "noShow", 6 )
					)
				{
					SkipRestOfLine( &textPtr );
					continue;
				}

				if ( !Q_stricmpn( token, "}", 1 ) ) 
				{
					break;
				}
			}

			
			if ( classValid ) 
			{
				classIndex++;
				classValid = qfalse;
			}
		}
		
		token = COM_Parse( &textPtr );	
		if (!token[0]) 
		{
			break;
		}
	}

	free(buffer);

	//build ourselves custom CVARs for each class
	for ( i=0; g_classData[i].consoleName[0] && i < MAX_CLASSES; i++ ) 
	{
		trap_Cvar_Register( NULL, va("rpg_%sPass", g_classData[i].consoleName ), g_classData[i].consoleName, CVAR_ARCHIVE );
		trap_Cvar_Register( NULL, va("rpg_%sFlags", g_classData[i].consoleName ), va("%i", g_classData[i].weaponsFlags), CVAR_ARCHIVE );
	}

	if ( classIndex > 0 ) 
	{
		return qtrue;
	}
	else 
	{
		G_Printf( S_COLOR_RED "ERROR: No valid classes were found.\n");
		return qfalse;
	}
}
#endif

void BG_LanguageFilename(char *baseName,char *baseExtension,char *finalName);
void SP_target_location (gentity_t *ent);

holoData_t holoData;

#ifdef Q3_VM
void G_LoadHolodeckFile(void) {
	char			fileRoute[MAX_QPATH];
	char			mapRoute[MAX_QPATH];
	char			info[MAX_INFO_STRING];
	fileHandle_t	f;
	char			buffer[20000];
	int				file_len;
	char			*txtPtr, *token;
	int				numProgs = 0;
	int				i;

	//get the map name out of the server data
	trap_GetServerinfo( info, sizeof( info ) );

	//setup the file route
	Com_sprintf( mapRoute, sizeof( mapRoute ), "maps/%s", Info_ValueForKey( info, "mapname" ) );

	BG_LanguageFilename( mapRoute, "holodeck", fileRoute );

	file_len = trap_FS_FOpenFile( fileRoute, &f, FS_READ );

	if ( !file_len )
		return;

	memset( buffer, 0, sizeof(buffer) );

	trap_FS_Read( buffer, file_len, f );
	if ( !buffer[0] )
	{
		G_Printf( S_COLOR_RED "ERROR: Couldn't read in file: %s!\n", fileRoute );
		trap_FS_FCloseFile( f );
		return;
	}

	buffer[file_len] = '\0';
	trap_FS_FCloseFile( f );

	COM_BeginParseSession();
	txtPtr = buffer;

	while(1) {
		token = COM_Parse(&txtPtr);
		if(!token[0]) break;

		if(!Q_stricmpn(token, "HolodeckData", 12)) {
			token = COM_Parse(&txtPtr);
			if(Q_stricmpn(token, "{", 1)) {
				G_Printf( S_COLOR_RED "ERROR: HolodeckData had no opening brace ( { )!\n");
				continue;
			}
			while(Q_stricmpn(token, "}", 1)) {
				token = COM_Parse(&txtPtr);
				if(!token[0]) break;

				if(!Q_stricmpn(token, "Program", 7)) {
					token = COM_Parse(&txtPtr);
					if(Q_stricmpn(token, "[", 1)) {
						G_Printf( S_COLOR_RED "ERROR: Program had no opening brace ( [ )!\n");
						continue;
					}

					// expected format:
					// <string> - target notnull
					// <string> - name
					// <string> - desc1
					// <string> - desc2
					// <string> - image
					// <string> - iTrigger
					// <string> - dTrigger
					while(Q_stricmpn(token, "]", 1)) {
						if(!token[0]) break;

						if(numProgs >= 5) return;

						// targetname of info_notnull
						token = COM_Parse(&txtPtr);
						Q_strncpyz(holoData.target[numProgs], token, sizeof(holoData.target[numProgs]));

						// parse name
						token = COM_Parse(&txtPtr);
						Q_strncpyz(holoData.name[numProgs], token, sizeof(holoData.name[numProgs]));

						// parse desc1
						token = COM_Parse(&txtPtr);
						Q_strncpyz(holoData.desc1[numProgs], token, sizeof(holoData.desc1[numProgs]));

						// parse desc2
						token = COM_Parse(&txtPtr);
						Q_strncpyz(holoData.desc2[numProgs], token, sizeof(holoData.desc2[numProgs]));

						// parse image
						token = COM_Parse(&txtPtr);
						Q_strncpyz(holoData.image[numProgs], token, sizeof(holoData.image[numProgs]));

						// parse iTrigger
						token = COM_Parse(&txtPtr);
						Q_strncpyz(holoData.iTrigger[numProgs+1], token, sizeof(holoData.iTrigger[numProgs+1]));

						// parse dTrigger
						token = COM_Parse(&txtPtr);
						Q_strncpyz(holoData.dTrigger[numProgs+1], token, sizeof(holoData.dTrigger[numProgs+1]));

						holoData.active = -1;

						numProgs++;

						token = COM_Parse(&txtPtr);
					}
				}
			}
		}
	}

	for(i = 0; i < MAX_GENTITIES; i++)
		if(!strcmp("target_holodeck", &g_entities[i]->classname)) {
			strcpy(holoData.iTrigger[0], &g_entities[i]->target);
			strcpy(holoData.dTrigger[0], &g_entities[i]->redsound);
			break;
		}

	holoData.numProgs = numProgs;
}
#else
void G_LoadHolodeckFile(void) {
	char			fileRoute[MAX_QPATH];
	char			mapRoute[MAX_QPATH];
	char			*info;
	fileHandle_t	f;
	char			*buffer;
	int				file_len;
	char			*txtPtr, *token;
	int				numProgs = 0;
	//int				i;

	info = (char *)malloc(MAX_INFO_STRING * sizeof(char));
	if(!info) {
		G_Printf(S_COLOR_RED "ERROR: Was unable to allocate %i byte.\n", MAX_INFO_STRING * sizeof(char) );
		return;
	}

	//get the map name out of the server data
	trap_GetServerinfo( info, MAX_INFO_STRING * sizeof(char) );

	//setup the file route
	Com_sprintf( mapRoute, sizeof( mapRoute ), "maps/%s", Info_ValueForKey( info, "mapname" ) );

	BG_LanguageFilename( mapRoute, "holodeck", fileRoute );

	file_len = trap_FS_FOpenFile( fileRoute, &f, FS_READ );

	free(info);

	if ( !file_len ) return;

	buffer = (char *)malloc(32000 * sizeof(char));
	if(!buffer) {
		G_Printf(S_COLOR_RED "ERROR: Was unable to allocate %i bytes.\n", 32000 * sizeof(char) );
		trap_FS_FCloseFile(f);
		return;
	}

	trap_FS_Read( buffer, file_len, f );
	if ( !buffer[0] )
	{
		G_Printf( S_COLOR_RED "ERROR: Couldn't read in file: %s!\n", fileRoute );
		trap_FS_FCloseFile( f );
		free(buffer);
		return;
	}

	buffer[file_len] = '\0';
	trap_FS_FCloseFile( f );

	memset(&holoData, 0, sizeof(holoData));

	COM_BeginParseSession();
	txtPtr = buffer;

	while(1) {
		token = COM_Parse(&txtPtr);
		if(!token[0]) break;

		if(!Q_stricmpn(token, "HolodeckData", 12)) {
			token = COM_Parse(&txtPtr);
			if(Q_stricmpn(token, "{", 1)) {
				G_Printf( S_COLOR_RED "ERROR: HolodeckData had no opening brace ( { )!\n");
				continue;
			}
			while(Q_stricmpn(token, "}", 1)) {
				token = COM_Parse(&txtPtr);
				if(!token[0]) break;

				if(!Q_stricmpn(token, "Program", 7)) {
					token = COM_Parse(&txtPtr);
					if(Q_stricmpn(token, "[", 1)) {
						G_Printf( S_COLOR_RED "ERROR: Program had no opening brace ( [ )!\n");
						continue;
					}

					// expected format:
					// <string> - target notnull
					// <string> - name
					// <string> - desc1
					// <string> - desc2
					// <string> - image
					while(Q_stricmpn(token, "]", 1)) {
						if(!token[0]) break;

						if(numProgs >= 5) {
							free(buffer);
							return;
						}

						// targetname of info_notnull
						token = COM_Parse(&txtPtr);
						Q_strncpyz(holoData.target[numProgs], token, sizeof(holoData.target[numProgs]));

						// parse name
						token = COM_Parse(&txtPtr);
						Q_strncpyz(holoData.name[numProgs], token, sizeof(holoData.name[numProgs]));

						// parse desc1
						token = COM_Parse(&txtPtr);
						Q_strncpyz(holoData.desc1[numProgs], token, sizeof(holoData.desc1[numProgs]));

						// parse desc2
						token = COM_Parse(&txtPtr);
						Q_strncpyz(holoData.desc2[numProgs], token, sizeof(holoData.desc2[numProgs]));

						// parse image
						token = COM_Parse(&txtPtr);
						Q_strncpyz(holoData.image[numProgs], token, sizeof(holoData.image[numProgs]));

						holoData.active = -1;

						numProgs++;

						token = COM_Parse(&txtPtr);
					}
				}
			}
		}
	}

	holoData.numProgs = numProgs;

	free(buffer);
}
#endif

srvChangeData_t srvChangeData;

#ifdef Q3_VM
static void G_LoadServerChangeFile(void) {
	char			fileRoute[MAX_QPATH];
	//char			mapRoute[MAX_QPATH];
	char			infoString[MAX_INFO_STRING];
	fileHandle_t	f;
	char			buffer[20000];
	int				file_len;
	char			*txtPtr, *token;
	char			*temp;
	int				cnt = 0;
	int				i = 0;

	BG_LanguageFilename("serverchange", "cfg", fileRoute);

	file_len = trap_FS_FOpenFile(fileRoute, &f, FS_READ);

	if(!file_len) 
		return;

	memset(buffer, 0, sizeof(buffer));
	memset(infoString, 0, sizeof(infoString));

	trap_FS_Read(buffer, file_len, f);
	if ( !buffer[0] )
	{
		G_Printf( S_COLOR_RED "ERROR: Couldn't read in file: %s!\n", fileRoute );
		trap_FS_FCloseFile( f );
		return;
	}

	buffer[file_len] = '\0';
	trap_FS_FCloseFile(f);

	COM_BeginParseSession();
	txtPtr = buffer;

	while(1) {
		token = COM_Parse(&txtPtr);
		if(!token[0]) break;

		if(!Q_stricmp(token, "ServerChangeConfig")) {
			token = COM_Parse( &txtPtr );
			if ( Q_strncmp( token, "{", 1 ) != 0 )
			{
				G_Printf( S_COLOR_RED "ERROR: ServerChangeConfig had no opening brace ( { )!\n" );
				continue;
			}
			
			while(Q_strncmp(token, "}", 1)) {
				token = COM_Parse(&txtPtr);
				if(!token[0]) break;

				if(!Q_stricmp(token, "Server")) {
					token = COM_Parse(&txtPtr);
					if ( Q_strncmp( token, "[", 1 ) != 0 )
					{
						G_Printf( S_COLOR_RED "ERROR: Server had no opening brace ( [ )!\n" );
						continue;
					}

					token = COM_Parse(&txtPtr);
					while(Q_strncmp(token, "]", 1)) {
						if(!token[0]) break;

						if(cnt > 12) break;

						temp = G_NewString(token);

						/*if(!infoString[0])
							Com_sprintf(infoString, sizeof(infoString), "i%i\\%s\\", cnt, temp);
						else {
							if(cnt % 2 == 0)
								Com_sprintf(infoString, sizeof(infoString), "%si%i\\%s\\", infoString, i, temp);
							else
								Com_sprintf(infoString, sizeof(infoString), "%sd%i\\%s\\", infoString, i, temp);
						}*/

						if(cnt % 2 == 0)
							Q_strncpyz(srvChangeData.ip[i], token, sizeof(srvChangeData.ip[i]));
						else
							Q_strncpyz(srvChangeData.name[i], token, sizeof(srvChangeData.name[i]));

						cnt++;
						if(cnt % 2 == 0)
							i++;

						token = COM_Parse(&txtPtr);
					}
				}
			}
		}
	}

	//trap_SetConfigstring(CS_SERVERCHANGE, infoString);
}
#else
static void G_LoadServerChangeFile(void) {
	char			fileRoute[MAX_QPATH];
	//char			mapRoute[MAX_QPATH];
	fileHandle_t	f;
	char			*buffer;
	int				file_len;
	char			*txtPtr, *token;
	char			*temp;
	int				cnt = 0;
	int				i = 0;

	BG_LanguageFilename("serverchange", "cfg", fileRoute);

	file_len = trap_FS_FOpenFile(fileRoute, &f, FS_READ);

	if(!file_len) 
		return;

	buffer = (char *)malloc(32000 * sizeof(char));
	if(!buffer) {
		G_Printf(S_COLOR_RED "ERROR: Was unable to allocate %i bytes.\n", 32000 * sizeof(char) );
		trap_FS_FCloseFile(f);
		return;
	}

	trap_FS_Read(buffer, file_len, f);
	if ( !buffer[0] )
	{
		G_Printf( S_COLOR_RED "ERROR: Couldn't read in file: %s!\n", fileRoute );
		trap_FS_FCloseFile( f );
		free(buffer);
		return;
	}

	buffer[file_len] = '\0';
	trap_FS_FCloseFile(f);

	memset(&srvChangeData, 0, sizeof(srvChangeData));

	COM_BeginParseSession();
	txtPtr = buffer;

	while(1) {
		token = COM_Parse(&txtPtr);
		if(!token[0]) break;

		if(!Q_stricmp(token, "ServerChangeConfig")) {
			token = COM_Parse( &txtPtr );
			if ( Q_strncmp( token, "{", 1 ) != 0 )
			{
				G_Printf( S_COLOR_RED "ERROR: ServerChangeConfig had no opening brace ( { )!\n" );
				continue;
			}
			
			while(Q_strncmp(token, "}", 1)) {
				token = COM_Parse(&txtPtr);
				if(!token[0]) break;

				if(!Q_stricmp(token, "Server")) {
					token = COM_Parse(&txtPtr);
					if ( Q_strncmp( token, "[", 1 ) != 0 )
					{
						G_Printf( S_COLOR_RED "ERROR: Server had no opening brace ( [ )!\n" );
						continue;
					}

					token = COM_Parse(&txtPtr);
					while(Q_strncmp(token, "]", 1)) {
						if(!token[0]) break;

						if(cnt > 12) break;

						temp = G_NewString(token);

						/*if(!infoString[0])
							Com_sprintf(infoString, sizeof(infoString), "i%i\\%s\\", cnt, temp);
						else {
							if(cnt % 2 == 0)
								Com_sprintf(infoString, sizeof(infoString), "%si%i\\%s\\", infoString, i, temp);
							else
								Com_sprintf(infoString, sizeof(infoString), "%sd%i\\%s\\", infoString, i, temp);
						}*/

						if(cnt % 2 == 0)
							Q_strncpyz(srvChangeData.ip[i], token, sizeof(srvChangeData.ip[i]));
						else
							Q_strncpyz(srvChangeData.name[i], token, sizeof(srvChangeData.name[i]));

						cnt++;
						if(cnt % 2 == 0)
							i++;

						token = COM_Parse(&txtPtr);
					}
				}
			}
		}
	}

	free(buffer);
	//trap_SetConfigstring(CS_SERVERCHANGE, infoString);
}
#endif

mapChangeData_t mapChangeData;

#ifdef Q3_VM
static void G_LoadMapChangeFile(void) {
	char			fileRoute[MAX_QPATH];
	//char			mapRoute[MAX_QPATH];
	char			infoString[MAX_INFO_STRING];
	fileHandle_t	f;
	char			buffer[20000];
	int				file_len;
	char			*txtPtr, *token;
	char			*temp;
	int				cnt = 0;
	int				i = 0;

	BG_LanguageFilename("mapchange", "cfg", fileRoute);

	file_len = trap_FS_FOpenFile(fileRoute, &f, FS_READ);

	if(!file_len) 
		return;

	memset(buffer, 0, sizeof(buffer));
	memset(infoString, 0, sizeof(infoString));

	trap_FS_Read(buffer, file_len, f);
	if ( !buffer[0] )
	{
		G_Printf( S_COLOR_RED "ERROR: Couldn't read in file: %s!\n", fileRoute );
		trap_FS_FCloseFile( f );
		return;
	}

	buffer[file_len] = '\0';
	trap_FS_FCloseFile(f);

	COM_BeginParseSession();
	txtPtr = buffer;

	while(1) {
		token = COM_Parse(&txtPtr);
		if(!token[0]) break;

		if(!Q_stricmp(token, "MapChangeConfig")) {
			token = COM_Parse( &txtPtr );
			if ( Q_strncmp( token, "{", 1 ) != 0 )
			{
				G_Printf( S_COLOR_RED "ERROR: MapChangeConfig had no opening brace ( { )!\n" );
				continue;
			}
			
			while(Q_strncmp(token, "}", 1)) {
				token = COM_Parse(&txtPtr);
				if(!token[0]) break;

				if(!Q_stricmp(token, "Map")) {
					token = COM_Parse(&txtPtr);
					if ( Q_strncmp( token, "[", 1 ) != 0 )
					{
						G_Printf( S_COLOR_RED "ERROR: Server had no opening brace ( [ )!\n" );
						continue;
					}

					token = COM_Parse(&txtPtr);
					while(Q_strncmp(token, "]", 1)) {
						if(!token[0]) break;

						if(cnt > 12) break;

						temp = G_NewString(token);

						/*if(!infoString[0])
							Com_sprintf(infoString, sizeof(infoString), "i%i\\%s\\", cnt, temp);
						else {
							if(cnt % 2 == 0)
								Com_sprintf(infoString, sizeof(infoString), "%si%i\\%s\\", infoString, i, temp);
							else
								Com_sprintf(infoString, sizeof(infoString), "%sd%i\\%s\\", infoString, i, temp);
						}*/

						if(cnt % 2 == 0)
							Q_strncpyz(mapChangeData.name[i], token, sizeof(mapChangeData.name[i]));
						else
							Q_strncpyz(mapChangeData.bspname[i], token, sizeof(mapChangeData.bspname[i]));

						cnt++;
						if(cnt % 2 == 0)
							i++;

						token = COM_Parse(&txtPtr);
					}
				}
			}
		}
	}

	//trap_SetConfigstring(CS_SERVERCHANGE, infoString);
}
#else
static void G_LoadMapChangeFile(void) {
	char			fileRoute[MAX_QPATH];
	//char			mapRoute[MAX_QPATH];
	fileHandle_t	f;
	char			*buffer;
	int				file_len;
	char			*txtPtr, *token;
	char			*temp;
	int				cnt = 0;
	int				i = 0;

	BG_LanguageFilename("mapchange", "cfg", fileRoute);

	file_len = trap_FS_FOpenFile(fileRoute, &f, FS_READ);

	if(!file_len) 
		return;

	buffer = (char *)malloc(32000 * sizeof(char));
	if(!buffer) {
		G_Printf(S_COLOR_RED "ERROR: Was unable to allocate %i bytes.\n", 32000 * sizeof(char) );
		trap_FS_FCloseFile(f);
		return;
	}

	trap_FS_Read(buffer, file_len, f);
	if ( !buffer[0] )
	{
		G_Printf( S_COLOR_RED "ERROR: Couldn't read in file: %s!\n", fileRoute );
		trap_FS_FCloseFile( f );
		free(buffer);
		return;
	}

	buffer[file_len] = '\0';
	trap_FS_FCloseFile(f);

	memset(&srvChangeData, 0, sizeof(srvChangeData));

	COM_BeginParseSession();
	txtPtr = buffer;

	while(1) {
		token = COM_Parse(&txtPtr);
		if(!token[0]) break;

		if(!Q_stricmp(token, "MapChangeConfig")) {
			token = COM_Parse( &txtPtr );
			if ( Q_strncmp( token, "{", 1 ) != 0 )
			{
				G_Printf( S_COLOR_RED "ERROR: MapChangeConfig had no opening brace ( { )!\n" );
				continue;
			}
			
			while(Q_strncmp(token, "}", 1)) {
				token = COM_Parse(&txtPtr);
				if(!token[0]) break;

				if(!Q_stricmp(token, "Map")) {
					token = COM_Parse(&txtPtr);
					if ( Q_strncmp( token, "[", 1 ) != 0 )
					{
						G_Printf( S_COLOR_RED "ERROR: Server had no opening brace ( [ )!\n" );
						continue;
					}

					token = COM_Parse(&txtPtr);
					while(Q_strncmp(token, "]", 1)) {
						if(!token[0]) break;

						if(cnt > 12) break;

						temp = G_NewString(token);

						/*if(!infoString[0])
							Com_sprintf(infoString, sizeof(infoString), "i%i\\%s\\", cnt, temp);
						else {
							if(cnt % 2 == 0)
								Com_sprintf(infoString, sizeof(infoString), "%si%i\\%s\\", infoString, i, temp);
							else
								Com_sprintf(infoString, sizeof(infoString), "%sd%i\\%s\\", infoString, i, temp);
						}*/

						if(cnt % 2 == 0)
							Q_strncpyz(mapChangeData.name[i], token, sizeof(mapChangeData.name[i]));
						else
							Q_strncpyz(mapChangeData.bspname[i], token, sizeof(mapChangeData.bspname[i]));

						cnt++;
						if(cnt % 2 == 0)
							i++;

						token = COM_Parse(&txtPtr);
					}
				}
			}
		}
	}

	free(buffer);
	//trap_SetConfigstring(CS_SERVERCHANGE, infoString);
}
#endif

#ifdef Q3_VM
static void G_LoadLocationsFile( void )
{
	char			fileRoute[MAX_QPATH];
	char			mapRoute[MAX_QPATH];
	char			serverInfo[MAX_TOKEN_CHARS];
	fileHandle_t	f;
	char			buffer[20000];
	int				file_len;
	char			*textPtr, *token;
	vec3_t			origin, angles;
	gentity_t		*ent;
	char			*desc;
	int				rest;

	//get the map name out of the server data
	trap_GetServerinfo( serverInfo, sizeof( serverInfo ) );

	//setup the file route
	Com_sprintf( mapRoute, sizeof( mapRoute ), "maps/%s", Info_ValueForKey( serverInfo, "mapname" ) );

	BG_LanguageFilename( mapRoute, "locations", fileRoute );

	file_len = trap_FS_FOpenFile( fileRoute, &f, FS_READ );

	if ( !file_len )
		return;

	memset( buffer, 0, sizeof(buffer) );

	trap_FS_Read( buffer, file_len, f );
	if ( !buffer[0] )
	{
		G_Printf( S_COLOR_RED "ERROR: Couldn't read in file: %s!\n", fileRoute );
		trap_FS_FCloseFile( f );
		return;
	}

	buffer[file_len] = '\0';
	trap_FS_FCloseFile( f );
	
	G_Printf( "Locations file %s located. Proceeding to load scan data.\n", fileRoute ); //GSIO01: why did this say "Usables file ..."? lol

	COM_BeginParseSession();
	textPtr = buffer;

	while( 1 )
	{
		token = COM_Parse( &textPtr );
		if ( !token[0] )
			break;

		if(!Q_strncmp( token, "LocationsList2", 19 )) { // new style locations list with restricted locations
			token = COM_Parse( &textPtr );
			if ( Q_strncmp( token, "{", 1 ) != 0 )
			{
				G_Printf( S_COLOR_RED "ERROR: LocationsList2 had no opening brace ( { )!\n", fileRoute );
				continue;
			}

			//expected format is "<origin> <angle> <int> <string>"
			while ( Q_strncmp( token, "}", 1 ) )
			{
				if ( !token[0] )
					break;

				//Parse origin
				if ( COM_ParseVec3( &textPtr, origin ) )
				{
					G_Printf( S_COLOR_RED "Invalid origin entry in %s!\n", fileRoute );
					return;
				}

				//Parse angles
				if ( COM_ParseVec3( &textPtr, angles ) )
				{
					G_Printf( S_COLOR_RED "Invalid origin entry in %s!\n", fileRoute );
					return;
				}

				//Pars restriction value
				if( COM_ParseInt( &textPtr, &rest ) )
				{
					G_Printf( S_COLOR_RED "Invalid restriction entry in %s!\n", fileRoute );
					return;
				}

				//Parse Location string
				token = COM_ParseExt( &textPtr, qfalse );
				if ( !token[0] )
				{
					G_Printf( S_COLOR_RED "Invalid string desc entry in %s!\n", fileRoute );
					return;
				}

				desc = token;

				//create a new entity
				ent = G_Spawn();
				if ( !ent )
				{
					G_Printf( S_COLOR_RED "Couldn't create entity in %s!\n", fileRoute );
					return;
				}

				ent->classname = "target_location";

				//copy position data
				VectorCopy( origin, ent->s.origin );
				VectorCopy( angles, ent->s.angles );

				//copy string
				ent->message = G_NewString( desc );

				//copy desc into target as well
				ent->target = ent->targetname = G_NewString( desc );

				// copy restriction value
				ent->sound1to2 = rest;

				//G_Printf( S_COLOR_RED "Added string %s to entity %i.\n", ent->message, (int)(ent-g_entities) );

				//initiate it as a location ent
				SP_target_location( ent );

				//reset the ent
				ent = NULL;

				//--
				token = COM_Parse( &textPtr );
			}
		} else if ( !Q_strncmp( token, "LocationsList", 18 ) ) // old stly locations file
		{
			token = COM_Parse( &textPtr );
			if ( Q_strncmp( token, "{", 1 ) != 0 )
			{
				G_Printf( S_COLOR_RED "ERROR: LocationsList had no opening brace ( { )!\n", fileRoute );
				continue;
			}

			//expected format is "<origin> <angle> <string>"
			while ( Q_strncmp( token, "}", 1 ) )
			{
				if ( !token[0] )
					break;

				//Parse origin
				if ( COM_ParseVec3( &textPtr, origin ) )
				{
					G_Printf( S_COLOR_RED "Invalid origin entry in %s!\n", fileRoute );
					return;
				}

				//Parse angles
				if ( COM_ParseVec3( &textPtr, angles ) )
				{
					G_Printf( S_COLOR_RED "Invalid origin entry in %s!\n", fileRoute );
					return;
				}

				//Parse Location string
				token = COM_ParseExt( &textPtr, qfalse );
				if ( !token[0] )
				{
					G_Printf( S_COLOR_RED "Invalid string desc entry in %s!\n", fileRoute );
					return;
				}

				desc = token;

				//create a new entity
				ent = G_Spawn();
				if ( !ent )
				{
					G_Printf( S_COLOR_RED "Couldn't create entity in %s!\n", fileRoute );
					return;
				}

				ent->classname = "target_location";

				//copy position data
				VectorCopy( origin, ent->s.origin );
				VectorCopy( angles, ent->s.angles );

				//copy string
				ent->message = G_NewString( desc );

				//copy desc into target as well
				ent->target = ent->targetname = G_NewString( desc );

				//G_Printf( S_COLOR_RED "Added string %s to entity %i.\n", ent->message, (int)(ent-g_entities) );

				//initiate it as a location ent
				SP_target_location( ent );

				//reset the ent
				ent = NULL;

				//--
				token = COM_Parse( &textPtr );
			}
		}
	} 
}
#else
static void G_LoadLocationsFile( void )
{
	char			fileRoute[MAX_QPATH];
	char			mapRoute[MAX_QPATH];
	char			*serverInfo;
	fileHandle_t	f;
	char			*buffer;
	int				file_len;
	char			*textPtr, *token;
	vec3_t			origin, angles;
	gentity_t		*ent;
	char			*desc;
	int				rest;

	serverInfo = (char *)malloc(MAX_INFO_STRING * sizeof(char));
	if(!serverInfo) {
		G_Printf(S_COLOR_RED "ERROR: Was unable to allocate %i bytes.\n", MAX_INFO_STRING * sizeof(char));
		return;
	}

	//get the map name out of the server data
	trap_GetServerinfo( serverInfo, MAX_INFO_STRING * sizeof(char) );

	//setup the file route
	Com_sprintf( mapRoute, sizeof( mapRoute ), "maps/%s", Info_ValueForKey( serverInfo, "mapname" ) );

	BG_LanguageFilename( mapRoute, "locations", fileRoute );

	file_len = trap_FS_FOpenFile( fileRoute, &f, FS_READ );

	free(serverInfo);

	if ( !file_len )
		return;

	buffer = (char *)malloc(32000 * sizeof(char));
	if(!buffer) {
		G_Printf(S_COLOR_RED "ERROR: Was unable to allocate %i bytes.\n", 32000 * sizeof(char));
		trap_FS_FCloseFile(f);
		return;
	}

	trap_FS_Read( buffer, file_len, f );
	if ( !buffer[0] )
	{
		G_Printf( S_COLOR_RED "ERROR: Couldn't read in file: %s!\n", fileRoute );
		trap_FS_FCloseFile( f );
		free(buffer);
		return;
	}

	buffer[file_len] = '\0';
	trap_FS_FCloseFile( f );
	
	G_Printf( "Locations file %s located. Proceeding to load scan data.\n", fileRoute ); //GSIO01: why did this say "Usables file ..."? lol

	COM_BeginParseSession();
	textPtr = buffer;

	while( 1 )
	{
		token = COM_Parse( &textPtr );
		if ( !token[0] )
			break;

		if(!Q_strncmp( token, "LocationsList2", 19 )) { // new style locations list with restricted locations
			token = COM_Parse( &textPtr );
			if ( Q_strncmp( token, "{", 1 ) != 0 )
			{
				G_Printf( S_COLOR_RED "ERROR: LocationsList2 had no opening brace ( { )!\n", fileRoute );
				continue;
			}

			//expected format is "<origin> <angle> <int> <string>"
			while ( Q_strncmp( token, "}", 1 ) )
			{
				if ( !token[0] )
					break;

				//Parse origin
				if ( COM_ParseVec3( &textPtr, origin ) )
				{
					G_Printf( S_COLOR_RED "Invalid origin entry in %s!\n", fileRoute );
					free(buffer);
					return;
				}

				//Parse angles
				if ( COM_ParseVec3( &textPtr, angles ) )
				{
					G_Printf( S_COLOR_RED "Invalid origin entry in %s!\n", fileRoute );
					free(buffer);
					return;
				}

				//Pars restriction value
				if( COM_ParseInt( &textPtr, &rest ) )
				{
					G_Printf( S_COLOR_RED "Invalid restriction entry in %s!\n", fileRoute );
					free(buffer);
					return;
				}

				//Parse Location string
				token = COM_ParseExt( &textPtr, qfalse );
				if ( !token[0] )
				{
					G_Printf( S_COLOR_RED "Invalid string desc entry in %s!\n", fileRoute );
					free(buffer);
					return;
				}

				desc = token;

				//create a new entity
				ent = G_Spawn();
				if ( !ent )
				{
					G_Printf( S_COLOR_RED "Couldn't create entity in %s!\n", fileRoute );
					free(buffer);
					return;
				}

				ent->classname = "target_location";

				//copy position data
				VectorCopy( origin, ent->s.origin );
				VectorCopy( angles, ent->s.angles );

				//copy string
				ent->message = G_NewString( desc );

				//copy desc into target as well
				ent->target = ent->targetname = G_NewString( desc );

				// copy restriction value
				ent->sound1to2 = rest;

				//G_Printf( S_COLOR_RED "Added string %s to entity %i.\n", ent->message, (int)(ent-g_entities) );

				//initiate it as a location ent
				SP_target_location( ent );

				//reset the ent
				ent = NULL;

				//--
				token = COM_Parse( &textPtr );
			}
		} else if ( !Q_strncmp( token, "LocationsList", 18 ) ) // old stly locations file
		{
			token = COM_Parse( &textPtr );
			if ( Q_strncmp( token, "{", 1 ) != 0 )
			{
				G_Printf( S_COLOR_RED "ERROR: LocationsList had no opening brace ( { )!\n", fileRoute );
				continue;
			}

			//expected format is "<origin> <angle> <string>"
			while ( Q_strncmp( token, "}", 1 ) )
			{
				if ( !token[0] )
					break;

				//Parse origin
				if ( COM_ParseVec3( &textPtr, origin ) )
				{
					G_Printf( S_COLOR_RED "Invalid origin entry in %s!\n", fileRoute );
					free(buffer);
					return;
				}

				//Parse angles
				if ( COM_ParseVec3( &textPtr, angles ) )
				{
					G_Printf( S_COLOR_RED "Invalid origin entry in %s!\n", fileRoute );
					free(buffer);
					return;
				}

				//Parse Location string
				token = COM_ParseExt( &textPtr, qfalse );
				if ( !token[0] )
				{
					G_Printf( S_COLOR_RED "Invalid string desc entry in %s!\n", fileRoute );
					free(buffer);
					return;
				}

				desc = token;

				//create a new entity
				ent = G_Spawn();
				if ( !ent )
				{
					G_Printf( S_COLOR_RED "Couldn't create entity in %s!\n", fileRoute );
					free(buffer);
					return;
				}

				ent->classname = "target_location";

				//copy position data
				VectorCopy( origin, ent->s.origin );
				VectorCopy( angles, ent->s.angles );

				//copy string
				ent->message = G_NewString( desc );

				//copy desc into target as well
				ent->target = ent->targetname = G_NewString( desc );

				//G_Printf( S_COLOR_RED "Added string %s to entity %i.\n", ent->message, (int)(ent-g_entities) );

				//initiate it as a location ent
				SP_target_location( ent );

				//reset the ent
				ent = NULL;

				//--
				token = COM_Parse( &textPtr );
			}
		}
	} 

	free(buffer);
}
#endif

/*void G_initGroupsList(void)
{
	char	filename[MAX_QPATH];
	char	dirlist[4096];
	int		i;
	char*	dirptr;
	char*	race_list;
	int		numdirs;
	int		dirlen;

	memset(group_list, 0, sizeof(group_list));
	group_count = 0;

	// search through each and every skin we can find
	//BOOKMARK
	numdirs = trap_FS_GetFileList("models/players_rpgx", "/", dirlist, sizeof(dirlist) );
	dirptr  = dirlist;
	for (i=0; i<numdirs; i++,dirptr+=dirlen+1)
	{
		dirlen = strlen(dirptr);
		
		if (dirlen && dirptr[dirlen-1]=='/')
		{
			dirptr[dirlen-1]='\0';
		}

		if (!strcmp(dirptr,".") || !strcmp(dirptr,".."))
		{
			continue;
		}

		if (group_count == MAX_GROUP_MEMBERS)
		{
			G_Printf("Number of possible models larger than group array - limiting to first %d models\n", MAX_GROUP_MEMBERS);
			break;
		}
		// work out racename to 
		Com_sprintf(filename, sizeof(filename), "models/players_rpgx/%s/groups.cfg", dirptr);
		race_list = BG_RegisterRace(filename);

		Q_strncpyz( group_list[group_count].name, dirptr , sizeof(group_list[0].name) );
		Q_strncpyz( group_list[group_count++].text, race_list , sizeof(group_list[0].text) );
	}
}*/



#define MAX_GROUP_FILE_SIZE	5000
char *G_searchGroupList(const char *name)
{
	char	*text_p = NULL, *slash = NULL;
	char	text[MAX_GROUP_FILE_SIZE];
	int		i;
	char	mod_name[200];

	memset (races, 0, sizeof(races));
	memset (text, 0, sizeof(text));

	// check to see if there is a '/' in the name
	Q_strncpyz(mod_name, name, sizeof(mod_name));
	slash = strstr( mod_name, "/" );
	if ( slash != NULL )
	{//drop the slash and everything after it for the purpose of finding the model name in th group
		*slash = 0;
	}

	// find the name in the group list
	for (i=0; i<group_count; i++)
	{
		if (!Q_stricmp(mod_name, group_list[i].name))
		{
			text_p = group_list[i].text;
			break;
		}
	}

	// did we find this group in the list?
	if (i == group_count)
	{
		Com_sprintf(races, sizeof(races), "unknown");
	}
	else
	{
		Com_sprintf(races, sizeof(races), text_p);
	}
	return races;

}


/*
================
G_FindTeams

Chain together all entities with a matching team field.
Entity teams are used for item groups and multi-entity mover groups.

All but the first will have the FL_TEAMSLAVE flag set and teammaster field set
All but the last will have the teamchain field set to the next one
================
*/
void G_FindTeams( void ) {
	gentity_t	*e, *e2;
	int		i, j;
	int		c, c2;

	c = 0;
	c2 = 0;
	for ( i=1, e=g_entities+i ; i < level.num_entities ; i++,e++ ){
		if (!e->inuse)
			continue;
		if (!e->team)
			continue;
		if (e->flags & FL_TEAMSLAVE)
			continue;
		if ( e->classname && Q_stricmp( "func_door", e->classname ) != 0 )
		{//not a door
			if ( Q_stricmp( "1", e->team ) == 0 || Q_stricmp( "2", e->team ) == 0 )
			{//is trying to tell us it belongs to the TEAM_RED or TEAM_BLUE
				continue;
			}
		}
		e->teammaster = e;
		c++;
		c2++;
		for (j=i+1, e2=e+1 ; j < level.num_entities ; j++,e2++)
		{
			if (!e2->inuse)
				continue;
			if (!e2->team)
				continue;
			if (e2->flags & FL_TEAMSLAVE)
				continue;
			if (!strcmp(e->team, e2->team))
			{
				c2++;
				e2->teamchain = e->teamchain;
				e->teamchain = e2;
				e2->teammaster = e;
				e2->flags |= FL_TEAMSLAVE;

				// make sure that targets only point at the master
				if ( e2->targetname ) {
					e->targetname = e2->targetname;
					e2->targetname = NULL;
				}
			}
		}
	}

	G_Printf ("%i teams with %i entities\n", c, c2);
}

/*
=================
G_RegisterCvars
=================
*/
void G_RegisterCvars( void ) {
	int			i;
	cvarTable_t	*cv;

	for ( i = 0, cv = gameCvarTable ; i < gameCvarTableSize ; i++, cv++ )
	{

		if ( rpg_rpg.integer != 0 )
		{
			trap_Cvar_Set( "g_pModDisintegration", "0" );
			trap_Cvar_Set( "g_pModActionHero", "0" );
			trap_Cvar_Set( "g_pModSpecialties", "0" );
			trap_Cvar_Set( "g_pModAssimilation", "0" );
			trap_Cvar_Set( "g_gametype", "0" );//RPG-X: RedTechie - Make sure we keep gametype at 0
		}

		trap_Cvar_Register( cv->vmCvar, cv->cvarName, cv->defaultString, cv->cvarFlags );
		if ( cv->vmCvar )
		{
			cv->modificationCount = cv->vmCvar->modificationCount;
		}
	}

	// check some things

	if ( g_gametype.integer < 0 || g_gametype.integer >= GT_MAX_GAME_TYPE ) {
		G_Printf( "g_gametype %i is out of range, defaulting to 0\n", g_gametype.integer );
		trap_Cvar_Set( "g_gametype", "0" );
	}

	level.warmupModificationCount = g_warmup.modificationCount;
}

/*
=================
G_UpdateCvars
=================
*/
void G_UpdateCvars( void )
{
	int			i;
	cvarTable_t	*cv;

	for ( i = 0, cv = gameCvarTable ; i < gameCvarTableSize ; i++, cv++ )
	{
		if ( cv->vmCvar )
		{
			trap_Cvar_Update( cv->vmCvar );

			if ( cv->modificationCount != cv->vmCvar->modificationCount )
			{
				cv->modificationCount = cv->vmCvar->modificationCount;

				if ( cv->trackChange )
				{
					if ( !levelExiting )
					{//no need to do this during level changes
						//RPG-X: J2J - Don't show gravity changed messages any more (for the gravity target ents)
						if(Q_stricmp(cv->cvarName,"g_gravity") != 0)
						{
							trap_SendServerCommand( -1, va("print \"Server: %s changed to %s\n\"", 
								cv->cvarName, cv->vmCvar->string ) );
						}
					}
				}
			}
		}
	}
}

extern int altAmmoUsage[];
extern team_t	borgTeam;
extern team_t	initialBorgTeam;
void G_InitModRules( void )
{
	numKilled = 0;

	if ( g_pModDisintegration.integer != 0 )
	{//don't use up ammo in disintegration mode
		altAmmoUsage[WP_COMPRESSION_RIFLE] = 0;
	}
	if ( g_pModSpecialties.integer != 0 )
	{//tripwires use more ammo
		altAmmoUsage[WP_GRENADE_LAUNCHER] = 3;
	}
	if ( g_pModAssimilation.integer != 0 )
	{
		borgTeam = initialBorgTeam;
	}
}

extern qboolean G_CallSpawn(gentity_t *ent);
extern qboolean G_ParseField(const char *key, const char *value, gentity_t *ent);
/*
============
G_LoadSpawnFile
If there is a spawn file it will parse it and spawn/change things.

Expected file Layout:
SpawnFile 
	{
	Spawn
	{
		Entity
		{
			classname	<string> //needs to be there
			<key>		<value>  //unlimited number of keys and values
		}
	}
	Convert
	{
		Entity
		{
			"Bmodel"	"*<int>"
			<key>		<value>
		}
		Entity
		{
			"targetname"	<string>
			<key>			<value>
		}
		Entity
		{
			"target"		<string>
			<key>			<value>
		}
	}
	Remove
	{
		Entity
		{
			"Bmodel"	"*<int>"
		}
		Entity
		{
			"targetname"	<string>
		}
		Entity
		{
			"target"	<string>
		}
	}
}
============
*/
void G_LoadSpawnFile( void ) {
/*	char			fileRoute[MAX_QPATH];
	char			mapRoute[MAX_QPATH];
	char			serverInfo[MAX_TOKEN_CHARS];
	fileHandle_t	f;
	char			buffer[29400];
	int				file_len;
	char			*textPtr, *token;
	gentity_t		*newEnt;
	char			tempKey[MAX_TOKEN_CHARS], tempValue[MAX_TOKEN_CHARS];
	//vec3_t			tempVec;
	//int				tempInt;
	//float			tempFloat;

	//get the map name out of the server data
	trap_GetServerinfo( serverInfo, sizeof( serverInfo ) );

	//setup the file route
	Com_sprintf( mapRoute, sizeof( mapRoute ), "maps/%s.%s", Info_ValueForKey( serverInfo, "mapname" ), "spawn" );

	file_len = trap_FS_FOpenFile( fileRoute, &f, FS_READ );

	if ( !file_len )
		return;

	memset( buffer, 0, sizeof(buffer) );

	trap_FS_Read( buffer, file_len, f );
	buffer[file_len] = '0';
	trap_FS_FCloseFile(f);
	if(!buffer[0]) {
		G_Printf( S_COLOR_RED "ERROR: Attempted to load %s, but no data was inside!\n", fileRoute );
		return;
	}

	G_Printf( "Spawn file %s located. Proceeding to load scan data.\n", fileRoute );
	
	COM_BeginParseSession();
	textPtr = buffer;
	while(1) {
		token = COM_Parse(&textPtr);
		if(!token[0])
			break;

		while(1) {
			token = COM_Parse(&textPtr);

			if(!token[0]) return;

			if(!Q_stricmpn(token, "SpawnFile", 9)) {
				token = COM_Parse(&textPtr);
				if ( Q_strncmp( token, "{", 1 ) != 0 )
				{
					G_Printf( S_COLOR_RED "ERROR: SpawnFile in %s had no opening brace ( { )!\n", fileRoute );
					continue;
				}

				token = COM_Parse(&textPtr);
				while(Q_stricmpn(token, "}", 1)) {
					token = COM_Parse(&textPtr);
					if(!Q_stricmpn(token, "Spawn", 5)) {
						token = COM_Parse(&textPtr);
						if( Q_strncmp(token, "{", 1)) {
							G_Printf(S_COLOR_RED "ERROR: Spawn block in %s had no opening brace ( { )!\n", fileRoute);
							continue;
						}

						token = COM_Parse(&textPtr);
						while(Q_strncmp(token, "}", 1)) {
							token = COM_Parse(&textPtr);
							if(!Q_stricmpn(token, "Entity", 6)) {
								if(Q_strncmp(token, "{", 1)) {
									G_Printf(S_COLOR_RED, "ERROR: Entity in %s had no opening brace ( { )!\n", fileRoute);
									continue;
								}

								token = COM_Parse(&textPtr);
								if(!Q_strncmp(token, "classname", 9)) {
									G_Printf(S_COLOR_RED, "ERROR: First key in Entity in Spawn block in %s was not \"classname\"!\n", fileRoute);
									continue;
								}

								newEnt = G_Spawn();
								if(!newEnt) continue;

								newEnt->tmpEntity = qtrue;
								
								token = COM_Parse(&textPtr);
								newEnt->classname = G_NewString(token);

								// check if this entity is valid in Spawn block ...
								if(!Q_strncmp(newEnt->classname, "func_", 5) // func entities are never valid as they need brushmodels
									|| !Q_strncmp(newEnt->classname, "misc_", 5) // misc entities are all invalid for now
									) {
										G_FreeEntity(newEnt);
										G_Printf(S_COLOR_RED "ERROR: Entities of type %s are invalid in Spawn Block!\n", token);
										continue;
								}
								
								while(Q_strncmp(token, "}", 1)) {
									token = COM_Parse(&textPtr);
									Com_sprintf(tempKey, sizeof(tempKey), "%s", token);
									token = COM_Parse(&textPtr);
									Com_sprintf(tempValue, sizeof(tempValue), "%s", token);
									if(!G_ParseField(tempKey, tempValue, newEnt)) {
										//GSIO01: oh well not part of fields ehh?
										//then let's see what entities this is and check if you are valid for it
									}
								}
							}
						}
					} else if(!Q_strncmp(token, "Convert", 7)) { 
						//all entities in here are converted as long as the wanted conversion is valid
						//criterias might be: 
						//				do both have a brushmodel? 
						//				do both have a origin brush? 
						//				and so on
						//because we simply can't convert a info_notnull to a func_door xD
						token = COM_Parse(&textPtr);
						if( Q_strncmp(token, "{", 1)) {
							G_Printf(S_COLOR_RED "ERROR: Convert block in %s had no opening brace ( { )!\n", fileRoute);
							continue;
						}

						//There are 3 ways to identify an entity 100 percent accurate:
						//		by it's targetname (only if it is the only one with it)
						//		by it's target (only if it is the only one targeting it)
						//		by it's brushmodel (always 100% accurate but only works on brushentities)
						//Entity IDs can't be used as loading the map locally or on a server
						//might result in diffrent entity IDs.


					} else if(!Q_strncmp(token, "Remove", 6)) {
						token = COM_Parse(&textPtr);
						if( Q_strncmp(token, "{", 1)) {
							G_Printf(S_COLOR_RED "ERROR: Remove block in %s had no opening brace ( { )!\n", fileRoute);
							continue;
						}
					}
						

				}
			}
		}
	}*/
}

static void Dev_ShowTriggers(gentity_t *ent) {
	int i;
	gentity_t *tar;

	ent->nextthink = level.time + 9500;

	for(i = 0; i < MAX_GENTITIES; i++) {
		if((tar = &g_entities[i]) == NULL) continue;
		if(!Q_stricmpn(tar->classname, "trigger_", 8)) {
			if(!Q_stricmp(tar->classname, "trigger_always")) continue;
			if(tar->r.svFlags & SVF_NOCLIENT)
				tar->r.svFlags ^= SVF_NOCLIENT;
			trap_LinkEntity(ent);
			if(!Q_stricmpn(tar->classname, "trigger_push", 13))
				G_AddEvent(tar, EV_TRIGGER_SHOW, 1);
			else
				G_AddEvent(tar, EV_TRIGGER_SHOW, 0);
		}
	}
}


/*
============
G_InitGame
============
*/
extern int lastKillTime[];
extern int LastFKRadius[];					//(RPG-X J2J) added so array can be initialised to 0 first.
extern RPGX_SiteTOSiteData TransDat[];		//(RPG-X J2J) added for tricorder transporter
extern RPGX_DragData DragDat[];
void G_InitGame( int levelTime, int randomSeed, int restart ) {
	int					i;//,j;
	//vec3_t				Zero = {0.0,0.0,0.0};			//RPG-X J2J //TiM - use vec3_origin instead
	gentity_t*			SpawnPnt;						//RPG-X J2J
	char				fileName[MAX_QPATH];
	float				messageTime;

	G_Printf ("------- Game Initialization -------\n");
	G_Printf ("gamename: %s\n", GAMEVERSION);
	G_Printf ("gamedate: %s\n", __DATE__);

	init_tonextint(qtrue);
	srand( randomSeed );

	numKilled = 0;
	level.numObjectives = 0;//no objectives by default

	G_RegisterCvars();

	G_ProcessIPBans();
	G_ProcessIDBans();

	G_InitMemory();

	//G_initGroupsList();

	BG_LoadItemNames();

	// set some level globals
	memset( &level, 0, sizeof( level ) );

	//Class loader
	memset( fileName, 0, sizeof( fileName ) );
	Com_sprintf( fileName, sizeof( fileName ), "ext_data/classes/%s.classes", rpg_classSet.string );	
	if ( !G_LoadClassData( fileName ) ) 
	{
		G_Printf( S_COLOR_RED "ERROR: Could not load class set %s. Reverting to default.\n", fileName );
		trap_Cvar_Set( "rpg_classSet", CLASS_DEFAULT );

		if ( !G_LoadClassData( va( "ext_data/classes/%s.classes", CLASS_DEFAULT ) ) )
		{
			G_Error( "Could not load default class set: %s", CLASS_DEFAULT );
		}
	}

	//Rank Loader
	memset( fileName, 0, sizeof( fileName ) );
	Com_sprintf( fileName, sizeof( fileName ), "ext_data/ranksets/%s.ranks", rpg_rankSet.string );
	if ( !BG_ParseRankNames( fileName, g_rankNames ) ) 
	{
		G_Printf( S_COLOR_RED "ERROR: Could not load rankset %s. Reverting to default.\n", fileName );
		trap_Cvar_Set( "rpg_rankSet", RANKSET_DEFAULT );

		if ( !BG_ParseRankNames( va( "ext_data/ranksets/%s.ranks", RANKSET_DEFAULT ), g_rankNames ) ) 
		{
			G_Error( "Could not load default rankset: %s", RANKSET_DEFAULT );
		}
	}

	level.time = levelTime;
	level.startTime = levelTime;
	level.restarted = restart;

	//level.message = levelTime - (int)(rpg_timedmessagetime.value * 60000) + 30000;
	if ( rpg_timedmessagetime.value < 0.2 ) {
		messageTime = 0.2;
	} else {
		messageTime = rpg_timedmessagetime.value;
	}

	level.message = levelTime + (messageTime * 60000);

	level.snd_fry = G_SoundIndex("sound/player/fry.wav");	// FIXME standing in lava / slime

	if ( g_gametype.integer != GT_SINGLE_PLAYER && g_log.string[0] ) {
		if ( g_logSync.integer ) {
			trap_FS_FOpenFile( g_log.string, &level.logFile, FS_APPEND_SYNC );
		} else {
			trap_FS_FOpenFile( g_log.string, &level.logFile, FS_APPEND );
		}
		if ( !level.logFile ) {
			G_Printf( "WARNING: Couldn't open logfile: %s\n", g_log.string );
		} else {
			char	serverinfo[MAX_INFO_STRING];

			trap_GetServerinfo( serverinfo, sizeof( serverinfo ) );

			G_LogPrintf("------------------------------------------------------------\n" );
			G_LogPrintf("InitGame: %s\n", serverinfo );
		}
	} else {
		G_Printf( "Not logging to disk.\n" );
	}

	#ifdef G_LUA
	G_LuaInit();
	#endif

	G_LogWeaponInit();

	G_InitWorldSession();

	// initialize all entities for this game
	memset( g_entities, 0, MAX_GENTITIES * sizeof(g_entities[0]) );
	level.gentities = g_entities;

	// initialize all clients for this game
	level.maxclients = g_maxclients.integer;
	memset( g_clients, 0, MAX_CLIENTS * sizeof(g_clients[0]) );
	level.clients = g_clients;

	// set client fields on player ents
	for ( i=0 ; i<level.maxclients ; i++ ) {
		g_entities[i].client = level.clients + i;
	}
	
	// always leave room for the max number of clients,
	// even if they aren't all used, so numbers inside that
	// range are NEVER anything but clients
	level.num_entities = MAX_CLIENTS;

	// let the server system know where the entites are
	trap_LocateGameData( level.gentities, level.num_entities, sizeof( gentity_t ), 
		&level.clients[0].ps, sizeof( level.clients[0] ) );

	// reserve some spots for dead player bodies
	InitBodyQue();

	ClearRegisteredItems();

	// parse the map usables file
	G_SetupUsablesStrings();

	// parse the key/value pairs and spawn gentities
	G_SpawnEntitiesFromString();

	//TiM: load a locations file, whereever possible
	G_LoadLocationsFile();

	//GSIO: load server change file if avaible
	G_LoadServerChangeFile();

	//GSIO: load map change file if avaible
	G_LoadMapChangeFile();

	//GSIO: load holodeck file if avaible
	G_LoadHolodeckFile();

	// general initialization
	G_FindTeams();

	// make sure we have flags for CTF, etc
	G_CheckTeamItems();

	SaveRegisteredItems();

	G_Printf ("-----------------------------------\n");

	if( g_gametype.integer == GT_SINGLE_PLAYER || trap_Cvar_VariableIntegerValue( "com_buildScript" ) ) {
		G_ModelIndex( SP_PODIUM_MODEL );
		G_SoundIndex( "sound/player/gurp1.wav" );
		G_SoundIndex( "sound/player/gurp2.wav" );
	}
	if (g_gametype.integer >= GT_TEAM || trap_Cvar_VariableIntegerValue( "com_buildScript" ) )
	{
		G_ModelIndex( TEAM_PODIUM_MODEL );
	}

	if ( trap_Cvar_VariableIntegerValue( "bot_enable" ) ) {
		BotAISetup( restart );
		BotAILoadMap( restart );
		G_InitBots( restart );
	}

	G_InitModRules();
	
	levelExiting = qfalse;

/*RPG-X J2J************************************************************************************/
	G_Printf ("Initializing RPG-X Globals...");
	SpawnPnt = SelectRandomSpawnPoint();			//Grab a random spawn point.

	//TiM : Reset teh recon system on game init.
	//Leave this out for now to make this data persistant.
	//Altho, make sure to init the arrays before actually using lol
	
	//memset( &g_reconData, 0, sizeof( g_reconData ) );
	//g_reconNum = 0;

	//WARNING - used hard coded number to shut up compiler, 1023 is MAX_ENTITIES (which apperently cant be increased without substansial exe recoding)
	//TiM : NB Ents 0 -> 128 are clients only. cyclicng thru all ents here is not needed.
	for(i = 0; i < MAX_CLIENTS; i++)
	{
		//g_entities[i].last_tr116_fire = 0;
		
		//RPG-X: Redtechie - Make sure score cant be chnaged unless other wise told to
		if(g_entities[i].client){
			g_entities[i].client->UpdateScore = qfalse;
			g_entities[i].client->AdminFailed = 0; // RPG-X | Phenix | 21/11/2004 | Init Admin Failed Integer
			g_entities[i].client->LoggedAsAdmin = qfalse;
			g_entities[i].client->LoggedAsDeveloper = qfalse;
		}
	}

	for ( i = 0; i < MAX_CLIENTS; i++ )
	{
		lastKillTime[i] = level.time-30000;

		//FKR
		LastFKRadius[i] = level.time - rpg_forcekillradiuswaittime.integer;

		//Transporter
		memset( &TransDat[i], 0, sizeof( TransDat[i] ) );
		TransDat[i].LastClick = level.time-5000;				//Make last click current time less 5 seconds.
		//TransDat[i].Used = qfalse;							//And set both site to site and tricorder to unused.
		//TransDat[i].pUsed = qfalse;
		//And Zero the vectors
		//Huh... why couldn't we use the memset func 
		//here for most of those =0 statements?
		/*VectorCopy(vec3_origin, TransDat[i].TransCoord);
		VectorCopy(vec3_origin, TransDat[i].TransCoordRot);
		VectorCopy(vec3_origin, TransDat[i].pTransCoord);
		VectorCopy(vec3_origin, TransDat[i].pTransCoordRot);*/
		//TransDat[i].beamed = qfalse;
		//TransDat[i].beamer = -1;
		//TransDat[i].beamTime = 0;

		//Drag Data
		DragDat[i].AdminId = -1;
		//DragDat[i].distance = 0.0f;
	}

	//Couldn't think of anywhere else for this, so here it goes.
	//TiM - WTF?  You can't cache multimedia assets like that in the game module. O_o
	//The server couldn't care less about playing sounds.  No one would hear them >.<
	//n00bsnd = trap_S_RegisterSound("sound\n00b.mp3");

	//RPG-X: RedTechie - Set Shake cvars back to normal just to stop hacking
	//trap_SendConsoleCommand( EXEC_APPEND, "set rpg_servershakeallclients 0\n" );
	//trap_SendConsoleCommand( EXEC_APPEND, "set rpg_servershakeallclientsintensity 2\n" );

	// check for remap file, load and apply if one if found
	//G_LoadShaderRemaps();

	//Check spawn file - not in this release yet
	//G_ParseSpawnFile();

	G_Printf( "%i entities loaded.\n", level.num_entities );

	G_Printf ("COMPLETED\n");

	#ifdef G_LUA
	LuaHook_G_InitGame(levelTime, randomSeed, restart);
	#endif

	if(dev_showTriggers.integer && !restart) {
		gentity_t *t;
		t = G_Spawn();
		if(t) {
			t->think = Dev_ShowTriggers;
			t->nextthink = level.time + 1000;
		}
	}
/*************************************************************************************************/

	G_Printf("                       ,.                      \n");	G_Printf("          ..:,        :Xt.       ,:.            \n");
    G_Printf("         ,=+t:       .IRX=       :++=.         \n");	G_Printf("        .=iVt:.      :RYYI.      .itt+         \n");    
	G_Printf("       .:tXI=;.      tRtiV;       ,IYY:.       \n");	G_Printf("      .+;ii=;.      ,XVi+Vt.       :tIi+      \n");    
	G_Printf("     .;ti;;:.       +RI++IY,        ,+tt=.     \n");	G_Printf("    ,++YY;.        ,XXi+++X=         ;IYI=.    \n");    
	G_Printf("    ;ttY+;.    .,=iVRI++++YX+;.       ;VYt;    \n");	G_Printf("   .;ii+=,   .;IXRRXVi++++iVRXVi:.    ,=iii.   \n");    
	G_Printf("  .==;ti,  .;YRRVVXYii+++++IVIVRXt,   ,+=tI=   \n");	G_Printf("  .iitY=, .tRRVXXVRV+++ii++YRXVIYXV;   :tYti,  \n");   
	G_Printf("  .+iii=,,IBVVXYiiXViiiiiiitVtIXViVR=  ,+t+I:  \n");	G_Printf("   =+=I:.tBVXVt=;tRIiiiiiiiiXi:=YXiIX; :+=It;  \n");    
	G_Printf(" .;;tYt:;RVVV+=:,YRiiiiiiiiiYI,.:IXiVY..+IYi=  \n");	G_Printf(" .ti=t+;tRIXi;, :XViiiiiiiiiIV:  ,YViX=.:titt. \n");
	G_Printf("  iY++I;YVYY=:  +BIiiiiiiiiiiX=   +XiVi;i++Vi, \n");    G_Printf(" ,+YYYI:VYYY;. .YRiiiiiiiiiiiVt.  ;RIYt:IIVVi: \n");	
	G_Printf(" ,+tYXi;YVIX;  ;RVtiiiiIXXtiiVI,  iRIVt,=XVit: \n");    G_Printf(" .+iiti++XiXI. iBIiiiiYXIIXtiIV: :XXIV++;i+iI;.\n");
	G_Printf("  ;Ii=ii:VYtRi,VRtiiiVVi=;IXitX=;VBYXI=i+;iV+;.\n");    G_Printf("  ;tYtVt;;XYIRXBVttiVV+;:.:VYiXVRBVXY+;+IYVt+, \n");	
	G_Printf("  =iiItii,=XVIRRIttXV+=:..,tRtVBXVRI+=i:iIit+. \n");    G_Printf("  :t==++I:.=YXYIIiYBXYIttIVRBYtVXXI+;;t+;;+Y=, \n");
	G_Printf("   +I=;+Y= .:IRItYIVXRRRBBRXXVIRY+=;.:i=;iVi;. \n");    G_Printf("   .+IYVV+:  +BYXXVXXXXXXXXXVRVVi;:.:;tVYY+=:  \n");	
	G_Printf("    .+ttii+ .IBXY++ittIIIti++tXXi, .++=tI+;:   \n");    G_Printf("     ;YYtIY;;VBI+;:,::;;;;;:,:IBt,::tItYV=.    \n");
	G_Printf("      =IYYI++ti+;,   .......  :Xt;i=iYYI+;.    \n");    G_Printf("      .:+i++ii;;.             .=i=+i=t+;;:.    \n");
	G_Printf("        ,tYIVI==:,..       ..,;=+iYIVt:..      \n");    G_Printf("         ,itt+iIYYti;.   ,;itYIIt:iIi=;.       \n");
	G_Printf("          .:;;:+tIIVIi:.;iYYIii+=:,;;:.        \n");    G_Printf("            .  ,:=itIXi.tXYit=;::,  .          \n");	
	G_Printf("                 .+tti=,,iIt+;.                \n");    G_Printf("                  .:;;:. ,;;;:.                \n");	
	
}

extern void G_RestoreClientInitialStatus( gentity_t *ent );
extern int	borgQueenClientNum;
void G_CheckResetAssimilationClients( void )
{
	if ( g_pModAssimilation.integer != 0 )
	{
		gentity_t *ent;
		int			i;
		//clear current queen
		borgQueenClientNum = -1;
		//put the assimilated players back on their original team and class
		for ( i = 0; i < level.maxclients; i++ )
		{
			ent = &g_entities[i];
			if ( ent->client && ent->inuse )
			{
				G_RestoreClientInitialStatus( ent );
			}
		}
		//clear borg team
		borgTeam = initialBorgTeam;
	}
}
void EliminationRespawn( gentity_t *ent, char *team );
void G_CheckResetEliminationClients( void )
{
	if ( g_pModElimination.integer != 0 )
	{//no players respawn when in elimination
		gentity_t	*client;
		int			i;

		for ( i = 0; i < level.numConnectedClients; i++ )
		{
			client = &g_entities[&level.clients[level.sortedClients[i]] - level.clients];
			if ( client->team && client->client->sess.sessionTeam == TEAM_SPECTATOR )
			{
				EliminationRespawn( client, client->team );
			}
		}
	}
}

/*
=================
G_ShutdownGame
=================
*/
void G_ShutdownGame( int restart ) {
	G_CheckResetAssimilationClients();
	G_CheckResetEliminationClients();

	G_Printf ("==== ShutdownGame ====\n");

	#ifdef G_LUA
	LuaHook_G_Shutdown(restart);
	G_LuaShutdown();
	#endif

#if 0	// kef -- Pat sez this is causing some trouble these days
	G_LogWeaponOutput();
#endif
	if ( level.logFile ) {
		G_LogPrintf("ShutdownGame:\n" );
		G_LogPrintf("------------------------------------------------------------\n" );
		trap_FS_FCloseFile( level.logFile );
	}

	// write all the client session data so we can get it back
	G_WriteSessionData();

	if ( trap_Cvar_VariableIntegerValue( "bot_enable" ) ) {
		BotAIShutdown( restart );
	}
}



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

#ifndef GAME_HARD_LINKED
// this is only here so the functions in q_shared.c and bg_*.c can link

void QDECL Com_Error ( int errlevel, const char *error, ... ) {
	va_list		argptr;
	char		text[1024];

	va_start (argptr, error);
	vsprintf (text, error, argptr);
	va_end (argptr);

	G_Error( "%s", text);
}

void QDECL Com_Printf( const char *msg, ... ) {
	va_list		argptr;
	char		text[1024];

	va_start (argptr, msg);
	vsprintf (text, msg, argptr);
	va_end (argptr);

	G_Printf ("%s", text);
}

#endif

/*
========================================================================

PLAYER COUNTING / SCORE SORTING

========================================================================
*/

/*
=============
AddTournamentPlayer

If there are less than two tournament players, put a
spectator in the game and restart
=============
*/
void AddTournamentPlayer( void ) {
	int			i;
	gclient_t	*client;
	gclient_t	*nextInLine;
	clientSession_t *sess;

	if ( level.numPlayingClients >= 2 ) {
		return;
	}

	// never change during intermission
	if ( level.intermissiontime ) {
		return;
	}

	nextInLine = NULL;

	for ( i = 0 ; i < level.maxclients ; i++ ) {
		client = &level.clients[i];
		if ( client->pers.connected != CON_CONNECTED ) {
			continue;
		}
		sess = &client->sess;
		if ( sess->sessionTeam != TEAM_SPECTATOR ) {
			continue;
		}
		// never select the dedicated follow or scoreboard clients
		if ( sess->spectatorState == SPECTATOR_SCOREBOARD || 
			sess->spectatorClient < 0  ) {
			continue;
		}

		if ( !nextInLine || sess->spectatorTime < nextInLine->sess.spectatorTime ) {
			nextInLine = client;
		}
	}

	if ( !nextInLine ) {
		return;
	}

	level.warmupTime = -1;

	// set them to free-for-all team
	SetTeam( &g_entities[ nextInLine - level.clients ], "f" );
}


/*
=======================
RemoveTournamentLoser

Make the loser a spectator at the back of the line
=======================
*/
void RemoveTournamentLoser( void ) {
	int			clientNum;

	if ( level.numPlayingClients != 2 ) {
		return;
	}

	clientNum = level.sortedClients[1];

	if ( level.clients[ clientNum ].pers.connected != CON_CONNECTED ) {
		return;
	}

	// make them a spectator
	SetTeam( &g_entities[ clientNum ], "s" );
}


/*
=======================
AdjustTournamentScores

=======================
*/
void AdjustTournamentScores( void ) {
	int			clientNum;

	clientNum = level.sortedClients[0];
	if ( level.clients[ clientNum ].pers.connected == CON_CONNECTED ) {
		level.clients[ clientNum ].sess.wins++;
		ClientUserinfoChanged( clientNum );
	}

	clientNum = level.sortedClients[1];
	if ( level.clients[ clientNum ].pers.connected == CON_CONNECTED ) {
		level.clients[ clientNum ].sess.losses++;
		ClientUserinfoChanged( clientNum );
	}

}



/*
=============
SortRanks

=============
*/
int QDECL SortRanks( const void *a, const void *b ) {
	gclient_t	*ca, *cb;

	ca = &level.clients[*(int *)a];
	cb = &level.clients[*(int *)b];

	// sort special clients last
	if ( ca->sess.spectatorState == SPECTATOR_SCOREBOARD || ca->sess.spectatorClient < 0 ) {
		return 1;
	}
	if ( cb->sess.spectatorState == SPECTATOR_SCOREBOARD || cb->sess.spectatorClient < 0  ) {
		return -1;
	}

	// then connecting clients
	if ( ca->pers.connected == CON_CONNECTING ) {
		return 1;
	}
	if ( cb->pers.connected == CON_CONNECTING ) {
		return -1;
	}


	// then spectators
	if ( ca->sess.sessionTeam == TEAM_SPECTATOR && cb->sess.sessionTeam == TEAM_SPECTATOR ) {
		if ( ca->sess.spectatorTime < cb->sess.spectatorTime ) {
			return -1;
		}
		if ( ca->sess.spectatorTime > cb->sess.spectatorTime ) {
			return 1;
		}
		return 0;
	}
	if ( ca->sess.sessionTeam == TEAM_SPECTATOR ) {
		return 1;
	}
	if ( cb->sess.sessionTeam == TEAM_SPECTATOR ) {
		return -1;
	}

	// then sort by score & number of times killed
	if ( ca->ps.persistant[PERS_SCORE]
		> cb->ps.persistant[PERS_SCORE] ) {
		return -1;
	}
	if ((ca->ps.persistant[PERS_SCORE] == cb->ps.persistant[PERS_SCORE]) &&
		(ca->ps.persistant[PERS_KILLED] < cb->ps.persistant[PERS_KILLED])   )
	{	return -1;}

	if ( ca->ps.persistant[PERS_SCORE]
		< cb->ps.persistant[PERS_SCORE] ) {
		return 1;
	}
	if ((ca->ps.persistant[PERS_SCORE] == cb->ps.persistant[PERS_SCORE]) &&
		(ca->ps.persistant[PERS_KILLED] > cb->ps.persistant[PERS_KILLED])   )
	{	return 1;}

	return 0;
}

/*
============
CalculateRanks

Recalculates the score ranks of all players
This will be called on every client connect, begin, disconnect, death,
and team change.

FIXME: for elimination, the last man standing must be ranked first
============
*/
void CalculateRanks( qboolean fromExit ) {
	int		i;
	int		rank;
	int		score;
	int		newScore;
	gclient_t	*cl;

	level.follow1 = -1;
	level.follow2 = -1;
	level.numConnectedClients = 0;
	level.numNonSpectatorClients = 0;
	level.numPlayingClients = 0;
	level.numVotingClients = 0;		// don't count bots
	for ( i = 0 ; i < level.maxclients ; i++ ) {
		if ( level.clients[i].pers.connected != CON_DISCONNECTED ) {
			level.sortedClients[level.numConnectedClients] = i;
			level.numConnectedClients++;

			if ( level.clients[i].sess.sessionTeam != TEAM_SPECTATOR ) {
				level.numNonSpectatorClients++;
			
				// decide if this should be auto-followed
				if ( level.clients[i].pers.connected == CON_CONNECTED ) {
					level.numPlayingClients++;
					if ( !(g_entities[i].r.svFlags & SVF_BOT) ) {
						level.numVotingClients++;
					}
					if ( level.follow1 == -1 ) {
						level.follow1 = i;
					} else if ( level.follow2 == -1 ) {
						level.follow2 = i;
					}
				}
			}
		}
	}

	qsort( level.sortedClients, level.numConnectedClients, 
		sizeof(level.sortedClients[0]), SortRanks );

	// set the rank value for all clients that are connected and not spectators
	if ( g_gametype.integer >= GT_TEAM ) {
		// in team games, rank is just the order of the teams, 0=red, 1=blue, 2=tied
		for ( i = 0;  i < level.numConnectedClients; i++ ) {
			cl = &level.clients[ level.sortedClients[i] ];
			if ( level.teamScores[TEAM_RED] == level.teamScores[TEAM_BLUE] ) {
				cl->ps.persistant[PERS_RANK] = 2;
			} else if ( level.teamScores[TEAM_RED] > level.teamScores[TEAM_BLUE] ) {
				cl->ps.persistant[PERS_RANK] = 0;
			} else {
				cl->ps.persistant[PERS_RANK] = 1;
			}
		}
	} else {	
		rank = -1;
		score = 0;
		for ( i = 0;  i < level.numPlayingClients; i++ ) {
			cl = &level.clients[ level.sortedClients[i] ];
			newScore = cl->ps.persistant[PERS_SCORE];
			if ( i == 0 || newScore != score ) {
				rank = i;
				// assume we aren't tied until the next client is checked
				level.clients[ level.sortedClients[i] ].ps.persistant[PERS_RANK] = rank;
			} else {
				// we are tied with the previous client
				level.clients[ level.sortedClients[i-1] ].ps.persistant[PERS_RANK] = rank | RANK_TIED_FLAG;
				level.clients[ level.sortedClients[i] ].ps.persistant[PERS_RANK] = rank | RANK_TIED_FLAG;
			}
			score = newScore;
			if ( g_gametype.integer == GT_SINGLE_PLAYER && level.numPlayingClients == 1 ) {
				level.clients[ level.sortedClients[i] ].ps.persistant[PERS_RANK] = rank | RANK_TIED_FLAG;
			}
		}
	}

	// set the CS_SCORES1/2 configstrings, which will be visible to everyone
	if ( g_gametype.integer >= GT_TEAM ) {
		trap_SetConfigstring( CS_SCORES1, va("%i", level.teamScores[TEAM_RED] ) );
		trap_SetConfigstring( CS_SCORES2, va("%i", level.teamScores[TEAM_BLUE] ) );
	} else {
		if ( level.numConnectedClients == 0 ) {
			trap_SetConfigstring( CS_SCORES1, va("%i", SCORE_NOT_PRESENT) );
			trap_SetConfigstring( CS_SCORES2, va("%i", SCORE_NOT_PRESENT) );
		} else if ( level.numConnectedClients == 1 ) {
			trap_SetConfigstring( CS_SCORES1, va("%i", level.clients[ level.sortedClients[0] ].ps.persistant[PERS_SCORE] ) );
			trap_SetConfigstring( CS_SCORES2, va("%i", SCORE_NOT_PRESENT) );
		} else {
			trap_SetConfigstring( CS_SCORES1, va("%i", level.clients[ level.sortedClients[0] ].ps.persistant[PERS_SCORE] ) );
			trap_SetConfigstring( CS_SCORES2, va("%i", level.clients[ level.sortedClients[1] ].ps.persistant[PERS_SCORE] ) );
		}
	}

	// see if it is time to end the level
	if ( !fromExit )
	{//not coming this from the CheckExitRules func
		CheckExitRules();
	}

	// if we are at the intermission, send the new info to everyone
	if ( level.intermissiontime ) {
		SendScoreboardMessageToAllClients();
	}
}


/*
========================================================================

MAP CHANGING

========================================================================
*/

/*
========================
SendScoreboardMessageToAllClients

Do this at BeginIntermission time and whenever ranks are recalculated
due to enters/exits/forced team changes
========================
*/
void SendScoreboardMessageToAllClients( void ) {
	int		i;

	for ( i = 0 ; i < level.maxclients ; i++ ) {
		if ( level.clients[ i ].pers.connected == CON_CONNECTED ) {
			DeathmatchScoreboardMessage( g_entities + i );
		}
	}
}

/*
========================
MoveClientToIntermission

When the intermission starts, this will be called for all players.
If a new client connects, this will be called after the spawn function.
========================
*/
void MoveClientToIntermission( gentity_t *ent ) {
	entityState_t *es = &ent->s;
	playerState_t *ps = &ent->client->ps;

	// take out of follow mode if needed
	if ( ent->client->sess.spectatorState == SPECTATOR_FOLLOW ) {
		StopFollowing( ent );
	}


	// move to the spot
	VectorCopy( level.intermission_origin, es->origin );
	VectorCopy( level.intermission_origin, ps->origin );
	VectorCopy (level.intermission_angle, ps->viewangles);
	ps->pm_type = PM_INTERMISSION;
	ps->eFlags ^= EF_TELEPORT_BIT;

	// clean up powerup info
	memset( ps->powerups, 0, sizeof(ps->powerups) );

	ps->eFlags = 0;
	es->eFlags = 0;
	es->eType = ET_GENERAL;
	es->modelindex = 0;
	es->loopSound = 0;
	es->event = 0;
	ent->r.contents = 0;
}

/*
==================
FindIntermissionPoint

This is also used for spectator spawns
==================
*/
void FindIntermissionPoint( void ) {
	gentity_t	*ent, *target;
	vec3_t		dir;

	// find the intermission spot
	ent = G_Find (NULL, FOFS(classname), "info_player_intermission");
	if ( !ent ) {	// the map creator forgot to put in an intermission point...
		SelectSpawnPoint ( vec3_origin, level.intermission_origin, level.intermission_angle );
	} else {
		VectorCopy (ent->s.origin, level.intermission_origin);
		VectorCopy (ent->s.angles, level.intermission_angle);
		// if it has a target, look towards it
		if ( ent->target ) {
			target = G_PickTarget( ent->target );
			if ( target ) {
				VectorSubtract( target->s.origin, level.intermission_origin, dir );
				vectoangles( dir, level.intermission_angle );
			}
		}
	}

}

/*
==================
ClearFiringFlags
==================
*/
void ClearFiringFlags()
{
	int i = 0;
	gentity_t	*ent = NULL;

	for (i=0 ; i< level.maxclients ; i++) 
	{
		ent = g_entities + i;
		if (!ent->inuse)
			continue;
		// clear the firing flag
		if (ent->client)
		{
			ent->client->ps.eFlags &= ~EF_FIRING;
		}
	}
}

/*
==================
BeginIntermission
==================
*/
void BeginIntermission( void ) {
	int			i;
	gentity_t	*client;
	qboolean	doingLevelshot;

	if (level.intermissiontime == -1)
		doingLevelshot = qtrue;
	else
		doingLevelshot = qfalse;

	if ( level.intermissiontime && level.intermissiontime != -1 ) {
		return;		// already active
	}

	G_CheckResetEliminationClients();

	// if in tournament mode, change the wins / losses
	if ( g_gametype.integer == GT_TOURNAMENT ) {
		AdjustTournamentScores();
	}

	level.intermissiontime = level.time;
	FindIntermissionPoint();

	// kef -- make sure none of the players are still firing (cuz we don't want weapons fx going off while
	//they're on the podium)
	ClearFiringFlags();


	// cdr - Want to generate victory pads for all game types  - except level shots (gametype 10)
	UpdateTournamentInfo();
	if (!doingLevelshot)
		SpawnModelsOnVictoryPads();


	// move all clients to the intermission point
	for (i=0 ; i< level.maxclients ; i++) {
		client = g_entities + i;
		if (!client->inuse)
			continue;
		// respawn if dead
		//if ( BG_BorgTransporting( &client->client->ps ) )
		//{//in borg teleport fly around mode, turn it off
		//	client->client->ps.stats[STAT_USEABLE_PLACED] = 0;
		//	client->client->ps.stats[STAT_HOLDABLE_ITEM] = 0;
		//	client->client->ps.eFlags &= ~EF_NODRAW;
		//	client->s.eFlags &= ~EF_NODRAW;
		//	client->flags &= ~FL_NOTARGET;
		//}
		if (client->health <= 0) {
			respawn(client);
		}
		MoveClientToIntermission( client );

	}

	// send the current scoring to all clients
	SendScoreboardMessageToAllClients();
}


void G_ClearObjectives( void )
{
	gentity_t *tent;

	tent = G_TempEntity( vec3_origin, EV_OBJECTIVE_COMPLETE );
	//Be sure to send the event to everyone
	tent->r.svFlags |= SVF_BROADCAST;
	tent->s.eventParm = 0;//tells it to clear all
}
/*
=============
ExitLevel

When the intermission has been exited, the server is either killed
or moved to a new level based on the "nextmap" cvar 

=============
*/
qboolean levelExiting = qfalse;
void ExitLevel (void) {
	int		i;

	levelExiting = qtrue;

	//bot interbreeding
	BotInterbreedEndMatch();

	G_ClearObjectives();
	// if we are running a tournement map, kick the loser to spectator status,
	// which will automatically grab the next spectator and restart
	if ( g_gametype.integer == GT_TOURNAMENT ) {
		if ( !level.restarted ) {
			RemoveTournamentLoser();
			trap_SendConsoleCommand( EXEC_APPEND, "map_restart 0\n" );
			level.restarted = qtrue;
			level.changemap = NULL;
			level.intermissiontime = 0;
		}
		return;	
	}

	trap_SendConsoleCommand( EXEC_APPEND, "vstr nextmap\n" );
	level.changemap = NULL;
	level.intermissiontime = 0;

	//don't reset the bots until after level.intermission is off so that it doesn't send 5 billion score updates
	G_CheckResetAssimilationClients();

	// we need to do this here before chaning to CON_CONNECTING
	G_WriteSessionData();

	// change all client states to connecting, so the early players into the
	// next level will know the others aren't done reconnecting
	for (i=0 ; i< g_maxclients.integer ; i++) {
		if ( level.clients[i].pers.connected == CON_CONNECTED ) {
			level.clients[i].pers.connected = CON_CONNECTING;
		}
	}

}


/*
=================
CheckIntermissionExit

The level will stay at the intermission for a minimum of 5 seconds
If all players wish to continue, the level will then exit.
If one or more players have not acknowledged the continue, the game will
wait 20 seconds before going on.
=================
*/
void CheckIntermissionExit( void ) {
	int			ready, notReady;
	int			i;
	gclient_t	*cl;
	int			readyMask;


	if ( levelExiting )
	{//already on our way out, skip the check
		return;
	}

	if ( level.time < level.intermissiontime + 5000 )
	{
			// bring up the scoreboard after 5 seconds
	}


	// Single player exit does not happen until menu event
	if ( g_gametype.integer == GT_SINGLE_PLAYER ) {
		return;
	}

	// see which players are ready
	ready = 0;
	notReady = 0;
	readyMask = 0;
	for (i=0 ; i< g_maxclients.integer ; i++) {
		cl = level.clients + i;
		if ( cl->pers.connected != CON_CONNECTED ) {
			continue;
		}
		if ( g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT ) {
			continue;
		}

		if ( cl->readyToExit ) {
			ready++;
			if ( i < 16 ) {
				readyMask |= 1 << i;
			}
		} else {
			notReady++;
		}
	}

	// copy the readyMask to each player's stats so
	// it can be displayed on the scoreboard
	for (i=0 ; i< g_maxclients.integer ; i++) {
		cl = level.clients + i;
		if ( cl->pers.connected != CON_CONNECTED ) {
			continue;
		}
		cl->ps.stats[STAT_CLIENTS_READY] = readyMask;
	}

	// never exit in less than five seconds
	if ( level.time < level.intermissiontime + 5000 ) {
		return;
	}

	// if nobody wants to go, clear timer
	if ( !ready ) {
		level.readyToExit = qfalse;
		return;
	}

	// if everyone wants to go, go now
	if ( !notReady ) {
		ExitLevel();
		return;
	}

	// the first person to ready starts the ten second timeout
	if ( !level.readyToExit ) {
		level.readyToExit = qtrue;
		level.exitTime = level.time;
	}

	// if we have waited g_intermissionTime seconds since at least one player
	// wanted to exit, go ahead
	if ( level.time < level.exitTime + (1000 * g_intermissionTime.integer) ) {
		return;
	}

	ExitLevel();
}

/*
=============
ScoreIsTied
=============
*/
qboolean ScoreIsTied( void ) {
	int		a, b;

	if ( level.numPlayingClients < 2 ) {
		return qfalse;
	}
	
	if ( g_gametype.integer >= GT_TEAM ) {
		return level.teamScores[TEAM_RED] == level.teamScores[TEAM_BLUE];
	}

	a = level.clients[level.sortedClients[0]].ps.persistant[PERS_SCORE];
	b = level.clients[level.sortedClients[1]].ps.persistant[PERS_SCORE];

	return a == b;
}

/*
=================
CheckExitRules

There will be a delay between the time the exit is qualified for
and the time everyone is moved to the intermission spot, so you
can see the last frag.
=================
*/
extern int	borgQueenClientNum;
void CheckExitRules( void ) {
	
	//RPG-X: RedTechie - No exit in RPG Your TRAPED! MHAHAHA
	return;

	/*int			i;
	gclient_t	*cl;

	// if at the intermission, wait for all non-bots to
	// signal ready, then go to next level
	if ( level.intermissiontime ) {
		CheckIntermissionExit ();
		return;
	}

	if ( level.intermissionQueued ) {
		if ( level.time - level.intermissionQueued >= INTERMISSION_DELAY_TIME ) {
			level.intermissionQueued = 0;
			BeginIntermission();
		}
		return;
	}
	
	//RPG-X: RedTechie - hihohiho is off to commenting out warmup code i go
	//if ( g_doWarmup.integer )
	//{
	//	if ( level.warmupTime != 0 )
	//	{
	//		if ( level.warmupTime < 0 || level.time - level.startTime <= level.warmupTime )
	//		{//don't win until warmup is done
	//			if ( g_pModAssimilation.integer != 0 || g_pModElimination.integer != 0 )
	//			{
	//				numKilled = 0;
	//			}
	//			return;
	//		}
	//	}
	//}

	// check for sudden death
	if ( ScoreIsTied() && g_pModAssimilation.integer == 0 && g_pModElimination.integer == 0 )
	{
		// always wait for sudden death
		return;
	}

	if ( g_timelimit.integer && !level.warmupTime && g_pModAssimilation.integer == 0 && g_pModElimination.integer == 0 )
	{
		if ( level.time - level.startTime >= g_timelimit.integer*60000 )
		{
			trap_SendServerCommand( -1, "print \"Timelimit hit.\n\"");
			G_LogExit( "Timelimit hit." );
			return;
		}
	}

	if ( level.numPlayingClients < 2 )
	{
		//not enough players
		if ( g_pModAssimilation.integer != 0 || g_pModElimination.integer != 0 )
		{
			numKilled = 0;
		}
		return;
	}

	if ( g_pModAssimilation.integer != 0 )
	{//check assimilation rules
		if ( level.numConnectedClients > 1 && numKilled > 0 )
		{
			gclient_t *survivor = NULL;

			if ( borgQueenClientNum != -1 )
			{//see if borg queen is dead first
				if ( g_entities[borgQueenClientNum].health <= 0 )
				{//the queen is dead!
					//FIXME: What if the queen disconnects somehow...?  Shouldn't be possible
					G_LogExit( "The Borg Queen has been killed!" );
					return;
				}
			}

			//See if only one player remains alive, if so, end it.
			for ( i = 0; i < level.maxclients; i++ )
			{
				cl = &level.clients[i];
				if ( cl->pers.connected == CON_CONNECTED && cl->sess.sessionTeam != TEAM_SPECTATOR && cl->sess.sessionClass != PC_BORG )
				{
					survivor = cl;
					break;
				}
			}
			if ( survivor == NULL )
			{
				G_LogExit( "Assimilation Complete." );
				return;
			}
		}
		//don't check anything else
		return;
	}

	if ( g_pModElimination.integer != 0 )
	{//check elimination rules
		gclient_t *survivor = NULL;
		//See if only one player remains alive, if so, end it.
		if ( level.numConnectedClients > 1 && numKilled > 0 )
		{
			for ( i = 0; i < level.numConnectedClients; i++ )
			{
				cl = &level.clients[ level.sortedClients[i] ];
				if ( cl->sess.sessionTeam != TEAM_SPECTATOR && !(cl->ps.eFlags&EF_ELIMINATED) )
				{
					if ( survivor != NULL )
					{
						if ( g_gametype.integer < GT_TEAM || cl->sess.sessionTeam != survivor->sess.sessionTeam )
						{//not in a team game or survivor is on same team as previously found survivor, keep looking
							survivor = NULL;
							break;
						}
					}
					else
					{
						survivor = cl;
					}
				}
			}
		}
		if ( survivor != NULL )
		{
			G_LogExit( "Last Man Standing." );
		}
		//don't check anything else
		return;
	}

	if ( g_gametype.integer != GT_CTF && g_fraglimit.integer ) 
	{//check fraglimit
		if ( level.teamScores[TEAM_RED] >= g_fraglimit.integer ) {
			trap_SendServerCommand( -1, "print \"Red hit the point limit.\n\"" );
			G_LogExit( "Fraglimit hit." );
			return;
		}

		if ( level.teamScores[TEAM_BLUE] >= g_fraglimit.integer ) {
			trap_SendServerCommand( -1, "print \"Blue hit the point limit.\n\"" );
			G_LogExit( "Fraglimit hit." );
			return;
		}

		for ( i=0 ; i< g_maxclients.integer ; i++ ) {
			cl = level.clients + i;
			if ( cl->pers.connected != CON_CONNECTED ) {
				continue;
			}
			if ( cl->sess.sessionTeam != TEAM_FREE ) {
				continue;
			}

			if ( cl->ps.persistant[PERS_SCORE] >= g_fraglimit.integer ) {
				G_LogExit( "Fraglimit hit." );
				trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " hit the point limit.\n\"",
					cl->pers.netname ) );
				return;
			}
		}
	}

	if ( g_gametype.integer == GT_CTF && g_capturelimit.integer ) 
	{//check CTF
		if ( level.teamScores[TEAM_RED] >= g_capturelimit.integer ) {
			trap_SendServerCommand( -1, "print \"Red hit the capturelimit.\n\"" );
			G_LogExit( "Capturelimit hit." );
			return;
		}

		if ( level.teamScores[TEAM_BLUE] >= g_capturelimit.integer ) {
			trap_SendServerCommand( -1, "print \"Blue hit the capturelimit.\n\"" );
			G_LogExit( "Capturelimit hit." );
			return;
		}
	}*/
}



/*
========================================================================

FUNCTIONS CALLED EVERY FRAME

========================================================================
*/


/*
=============
CheckTournement

Once a frame, check for changes in tournement player state
=============
*/
void CheckTournement( void ) {
	if ( level.numPlayingClients == 0 ) {
		return;
	}

	if ( g_gametype.integer == GT_TOURNAMENT ) {

		// pull in a spectator if needed
		//RPG-X: RedTechie - pulling on people isnt nice
		/*if ( level.numPlayingClients < 2 ) {
			AddTournamentPlayer();
		}*/

		// if we don't have two players, go back to "waiting for players"
		//RPG-X: RedTechie - No warmup!
		/*if ( level.numPlayingClients != 2 ) {
			if ( level.warmupTime != -1 ) {
				level.warmupTime = -1;
				trap_SetConfigstring( CS_WARMUP, va("%i", level.warmupTime) );
				G_LogPrintf( "Warmup:\n" );
			}
			return;
		}*/

		if ( level.warmupTime == 0 || level.warmupTime != 0) {//RPG-X: RedTechie - No warmup Fail safe
			return;
		}

		// if the warmup is changed at the console, restart it
		//RPG-X: RedTechie - No warmup!
		/*if ( g_warmup.modificationCount != level.warmupModificationCount ) {
			level.warmupModificationCount = g_warmup.modificationCount;
			level.warmupTime = -1;
		}*/

		// if all players have arrived, start the countdown
		//RPG-X: RedTechie - No warmup!
		/*if ( level.warmupTime < 0 )
		{
			if ( level.numPlayingClients == 2 )
			{
				if ( g_warmup.integer > 1 )
				{
					// fudge by -1 to account for extra delays
					level.warmupTime = level.time + ( g_warmup.integer - 1 ) * 1000;
					trap_SetConfigstring( CS_WARMUP, va("%i", level.warmupTime) );
				}
				else
				{
					level.warmupTime = 0;
				}
			}
			return;
		}*/
		
		//RPG-X: RedTechie - No warmup!
		// if the warmup time has counted down, restart
		/*if ( level.time > level.warmupTime ) {
			level.warmupTime += 10000;
			trap_Cvar_Set( "g_restarted", "1" );
			trap_SendConsoleCommand( EXEC_APPEND, "map_restart 0\n" );
			level.restarted = qtrue;
			return;
		}*/
	} else if ( g_gametype.integer != GT_SINGLE_PLAYER /*&& g_doWarmup.integer*/ ) { //RPG-X: RedTechie - No warmup!
		int		counts[TEAM_NUM_TEAMS];
		//qboolean	notEnough = qfalse;

		if ( g_gametype.integer > GT_TEAM ) {
			counts[TEAM_BLUE] = TeamCount( -1, TEAM_BLUE );
			counts[TEAM_RED] = TeamCount( -1, TEAM_RED );
		
		//RPG-X: RedTechie - Enough players always
		/*	if (counts[TEAM_RED] < 1 || counts[TEAM_BLUE] < 1) {
				notEnough = qtrue;
			}
		} else if ( level.numPlayingClients < 2 ) {
			notEnough = qtrue;
		}*/
		
		//RPG-X: RedTechie - No warmup!
		/*if ( notEnough ) {
			if ( level.warmupTime != -1 ) {
				level.warmupTime = -1;
				trap_SetConfigstring( CS_WARMUP, va("%i", level.warmupTime) );
				G_LogPrintf( "Warmup:\n" );
			}
			return; // still waiting for team members
		}*/
		
		if ( level.warmupTime == 0) {
			return;
		}

		// if the warmup is changed at the console, restart it
		//RPG-X: RedTechie - No warmup!
		/*if ( g_warmup.modificationCount != level.warmupModificationCount ) {
			level.warmupModificationCount = g_warmup.modificationCount;
			level.warmupTime = -1;
		}*/

		// if all players have arrived, start the countdown
		//RPG-X: RedTechie - No warmup!
		/*if ( level.warmupTime < 0 ) {
			// fudge by -1 to account for extra delays
			level.warmupTime = level.time + ( g_warmup.integer - 1 ) * 1000;
			trap_SetConfigstring( CS_WARMUP, va("%i", level.warmupTime) );
			return;
		}*/

		// if the warmup time has counted down, restart
		//RPG-X: RedTechie - No warmup!
		/*if ( level.time > level.warmupTime ) {
			level.warmupTime += 10000;
			trap_Cvar_Set( "g_restarted", "1" );
			trap_SendConsoleCommand( EXEC_APPEND, "map_restart 0\n" );
			level.restarted = qtrue;
			return;*/
		}
	}
}


/*
==================
CheckVote
==================
*/
void CheckVote( void ) {
	if ( !level.voteTime ) {
		return;
	}
	if ( level.time - level.voteTime >= VOTE_TIME ) {
		trap_SendServerCommand( -1, "print \"Vote failed.\n\"" );
	} else {
		if ( level.voteYes > level.numVotingClients/2 ) {
			// execute the command, then remove the vote
			trap_SendServerCommand( -1, "print \"Vote passed.\n\"" );
			trap_SendConsoleCommand( EXEC_APPEND, va("%s\n", level.voteString ) );
		} else if ( level.voteNo >= level.numVotingClients/2 ) {
			// same behavior as a timeout
			trap_SendServerCommand( -1, "print \"Vote failed.\n\"" );
		} else {
			// still waiting for a majority
			return;
		}
	}
	level.voteTime = 0;
	trap_SetConfigstring( CS_VOTE_TIME, "" );

}


/*
==================
CheckCvars
==================
*/
void CheckCvars( void ) {
	static int lastMod = -1;

	if ( g_password.modificationCount != lastMod ) {
		lastMod = g_password.modificationCount;
		if ( *g_password.string && Q_stricmp( g_password.string, "none" ) ) {
			trap_Cvar_Set( "g_needpass", "1" );
		} else {
			trap_Cvar_Set( "g_needpass", "0" );
		}
	}
}

/*
=============
G_RunThink

Runs thinking code for this frame if necessary
=============
*/
void G_RunThink (gentity_t *ent) {
	float	thinktime;

	thinktime = ent->nextthink;
	if (thinktime <= 0) {
		return;
	}
	if (thinktime > level.time) {
		return;
	}
	
	ent->nextthink = 0;
	if (!ent->think) {
		G_Error ( "NULL ent->think");
	}

	#ifdef G_LUA
	if(ent->luaThink && !ent->client)
	{
		LuaHook_G_EntityThink(ent->luaThink, ent->s.number);
	}
	#endif

	ent->think (ent);
}

/*
================
G_RunFrame

Advances the non-player objects in the world
================
*/

extern void SetClass( gentity_t *ent, char *s, char *teamName, qboolean SaveToCvar );
void DragCheck( void );								//RPG-X: J2J - Added to rid warning.
void CheckHealthInfoMessage( void );
extern void G_PickBorgQueen( void );
extern void INeedAHero( void );
extern qboolean levelExiting;
extern int actionHeroClientNum;
void G_RunFrame( int levelTime ) {
	int			i;
	gentity_t	*ent;
	gclient_t	*client;
	playerState_t *ps;
	entityState_t *es;
	int			msec;
int start, end;

	// if we are waiting for the level to restart, do nothing
	if ( level.restarted ) {
		return;
	}

	level.framenum++;
	level.previousTime = level.time;
	level.time = levelTime;
	msec = level.time - level.previousTime;

	// get any cvar changes
	G_UpdateCvars();

	//
	// go through all allocated objects
	//
start = trap_Milliseconds();
	ent = &g_entities[0];
	for (i=0 ; i<level.num_entities ; i++, ent++) {
		if ( !ent->inuse ) {
			continue;
		}

		es = &ent->s;
		ps = &ent->client->ps;

		// clear events that are too old
		if ( level.time - ent->eventTime > EVENT_VALID_MSEC ) {
			if ( es->event ) {
				es->event = 0;	// &= EV_EVENT_BITS;
				if ( ent->client ) {
					ps->externalEvent = 0;
					ps->events[0] = 0;
					ps->events[1] = 0;
					ps->events[2] = 0;
					ps->events[3] = 0;
				}
			}
			if ( ent->freeAfterEvent ) {
				// tempEntities or dropped items completely go away after their event
				G_FreeEntity( ent );
				continue;
			} else if ( ent->unlinkAfterEvent ) {
				// items that will respawn will hide themselves after their pickup event
				ent->unlinkAfterEvent = qfalse;
				trap_UnlinkEntity( ent );
			}
		}

		// temporary entities don't think
		if ( ent->freeAfterEvent ) {
			continue;
		}

		if ( !ent->r.linked && ent->neverFree ) {
			continue;
		}

		if ( !ent->client )
		{
			if ( es->eFlags & EF_ANIM_ONCE )
			{//this must be capped render-side
				es->frame++;
			}
		}

		if ( (es->eType == ET_MISSILE) || (es->eType == ET_ALT_MISSILE) ) {
			G_RunMissile( ent );
			continue;
		}

		if ( es->eType == ET_ITEM || ent->physicsObject ) {
			G_RunItem( ent );
			continue;
		}

		if ( es->eType == ET_MOVER || es->eType == ET_MOVER_STR ) { //RPG-X | GSIO01 | 13/05/2009
			G_RunMover( ent );
			continue;
		}

		if ( i < MAX_CLIENTS ) {
			G_RunClient( ent );
			continue;
		}

		G_RunThink( ent );
	}
	end = trap_Milliseconds();

	start = trap_Milliseconds();
	// perform final fixups on the players
	ent = &g_entities[0];
	for (i=0 ; i < level.maxclients ; i++, ent++ ) {
		if ( ent->inuse ) {
			ClientEndFrame( ent );
		}
	}
	end = trap_Milliseconds();

	// see if it is time to do a tournement restart
	CheckTournement();

	// see if it is time to end the level
	CheckExitRules();

	// update to team status?
	CheckTeamStatus();

	// update to health status
	//CheckHealthInfoMessage();//done from inside CheckTeamStatus now

	// cancel vote if timed out
	CheckVote();

	// for tracking changes
	CheckCvars();

	if ( !levelExiting )
	{
		//keep looking for a borgQueen if we don't have one yet
		if ( borgQueenClientNum == -1 )
		{
			G_PickBorgQueen();
		}
		//keep looking for an actionHero if we don't have one yet
		if ( actionHeroClientNum == -1 )
		{
			INeedAHero();
		}
	}

	//RPG-X: RedTechie - Count down our shake camera timer
	//TiM: NOT NECESSARY
	/*if(rpg_servershakeallclients.integer == 1){
		if(shaketimer < level.time){
			trap_SendConsoleCommand( EXEC_APPEND, "set rpg_servershakeallclients 0\n" );
		}
	}*/

	//RPG-X: J2J - This will check for drag movements that need to be calculated.
	DragCheck();

	for ( i = 0; i < MAX_CLIENTS; i++ )
	{
		ent = &g_entities[i];

		if(!ent || !ent->client)
			continue;

		client = ent->client;

		if (!(client->pers.cmd.buttons & BUTTON_USE)) {
			client->pressedUse = qfalse;
		}

		if (g_classData[client->sess.sessionClass].isn00b/*ent->client->sess.sessionClass == PC_N00B*/)
		{
			if ((client->n00bTime != -1) && (client->n00bTime <= level.time)&&client->origClass[0])
			{
				SetClass( ent, client->origClass, NULL, qtrue );
			}
		}
	}

	//RPG-X: Marcin: To clear pressedUse. - 30/12/2008

	#ifdef G_LUA
	LuaHook_G_RunFrame(levelTime);
	#endif

}