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