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