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