|
|
1.1 root 1: #include "g_local.h"
2:
3:
4:
5: /*
6: ======================================================================
7:
8: INTERMISSION
9:
10: ======================================================================
11: */
12:
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:
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: */
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: */
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: */
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: */
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: */
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: */
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: */
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: */
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.