/*
* 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.
*
*/
/* Modifications
Copyright 2003-2004 Bytonic Software
Copyright 2010 Google Inc.
*/
package com.googlecode.gwtquake.shared.game;
import com.googlecode.gwtquake.*;
import com.googlecode.gwtquake.shared.client.*;
import com.googlecode.gwtquake.shared.common.*;
import com.googlecode.gwtquake.shared.render.*;
import com.googlecode.gwtquake.shared.server.*;
import com.googlecode.gwtquake.shared.util.Lib;
import com.googlecode.gwtquake.shared.util.Math3D;
import com.googlecode.gwtquake.shared.util.Vargs;
public class PlayerHud {
/*
* ======================================================================
*
* INTERMISSION
*
* ======================================================================
*/
public static void MoveClientToIntermission(Entity 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 = Constants.PM_FREEZE;
ent.client.ps.gunindex = 0;
ent.client.ps.blend[3] = 0;
ent.client.ps.rdflags &= ~Constants.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 = Constants.SOLID_NOT;
// add the layout
if (GameBase.deathmatch.value != 0 || GameBase.coop.value != 0) {
DeathmatchScoreboardMessage(ent, null);
ServerGame.PF_Unicast(ent, true);
}
}
public static void BeginIntermission(Entity targ) {
int i, n;
Entity 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 & Constants.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;
EntityIterator 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(Entity ent, Entity killer) {
StringBuffer string = new StringBuffer(1400);
int stringlength;
int i, j, k;
int sorted[] = new int[Constants.MAX_CLIENTS];
int sortedscores[] = new int[Constants.MAX_CLIENTS];
int score, total;
int picnum;
int x, y;
GameClient cl;
Entity 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 = ServerInit.SV_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);
}
ServerGame.PF_WriteByte(Constants.svc_layout);
ServerGame.PF_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(Entity ent) {
DeathmatchScoreboardMessage(ent, ent.enemy);
ServerGame.PF_Unicast(ent, true);
}
/*
* ==================
* Cmd_Score_f
*
* Display the scoreboard
* ==================
*/
public static void Cmd_Score_f(Entity 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(Entity ent) {
GameItem item;
int index, cells = 0;
int power_armor_type;
//
// health
//
ent.client.ps.stats[Constants.STAT_HEALTH_ICON] = (short) GameBase.level.pic_health;
ent.client.ps.stats[Constants.STAT_HEALTH] = (short) ent.health;
//
// ammo
//
if (0 == ent.client.ammo_index /*
* ||
* !ent.client.pers.inventory[ent.client.ammo_index]
*/
) {
ent.client.ps.stats[Constants.STAT_AMMO_ICON] = 0;
ent.client.ps.stats[Constants.STAT_AMMO] = 0;
} else {
item = GameItemList.itemlist[ent.client.ammo_index];
ent.client.ps.stats[Constants.STAT_AMMO_ICON] = (short) ServerInit.SV_ImageIndex(item.icon);
ent.client.ps.stats[Constants.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 &= ~Constants.FL_POWER_ARMOR;
ServerGame.PF_StartSound(ent, Constants.CHAN_ITEM, ServerInit.SV_SoundIndex("misc/power2.wav"), (float) 1, (float) Constants.ATTN_NORM,
(float) 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[Constants.STAT_ARMOR_ICON] = (short) ServerInit.SV_ImageIndex("i_powershield");
ent.client.ps.stats[Constants.STAT_ARMOR] = (short) cells;
} else if (index != 0) {
item = GameItems.GetItemByIndex(index);
ent.client.ps.stats[Constants.STAT_ARMOR_ICON] = (short) ServerInit.SV_ImageIndex(item.icon);
ent.client.ps.stats[Constants.STAT_ARMOR] = (short) ent.client.pers.inventory[index];
} else {
ent.client.ps.stats[Constants.STAT_ARMOR_ICON] = 0;
ent.client.ps.stats[Constants.STAT_ARMOR] = 0;
}
//
// pickup message
//
if (GameBase.level.time > ent.client.pickup_msg_time) {
ent.client.ps.stats[Constants.STAT_PICKUP_ICON] = 0;
ent.client.ps.stats[Constants.STAT_PICKUP_STRING] = 0;
}
//
// timers
//
if (ent.client.quad_framenum > GameBase.level.framenum) {
ent.client.ps.stats[Constants.STAT_TIMER_ICON] = (short) ServerInit.SV_ImageIndex("p_quad");
ent.client.ps.stats[Constants.STAT_TIMER] = (short) ((ent.client.quad_framenum - GameBase.level.framenum) / 10);
} else if (ent.client.invincible_framenum > GameBase.level.framenum) {
ent.client.ps.stats[Constants.STAT_TIMER_ICON] = (short) ServerInit.SV_ImageIndex("p_invulnerability");
ent.client.ps.stats[Constants.STAT_TIMER] = (short) ((ent.client.invincible_framenum - GameBase.level.framenum) / 10);
} else if (ent.client.enviro_framenum > GameBase.level.framenum) {
ent.client.ps.stats[Constants.STAT_TIMER_ICON] = (short) ServerInit.SV_ImageIndex("p_envirosuit");
ent.client.ps.stats[Constants.STAT_TIMER] = (short) ((ent.client.enviro_framenum - GameBase.level.framenum) / 10);
} else if (ent.client.breather_framenum > GameBase.level.framenum) {
ent.client.ps.stats[Constants.STAT_TIMER_ICON] = (short) ServerInit.SV_ImageIndex("p_rebreather");
ent.client.ps.stats[Constants.STAT_TIMER] = (short) ((ent.client.breather_framenum - GameBase.level.framenum) / 10);
} else {
ent.client.ps.stats[Constants.STAT_TIMER_ICON] = 0;
ent.client.ps.stats[Constants.STAT_TIMER] = 0;
}
//
// selected item
//
// bugfix rst
if (ent.client.pers.selected_item <= 0)
ent.client.ps.stats[Constants.STAT_SELECTED_ICON] = 0;
else
ent.client.ps.stats[Constants.STAT_SELECTED_ICON] = (short) ServerInit.SV_ImageIndex(GameItemList.itemlist[ent.client.pers.selected_item].icon);
ent.client.ps.stats[Constants.STAT_SELECTED_ITEM] = (short) ent.client.pers.selected_item;
//
// layouts
//
ent.client.ps.stats[Constants.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[Constants.STAT_LAYOUTS] |= 1;
if (ent.client.showinventory && ent.client.pers.health > 0)
ent.client.ps.stats[Constants.STAT_LAYOUTS] |= 2;
} else {
if (ent.client.showscores || ent.client.showhelp)
ent.client.ps.stats[Constants.STAT_LAYOUTS] |= 1;
if (ent.client.showinventory && ent.client.pers.health > 0)
ent.client.ps.stats[Constants.STAT_LAYOUTS] |= 2;
}
//
// frags
//
ent.client.ps.stats[Constants.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[Constants.STAT_HELPICON] = (short) ServerInit.SV_ImageIndex("i_help");
else if ((ent.client.pers.hand == Constants.CENTER_HANDED || ent.client.ps.fov > 91)
&& ent.client.pers.weapon != null)
ent.client.ps.stats[Constants.STAT_HELPICON] = (short) ServerInit.SV_ImageIndex(ent.client.pers.weapon.icon);
else
ent.client.ps.stats[Constants.STAT_HELPICON] = 0;
ent.client.ps.stats[Constants.STAT_SPECTATOR] = 0;
}
/*
* ===============
* G_CheckChaseStats
* ===============
*/
public static void G_CheckChaseStats(Entity ent) {
int i;
GameClient 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,
Constants.MAX_STATS);
G_SetSpectatorStats(GameBase.g_edicts[i]);
}
}
/*
* ===============
* G_SetSpectatorStats
* ===============
*/
public static void G_SetSpectatorStats(Entity ent) {
GameClient cl = ent.client;
if (null == cl.chase_target)
G_SetStats(ent);
cl.ps.stats[Constants.STAT_SPECTATOR] = 1;
// layouts are independant in spectator
cl.ps.stats[Constants.STAT_LAYOUTS] = 0;
if (cl.pers.health <= 0 || GameBase.level.intermissiontime != 0
|| cl.showscores)
cl.ps.stats[Constants.STAT_LAYOUTS] |= 1;
if (cl.showinventory && cl.pers.health > 0)
cl.ps.stats[Constants.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[Constants.STAT_CHASE] = (short) (Constants.CS_PLAYERSKINS
+ cl.chase_target.index - 1);
else
cl.ps.stats[Constants.STAT_CHASE] = 0;
}
/**
* HelpComputer. Draws the help computer.
*/
public static void HelpComputer(Entity 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)));
ServerGame.PF_WriteByte(Constants.svc_layout);
ServerGame.PF_WriteString(sb.toString());
ServerGame.PF_Unicast(ent, true);
}
}