#include "g_local.h" /* ====================================================================== INTERMISSION ====================================================================== */ void MoveClientToIntermission (edict_t *ent) { if (deathmatch->value || coop->value) ent->client->showscores = true; VectorCopy (level.intermission_origin, ent->s.origin); ent->client->ps.pmove.origin[0] = level.intermission_origin[0]*8; ent->client->ps.pmove.origin[1] = level.intermission_origin[1]*8; ent->client->ps.pmove.origin[2] = level.intermission_origin[2]*8; VectorCopy (level.intermission_angle, ent->client->ps.viewangles); ent->client->ps.pmove.pm_type = PM_FREEZE; ent->client->ps.gunindex = 0; #ifdef KMQUAKE2_ENGINE_MOD ent->client->ps.gunindex2 = 0; #endif ent->client->ps.blend[3] = 0; ent->client->ps.rdflags &= ~RDF_UNDERWATER; #ifdef KMQUAKE2_ENGINE_MOD if (level.intermission_letterbox) // Knightmare- letterboxing ent->client->ps.rdflags |= RDF_LETTERBOX; #endif // clean up powerup info ent->client->quad_framenum = 0; ent->client->quadfire_framenum = 0; ent->client->invincible_framenum = 0; ent->client->breather_framenum = 0; ent->client->enviro_framenum = 0; ent->client->grenade_blew_up = false; ent->client->bfg_missfire = false; // Knightmare- added for Zaero EMP Nuke ent->client->grenade_time = 0; ent->client->ps.rdflags &= ~RDF_IRGOGGLES; // PGM ent->client->ir_framenum = 0; // PGM ent->client->nuke_framenum = 0; // PMM ent->client->double_framenum = 0; // PMM ent->viewheight = 0; ent->s.modelindex = 0; ent->s.modelindex2 = 0; ent->s.modelindex3 = 0; ent->s.modelindex4 = 0; #ifdef KMQUAKE2_ENGINE_MOD ent->s.modelindex5 = 0; ent->s.modelindex6 = 0; #endif ent->s.effects = 0; ent->s.sound = 0; ent->solid = SOLID_NOT; #ifdef JETPACK_MOD ent->client->jetpack_framenum = 0; #endif // add the layout if (deathmatch->value || coop->value) { DeathmatchScoreboardMessage (ent, NULL); gi.unicast (ent, true); } } void BeginIntermission (edict_t *targ) { int i, n; edict_t *ent, *client; if (level.intermissiontime) return; // already activated game.autosaved = false; // respawn any dead clients for (i=0; i < maxclients->value; i++) { client = g_edicts + 1 + i; if (!client->inuse) continue; if (client->health <= 0) respawn(client); //Knightmare- end chasecam, set to restart- //don't leave behind a player model if (client->client->chasetoggle) { ChasecamRemove (client); client->client->chasetoggle = 1; } } level.intermissiontime = level.time; level.changemap = targ->map; if (strstr(level.changemap, "*")) { if (coop->value) { for (i=0 ; ivalue ; i++) { client = g_edicts + 1 + i; if (!client->inuse) continue; // strip players of all keys between units for (n = 0; n < MAX_ITEMS; n++) { if (itemlist[n].flags & IT_KEY) client->client->pers.inventory[n] = 0; } } } } else { if (!deathmatch->value) { level.exitintermission = 1; // go immediately to the next level return; } } level.exitintermission = 0; // find an intermission spot ent = G_Find (NULL, FOFS(classname), "info_player_intermission"); if (!ent) { // the map creator forgot to put in an intermission point... ent = G_Find (NULL, FOFS(classname), "info_player_start"); if (!ent) ent = G_Find (NULL, FOFS(classname), "info_player_deathmatch"); } else { // chose one of four spots i = rand() & 3; while (i--) { ent = G_Find (ent, FOFS(classname), "info_player_intermission"); if (!ent) // wrap around the list ent = G_Find (ent, FOFS(classname), "info_player_intermission"); } } VectorCopy (ent->s.origin, level.intermission_origin); VectorCopy (ent->s.angles, level.intermission_angle); // Knightmare- letterboxing if (!strcmp(ent->classname, "info_player_intermission")) level.intermission_letterbox = (ent->spawnflags & 1); else level.intermission_letterbox = false; // move all clients to the intermission point for (i=0 ; ivalue ; i++) { client = g_edicts + 1 + i; if (!client->inuse) continue; MoveClientToIntermission (client); } } /* ================== DeathmatchScoreboardMessage ================== */ void DeathmatchScoreboardMessage (edict_t *ent, edict_t *killer) { char entry[1024]; char string[1400]; int stringlength; int i, j, k; int sorted[MAX_CLIENTS]; int sortedscores[MAX_CLIENTS]; int score, total; int picnum; int x, y; gclient_t *cl; edict_t *cl_ent; char *tag; // sort the clients by score total = 0; for (i=0 ; iinuse || game.clients[i].resp.spectator) continue; score = game.clients[i].resp.score; for (j=0 ; j sortedscores[j]) break; } for (k=total ; k>j ; k--) { sorted[k] = sorted[k-1]; sortedscores[k] = sortedscores[k-1]; } sorted[j] = i; sortedscores[j] = score; total++; } // print level name and exit rules string[0] = 0; stringlength = (int)strlen(string); // add the clients in sorted order if (total > 12) total = 12; for (i=0 ; i=6) ? 160 : 0; y = 32 + 32 * (i%6); // add a dogtag if (cl_ent == ent) tag = "tag1"; else if (cl_ent == killer) tag = "tag2"; else tag = NULL; //=============== //ROGUE // allow new DM games to override the tag picture if (gamerules && gamerules->value) { if (DMGame.DogTag) DMGame.DogTag(cl_ent, killer, &tag); } //ROGUE //=============== if (tag) { Com_sprintf (entry, sizeof(entry), "xv %i yv %i picn %s ",x+32, y, tag); j = (int)strlen(entry); if (stringlength + j > 1024) break; Com_strcpy (string + stringlength, sizeof(string)-stringlength, entry); stringlength += j; } // send the layout Com_sprintf (entry, sizeof(entry), "client %i %i %i %i %i %i ", x, y, sorted[i], cl->resp.score, cl->ping, (level.framenum - cl->resp.enterframe)/600); j = (int)strlen(entry); if (stringlength + j > 1024) break; Com_strcpy (string + stringlength, sizeof(string)-stringlength, entry); stringlength += j; } gi.WriteByte (svc_layout); gi.WriteString (string); } /* ================== DeathmatchScoreboard Draw instead of help message. Note that it isn't that hard to overflow the 1400 byte message limit! ================== */ void DeathmatchScoreboard (edict_t *ent) { DeathmatchScoreboardMessage (ent, ent->enemy); gi.unicast (ent, true); } /* ================== Cmd_Score_f Display the scoreboard ================== */ void Cmd_Score_f (edict_t *ent) { ent->client->showinventory = false; ent->client->showhelp = false; if (ent->client->menu) PMenu_Close(ent); if (ent->client->textdisplay) Text_Close(ent); if (!deathmatch->value && !coop->value) return; if (ent->client->showscores) { ent->client->showscores = false; return; } ent->client->showscores = true; DeathmatchScoreboard (ent); } /* ================== HelpComputer Draw help computer. ================== */ void HelpComputer (edict_t *ent) { char string[1024]; char *sk; if (skill->value == 0) sk = "easy"; else if (skill->value == 1) sk = "medium"; else if (skill->value == 2) sk = "hard"; else sk = "hard+"; // send the layout Com_sprintf (string, sizeof(string), "xv 32 yv 8 picn help " // background "xv 202 yv 12 string2 \"%s\" " // skill "xv 0 yv 24 cstring2 \"%s\" " // level name "xv 0 yv 54 cstring2 \"%s\" " // help 1 "xv 0 yv 110 cstring2 \"%s\" " // help 2 "xv 50 yv 164 string2 \" kills goals secrets\" " "xv 50 yv 172 string2 \"%3i/%3i %i/%i %i/%i\" ", sk, level.level_name, game.helpmessage1, game.helpmessage2, level.killed_monsters, level.total_monsters, level.found_goals, level.total_goals, level.found_secrets, level.total_secrets); gi.WriteByte (svc_layout); gi.WriteString (string); gi.unicast (ent, true); } /* ================== Cmd_Help_f Display the current help message ================== */ void Cmd_Help_f (edict_t *ent) { // this is for backwards compatability if (deathmatch->value) { Cmd_Score_f (ent); return; } ent->client->showinventory = false; ent->client->showscores = false; if (ent->client->showhelp && (ent->client->pers.game_helpchanged == game.helpchanged)) { ent->client->showhelp = false; return; } ent->client->showhelp = true; ent->client->pers.helpchanged = 0; HelpComputer (ent); } //======================================================================= void WhatIsIt (edict_t *ent) { float range; int i, num; edict_t *touch[MAX_EDICTS]; edict_t *who, *best; trace_t tr; vec3_t dir, end, entp, forward, mins, maxs, start, viewp; /* Check for looking directly at a player or other non-trigger entity */ VectorCopy(ent->s.origin, start); start[2] += ent->viewheight; AngleVectors(ent->client->v_angle, forward, NULL, NULL); VectorMA(start, WORLD_SIZE, forward, end); // was 8192 tr = gi.trace(start, NULL, NULL, end, ent, MASK_SHOT|CONTENTS_SLIME|CONTENTS_LAVA); if (tr.ent > world) { if (tr.ent->common_name) ent->client->whatsit = tr.ent->common_name; // else // ent->client->whatsit = tr.ent->classname; return; } /* Check for looking directly at a pickup item */ VectorCopy(ent->s.origin,viewp); viewp[2] += ent->viewheight; AngleVectors(ent->client->v_angle, forward, NULL, NULL); VectorSet(mins, MIN_WORLD_COORD, MIN_WORLD_COORD, MIN_WORLD_COORD); // was -4096, -4096, -4096 VectorSet(maxs, MAX_WORLD_COORD, MAX_WORLD_COORD, MAX_WORLD_COORD); // was 4096, 4096, 4096 num = gi.BoxEdicts (mins, maxs, touch, MAX_EDICTS, AREA_TRIGGERS); best = NULL; for (i=0 ; iinuse) continue; if (!who->item) continue; if (!visible(ent,who)) continue; if (!infront(ent,who)) continue; VectorSubtract(who->s.origin,viewp,dir); range = VectorLength(dir); VectorMA(viewp, range, forward, entp); if (entp[0] < who->s.origin[0] - 17) continue; if (entp[1] < who->s.origin[1] - 17) continue; if (entp[2] < who->s.origin[2] - 17) continue; if (entp[0] > who->s.origin[0] + 17) continue; if (entp[1] > who->s.origin[1] + 17) continue; if (entp[2] > who->s.origin[2] + 17) continue; best = who; break; } if (best) { ent->client->whatsit = best->item->pickup_name; return; } } /* =============== G_SetStats =============== */ void G_SetStats (edict_t *ent) { gitem_t *item; int index, cells; int power_armor_type; // // health // ent->client->ps.stats[STAT_HEALTH_ICON] = level.pic_health; ent->client->ps.stats[STAT_HEALTH] = ent->health; #ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD // ent->client->ps.stats[STAT_MAXHEALTH] = min(max(ent->client->pers.max_health, 0), 10000); ent->client->ps.stats[STAT_MAXHEALTH] = min(max(ent->max_health, 0), 10000); #endif // // ammo // if (!ent->client->ammo_index /* || !ent->client->pers.inventory[ent->client->ammo_index] */) { ent->client->ps.stats[STAT_AMMO_ICON] = 0; ent->client->ps.stats[STAT_AMMO] = 0; #ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD ent->client->ps.stats[STAT_MAXAMMO] = 0; #endif } else { item = &itemlist[ent->client->ammo_index]; ent->client->ps.stats[STAT_AMMO_ICON] = gi.imageindex (item->icon); ent->client->ps.stats[STAT_AMMO] = ent->client->pers.inventory[ent->client->ammo_index]; #ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD ent->client->ps.stats[STAT_MAXAMMO] = min(max(GetMaxAmmoByIndex(ent->client, ent->client->ammo_index), 0), 10000); #endif } // // armor // power_armor_type = PowerArmorType (ent); if (power_armor_type) { cells = ent->client->pers.inventory[ITEM_INDEX(FindItem ("cells"))]; if (cells == 0) { // ran out of cells for power armor ent->flags &= ~(FL_POWER_SHIELD|FL_POWER_SCREEN); gi.sound(ent, CHAN_ITEM, gi.soundindex("misc/power2.wav"), 1, ATTN_NORM, 0); power_armor_type = 0; } } index = ArmorIndex (ent); // Knightmare- show correct icon if (power_armor_type && (!index || (level.framenum & 8) ) ) { // flash between power armor and other armor icon if (power_armor_type == POWER_ARMOR_SHIELD) ent->client->ps.stats[STAT_ARMOR_ICON] = gi.imageindex ("i_powershield"); else // POWER_ARMOR_SCREEN ent->client->ps.stats[STAT_ARMOR_ICON] = gi.imageindex ("i_powerscreen"); ent->client->ps.stats[STAT_ARMOR] = cells; #ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD ent->client->ps.stats[STAT_MAXARMOR] = min(max(ent->client->pers.max_cells, 0), 10000); #endif } else if (index) { item = GetItemByIndex (index); ent->client->ps.stats[STAT_ARMOR_ICON] = gi.imageindex (item->icon); ent->client->ps.stats[STAT_ARMOR] = ent->client->pers.inventory[index]; #ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD ent->client->ps.stats[STAT_MAXARMOR] = min(max(GetMaxArmorByIndex(index), 0), 10000); #endif } else { ent->client->ps.stats[STAT_ARMOR_ICON] = 0; ent->client->ps.stats[STAT_ARMOR] = 0; #ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD ent->client->ps.stats[STAT_MAXARMOR] = 0; #endif } // // pickup message // if (level.time > ent->client->pickup_msg_time) { ent->client->ps.stats[STAT_PICKUP_ICON] = 0; ent->client->ps.stats[STAT_PICKUP_STRING] = 0; } // // timers // if (ent->client->quad_framenum > level.framenum) { ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_quad"); ent->client->ps.stats[STAT_TIMER] = (ent->client->quad_framenum - level.framenum)/10; #ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD ent->client->ps.stats[STAT_TIMER_RANGE] = min(max((int)sk_quad_time->value, 0), 10000); #endif } // RAFAEL else if (ent->client->quadfire_framenum > level.framenum) { // note to self // need to change imageindex ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_quadfire"); ent->client->ps.stats[STAT_TIMER] = (ent->client->quadfire_framenum - level.framenum)/10; #ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD ent->client->ps.stats[STAT_TIMER_RANGE] = min(max((int)sk_quad_fire_time->value, 0), 10000); #endif } // PMM else if (ent->client->double_framenum > level.framenum) { ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_double"); ent->client->ps.stats[STAT_TIMER] = (ent->client->double_framenum - level.framenum)/10; #ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD ent->client->ps.stats[STAT_TIMER_RANGE] = min(max((int)sk_double_time->value, 0), 10000); #endif } // PMM else if (ent->client->invincible_framenum > level.framenum) { ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_invulnerability"); ent->client->ps.stats[STAT_TIMER] = (ent->client->invincible_framenum - level.framenum)/10; #ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD ent->client->ps.stats[STAT_TIMER_RANGE] = min(max((int)sk_inv_time->value, 0), 10000); #endif } else if (ent->client->enviro_framenum > level.framenum) { ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_envirosuit"); ent->client->ps.stats[STAT_TIMER] = (ent->client->enviro_framenum - level.framenum)/10; #ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD ent->client->ps.stats[STAT_TIMER_RANGE] = min(max((int)sk_enviro_time->value, 0), 10000); #endif } else if (ent->client->breather_framenum > level.framenum) { ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_rebreather"); ent->client->ps.stats[STAT_TIMER] = (ent->client->breather_framenum - level.framenum)/10; #ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD ent->client->ps.stats[STAT_TIMER_RANGE] = min(max((int)sk_breather_time->value, 0), 10000); #endif } // PGM else if (ent->client->owned_sphere) { int sphere_time; if (ent->client->owned_sphere->spawnflags == 1) { // defender ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_defender"); sphere_time = sk_defender_time->value; } else if (ent->client->owned_sphere->spawnflags == 2) { // hunter ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_hunter"); sphere_time = sk_hunter_time->value; } else if (ent->client->owned_sphere->spawnflags == 4) { // vengeance ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_vengeance"); sphere_time = sk_vengeance_time->value; } else { // error case ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("i_fixme"); sphere_time = 0; } ent->client->ps.stats[STAT_TIMER] = (int)(ent->client->owned_sphere->wait - level.time); #ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD ent->client->ps.stats[STAT_TIMER_RANGE] = min(max(sphere_time, 0), 10000); #endif } else if (ent->client->ir_framenum > level.framenum) { ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_ir"); ent->client->ps.stats[STAT_TIMER] = (ent->client->ir_framenum - level.framenum)/10; #ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD ent->client->ps.stats[STAT_TIMER_RANGE] = min(max((int)sk_ir_time->value, 0), 10000); #endif } // PGM #ifdef JETPACK_MOD else if ( (ent->client->jetpack) && (!ent->client->jetpack_infinite) && (ent->client->pers.inventory[fuel_index] >= 0) && (ent->client->pers.inventory[fuel_index] < 100000)) { ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex("p_jet"); ent->client->ps.stats[STAT_TIMER] = ent->client->pers.inventory[fuel_index]; #ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD ent->client->ps.stats[STAT_TIMER_RANGE] = min(max(ent->client->pers.max_fuel, 0), 10000); #endif } #endif // added stasis generator support else if (level.freeze) { ent->client->ps.stats[STAT_TIMER_ICON] = gi.imageindex ("p_freeze"); ent->client->ps.stats[STAT_TIMER] = sk_stasis_time->value - level.freezeframes/10; // was 30 #ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD ent->client->ps.stats[STAT_TIMER_RANGE] = min(max((int)sk_stasis_time->value, 0), 10000); #endif } else { ent->client->ps.stats[STAT_TIMER_ICON] = 0; ent->client->ps.stats[STAT_TIMER] = 0; #ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD ent->client->ps.stats[STAT_TIMER_RANGE] = 0; #endif } // // selected item // if (ent->client->pers.selected_item == -1) ent->client->ps.stats[STAT_SELECTED_ICON] = 0; else ent->client->ps.stats[STAT_SELECTED_ICON] = gi.imageindex (itemlist[ent->client->pers.selected_item].icon); ent->client->ps.stats[STAT_SELECTED_ITEM] = ent->client->pers.selected_item; // Lazarus vehicle/tracktrain if (ent->vehicle && !(ent->vehicle->spawnflags & 16)) { switch (ent->vehicle->moveinfo.state) { case -3: ent->client->ps.stats[STAT_SPEED] = gi.imageindex("speedr3"); break; case -2: ent->client->ps.stats[STAT_SPEED] = gi.imageindex("speedr2"); break; case -1: ent->client->ps.stats[STAT_SPEED] = gi.imageindex("speedr1"); break; case 1: ent->client->ps.stats[STAT_SPEED] = gi.imageindex("speed1"); break; case 2: ent->client->ps.stats[STAT_SPEED] = gi.imageindex("speed2"); break; case 3: ent->client->ps.stats[STAT_SPEED] = gi.imageindex("speed3"); break; default: ent->client->ps.stats[STAT_SPEED] = gi.imageindex("speed0"); break; } } else ent->client->ps.stats[STAT_SPEED] = 0; // "whatsit" if (world->effects & FX_WORLDSPAWN_WHATSIT) { if (ent->client->showscores || ent->client->showhelp || ent->client->showinventory) ent->client->whatsit = NULL; else if (!(level.framenum % 5)) // only update every 1/2 second { char *temp = ent->client->whatsit; ent->client->whatsit = NULL; WhatIsIt(ent); if (ent->client->whatsit && !temp) WhatsIt(ent); } } else ent->client->whatsit = NULL; // // layouts // ent->client->ps.stats[STAT_LAYOUTS] = 0; if (deathmatch->value) { if (ent->client->pers.health <= 0 || level.intermissiontime || ent->client->showscores) ent->client->ps.stats[STAT_LAYOUTS] |= 1; if (ent->client->showinventory && ent->client->pers.health > 0) ent->client->ps.stats[STAT_LAYOUTS] |= 2; } else { if (ent->client->showscores || ent->client->showhelp) ent->client->ps.stats[STAT_LAYOUTS] |= 1; if (ent->client->showinventory && ent->client->pers.health > 0) ent->client->ps.stats[STAT_LAYOUTS] |= 2; } // // frags // ent->client->ps.stats[STAT_FRAGS] = ent->client->resp.score; // // help icon / current weapon if not shown // if (ent->client->pers.helpchanged && (level.framenum&8) ) ent->client->ps.stats[STAT_HELPICON] = gi.imageindex ("i_help"); else if ( (ent->client->pers.hand == CENTER_HANDED || ent->client->ps.fov > 91) && ent->client->pers.weapon) ent->client->ps.stats[STAT_HELPICON] = gi.imageindex (ent->client->pers.weapon->icon); else ent->client->ps.stats[STAT_HELPICON] = 0; #ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD if (ent->client->pers.weapon) { if (ITEM_INDEX(ent->client->pers.weapon) == hml_index) // homing rocket launcher has no icon ent->client->ps.stats[STAT_WEAPON] = gi.imageindex (GetItemByIndex(rl_index)->icon); else ent->client->ps.stats[STAT_WEAPON] = gi.imageindex (ent->client->pers.weapon->icon); } else ent->client->ps.stats[STAT_WEAPON] = 0; #endif ent->client->ps.stats[STAT_SPECTATOR] = 0; if (ent->client->zoomed) ent->client->ps.stats[STAT_ZOOM] = gi.imageindex("zoom"); else ent->client->ps.stats[STAT_ZOOM] = 0; // Zaero if (ent->client->zCameraTrack) { ent->client->ps.stats[STAT_CAMERA_ICON] = gi.imageindex("i_visor"); ent->client->ps.stats[STAT_CAMERA_TIMER] = ent->client->pers.visorFrames/10; #ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD // ent->client->ps.stats[STAT_CAMERA_RANGE] = min(max((int)sk_visor_time->value, 0), 10000); #endif } else { ent->client->ps.stats[STAT_CAMERA_ICON] = 0; #ifdef KMQUAKE2_ENGINE_MOD // for enhanced HUD // ent->client->ps.stats[STAT_CAMERA_RANGE] = 0; #endif } // end Zaero } /* =============== G_CheckChaseStats =============== */ void G_CheckChaseStats (edict_t *ent) { int i; gclient_t *cl; for (i = 1; i <= maxclients->value; i++) { cl = g_edicts[i].client; if (!g_edicts[i].inuse || cl->chase_target != ent) continue; memcpy(cl->ps.stats, ent->client->ps.stats, sizeof(cl->ps.stats)); G_SetSpectatorStats(g_edicts + i); } } /* =============== G_SetSpectatorStats =============== */ void G_SetSpectatorStats (edict_t *ent) { gclient_t *cl = ent->client; if (!cl->chase_target) G_SetStats (ent); cl->ps.stats[STAT_SPECTATOR] = 1; // layouts are independant in spectator cl->ps.stats[STAT_LAYOUTS] = 0; if (cl->pers.health <= 0 || level.intermissiontime || cl->showscores) cl->ps.stats[STAT_LAYOUTS] |= 1; if (cl->showinventory && cl->pers.health > 0) cl->ps.stats[STAT_LAYOUTS] |= 2; if (cl->chase_target && cl->chase_target->inuse) { cl->ps.stats[STAT_CHASE] = CS_PLAYERSKINS + (cl->chase_target - g_edicts) - 1; } else cl->ps.stats[STAT_CHASE] = 0; }