Quake-2

Quake 2 GPL Source Release
Log | Files | Refs

g_main.c (8538B)


      1 /*
      2 Copyright (C) 1997-2001 Id Software, Inc.
      3 
      4 This program is free software; you can redistribute it and/or
      5 modify it under the terms of the GNU General Public License
      6 as published by the Free Software Foundation; either version 2
      7 of the License, or (at your option) any later version.
      8 
      9 This program is distributed in the hope that it will be useful,
     10 but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
     12 
     13 See the GNU General Public License for more details.
     14 
     15 You should have received a copy of the GNU General Public License
     16 along with this program; if not, write to the Free Software
     17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
     18 
     19 */
     20 
     21 #include "g_local.h"
     22 
     23 game_locals_t	game;
     24 level_locals_t	level;
     25 game_import_t	gi;
     26 game_export_t	globals;
     27 spawn_temp_t	st;
     28 
     29 int	sm_meat_index;
     30 int	snd_fry;
     31 int meansOfDeath;
     32 
     33 edict_t		*g_edicts;
     34 
     35 cvar_t	*deathmatch;
     36 cvar_t	*coop;
     37 cvar_t	*dmflags;
     38 cvar_t	*skill;
     39 cvar_t	*fraglimit;
     40 cvar_t	*timelimit;
     41 //ZOID
     42 cvar_t	*capturelimit;
     43 cvar_t	*instantweap;
     44 //ZOID
     45 cvar_t	*password;
     46 cvar_t	*maxclients;
     47 cvar_t	*maxentities;
     48 cvar_t	*g_select_empty;
     49 cvar_t	*dedicated;
     50 
     51 cvar_t	*sv_maxvelocity;
     52 cvar_t	*sv_gravity;
     53 
     54 cvar_t	*sv_rollspeed;
     55 cvar_t	*sv_rollangle;
     56 cvar_t	*gun_x;
     57 cvar_t	*gun_y;
     58 cvar_t	*gun_z;
     59 
     60 cvar_t	*run_pitch;
     61 cvar_t	*run_roll;
     62 cvar_t	*bob_up;
     63 cvar_t	*bob_pitch;
     64 cvar_t	*bob_roll;
     65 
     66 cvar_t	*sv_cheats;
     67 
     68 cvar_t	*flood_msgs;
     69 cvar_t	*flood_persecond;
     70 cvar_t	*flood_waitdelay;
     71 
     72 cvar_t	*sv_maplist;
     73 
     74 void SpawnEntities (char *mapname, char *entities, char *spawnpoint);
     75 void ClientThink (edict_t *ent, usercmd_t *cmd);
     76 qboolean ClientConnect (edict_t *ent, char *userinfo);
     77 void ClientUserinfoChanged (edict_t *ent, char *userinfo);
     78 void ClientDisconnect (edict_t *ent);
     79 void ClientBegin (edict_t *ent);
     80 void ClientCommand (edict_t *ent);
     81 void RunEntity (edict_t *ent);
     82 void WriteGame (char *filename, qboolean autosave);
     83 void ReadGame (char *filename);
     84 void WriteLevel (char *filename);
     85 void ReadLevel (char *filename);
     86 void InitGame (void);
     87 void G_RunFrame (void);
     88 
     89 
     90 //===================================================================
     91 
     92 
     93 void ShutdownGame (void)
     94 {
     95 	gi.dprintf ("==== ShutdownGame ====\n");
     96 
     97 	gi.FreeTags (TAG_LEVEL);
     98 	gi.FreeTags (TAG_GAME);
     99 }
    100 
    101 
    102 /*
    103 =================
    104 GetGameAPI
    105 
    106 Returns a pointer to the structure with all entry points
    107 and global variables
    108 =================
    109 */
    110 game_export_t *GetGameAPI (game_import_t *import)
    111 {
    112 	gi = *import;
    113 
    114 	globals.apiversion = GAME_API_VERSION;
    115 	globals.Init = InitGame;
    116 	globals.Shutdown = ShutdownGame;
    117 	globals.SpawnEntities = SpawnEntities;
    118 
    119 	globals.WriteGame = WriteGame;
    120 	globals.ReadGame = ReadGame;
    121 	globals.WriteLevel = WriteLevel;
    122 	globals.ReadLevel = ReadLevel;
    123 
    124 	globals.ClientThink = ClientThink;
    125 	globals.ClientConnect = ClientConnect;
    126 	globals.ClientUserinfoChanged = ClientUserinfoChanged;
    127 	globals.ClientDisconnect = ClientDisconnect;
    128 	globals.ClientBegin = ClientBegin;
    129 	globals.ClientCommand = ClientCommand;
    130 
    131 	globals.RunFrame = G_RunFrame;
    132 
    133 	globals.ServerCommand = ServerCommand;
    134 
    135 	globals.edict_size = sizeof(edict_t);
    136 
    137 	return &globals;
    138 }
    139 
    140 #ifndef GAME_HARD_LINKED
    141 // this is only here so the functions in q_shared.c and q_shwin.c can link
    142 void Sys_Error (char *error, ...)
    143 {
    144 	va_list		argptr;
    145 	char		text[1024];
    146 
    147 	va_start (argptr, error);
    148 	vsprintf (text, error, argptr);
    149 	va_end (argptr);
    150 
    151 	gi.error (ERR_FATAL, "%s", text);
    152 }
    153 
    154 void Com_Printf (char *msg, ...)
    155 {
    156 	va_list		argptr;
    157 	char		text[1024];
    158 
    159 	va_start (argptr, msg);
    160 	vsprintf (text, msg, argptr);
    161 	va_end (argptr);
    162 
    163 	gi.dprintf ("%s", text);
    164 }
    165 
    166 #endif
    167 
    168 //======================================================================
    169 
    170 
    171 /*
    172 =================
    173 ClientEndServerFrames
    174 =================
    175 */
    176 void ClientEndServerFrames (void)
    177 {
    178 	int		i;
    179 	edict_t	*ent;
    180 
    181 	// calc the player views now that all pushing
    182 	// and damage has been added
    183 	for (i=0 ; i<maxclients->value ; i++)
    184 	{
    185 		ent = g_edicts + 1 + i;
    186 		if (!ent->inuse || !ent->client)
    187 			continue;
    188 		ClientEndServerFrame (ent);
    189 	}
    190 
    191 }
    192 
    193 /*
    194 =================
    195 CreateTargetChangeLevel
    196 
    197 Returns the created target changelevel
    198 =================
    199 */
    200 edict_t *CreateTargetChangeLevel(char *map)
    201 {
    202 	edict_t *ent;
    203 
    204 	ent = G_Spawn ();
    205 	ent->classname = "target_changelevel";
    206 	Com_sprintf(level.nextmap, sizeof(level.nextmap), "%s", map);
    207 	ent->map = level.nextmap;
    208 	return ent;
    209 }
    210 
    211 /*
    212 =================
    213 EndDMLevel
    214 
    215 The timelimit or fraglimit has been exceeded
    216 =================
    217 */
    218 void EndDMLevel (void)
    219 {
    220 	edict_t		*ent;
    221 	char *s, *t, *f;
    222 	static const char *seps = " ,\n\r";
    223 
    224 	// stay on same level flag
    225 	if ((int)dmflags->value & DF_SAME_LEVEL)
    226 	{
    227 		BeginIntermission (CreateTargetChangeLevel (level.mapname) );
    228 		return;
    229 	}
    230 
    231 	if (*level.forcemap) {
    232 		BeginIntermission (CreateTargetChangeLevel (level.forcemap) );
    233 		return;
    234 	}
    235 
    236 	// see if it's in the map list
    237 	if (*sv_maplist->string) {
    238 		s = strdup(sv_maplist->string);
    239 		f = NULL;
    240 		t = strtok(s, seps);
    241 		while (t != NULL) {
    242 			if (Q_stricmp(t, level.mapname) == 0) {
    243 				// it's in the list, go to the next one
    244 				t = strtok(NULL, seps);
    245 				if (t == NULL) { // end of list, go to first one
    246 					if (f == NULL) // there isn't a first one, same level
    247 						BeginIntermission (CreateTargetChangeLevel (level.mapname) );
    248 					else
    249 						BeginIntermission (CreateTargetChangeLevel (f) );
    250 				} else
    251 					BeginIntermission (CreateTargetChangeLevel (t) );
    252 				free(s);
    253 				return;
    254 			}
    255 			if (!f)
    256 				f = t;
    257 			t = strtok(NULL, seps);
    258 		}
    259 		free(s);
    260 	}
    261 
    262 	if (level.nextmap[0]) // go to a specific map
    263 		BeginIntermission (CreateTargetChangeLevel (level.nextmap) );
    264 	else {	// search for a changelevel
    265 		ent = G_Find (NULL, FOFS(classname), "target_changelevel");
    266 		if (!ent)
    267 		{	// the map designer didn't include a changelevel,
    268 			// so create a fake ent that goes back to the same level
    269 			BeginIntermission (CreateTargetChangeLevel (level.mapname) );
    270 			return;
    271 		}
    272 		BeginIntermission (ent);
    273 	}
    274 }
    275 
    276 /*
    277 =================
    278 CheckDMRules
    279 =================
    280 */
    281 void CheckDMRules (void)
    282 {
    283 	int			i;
    284 	gclient_t	*cl;
    285 
    286 	if (level.intermissiontime)
    287 		return;
    288 
    289 	if (!deathmatch->value)
    290 		return;
    291 
    292 //ZOID
    293 	if (ctf->value && CTFCheckRules()) {
    294 		EndDMLevel ();
    295 		return;
    296 	}
    297 	if (CTFInMatch())
    298 		return; // no checking in match mode
    299 //ZOID
    300 
    301 	if (timelimit->value)
    302 	{
    303 		if (level.time >= timelimit->value*60)
    304 		{
    305 			gi.bprintf (PRINT_HIGH, "Timelimit hit.\n");
    306 			EndDMLevel ();
    307 			return;
    308 		}
    309 	}
    310 
    311 	if (fraglimit->value)
    312 		for (i=0 ; i<maxclients->value ; i++)
    313 		{
    314 			cl = game.clients + i;
    315 			if (!g_edicts[i+1].inuse)
    316 				continue;
    317 
    318 			if (cl->resp.score >= fraglimit->value)
    319 			{
    320 				gi.bprintf (PRINT_HIGH, "Fraglimit hit.\n");
    321 				EndDMLevel ();
    322 				return;
    323 			}
    324 		}
    325 }
    326 
    327 
    328 /*
    329 =============
    330 ExitLevel
    331 =============
    332 */
    333 void ExitLevel (void)
    334 {
    335 	int		i;
    336 	edict_t	*ent;
    337 	char	command [256];
    338 
    339 	level.exitintermission = 0;
    340 	level.intermissiontime = 0;
    341 
    342 	if (CTFNextMap())
    343 		return;
    344 
    345 	Com_sprintf (command, sizeof(command), "gamemap \"%s\"\n", level.changemap);
    346 	gi.AddCommandString (command);
    347 	ClientEndServerFrames ();
    348 
    349 	level.changemap = NULL;
    350 
    351 	// clear some things before going to next level
    352 	for (i=0 ; i<maxclients->value ; i++)
    353 	{
    354 		ent = g_edicts + 1 + i;
    355 		if (!ent->inuse)
    356 			continue;
    357 		if (ent->health > ent->client->pers.max_health)
    358 			ent->health = ent->client->pers.max_health;
    359 	}
    360 }
    361 
    362 /*
    363 ================
    364 G_RunFrame
    365 
    366 Advances the world by 0.1 seconds
    367 ================
    368 */
    369 void G_RunFrame (void)
    370 {
    371 	int		i;
    372 	edict_t	*ent;
    373 
    374 	level.framenum++;
    375 	level.time = level.framenum*FRAMETIME;
    376 
    377 	// choose a client for monsters to target this frame
    378 	AI_SetSightClient ();
    379 
    380 	// exit intermissions
    381 
    382 	if (level.exitintermission)
    383 	{
    384 		ExitLevel ();
    385 		return;
    386 	}
    387 
    388 	//
    389 	// treat each object in turn
    390 	// even the world gets a chance to think
    391 	//
    392 	ent = &g_edicts[0];
    393 	for (i=0 ; i<globals.num_edicts ; i++, ent++)
    394 	{
    395 		if (!ent->inuse)
    396 			continue;
    397 
    398 		level.current_entity = ent;
    399 
    400 		VectorCopy (ent->s.origin, ent->s.old_origin);
    401 
    402 		// if the ground entity moved, make sure we are still on it
    403 		if ((ent->groundentity) && (ent->groundentity->linkcount != ent->groundentity_linkcount))
    404 		{
    405 			ent->groundentity = NULL;
    406 			if ( !(ent->flags & (FL_SWIM|FL_FLY)) && (ent->svflags & SVF_MONSTER) )
    407 			{
    408 				M_CheckGround (ent);
    409 			}
    410 		}
    411 
    412 		if (i > 0 && i <= maxclients->value)
    413 		{
    414 			ClientBeginServerFrame (ent);
    415 			continue;
    416 		}
    417 
    418 		G_RunEntity (ent);
    419 	}
    420 
    421 	// see if it is time to end a deathmatch
    422 	CheckDMRules ();
    423 
    424 	// build the playerstate_t structures for all players
    425 	ClientEndServerFrames ();
    426 }
    427