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