123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572 |
- /*
- Copyright (C) 1997-2001 Id Software, Inc.
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
- #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;
- ent->client->ps.blend[3] = 0;
- ent->client->ps.rdflags &= ~RDF_UNDERWATER;
- // clean up powerup info
- ent->client->quad_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->grenade_time = 0;
- ent->viewheight = 0;
- ent->s.modelindex = 0;
- ent->s.modelindex2 = 0;
- ent->s.modelindex3 = 0;
- ent->s.modelindex = 0;
- ent->s.effects = 0;
- ent->s.sound = 0;
- ent->solid = SOLID_NOT;
- // 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);
- }
- level.intermissiontime = level.time;
- level.changemap = targ->map;
- if (strstr(level.changemap, "*"))
- {
- if (coop->value)
- {
- for (i=0 ; i<maxclients->value ; 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);
- // move all clients to the intermission point
- for (i=0 ; i<maxclients->value ; 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 ; i<game.maxclients ; i++)
- {
- cl_ent = g_edicts + 1 + i;
- if (!cl_ent->inuse || game.clients[i].resp.spectator)
- continue;
- score = game.clients[i].resp.score;
- for (j=0 ; j<total ; j++)
- {
- if (score > 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 = strlen(string);
- // add the clients in sorted order
- if (total > 12)
- total = 12;
- for (i=0 ; i<total ; i++)
- {
- cl = &game.clients[sorted[i]];
- cl_ent = g_edicts + 1 + sorted[i];
- picnum = gi.imageindex ("i_fixme");
- x = (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;
- if (tag)
- {
- Com_sprintf (entry, sizeof(entry),
- "xv %i yv %i picn %s ",x+32, y, tag);
- j = strlen(entry);
- if (stringlength + j > 1024)
- break;
- strcpy (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 = strlen(entry);
- if (stringlength + j > 1024)
- break;
- strcpy (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 (!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);
- }
- //=======================================================================
- /*
- ===============
- 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;
- //
- // 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;
- }
- 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];
- }
-
- //
- // 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_ARMOR;
- gi.sound(ent, CHAN_ITEM, gi.soundindex("misc/power2.wav"), 1, ATTN_NORM, 0);
- power_armor_type = 0;;
- }
- }
- index = ArmorIndex (ent);
- if (power_armor_type && (!index || (level.framenum & 8) ) )
- { // flash between power armor and other armor icon
- ent->client->ps.stats[STAT_ARMOR_ICON] = gi.imageindex ("i_powershield");
- ent->client->ps.stats[STAT_ARMOR] = cells;
- }
- 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];
- }
- else
- {
- ent->client->ps.stats[STAT_ARMOR_ICON] = 0;
- ent->client->ps.stats[STAT_ARMOR] = 0;
- }
- //
- // 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;
- }
- 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;
- }
- 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;
- }
- 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;
- }
- else
- {
- ent->client->ps.stats[STAT_TIMER_ICON] = 0;
- ent->client->ps.stats[STAT_TIMER] = 0;
- }
- //
- // 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;
- //
- // 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;
- ent->client->ps.stats[STAT_SPECTATOR] = 0;
- }
- /*
- ===============
- 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;
- }
|