1 #include "g_local.h"
2 
3 
4 
5 /*
6 ======================================================================
7 
8 INTERMISSION
9 
10 ======================================================================
11 */
12 
MoveClientToIntermission(edict_t * ent)13 void MoveClientToIntermission (edict_t *ent)
14 {
15 	if (deathmatch->value || coop->value)
16 		ent->client->showscores = true;
17 	VectorCopy (level.intermission_origin, ent->s.origin);
18 	ent->client->ps.pmove.origin[0] = level.intermission_origin[0]*8;
19 	ent->client->ps.pmove.origin[1] = level.intermission_origin[1]*8;
20 	ent->client->ps.pmove.origin[2] = level.intermission_origin[2]*8;
21 	VectorCopy (level.intermission_angle, ent->client->ps.viewangles);
22 	ent->client->ps.pmove.pm_type = PM_FREEZE;
23 	ent->client->ps.gunindex = 0;
24 	ent->client->ps.blend[3] = 0;
25 	ent->client->ps.rdflags &= ~RDF_UNDERWATER;
26 
27 	// clean up powerup info
28 	ent->client->quad_framenum = 0;
29 	ent->client->invincible_framenum = 0;
30 	ent->client->breather_framenum = 0;
31 	ent->client->enviro_framenum = 0;
32 	ent->client->grenade_blew_up = false;
33 	ent->client->grenade_time = 0;
34 
35 	ent->client->ps.rdflags &= ~RDF_IRGOGGLES;		// PGM
36 	ent->client->ir_framenum = 0;					// PGM
37 	ent->client->nuke_framenum = 0;					// PMM
38 	ent->client->double_framenum = 0;				// PMM
39 
40 	ent->viewheight = 0;
41 	ent->s.modelindex = 0;
42 	ent->s.modelindex2 = 0;
43 	ent->s.modelindex3 = 0;
44 	ent->s.modelindex = 0;
45 	ent->s.effects = 0;
46 	ent->s.sound = 0;
47 	ent->solid = SOLID_NOT;
48 
49 	// add the layout
50 
51 	if (deathmatch->value || coop->value)
52 	{
53 		DeathmatchScoreboardMessage (ent, NULL);
54 		gi.unicast (ent, true);
55 	}
56 
57 }
58 
BeginIntermission(edict_t * targ)59 void BeginIntermission (edict_t *targ)
60 {
61 	int		i, n;
62 	edict_t	*ent, *client;
63 
64 	if (level.intermissiontime)
65 		return;		// already activated
66 
67 	game.autosaved = false;
68 
69 	// respawn any dead clients
70 	for (i=0 ; i<maxclients->value ; i++)
71 	{
72 		client = g_edicts + 1 + i;
73 		if (!client->inuse)
74 			continue;
75 		if (client->health <= 0)
76 			respawn(client);
77 	}
78 
79 	level.intermissiontime = level.time;
80 	level.changemap = targ->map;
81 
82 	if (strstr(level.changemap, "*"))
83 	{
84 		if (coop->value)
85 		{
86 			for (i=0 ; i<maxclients->value ; i++)
87 			{
88 				client = g_edicts + 1 + i;
89 				if (!client->inuse)
90 					continue;
91 				// strip players of all keys between units
92 				for (n = 0; n < MAX_ITEMS; n++)
93 				{
94 					if (itemlist[n].flags & IT_KEY)
95 						client->client->pers.inventory[n] = 0;
96 				}
97 			}
98 		}
99 	}
100 	else
101 	{
102 		if (!deathmatch->value)
103 		{
104 			level.exitintermission = 1;		// go immediately to the next level
105 			return;
106 		}
107 	}
108 
109 	level.exitintermission = 0;
110 
111 	// find an intermission spot
112 	ent = G_Find (NULL, FOFS(classname), "info_player_intermission");
113 	if (!ent)
114 	{	// the map creator forgot to put in an intermission point...
115 		ent = G_Find (NULL, FOFS(classname), "info_player_start");
116 		if (!ent)
117 			ent = G_Find (NULL, FOFS(classname), "info_player_deathmatch");
118 	}
119 	else
120 	{	// chose one of four spots
121 		i = rand() & 3;
122 		while (i--)
123 		{
124 			ent = G_Find (ent, FOFS(classname), "info_player_intermission");
125 			if (!ent)	// wrap around the list
126 				ent = G_Find (ent, FOFS(classname), "info_player_intermission");
127 		}
128 	}
129 
130 	VectorCopy (ent->s.origin, level.intermission_origin);
131 	VectorCopy (ent->s.angles, level.intermission_angle);
132 
133 	// move all clients to the intermission point
134 	for (i=0 ; i<maxclients->value ; i++)
135 	{
136 		client = g_edicts + 1 + i;
137 		if (!client->inuse)
138 			continue;
139 		MoveClientToIntermission (client);
140 	}
141 }
142 
143 
144 /*
145 ==================
146 DeathmatchScoreboardMessage
147 
148 ==================
149 */
DeathmatchScoreboardMessage(edict_t * ent,edict_t * killer)150 void DeathmatchScoreboardMessage (edict_t *ent, edict_t *killer)
151 {
152 	char	entry[1024];
153 	char	string[1400];
154 	int		stringlength;
155 	int		i, j, k;
156 	int		sorted[MAX_CLIENTS];
157 	int		sortedscores[MAX_CLIENTS];
158 	int		score, total;
159 	int		picnum;
160 	int		x, y;
161 	gclient_t	*cl;
162 	edict_t		*cl_ent;
163 	char	*tag;
164 
165 	// sort the clients by score
166 	total = 0;
167 	for (i=0 ; i<game.maxclients ; i++)
168 	{
169 		cl_ent = g_edicts + 1 + i;
170 		if (!cl_ent->inuse || game.clients[i].resp.spectator)
171 			continue;
172 		score = game.clients[i].resp.score;
173 		for (j=0 ; j<total ; j++)
174 		{
175 			if (score > sortedscores[j])
176 				break;
177 		}
178 		for (k=total ; k>j ; k--)
179 		{
180 			sorted[k] = sorted[k-1];
181 			sortedscores[k] = sortedscores[k-1];
182 		}
183 		sorted[j] = i;
184 		sortedscores[j] = score;
185 		total++;
186 	}
187 
188 	// print level name and exit rules
189 	string[0] = 0;
190 
191 	stringlength = strlen(string);
192 
193 	// add the clients in sorted order
194 	if (total > 12)
195 		total = 12;
196 
197 	for (i=0 ; i<total ; i++)
198 	{
199 		cl = &game.clients[sorted[i]];
200 		cl_ent = g_edicts + 1 + sorted[i];
201 
202 		picnum = gi.imageindex ("i_fixme");
203 		x = (i>=6) ? 160 : 0;
204 		y = 32 + 32 * (i%6);
205 
206 		// add a dogtag
207 		if (cl_ent == ent)
208 			tag = "tag1";
209 		else if (cl_ent == killer)
210 			tag = "tag2";
211 		else
212 			tag = NULL;
213 
214 //===============
215 //ROGUE
216 		// allow new DM games to override the tag picture
217 		if (gamerules && gamerules->value)
218 		{
219 			if(DMGame.DogTag)
220 				DMGame.DogTag(cl_ent, killer, &tag);
221 		}
222 //ROGUE
223 //===============
224 
225 		if (tag)
226 		{
227 			Com_sprintf (entry, sizeof(entry),
228 				"xv %i yv %i picn %s ",x+32, y, tag);
229 			j = strlen(entry);
230 			if (stringlength + j > 1024)
231 				break;
232 			strcpy (string + stringlength, entry);
233 			stringlength += j;
234 		}
235 
236 		// send the layout
237 		Com_sprintf (entry, sizeof(entry),
238 			"client %i %i %i %i %i %i ",
239 			x, y, sorted[i], cl->resp.score, cl->ping, (level.framenum - cl->resp.enterframe)/600);
240 		j = strlen(entry);
241 		if (stringlength + j > 1024)
242 			break;
243 		strcpy (string + stringlength, entry);
244 		stringlength += j;
245 	}
246 
247 	gi.WriteByte (svc_layout);
248 	gi.WriteString (string);
249 }
250 
251 
252 /*
253 ==================
254 DeathmatchScoreboard
255 
256 Draw instead of help message.
257 Note that it isn't that hard to overflow the 1400 byte message limit!
258 ==================
259 */
DeathmatchScoreboard(edict_t * ent)260 void DeathmatchScoreboard (edict_t *ent)
261 {
262 	DeathmatchScoreboardMessage (ent, ent->enemy);
263 	gi.unicast (ent, true);
264 }
265 
266 
267 /*
268 ==================
269 Cmd_Score_f
270 
271 Display the scoreboard
272 ==================
273 */
Cmd_Score_f(edict_t * ent)274 void Cmd_Score_f (edict_t *ent)
275 {
276 	ent->client->showinventory = false;
277 	ent->client->showhelp = false;
278 
279 	if (!deathmatch->value && !coop->value)
280 		return;
281 
282 	if (ent->client->showscores)
283 	{
284 		ent->client->showscores = false;
285 		return;
286 	}
287 
288 	ent->client->showscores = true;
289 	DeathmatchScoreboard (ent);
290 }
291 
292 
293 /*
294 ==================
295 HelpComputer
296 
297 Draw help computer.
298 ==================
299 */
HelpComputer(edict_t * ent)300 void HelpComputer (edict_t *ent)
301 {
302 	char	string[1024];
303 	char	*sk;
304 
305 	if (skill->value == 0)
306 		sk = "easy";
307 	else if (skill->value == 1)
308 		sk = "medium";
309 	else if (skill->value == 2)
310 		sk = "hard";
311 	else
312 		sk = "hard+";
313 
314 	// send the layout
315 	Com_sprintf (string, sizeof(string),
316 		"xv 32 yv 8 picn help "			// background
317 		"xv 202 yv 12 string2 \"%s\" "		// skill
318 		"xv 0 yv 24 cstring2 \"%s\" "		// level name
319 		"xv 0 yv 54 cstring2 \"%s\" "		// help 1
320 		"xv 0 yv 110 cstring2 \"%s\" "		// help 2
321 		"xv 50 yv 164 string2 \" kills     goals    secrets\" "
322 		"xv 50 yv 172 string2 \"%3i/%3i     %i/%i       %i/%i\" ",
323 		sk,
324 		level.level_name,
325 		game.helpmessage1,
326 		game.helpmessage2,
327 		level.killed_monsters, level.total_monsters,
328 		level.found_goals, level.total_goals,
329 		level.found_secrets, level.total_secrets);
330 
331 	gi.WriteByte (svc_layout);
332 	gi.WriteString (string);
333 	gi.unicast (ent, true);
334 }
335 
336 
337 /*
338 ==================
339 Cmd_Help_f
340 
341 Display the current help message
342 ==================
343 */
Cmd_Help_f(edict_t * ent)344 void Cmd_Help_f (edict_t *ent)
345 {
346 	// this is for backwards compatability
347 	if (deathmatch->value)
348 	{
349 		Cmd_Score_f (ent);
350 		return;
351 	}
352 
353 	ent->client->showinventory = false;
354 	ent->client->showscores = false;
355 
356 	if (ent->client->showhelp && (ent->client->pers.game_helpchanged == game.helpchanged))
357 	{
358 		ent->client->showhelp = false;
359 		return;
360 	}
361 
362 	ent->client->showhelp = true;
363 	ent->client->pers.helpchanged = 0;
364 	HelpComputer (ent);
365 }
366 
367 
368 //=======================================================================
369 
370 /*
371 ===============
372 G_SetStats
373 ===============
374 */
G_SetStats(edict_t * ent)375 void G_SetStats (edict_t *ent)
376 {
377 	gitem_t		*item;
378 	int			index, cells;
379 	int			power_armor_type;
380 
381 	//
382 	// health
383 	//
384 	ent->client->ps.stats[STAT_HEALTH_ICON] = level.pic_health;
385 	ent->client->ps.stats[STAT_HEALTH] = ent->health;
386 
387 	//
388 	// ammo
389 	//
390 	if (!ent->client->ammo_index /* || !ent->client->pers.inventory[ent->client->ammo_index] */)
391 	{
392 		ent->client->ps.stats[STAT_AMMO_ICON] = 0;
393 		ent->client->ps.stats[STAT_AMMO] = 0;
394 	}
395 	else
396 	{
397 		item = &itemlist[ent->client->ammo_index];
398 		ent->client->ps.stats[STAT_AMMO_ICON] = gi.imageindex (item->icon);
399 		ent->client->ps.stats[STAT_AMMO] = ent->client->pers.inventory[ent->client->ammo_index];
400 	}
401 
402 	//
403 	// armor
404 	//
405 	power_armor_type = PowerArmorType (ent);
406 	if (power_armor_type)
407 	{
408 		cells = ent->client->pers.inventory[ITEM_INDEX(FindItem ("cells"))];
409 		if (cells == 0)
410 		{	// ran out of cells for power armor
411 			ent->flags &= ~FL_POWER_ARMOR;
412 			gi.sound(ent, CHAN_ITEM, gi.soundindex("misc/power2.wav"), 1, ATTN_NORM, 0);
413 			power_armor_type = 0;;
414 		}
415 	}
416 
417 	index = ArmorIndex (ent);
418 	if (power_armor_type && (!index || (level.framenum & 8) ) )
419 	{	// flash between power armor and other armor icon
420 		ent->client->ps.stats[STAT_ARMOR_ICON] = gi.imageindex ("i_powershield");
421 		ent->client->ps.stats[STAT_ARMOR] = cells;
422 	}
423 	else if (index)
424 	{
425 		item = GetItemByIndex (index);
426 		ent->client->ps.stats[STAT_ARMOR_ICON] = gi.imageindex (item->icon);
427 		ent->client->ps.stats[STAT_ARMOR] = ent->client->pers.inventory[index];
428 	}
429 	else
430 	{
431 		ent->client->ps.stats[STAT_ARMOR_ICON] = 0;
432 		ent->client->ps.stats[STAT_ARMOR] = 0;
433 	}
434 
435 	//
436 	// pickup message
437 	//
438 	if (level.time > ent->client->pickup_msg_time)
439 	{
440 		ent->client->ps.stats[STAT_PICKUP_ICON] = 0;
441 		ent->client->ps.stats[STAT_PICKUP_STRING] = 0;
442 	}
443 
444 	//
445 	// timers
446 	//
447 	if (ent->client->quad_framenum > level.framenum)
448 	{
449 		ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_quad");
450 		ent->client->ps.stats[STAT_TIMER] = (ent->client->quad_framenum - level.framenum)/10;
451 	}
452 // PMM
453 	else if (ent->client->double_framenum > level.framenum)
454 	{
455 		ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_double");
456 		ent->client->ps.stats[STAT_TIMER] = (ent->client->double_framenum - level.framenum)/10;
457 	}
458 // PMM
459 	else if (ent->client->invincible_framenum > level.framenum)
460 	{
461 		ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_invulnerability");
462 		ent->client->ps.stats[STAT_TIMER] = (ent->client->invincible_framenum - level.framenum)/10;
463 	}
464 	else if (ent->client->enviro_framenum > level.framenum)
465 	{
466 		ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_envirosuit");
467 		ent->client->ps.stats[STAT_TIMER] = (ent->client->enviro_framenum - level.framenum)/10;
468 	}
469 	else if (ent->client->breather_framenum > level.framenum)
470 	{
471 		ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_rebreather");
472 		ent->client->ps.stats[STAT_TIMER] = (ent->client->breather_framenum - level.framenum)/10;
473 	}
474 // PGM
475 	else if (ent->client->owned_sphere)
476 	{
477 		if(ent->client->owned_sphere->spawnflags == 1)			// defender
478 			ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_defender");
479 		else if(ent->client->owned_sphere->spawnflags == 2)		// hunter
480 			ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_hunter");
481 		else if(ent->client->owned_sphere->spawnflags == 4)		// vengeance
482 			ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_vengeance");
483 		else													// error case
484 			ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("i_fixme");
485 
486 		ent->client->ps.stats[STAT_TIMER] = (int)(ent->client->owned_sphere->wait - level.time);
487 	}
488 	else if (ent->client->ir_framenum > level.framenum)
489 	{
490 		ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_ir");
491 		ent->client->ps.stats[STAT_TIMER] = (ent->client->ir_framenum - level.framenum)/10;
492 	}
493 // PGM
494 	else
495 	{
496 		ent->client->ps.stats[STAT_TIMER_ICON] = 0;
497 		ent->client->ps.stats[STAT_TIMER] = 0;
498 	}
499 
500 	//
501 	// selected item
502 	//
503 	if (ent->client->pers.selected_item == -1)
504 		ent->client->ps.stats[STAT_SELECTED_ICON] = 0;
505 	else
506 		ent->client->ps.stats[STAT_SELECTED_ICON] = gi.imageindex (itemlist[ent->client->pers.selected_item].icon);
507 
508 	ent->client->ps.stats[STAT_SELECTED_ITEM] = ent->client->pers.selected_item;
509 
510 	//
511 	// layouts
512 	//
513 	ent->client->ps.stats[STAT_LAYOUTS] = 0;
514 
515 	if (deathmatch->value)
516 	{
517 		if (ent->client->pers.health <= 0 || level.intermissiontime
518 			|| ent->client->showscores)
519 			ent->client->ps.stats[STAT_LAYOUTS] |= 1;
520 		if (ent->client->showinventory && ent->client->pers.health > 0)
521 			ent->client->ps.stats[STAT_LAYOUTS] |= 2;
522 	}
523 	else
524 	{
525 		if (ent->client->showscores || ent->client->showhelp)
526 			ent->client->ps.stats[STAT_LAYOUTS] |= 1;
527 		if (ent->client->showinventory && ent->client->pers.health > 0)
528 			ent->client->ps.stats[STAT_LAYOUTS] |= 2;
529 	}
530 
531 	//
532 	// frags
533 	//
534 	ent->client->ps.stats[STAT_FRAGS] = ent->client->resp.score;
535 
536 	//
537 	// help icon / current weapon if not shown
538 	//
539 	if (ent->client->pers.helpchanged && (level.framenum&8) )
540 		ent->client->ps.stats[STAT_HELPICON] = gi.imageindex ("i_help");
541 	else if ( (ent->client->pers.hand == CENTER_HANDED || ent->client->ps.fov > 91)
542 		&& ent->client->pers.weapon)
543 		ent->client->ps.stats[STAT_HELPICON] = gi.imageindex (ent->client->pers.weapon->icon);
544 	else
545 		ent->client->ps.stats[STAT_HELPICON] = 0;
546 
547 	ent->client->ps.stats[STAT_SPECTATOR] = 0;
548 }
549 
550 /*
551 ===============
552 G_CheckChaseStats
553 ===============
554 */
G_CheckChaseStats(edict_t * ent)555 void G_CheckChaseStats (edict_t *ent)
556 {
557 	int i;
558 	gclient_t *cl;
559 
560 	for (i = 1; i <= maxclients->value; i++)
561 	{
562 		cl = g_edicts[i].client;
563 		if (!g_edicts[i].inuse || cl->chase_target != ent)
564 			continue;
565 		memcpy(cl->ps.stats, ent->client->ps.stats, sizeof(cl->ps.stats));
566 		G_SetSpectatorStats(g_edicts + i);
567 	}
568 }
569 
570 /*
571 ===============
572 G_SetSpectatorStats
573 ===============
574 */
G_SetSpectatorStats(edict_t * ent)575 void G_SetSpectatorStats (edict_t *ent)
576 {
577 	gclient_t *cl = ent->client;
578 
579 	if (!cl->chase_target)
580 		G_SetStats (ent);
581 
582 	cl->ps.stats[STAT_SPECTATOR] = 1;
583 
584 	// layouts are independant in spectator
585 	cl->ps.stats[STAT_LAYOUTS] = 0;
586 	if (cl->pers.health <= 0 || level.intermissiontime || cl->showscores)
587 		cl->ps.stats[STAT_LAYOUTS] |= 1;
588 	if (cl->showinventory && cl->pers.health > 0)
589 		cl->ps.stats[STAT_LAYOUTS] |= 2;
590 
591 	if (cl->chase_target && cl->chase_target->inuse)
592 	{
593 		cl->ps.stats[STAT_CHASE] = CS_PLAYERSKINS +
594 			(cl->chase_target - g_edicts) - 1;
595 	}
596 	else
597 		cl->ps.stats[STAT_CHASE] = 0;
598 }
599 
600