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