1
2 #include "g_local.h"
3
4
5
6 game_locals_t game;
7 level_locals_t level;
8 game_import_t gi;
9 game_export_t globals;
10 spawn_temp_t st;
11
12 int sm_meat_index;
13 int snd_fry;
14 int meansOfDeath;
15
16 edict_t *g_edicts;
17
18 cvar_t *deathmatch;
19 cvar_t *coop;
20 cvar_t *dmflags;
21 cvar_t *skill;
22 cvar_t *fraglimit;
23 cvar_t *timelimit;
24 cvar_t *password;
25 cvar_t *spectator_password;
26 cvar_t *needpass;
27 cvar_t *maxclients;
28 cvar_t *maxspectators;
29 cvar_t *maxentities;
30 cvar_t *g_select_empty;
31 cvar_t *dedicated;
32
33 cvar_t *filterban;
34
35 cvar_t *sv_maxvelocity;
36 cvar_t *sv_gravity;
37
38 cvar_t *sv_rollspeed;
39 cvar_t *sv_rollangle;
40 cvar_t *gun_x;
41 cvar_t *gun_y;
42 cvar_t *gun_z;
43
44 cvar_t *run_pitch;
45 cvar_t *run_roll;
46 cvar_t *bob_up;
47 cvar_t *bob_pitch;
48 cvar_t *bob_roll;
49
50 cvar_t *flood_msgs;
51 cvar_t *flood_persecond;
52 cvar_t *flood_waitdelay;
53
54 cvar_t *sv_maplist;
55
56 //added by psychospaz
57 cvar_t *sv_teams;
58 cvar_t *sv_teams_locked;
59 cvar_t *sv_cheats;
60 cvar_t *sv_bullet_marks;
61 cvar_t *sv_tracers;
62 cvar_t *sv_fall;
63 cvar_t *sv_bulletmarks;
64 cvar_t *sv_laser_type;
65 cvar_t *sv_waterlevel;
66 cvar_t *sv_stunts;
67 cvar_t *sv_matrix;
68 cvar_t *sv_bloodyview;
69 cvar_t *sv_banned_weapons;
70 cvar_t *sv_grapple;
71 cvar_t *sv_chatdistance;
72 cvar_t *sv_stunt_door;
73 cvar_t *sv_realbullets;
74 cvar_t *sv_spawner;
75 cvar_t *sv_serversideonly;
76 cvar_t *sv_sprite_explosions;
77 cvar_t *sv_damageslow;
78 cvar_t *sv_surfacereflection;
79 cvar_t *sv_itemrotate;
80 cvar_t *sv_mzlmodel;
81 cvar_t *sv_lowlag;
82
83 cvar_t *sv_monsterspawntime;
84
85 cvar_t *motd;
86 int bulletmarks = 0; //actual in-game
87 int tracers=0;
88 cvar_t *day;
89 int headShot;
90 //psychospaz end
91
92
93 void SpawnEntities (char *mapname, char *entities, char *spawnpoint);
94 void ClientThink (edict_t *ent, usercmd_t *cmd);
95 qboolean ClientConnect (edict_t *ent, char *userinfo);
96 void ClientUserinfoChanged (edict_t *ent, char *userinfo);
97 void ClientDisconnect (edict_t *ent);
98 void ClientBegin (edict_t *ent);
99 void ClientCommand (edict_t *ent);
100 void RunEntity (edict_t *ent);
101 void WriteGame (char *filename, qboolean autosave);
102 void ReadGame (char *filename);
103 void WriteLevel (char *filename);
104 void ReadLevel (char *filename);
105 void InitGame (void);
106 void G_RunFrame (void);
107
108
109 //===================================================================
110
111
ShutdownGame(void)112 void ShutdownGame (void)
113 {
114 gi.dprintf ("\n%c%c%c%c Shutdown PsychoMod %c%c%c%c\n\n",
115 (char)128, (char)129, (char)129, (char)129, (char)129, (char)129, (char)129, (char)130);
116
117 gi.FreeTags (TAG_LEVEL);
118 gi.FreeTags (TAG_GAME);
119 }
120
121
122 /*
123 =================
124 GetGameAPI
125
126 Returns a pointer to the structure with all entry points
127 and global variables
128 =================
129 */
GetGameAPI(game_import_t * import)130 game_export_t *GetGameAPI (game_import_t *import)
131 {
132 gi = *import;
133
134 globals.apiversion = GAME_API_VERSION;
135 globals.Init = InitGame;
136 globals.Shutdown = ShutdownGame;
137 globals.SpawnEntities = SpawnEntities;
138
139 globals.WriteGame = WriteGame;
140 globals.ReadGame = ReadGame;
141 globals.WriteLevel = WriteLevel;
142 globals.ReadLevel = ReadLevel;
143
144 globals.ClientThink = ClientThink;
145 globals.ClientConnect = ClientConnect;
146 globals.ClientUserinfoChanged = ClientUserinfoChanged;
147 globals.ClientDisconnect = ClientDisconnect;
148 globals.ClientBegin = ClientBegin;
149 globals.ClientCommand = ClientCommand;
150
151 globals.RunFrame = G_RunFrame;
152
153 globals.ServerCommand = ServerCommand;
154
155 globals.edict_size = sizeof(edict_t);
156
157 return &globals;
158 }
159
160 #ifndef GAME_HARD_LINKED
161 // this is only here so the functions in q_shared.c and q_shwin.c can link
Sys_Error(char * error,...)162 void Sys_Error (char *error, ...)
163 {
164 va_list argptr;
165 char text[1024];
166
167 va_start (argptr, error);
168 vsprintf (text, error, argptr);
169 va_end (argptr);
170
171 gi.error (ERR_FATAL, "%s", text);
172 }
173
Com_Printf(char * msg,...)174 void Com_Printf (char *msg, ...)
175 {
176 va_list argptr;
177 char text[1024];
178
179 va_start (argptr, msg);
180 vsprintf (text, msg, argptr);
181 va_end (argptr);
182
183 gi.dprintf ("%s", text);
184 }
185
186 #endif
187
188 //======================================================================
189
190
191 /*
192 =================
193 ClientEndServerFrames
194 =================
195 */
ClientEndServerFrames(void)196 void ClientEndServerFrames (void)
197 {
198 int i;
199 edict_t *ent;
200
201 // calc the player views now that all pushing
202 // and damage has been added
203 for (i=0 ; i<maxclients->value ; i++)
204 {
205 ent = g_edicts + 1 + i;
206 if (!ent->inuse || !ent->client)
207 continue;
208 ClientEndServerFrame (ent);
209 }
210
211
212 ent = &g_edicts[0];
213 for (i=0 ; i<globals.num_edicts ; i++, ent++)
214 {
215 if (!ent->inuse)
216 continue;
217
218 if (!sv_itemrotate->value)
219 ent->s.effects &= ~EF_ROTATE;
220 if (!(ent->svflags&SVF_MONSTER) && !(ent->PlayerDeadName)
221 && !(ent->item && !(ent->flags&FL_RESPAWN) && ent->solid && !(ent->s.effects&EF_ROTATE)))
222 continue;
223 if (ent->svflags&SVF_MONSTER && ent->solid!=SOLID_BBOX)
224 continue;
225
226 if ((int)sv_surfacereflection->value)
227 AddReflection(ent);
228
229 if (ent->item) //trying to sneak yerselves shadows eh?
230 continue;
231
232 if (((int)sv_bulletmarks->value || (!deathmatch->value && !coop->value)))
233 AddShadow(ent);
234 }
235 }
236
237 /*
238 =================
239 CreateTargetChangeLevel
240
241 Returns the created target changelevel
242 =================
243 */
CreateTargetChangeLevel(char * map)244 edict_t *CreateTargetChangeLevel(char *map)
245 {
246 edict_t *ent;
247
248 ent = G_Spawn ();
249 ent->classname = "target_changelevel";
250 Com_sprintf(level.nextmap, sizeof(level.nextmap), "%s", map);
251 ent->map = level.nextmap;
252 return ent;
253 }
254
255 /*
256 =================
257 EndDMLevel
258
259 The timelimit or fraglimit has been exceeded
260 =================
261 */
EndDMLevel(void)262 void EndDMLevel (void)
263 {
264 edict_t *ent;
265 char *s, *t, *f;
266 static const char *seps = " ,\n\r";
267
268 // stay on same level flag
269 if ((int)dmflags->value & DF_SAME_LEVEL)
270 {
271 BeginIntermission (CreateTargetChangeLevel (level.mapname) );
272 return;
273 }
274
275 // see if it's in the map list
276 if (*sv_maplist->string) {
277 s = strdup(sv_maplist->string);
278 f = NULL;
279 t = strtok(s, seps);
280 while (t != NULL) {
281 if (Q_stricmp(t, level.mapname) == 0) {
282 // it's in the list, go to the next one
283 t = strtok(NULL, seps);
284 if (t == NULL) { // end of list, go to first one
285 if (f == NULL) // there isn't a first one, same level
286 BeginIntermission (CreateTargetChangeLevel (level.mapname) );
287 else
288 BeginIntermission (CreateTargetChangeLevel (f) );
289 } else
290 BeginIntermission (CreateTargetChangeLevel (t) );
291 free(s);
292 return;
293 }
294 if (!f)
295 f = t;
296 t = strtok(NULL, seps);
297 }
298 free(s);
299 }
300
301 if (level.nextmap[0]) // go to a specific map
302 BeginIntermission (CreateTargetChangeLevel (level.nextmap) );
303 else { // search for a changelevel
304 ent = G_Find (NULL, FOFS(classname), "target_changelevel");
305 if (!ent)
306 { // the map designer didn't include a changelevel,
307 // so create a fake ent that goes back to the same level
308 BeginIntermission (CreateTargetChangeLevel (level.mapname) );
309 return;
310 }
311 BeginIntermission (ent);
312 }
313 }
314
315
316 /*
317 =================
318 CheckNeedPass
319 =================
320 */
CheckNeedPass(void)321 void CheckNeedPass (void)
322 {
323 int need;
324
325 // if password or spectator_password has changed, update needpass
326 // as needed
327 if (password->modified || spectator_password->modified)
328 {
329 password->modified = spectator_password->modified = false;
330
331 need = 0;
332
333 if (*password->string && Q_stricmp(password->string, "none"))
334 need |= 1;
335 if (*spectator_password->string && Q_stricmp(spectator_password->string, "none"))
336 need |= 2;
337
338 gi.cvar_set("needpass", va("%d", need));
339 }
340 }
341
342 /*
343 =================
344 CheckDMRules
345 =================
346 */
CheckDMRules(void)347 void CheckDMRules (void)
348 {
349 int i;
350 gclient_t *cl;
351
352 if (level.intermissiontime)
353 return;
354
355 if (!deathmatch->value)
356 return;
357
358 if (timelimit->value)
359 {
360 if (level.time >= timelimit->value*60)
361 {
362 gi.bprintf (PRINT_HIGH, "Timelimit hit.\n");
363 EndDMLevel ();
364 return;
365 }
366 }
367
368 if (fraglimit->value)
369 {
370 for (i=0 ; i<maxclients->value ; i++)
371 {
372 cl = game.clients + i;
373 if (!g_edicts[i+1].inuse)
374 continue;
375
376 if (cl->resp.score >= fraglimit->value)
377 {
378 gi.bprintf (PRINT_HIGH, "Fraglimit hit.\n");
379 EndDMLevel ();
380 return;
381 }
382 }
383 }
384 }
385
386
387 /*
388 =============
389 ExitLevel
390 =============
391 */
ExitLevel(void)392 void ExitLevel (void)
393 {
394 int i;
395 edict_t *ent;
396 char command [256];
397
398 Com_sprintf (command, sizeof(command), "gamemap \"%s\"\n", level.changemap);
399 gi.AddCommandString (command);
400 level.changemap = NULL;
401 level.exitintermission = 0;
402 level.intermissiontime = 0;
403 ClientEndServerFrames ();
404
405 // clear some things before going to next level
406 for (i=0 ; i<maxclients->value ; i++)
407 {
408 ent = g_edicts + 1 + i;
409 if (!ent->inuse)
410 continue;
411 if (ent->health > ent->client->pers.max_health)
412 ent->health = ent->client->pers.max_health;
413 if (ent->client->aquasuit)
414 {
415 ent->client->newweapon = ent->client->pers.lastweapon;
416 ChangeWeapon (ent);
417 gi.cprintf(ent, PRINT_HIGH, "Weapons Mode\n");
418 }
419 }
420
421 }
422
423 /*
424 ================
425 G_RunFrame
426
427 Advances the world by 0.1 seconds
428 ================
429 */
430 void MonsterSpawn (edict_t *ent, vec3_t origin, vec3_t angles);
Random_Monster_Spawn(void)431 void Random_Monster_Spawn (void)
432 {
433 edict_t *ent;
434 char *monster;
435 int j;
436
437 if (!(deathmatch->value))
438 return;
439
440 deathmatch->value=0;
441
442 ent = G_Spawn();
443 MonsterSpawn (ent, ent->s.origin, ent->s.angles);
444 VectorCopy(ent->s.origin,ent->s.old_origin);
445 if (random()>.8)
446 {
447 ent->classname="";
448 monster="Hover";
449 SP_monster_hover(ent);
450 }
451 else if (random()>.85)
452 {
453 ent->classname="monster_floater";
454 monster="Floater";
455 SP_monster_floater(ent);
456 }
457 else if (random()>.85)
458 {
459 ent->classname="monster_mutant";
460 monster="Mutant";
461 SP_monster_mutant(ent);
462 }
463 else if (random()>.85)
464 {
465 ent->classname="monster_chick";
466 monster="Chick";
467 SP_monster_chick(ent);
468 }
469 else if (random()>.85)
470 {
471 ent->classname="monster_soldier_ss";
472 monster="SMG Soldier";
473 SP_monster_soldier_ss(ent);
474 }
475 else if (random()>.85)
476 {
477 ent->classname="monster_soldier";
478 monster="Shotgun Soldier";
479 SP_monster_soldier(ent);
480 }
481 else if (random()>.85)
482 {
483 ent->classname="monster_soldier_light";
484 monster="Blaster Soldier";
485 SP_monster_soldier_light(ent);
486 }
487 else if (random()>.85)
488 {
489 ent->classname="monster_infantry";
490 monster="Infantry";
491 SP_monster_infantry(ent);
492 }
493 else if (random()>.85)
494 {
495 ent->classname="monster_gunner";
496 monster="Gunner";
497 SP_monster_gunner(ent);
498 }
499 else
500 {
501 ent->classname="monster_berserk";
502 monster="Berserk";
503 SP_monster_berserk(ent);
504 }
505 gi.cprintf (NULL, PRINT_HIGH, "Spawning %s\n", monster);
506
507 //END MONSTER SPAWN CODE
508 //clear spawn point
509
510 ent->target_ent = ent;
511 ent->MonsterFind = ent;
512 ent->enemy = ent;
513 ent->goalentity = ent;
514 ent->movetarget = ent;
515
516 deathmatch->value=1;
517 }
518
G_RunFrame(void)519 void G_RunFrame (void)
520 {
521 int i;
522 edict_t *ent;
523
524 char lights[2]; // new line
525
526 level.framenum++;
527 level.time = level.framenum*FRAMETIME;
528
529 if (level.framenum == 1)
530 {
531 if (!deathmatch->value && !coop->value)
532 sv_serversideonly->value = 0;
533 }
534
535
536 // new code starts here
537 if (day->value)
538 daycycletime = (int)((day->value) * 600 + 1);
539 else
540 daycycletime = 0;
541
542 if (daycycletime > 0)
543 {
544 oldlightlevel = lightlevel;
545 lightlevel = level.framenum % (daycycletime);
546 if (lightlevel > (daycycletime / 2))
547 lightlevel = daycycletime - lightlevel;
548 lightlevel = 52 - (int)(((float) lightlevel / (float) (daycycletime/2)) * 52);
549 if (lightlevel <= 13)
550 lightlevel = 0;
551 else if (lightlevel >= 35)
552 lightlevel = 25;
553 else
554 lightlevel = lightlevel - 13;
555 lightlevel = 'c' + lightlevel;
556 if (lightlevel > 'z') lightlevel = 'z' - (lightlevel - 'z');
557 lights[0] = lightlevel;
558 lights[1] = '\0';
559 gi.configstring(CS_LIGHTS+0, lights);
560 }
561 // new code ends here
562
563 // choose a client for monsters to target this frame
564 AI_SetSightClient ();
565
566 // exit intermissions
567
568 if (level.exitintermission)
569 {
570 ExitLevel ();
571 return;
572 }
573
574 //
575 // treat each object in turn
576 // even the world gets a chance to think
577 //
578 ent = &g_edicts[0];
579 for (i=0 ; i<globals.num_edicts ; i++, ent++)
580 {
581 if (!ent->inuse)
582 continue;
583
584 level.current_entity = ent;
585
586 VectorCopy (ent->s.origin, ent->s.old_origin);
587
588 // if the ground entity moved, make sure we are still on it
589 if ((ent->groundentity) && (ent->groundentity->linkcount != ent->groundentity_linkcount))
590 {
591 ent->groundentity = NULL;
592 if ( !(ent->flags & (FL_SWIM|FL_FLY)) && (ent->svflags & SVF_MONSTER) )
593 {
594 M_CheckGround (ent);
595 }
596 }
597
598 if (i > 0 && i <= maxclients->value)
599 {
600 ClientBeginServerFrame (ent);
601 continue;
602 }
603
604 G_RunEntity (ent);
605 }
606
607 if ((int)sv_monsterspawntime->value>0)
608 if (((int)(level.time*10)%(int)(sv_monsterspawntime->value*10))==0)
609 Random_Monster_Spawn();
610
611 // see if it is time to end a deathmatch
612 CheckDMRules ();
613
614 // see if needpass needs updated
615 CheckNeedPass ();
616
617 // build the playerstate_t structures for all players
618 ClientEndServerFrames ();
619 }
620
621