/* * 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. * */ // Created on 28.12.2003 by RST. package jake2.game; import jake2.Defines; import jake2.qcommon.Com; import jake2.util.Lib; import jake2.util.Math3D; import jake2.util.Vargs; public class PlayerHud { /* * ====================================================================== * * INTERMISSION * * ====================================================================== */ public static void MoveClientToIntermission(edict_t ent) { if (GameBase.deathmatch.value != 0 || GameBase.coop.value != 0) ent.client.showscores = true; Math3D.VectorCopy(GameBase.level.intermission_origin, ent.s.origin); ent.client.ps.pmove.origin[0] = (short) (GameBase.level.intermission_origin[0] * 8); ent.client.ps.pmove.origin[1] = (short) (GameBase.level.intermission_origin[1] * 8); ent.client.ps.pmove.origin[2] = (short) (GameBase.level.intermission_origin[2] * 8); Math3D.VectorCopy(GameBase.level.intermission_angle, ent.client.ps.viewangles); ent.client.ps.pmove.pm_type = Defines.PM_FREEZE; ent.client.ps.gunindex = 0; ent.client.ps.blend[3] = 0; ent.client.ps.rdflags &= ~Defines.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 = Defines.SOLID_NOT; // add the layout if (GameBase.deathmatch.value != 0 || GameBase.coop.value != 0) { DeathmatchScoreboardMessage(ent, null); GameBase.gi.unicast(ent, true); } } public static void BeginIntermission(edict_t targ) { int i, n; edict_t ent, client; if (GameBase.level.intermissiontime != 0) return; // already activated GameBase.game.autosaved = false; // respawn any dead clients for (i = 0; i < GameBase.maxclients.value; i++) { client = GameBase.g_edicts[1 + i]; if (!client.inuse) continue; if (client.health <= 0) PlayerClient.respawn(client); } GameBase.level.intermissiontime = GameBase.level.time; GameBase.level.changemap = targ.map; if (GameBase.level.changemap.indexOf('*') > -1) { if (GameBase.coop.value != 0) { for (i = 0; i < GameBase.maxclients.value; i++) { client = GameBase.g_edicts[1 + i]; if (!client.inuse) continue; // strip players of all keys between units for (n = 1; n < GameItemList.itemlist.length; n++) { // null pointer exception fixed. (RST) if (GameItemList.itemlist[n] != null) if ((GameItemList.itemlist[n].flags & Defines.IT_KEY) != 0) client.client.pers.inventory[n] = 0; } } } } else { if (0 == GameBase.deathmatch.value) { GameBase.level.exitintermission = true; // go immediately to the // next level return; } } GameBase.level.exitintermission = false; // find an intermission spot ent = GameBase.G_FindEdict(null, GameBase.findByClass, "info_player_intermission"); if (ent == null) { // the map creator forgot to put in an intermission // point... ent = GameBase.G_FindEdict(null, GameBase.findByClass, "info_player_start"); if (ent == null) ent = GameBase.G_FindEdict(null, GameBase.findByClass, "info_player_deathmatch"); } else { // chose one of four spots i = Lib.rand() & 3; EdictIterator es = null; while (i-- > 0) { es = GameBase.G_Find(es, GameBase.findByClass, "info_player_intermission"); if (es == null) // wrap around the list continue; ent = es.o; } } Math3D.VectorCopy(ent.s.origin, GameBase.level.intermission_origin); Math3D.VectorCopy(ent.s.angles, GameBase.level.intermission_angle); // move all clients to the intermission point for (i = 0; i < GameBase.maxclients.value; i++) { client = GameBase.g_edicts[1 + i]; if (!client.inuse) continue; MoveClientToIntermission(client); } } /* * ================== * DeathmatchScoreboardMessage * ================== */ public static void DeathmatchScoreboardMessage(edict_t ent, edict_t killer) { StringBuffer string = new StringBuffer(1400); int stringlength; int i, j, k; int sorted[] = new int[Defines.MAX_CLIENTS]; int sortedscores[] = new int[Defines.MAX_CLIENTS]; int score, total; int picnum; int x, y; gclient_t cl; edict_t cl_ent; String tag; // sort the clients by score total = 0; for (i = 0; i < GameBase.game.maxclients; i++) { cl_ent = GameBase.g_edicts[1 + i]; if (!cl_ent.inuse || GameBase.game.clients[i].resp.spectator) continue; score = GameBase.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 // add the clients in sorted order if (total > 12) total = 12; for (i = 0; i < total; i++) { cl = GameBase.game.clients[sorted[i]]; cl_ent = GameBase.g_edicts[1 + sorted[i]]; picnum = GameBase.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 != null) { string.append("xv ").append(x + 32).append(" yv ").append(y) .append(" picn ").append(tag); } // send the layout string .append(" client ") .append(x) .append(" ") .append(y) .append(" ") .append(sorted[i]) .append(" ") .append(cl.resp.score) .append(" ") .append(cl.ping) .append(" ") .append( (GameBase.level.framenum - cl.resp.enterframe) / 600); } GameBase.gi.WriteByte(Defines.svc_layout); GameBase.gi.WriteString(string.toString()); } /* * ================== * DeathmatchScoreboard * * Draw instead of help message. Note that it isn't that hard to overflow * the 1400 byte message limit! * ================== */ public static void DeathmatchScoreboard(edict_t ent) { DeathmatchScoreboardMessage(ent, ent.enemy); GameBase.gi.unicast(ent, true); } /* * ================== * Cmd_Score_f * * Display the scoreboard * ================== */ public static void Cmd_Score_f(edict_t ent) { ent.client.showinventory = false; ent.client.showhelp = false; if (0 == GameBase.deathmatch.value && 0 == GameBase.coop.value) return; if (ent.client.showscores) { ent.client.showscores = false; return; } ent.client.showscores = true; DeathmatchScoreboard(ent); } //======================================================================= /* * =============== * G_SetStats * =============== */ public static void G_SetStats(edict_t ent) { gitem_t item; int index, cells = 0; int power_armor_type; // // health // ent.client.ps.stats[Defines.STAT_HEALTH_ICON] = (short) GameBase.level.pic_health; ent.client.ps.stats[Defines.STAT_HEALTH] = (short) ent.health; // // ammo // if (0 == ent.client.ammo_index /* * || * !ent.client.pers.inventory[ent.client.ammo_index] */ ) { ent.client.ps.stats[Defines.STAT_AMMO_ICON] = 0; ent.client.ps.stats[Defines.STAT_AMMO] = 0; } else { item = GameItemList.itemlist[ent.client.ammo_index]; ent.client.ps.stats[Defines.STAT_AMMO_ICON] = (short) GameBase.gi .imageindex(item.icon); ent.client.ps.stats[Defines.STAT_AMMO] = (short) ent.client.pers.inventory[ent.client.ammo_index]; } // // armor // power_armor_type = GameItems.PowerArmorType(ent); if (power_armor_type != 0) { cells = ent.client.pers.inventory[GameItems.ITEM_INDEX(GameItems .FindItem("cells"))]; if (cells == 0) { // ran out of cells for power armor ent.flags &= ~Defines.FL_POWER_ARMOR; GameBase.gi .sound(ent, Defines.CHAN_ITEM, GameBase.gi .soundindex("misc/power2.wav"), 1, Defines.ATTN_NORM, 0); power_armor_type = 0; ; } } index = GameItems.ArmorIndex(ent); if (power_armor_type != 0 && (0 == index || 0 != (GameBase.level.framenum & 8))) { // flash // between // power // armor // and // other // armor // icon ent.client.ps.stats[Defines.STAT_ARMOR_ICON] = (short) GameBase.gi .imageindex("i_powershield"); ent.client.ps.stats[Defines.STAT_ARMOR] = (short) cells; } else if (index != 0) { item = GameItems.GetItemByIndex(index); ent.client.ps.stats[Defines.STAT_ARMOR_ICON] = (short) GameBase.gi .imageindex(item.icon); ent.client.ps.stats[Defines.STAT_ARMOR] = (short) ent.client.pers.inventory[index]; } else { ent.client.ps.stats[Defines.STAT_ARMOR_ICON] = 0; ent.client.ps.stats[Defines.STAT_ARMOR] = 0; } // // pickup message // if (GameBase.level.time > ent.client.pickup_msg_time) { ent.client.ps.stats[Defines.STAT_PICKUP_ICON] = 0; ent.client.ps.stats[Defines.STAT_PICKUP_STRING] = 0; } // // timers // if (ent.client.quad_framenum > GameBase.level.framenum) { ent.client.ps.stats[Defines.STAT_TIMER_ICON] = (short) GameBase.gi .imageindex("p_quad"); ent.client.ps.stats[Defines.STAT_TIMER] = (short) ((ent.client.quad_framenum - GameBase.level.framenum) / 10); } else if (ent.client.invincible_framenum > GameBase.level.framenum) { ent.client.ps.stats[Defines.STAT_TIMER_ICON] = (short) GameBase.gi .imageindex("p_invulnerability"); ent.client.ps.stats[Defines.STAT_TIMER] = (short) ((ent.client.invincible_framenum - GameBase.level.framenum) / 10); } else if (ent.client.enviro_framenum > GameBase.level.framenum) { ent.client.ps.stats[Defines.STAT_TIMER_ICON] = (short) GameBase.gi .imageindex("p_envirosuit"); ent.client.ps.stats[Defines.STAT_TIMER] = (short) ((ent.client.enviro_framenum - GameBase.level.framenum) / 10); } else if (ent.client.breather_framenum > GameBase.level.framenum) { ent.client.ps.stats[Defines.STAT_TIMER_ICON] = (short) GameBase.gi .imageindex("p_rebreather"); ent.client.ps.stats[Defines.STAT_TIMER] = (short) ((ent.client.breather_framenum - GameBase.level.framenum) / 10); } else { ent.client.ps.stats[Defines.STAT_TIMER_ICON] = 0; ent.client.ps.stats[Defines.STAT_TIMER] = 0; } // // selected item // // bugfix rst if (ent.client.pers.selected_item <= 0) ent.client.ps.stats[Defines.STAT_SELECTED_ICON] = 0; else ent.client.ps.stats[Defines.STAT_SELECTED_ICON] = (short) GameBase.gi .imageindex(GameItemList.itemlist[ent.client.pers.selected_item].icon); ent.client.ps.stats[Defines.STAT_SELECTED_ITEM] = (short) ent.client.pers.selected_item; // // layouts // ent.client.ps.stats[Defines.STAT_LAYOUTS] = 0; if (GameBase.deathmatch.value != 0) { if (ent.client.pers.health <= 0 || GameBase.level.intermissiontime != 0 || ent.client.showscores) ent.client.ps.stats[Defines.STAT_LAYOUTS] |= 1; if (ent.client.showinventory && ent.client.pers.health > 0) ent.client.ps.stats[Defines.STAT_LAYOUTS] |= 2; } else { if (ent.client.showscores || ent.client.showhelp) ent.client.ps.stats[Defines.STAT_LAYOUTS] |= 1; if (ent.client.showinventory && ent.client.pers.health > 0) ent.client.ps.stats[Defines.STAT_LAYOUTS] |= 2; } // // frags // ent.client.ps.stats[Defines.STAT_FRAGS] = (short) ent.client.resp.score; // // help icon / current weapon if not shown // if (ent.client.pers.helpchanged != 0 && (GameBase.level.framenum & 8) != 0) ent.client.ps.stats[Defines.STAT_HELPICON] = (short) GameBase.gi .imageindex("i_help"); else if ((ent.client.pers.hand == Defines.CENTER_HANDED || ent.client.ps.fov > 91) && ent.client.pers.weapon != null) ent.client.ps.stats[Defines.STAT_HELPICON] = (short) GameBase.gi .imageindex(ent.client.pers.weapon.icon); else ent.client.ps.stats[Defines.STAT_HELPICON] = 0; ent.client.ps.stats[Defines.STAT_SPECTATOR] = 0; } /* * =============== * G_CheckChaseStats * =============== */ public static void G_CheckChaseStats(edict_t ent) { int i; gclient_t cl; for (i = 1; i <= GameBase.maxclients.value; i++) { cl = GameBase.g_edicts[i].client; if (!GameBase.g_edicts[i].inuse || cl.chase_target != ent) continue; //memcpy(cl.ps.stats, ent.client.ps.stats, sizeof(cl.ps.stats)); System.arraycopy(ent.client.ps.stats, 0, cl.ps.stats, 0, Defines.MAX_STATS); G_SetSpectatorStats(GameBase.g_edicts[i]); } } /* * =============== * G_SetSpectatorStats * =============== */ public static void G_SetSpectatorStats(edict_t ent) { gclient_t cl = ent.client; if (null == cl.chase_target) G_SetStats(ent); cl.ps.stats[Defines.STAT_SPECTATOR] = 1; // layouts are independant in spectator cl.ps.stats[Defines.STAT_LAYOUTS] = 0; if (cl.pers.health <= 0 || GameBase.level.intermissiontime != 0 || cl.showscores) cl.ps.stats[Defines.STAT_LAYOUTS] |= 1; if (cl.showinventory && cl.pers.health > 0) cl.ps.stats[Defines.STAT_LAYOUTS] |= 2; if (cl.chase_target != null && cl.chase_target.inuse) //cl.ps.stats[STAT_CHASE] = (short) (CS_PLAYERSKINS + // (cl.chase_target - g_edicts) - 1); cl.ps.stats[Defines.STAT_CHASE] = (short) (Defines.CS_PLAYERSKINS + cl.chase_target.index - 1); else cl.ps.stats[Defines.STAT_CHASE] = 0; } /** * HelpComputer. Draws the help computer. */ public static void HelpComputer(edict_t ent) { StringBuffer sb = new StringBuffer(256); String sk; if (GameBase.skill.value == 0) sk = "easy"; else if (GameBase.skill.value == 1) sk = "medium"; else if (GameBase.skill.value == 2) sk = "hard"; else sk = "hard+"; // send the layout sb.append("xv 32 yv 8 picn help "); // background sb.append("xv 202 yv 12 string2 \"").append(sk).append("\" "); // skill sb.append("xv 0 yv 24 cstring2 \"").append(GameBase.level.level_name) .append("\" "); // level name sb.append("xv 0 yv 54 cstring2 \"").append(GameBase.game.helpmessage1) .append("\" "); // help 1 sb.append("xv 0 yv 110 cstring2 \"").append(GameBase.game.helpmessage2) .append("\" "); // help 2 sb.append("xv 50 yv 164 string2 \" kills goals secrets\" "); sb.append("xv 50 yv 172 string2 \""); sb.append(Com.sprintf("%3i/%3i %i/%i %i/%i\" ", new Vargs(6) .add(GameBase.level.killed_monsters).add( GameBase.level.total_monsters).add( GameBase.level.found_goals).add( GameBase.level.total_goals).add( GameBase.level.found_secrets).add( GameBase.level.total_secrets))); GameBase.gi.WriteByte(Defines.svc_layout); GameBase.gi.WriteString(sb.toString()); GameBase.gi.unicast(ent, true); } }