summaryrefslogtreecommitdiffstats
path: root/src/jake2/client
diff options
context:
space:
mode:
Diffstat (limited to 'src/jake2/client')
-rw-r--r--src/jake2/client/CDAudio.java43
-rw-r--r--src/jake2/client/CL.java1625
-rw-r--r--src/jake2/client/CL_ents.java1287
-rw-r--r--src/jake2/client/CL_fx.java2292
-rw-r--r--src/jake2/client/CL_input.java564
-rw-r--r--src/jake2/client/CL_inv.java152
-rw-r--r--src/jake2/client/CL_newfx.java1027
-rw-r--r--src/jake2/client/CL_parse.java802
-rw-r--r--src/jake2/client/CL_pred.java347
-rw-r--r--src/jake2/client/CL_tent.java1720
-rw-r--r--src/jake2/client/CL_view.java189
-rw-r--r--src/jake2/client/Console.java610
-rw-r--r--src/jake2/client/Key.java812
-rw-r--r--src/jake2/client/M.java573
-rw-r--r--src/jake2/client/Menu.java4977
-rw-r--r--src/jake2/client/S.java33
-rw-r--r--src/jake2/client/SCR.java1420
-rw-r--r--src/jake2/client/SND_DMA.java1247
-rw-r--r--src/jake2/client/SND_JAVA.java168
-rw-r--r--src/jake2/client/SND_MEM.java374
-rw-r--r--src/jake2/client/SND_MIX.java513
-rw-r--r--src/jake2/client/V.java417
-rw-r--r--src/jake2/client/VID.java915
-rw-r--r--src/jake2/client/centity_t.java39
-rw-r--r--src/jake2/client/cl_sustain_t.java55
-rw-r--r--src/jake2/client/client_state_t.java137
-rw-r--r--src/jake2/client/client_static_t.java72
-rw-r--r--src/jake2/client/clientinfo_t.java53
-rw-r--r--src/jake2/client/console_t.java51
-rw-r--r--src/jake2/client/cparticle_t.java46
-rw-r--r--src/jake2/client/dlight_t.java31
-rw-r--r--src/jake2/client/entity_t.java76
-rw-r--r--src/jake2/client/frame_t.java61
-rw-r--r--src/jake2/client/kbutton_t.java36
-rw-r--r--src/jake2/client/lightstyle_t.java30
-rw-r--r--src/jake2/client/particle_t.java30
-rw-r--r--src/jake2/client/refdef_t.java47
-rw-r--r--src/jake2/client/refexport_t.java107
-rw-r--r--src/jake2/client/refimport_t.java76
-rw-r--r--src/jake2/client/sfx_t.java41
-rw-r--r--src/jake2/client/sfxcache_t.java34
-rw-r--r--src/jake2/client/viddef_t.java28
-rw-r--r--src/jake2/client/vidmode_t.java44
-rw-r--r--src/jake2/client/vrect_t.java39
44 files changed, 23240 insertions, 0 deletions
diff --git a/src/jake2/client/CDAudio.java b/src/jake2/client/CDAudio.java
new file mode 100644
index 0000000..49c5c42
--- /dev/null
+++ b/src/jake2/client/CDAudio.java
@@ -0,0 +1,43 @@
+/*
+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 31.01.2004 by RST.
+// $Id: CDAudio.java,v 1.1 2004-07-07 19:58:32 hzi Exp $
+
+package jake2.client;
+
+
+// import jake2.*;
+// import jake2.client.*;
+// import jake2.game.*;
+// import jake2.qcommon.*;
+// import jake2.render.*;
+// import jake2.server.*;
+
+public class CDAudio {
+
+ public static void CDAudio_Play(int i, boolean b) {
+ // TODO:implement CDAudio_Play
+ }
+
+ public static void Stop() {
+ // TODO impl: CDAudio.Stop()
+ }
+}
diff --git a/src/jake2/client/CL.java b/src/jake2/client/CL.java
new file mode 100644
index 0000000..58ce048
--- /dev/null
+++ b/src/jake2/client/CL.java
@@ -0,0 +1,1625 @@
+/*
+ * CL.java
+ * Copyright (C) 2004
+ *
+ * $Id: CL.java,v 1.1 2004-07-07 19:58:33 hzi Exp $
+ */
+/*
+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.
+
+*/
+package jake2.client;
+
+import jake2.Defines;
+import jake2.Globals;
+import jake2.game.*;
+import jake2.qcommon.*;
+import jake2.server.SV_MAIN;
+import jake2.sys.*;
+import jake2.util.Vargs;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+
+/**
+ * CL
+ */
+public final class CL extends CL_pred {
+
+ //// cl_main.c -- client main loop
+
+ /*
+ ====================
+ CL_WriteDemoMessage
+
+ Dumps the current net message, prefixed by the length
+ ====================
+ */
+ static void WriteDemoMessage() {
+ int swlen;
+
+ // the first eight bytes are just packet sequencing stuff
+ swlen = net_message.cursize - 8;
+
+ try {
+ cls.demofile.writeInt(swlen);
+ //fwrite (&swlen, 4, 1, cls.demofile);
+ cls.demofile.write(net_message.data, 8, swlen);
+ //fwrite (net_message.data+8, len, 1, cls.demofile);
+ } catch (IOException e) {}
+
+ }
+
+ /*
+ ====================
+ CL_Stop_f
+
+ stop recording a demo
+ ====================
+ */
+ static xcommand_t Stop_f = new xcommand_t() {
+ public void execute() {
+ try {
+
+ int len;
+
+ if (!cls.demorecording) {
+ Com.Printf("Not recording a demo.\n");
+ return;
+ }
+
+ // finish up
+ len = -1;
+ cls.demofile.writeInt(len);
+ cls.demofile.close();
+ cls.demofile = null;
+ cls.demorecording = false;
+ Com.Printf("Stopped demo.\n");
+
+ }
+ catch (IOException e) {
+ }
+ }
+ };
+
+ /*
+ ====================
+ CL_Record_f
+
+ record <demoname>
+
+ Begins recording a demo from the current position
+ ====================
+ */
+ private static entity_state_t nullstate = new entity_state_t(null);
+ static xcommand_t Record_f = new xcommand_t() {
+ public void execute() {
+ try {
+ String name;
+ byte buf_data[] = new byte[MAX_MSGLEN];
+ sizebuf_t buf = new sizebuf_t();
+ int i;
+ int len;
+ entity_state_t ent;
+
+ if (Cmd.Argc() != 2) {
+ Com.Printf("record <demoname>\n");
+ return;
+ }
+
+ if (cls.demorecording) {
+ Com.Printf("Already recording.\n");
+ return;
+ }
+
+ if (cls.state != ca_active) {
+ Com.Printf("You must be in a level to record.\n");
+ return;
+ }
+
+ //
+ // open the demo file
+ //
+ name = FS.Gamedir() + "/demos/" + Cmd.Argv(1) + ".dm2";
+
+ Com.Printf("recording to " + name + ".\n");
+ FS.CreatePath(name);
+ cls.demofile = new RandomAccessFile(name, "rw");
+ if (cls.demofile == null) {
+ Com.Printf("ERROR: couldn't open.\n");
+ return;
+ }
+ cls.demorecording = true;
+
+ // don't start saving messages until a non-delta compressed message is received
+ cls.demowaiting = true;
+
+ //
+ // write out messages to hold the startup information
+ //
+ SZ.Init(buf, buf_data, MAX_MSGLEN);
+
+ // send the serverdata
+ MSG.WriteByte(buf, svc_serverdata);
+ MSG.WriteInt(buf, PROTOCOL_VERSION);
+ MSG.WriteInt(buf, 0x10000 + cl.servercount);
+ MSG.WriteByte(buf, 1); // demos are always attract loops
+ MSG.WriteString(buf, cl.gamedir);
+ MSG.WriteShort(buf, cl.playernum);
+
+ MSG.WriteString(buf, cl.configstrings[CS_NAME]);
+
+ // configstrings
+ for (i = 0; i < MAX_CONFIGSTRINGS; i++) {
+ if (cl.configstrings[i].length()>0) {
+ if (buf.cursize + cl.configstrings[i].length() + 32 > buf.maxsize) { // write it out
+ //len = LittleLong(buf.cursize);
+ //fwrite(& len, 4, 1, cls.demofile);
+ cls.demofile.writeInt(buf.cursize);
+ //fwrite(buf.data, buf.cursize, 1, cls.demofile);
+ cls.demofile.write(buf.data, 0, buf.cursize);
+ buf.cursize = 0;
+ }
+
+ MSG.WriteByte(buf, svc_configstring);
+ MSG.WriteShort(buf, i);
+ MSG.WriteString(buf, cl.configstrings[i]);
+ }
+
+ }
+
+ // baselines
+ //memset( nullstate, 0, sizeof(nullstate));
+ for (i = 0; i < MAX_EDICTS; i++) {
+ ent = cl_entities[i].baseline;
+ if (ent.modelindex == 0)
+ continue;
+
+ if (buf.cursize + 64 > buf.maxsize) { // write it out
+ //len = LittleLong(buf.cursize);
+ //fwrite(& len, 4, 1, cls.demofile);
+ cls.demofile.writeInt(buf.cursize);
+ //fwrite(buf.data, buf.cursize, 1, cls.demofile);
+ cls.demofile.write(buf.data, 0, buf.cursize);
+ buf.cursize = 0;
+ }
+
+ MSG.WriteByte(buf, svc_spawnbaseline);
+ MSG.WriteDeltaEntity(nullstate, cl_entities[i].baseline, buf, true, true);
+ }
+
+ MSG.WriteByte(buf, svc_stufftext);
+ MSG.WriteString(buf, "precache\n");
+
+ // write it to the demo file
+
+ //len = LittleLong(buf.cursize);
+ //fwrite(& len, 4, 1, cls.demofile);
+ cls.demofile.writeInt(buf.cursize);
+ //fwrite(buf.data, buf.cursize, 1, cls.demofile);
+ cls.demofile.write(buf.data, 0, buf.cursize);
+ // the rest of the demo file will be individual frames
+
+ }
+ catch (IOException e) {
+ }
+ }
+ };
+
+ /*
+ ==================
+ CL_ForwardToServer_f
+ ==================
+ */
+ static xcommand_t ForwardToServer_f = new xcommand_t() {
+ public void execute() {
+ if (cls.state != ca_connected && cls.state != ca_active) {
+ Com.Printf("Can't \"" + Cmd.Argv(0) + "\", not connected\n");
+ return;
+ }
+
+ // don't forward the first argument
+ if (Cmd.Argc() > 1) {
+ MSG.WriteByte(cls.netchan.message, clc_stringcmd);
+ SZ.Print(cls.netchan.message, Cmd.Args());
+ }
+ }
+ };
+
+ /*
+ ==================
+ CL_Pause_f
+ ==================
+ */
+ static xcommand_t Pause_f = new xcommand_t() {
+ public void execute() {
+ // never pause in multiplayer
+
+ if (Cvar.VariableValue("maxclients") > 1 || Com.ServerState() == 0) {
+ Cvar.SetValue("paused", 0);
+ return;
+ }
+
+ Cvar.SetValue("paused", cl_paused.value);
+ }
+ };
+
+ /*
+ ==================
+ CL_Quit_f
+ ==================
+ */
+ static xcommand_t Quit_f = new xcommand_t() {
+ public void execute() {
+ Disconnect();
+ Com.Quit();
+ }
+ };
+
+ /*
+ =======================
+ CL_SendConnectPacket
+
+ We have gotten a challenge from the server, so try and
+ connect.
+ ======================
+ */
+ static void SendConnectPacket() {
+ netadr_t adr = new netadr_t();
+ int port;
+
+ if (!NET.StringToAdr(cls.servername, adr)) {
+ Com.Printf("Bad server address\n");
+ cls.connect_time = 0;
+ return;
+ }
+ if (adr.port == 0)
+ adr.port = PORT_SERVER;
+ // adr.port = BigShort(PORT_SERVER);
+
+ port = (int) Cvar.VariableValue("qport");
+ userinfo_modified = false;
+
+ Netchan.OutOfBandPrint(
+ NS_CLIENT,
+ adr,
+ "connect " + PROTOCOL_VERSION + " " + port + " " + cls.challenge + " \"" + Cvar.Userinfo() + "\"\n");
+ }
+
+ /*
+ =================
+ CL_CheckForResend
+
+ Resend a connect message if the last one has timed out
+ =================
+ */
+ static void CheckForResend() {
+ netadr_t adr = new netadr_t();
+
+ // if the local server is running and we aren't
+ // then connect
+ if (cls.state == ca_disconnected && Com.ServerState() != 0) {
+ cls.state = ca_connecting;
+ cls.servername = "localhost";
+ // we don't need a challenge on the localhost
+ CL.SendConnectPacket();
+ return;
+ }
+
+ // resend if we haven't gotten a reply yet
+ if (cls.state != ca_connecting)
+ return;
+
+ if (cls.realtime - cls.connect_time < 3000)
+ return;
+
+ if (!NET.StringToAdr(cls.servername, adr)) {
+ Com.Printf("Bad server address\n");
+ cls.state = ca_disconnected;
+ return;
+ }
+ if (adr.port == 0)
+ // adr.port = BigShort(PORT_SERVER);
+ adr.port = PORT_SERVER;
+
+ cls.connect_time = cls.realtime; // for retransmit requests
+
+ Com.Printf("Connecting to " + cls.servername + "...\n");
+
+ Netchan.OutOfBandPrint(NS_CLIENT, adr, "getchallenge\n");
+ }
+
+ /*
+ ================
+ CL_Connect_f
+
+ ================
+ */
+ static xcommand_t Connect_f = new xcommand_t() {
+ public void execute() {
+ String server;
+
+ if (Cmd.Argc() != 2) {
+ Com.Printf("usage: connect <server>\n");
+ return;
+ }
+
+ if (Com.ServerState() != 0) {
+ // if running a local server, kill it and reissue
+ SV_MAIN.SV_Shutdown("Server quit\n", false);
+ } else {
+ CL.Disconnect();
+ }
+
+ server = Cmd.Argv(1);
+
+ NET.Config(true); // allow remote
+
+ CL.Disconnect();
+
+ cls.state = ca_connecting;
+ //strncpy (cls.servername, server, sizeof(cls.servername)-1);
+ cls.servername = server;
+ cls.connect_time = -99999;
+ // CL_CheckForResend() will fire immediately
+ }
+ };
+
+ /*
+ =====================
+ CL_Rcon_f
+
+ Send the rest of the command line over as
+ an unconnected command.
+ =====================
+ */
+ static xcommand_t Rcon_f = new xcommand_t() {
+ public void execute() {
+ StringBuffer message = new StringBuffer(1024);
+ int i;
+ netadr_t to = new netadr_t();
+
+ if (rcon_client_password.string == null) {
+ Com.Printf("You must set 'rcon_password' before\nissuing an rcon command.\n");
+ return;
+ }
+
+ message.append((char)255);
+ message.append((char)255);
+ message.append((char)255);
+ message.append((char)255);
+
+ NET.Config(true); // allow remote
+
+ //strcat (message, "rcon ");
+ message.append("rcon ");
+
+ //strcat (message, rcon_client_password.string);
+ message.append(rcon_client_password.string);
+ //strcat (message, " ");
+ message.append(" ");
+
+ for (i = 1; i < Cmd.Argc(); i++) {
+ //strcat (message, Cmd.Argv(i));
+ message.append(Cmd.Argv(i));
+ //strcat (message, " ");
+ message.append(" ");
+ }
+
+ if (cls.state >= ca_connected)
+ to = cls.netchan.remote_address;
+ else {
+ if (strlen(rcon_address.string) == 0) {
+ Com.Printf(
+ "You must either be connected,\nor set the 'rcon_address' cvar\nto issue rcon commands\n");
+
+ return;
+ }
+ NET.StringToAdr(rcon_address.string, to);
+ if (to.port == 0)
+ //to.port = BigShort (PORT_SERVER);
+ to.port = PORT_SERVER;
+ }
+ message.append('\0');
+ String b = message.toString();
+ NET.SendPacket(NS_CLIENT, b.length(), b.getBytes(), to);
+ }
+ };
+
+ /*
+ =====================
+ CL_ClearState
+
+ =====================
+ */
+
+ static void ClearState() {
+ S.StopAllSounds();
+ CL.ClearEffects();
+ CL.ClearTEnts();
+
+ // wipe the entire cl structure
+
+ cl = new client_state_t();
+ for (int i = 0; i < cl_entities.length; i++) {
+ cl_entities[i] = new centity_t();
+ }
+
+ SZ.Clear(cls.netchan.message);
+ }
+
+ /*
+ =====================
+ CL_Disconnect
+
+ Goes from a connected state to full screen console state
+ Sends a disconnect message to the server
+ This is also called on Com_Error, so it shouldn't cause any errors
+ =====================
+ */
+
+ static void Disconnect() {
+
+ String fin;
+
+ if (cls.state == ca_disconnected)
+ return;
+
+ if (cl_timedemo != null && cl_timedemo.value != 0.0f) {
+ int time;
+
+ time = (int) (Sys.Milliseconds() - cl.timedemo_start);
+ if (time > 0)
+ Com.Printf(
+ "%i frames, %3.1f seconds: %3.1f fps\n",
+ new Vargs(3).add(cl.timedemo_frames).add(time / 1000.0).add(cl.timedemo_frames * 1000.0 / time));
+ }
+
+ VectorClear(cl.refdef.blend);
+ //re.CinematicSetPalette(null);
+
+ Menu.ForceMenuOff();
+
+ cls.connect_time = 0;
+
+ // SCR.StopCinematic();
+
+ if (cls.demorecording)
+ CL.Stop_f.execute();
+
+ // send a disconnect message to the server
+ fin = (char) clc_stringcmd + "disconnect";
+ Netchan.Transmit(cls.netchan, fin.length(), fin.getBytes());
+ Netchan.Transmit(cls.netchan, fin.length(), fin.getBytes());
+ Netchan.Transmit(cls.netchan, fin.length(), fin.getBytes());
+
+ CL.ClearState();
+
+ // stop download
+ if (cls.download != null) {
+ fclose(cls.download);
+ cls.download = null;
+ // fclose(cls.download);
+ // cls.download = NULL;
+ }
+
+ cls.state = ca_disconnected;
+ }
+
+ static xcommand_t Disconnect_f = new xcommand_t() {
+ public void execute() {
+ Com.Error(ERR_DROP, "Disconnected from server");
+ }
+ };
+
+ /*
+ =================
+ CL_Changing_f
+
+ Just sent as a hint to the client that they should
+ drop to full console
+ =================
+ */
+ static xcommand_t Changing_f = new xcommand_t() {
+ public void execute() {
+ //ZOID
+ //if we are downloading, we don't change!
+ // This so we don't suddenly stop downloading a map
+
+ if (cls.download != null)
+ return;
+
+ SCR.BeginLoadingPlaque();
+ cls.state = ca_connected; // not active anymore, but not disconnected
+ Com.Printf("\nChanging map...\n");
+ }
+ };
+
+ /*
+ =================
+ CL_Reconnect_f
+
+ The server is changing levels
+ =================
+ */
+ static xcommand_t Reconnect_f = new xcommand_t() {
+ public void execute() {
+ //ZOID
+ //if we are downloading, we don't change! This so we don't suddenly stop downloading a map
+ if (cls.download != null)
+ return;
+
+ S.StopAllSounds();
+ if (cls.state == ca_connected) {
+ Com.Printf("reconnecting...\n");
+ cls.state = ca_connected;
+ MSG.WriteChar(cls.netchan.message, clc_stringcmd);
+ MSG.WriteString(cls.netchan.message, "new");
+ return;
+ }
+
+ if (cls.servername != null) {
+ if (cls.state >= ca_connected) {
+ CL.Disconnect();
+ cls.connect_time = cls.realtime - 1500;
+ } else
+ cls.connect_time = -99999; // fire immediately
+
+ cls.state = ca_connecting;
+ Com.Printf("reconnecting...\n");
+ }
+ }
+ };
+
+ /*
+ =================
+ CL_ParseStatusMessage
+
+ Handle a reply from a ping
+ =================
+ */
+ static void ParseStatusMessage() {
+ String s;
+
+ s = MSG.ReadString(net_message);
+
+ Com.Printf(s + "\n");
+ Menu.AddToServerList(net_from, s);
+ }
+
+ /*
+ =================
+ CL_PingServers_f
+ =================
+ */
+ static xcommand_t PingServers_f = new xcommand_t() {
+ public void execute() {
+ int i;
+ netadr_t adr = new netadr_t();
+ //char name[32];
+ String name;
+ String adrstring;
+ cvar_t noudp;
+ cvar_t noipx;
+
+ NET.Config(true); // allow remote
+
+ // send a broadcast packet
+ Com.Printf("pinging broadcast...\n");
+
+ noudp = Cvar.Get("noudp", "0", CVAR_NOSET);
+ if (noudp.value == 0.0f) {
+ adr.type = NA_BROADCAST;
+ adr.port = PORT_SERVER;
+ //adr.port = BigShort(PORT_SERVER);
+ Netchan.OutOfBandPrint(NS_CLIENT, adr, "info " + PROTOCOL_VERSION);
+ }
+
+ // we use no IPX
+ noipx = Cvar.Get("noipx", "1", CVAR_NOSET);
+ if (noipx.value == 0.0f) {
+ adr.type = NA_BROADCAST_IPX;
+ //adr.port = BigShort(PORT_SERVER);
+ adr.port = PORT_SERVER;
+ Netchan.OutOfBandPrint(NS_CLIENT, adr, "info " + PROTOCOL_VERSION);
+ }
+
+ // send a packet to each address book entry
+ for (i = 0; i < 16; i++) {
+ //Com_sprintf (name, sizeof(name), "adr%i", i);
+ name = "adr" + i;
+ adrstring = Cvar.VariableString(name);
+ if (adrstring == null || adrstring.length() == 0)
+ continue;
+
+ Com.Printf("pinging " + adrstring + "...\n");
+ if (!NET.StringToAdr(adrstring, adr)) {
+ Com.Printf("Bad address: " + adrstring + "\n");
+ continue;
+ }
+ if (adr.port == 0)
+ //adr.port = BigShort(PORT_SERVER);
+ adr.port = PORT_SERVER;
+ Netchan.OutOfBandPrint(NS_CLIENT, adr, "info " + PROTOCOL_VERSION);
+ }
+ }
+ };
+
+
+ /*
+ =================
+ CL_Skins_f
+
+ Load or download any custom player skins and models
+ =================
+ */
+ static xcommand_t Skins_f = new xcommand_t() {
+ public void execute() {
+ int i;
+
+ for (i = 0; i < MAX_CLIENTS; i++) {
+ if (cl.configstrings[CS_PLAYERSKINS + i] == null)
+ continue;
+ Com.Printf("client " + i + ": " + cl.configstrings[CS_PLAYERSKINS + i] + "\n");
+ SCR.UpdateScreen();
+ Sys.SendKeyEvents(); // pump message loop
+ CL.ParseClientinfo(i);
+ }
+ }
+ };
+
+ /*
+ =================
+ CL_ConnectionlessPacket
+
+ Responses to broadcasts, etc
+ =================
+ */
+ static void ConnectionlessPacket() {
+ String s;
+ String c;
+
+ MSG.BeginReading(net_message);
+ MSG.ReadLong(net_message); // skip the -1
+
+ s = MSG.ReadStringLine(net_message);
+
+ Cmd.TokenizeString(s.toCharArray(), false);
+
+ c = Cmd.Argv(0);
+
+ Com.Printf(NET.AdrToString(net_from) + ": " + c + " \n");
+
+ // server connection
+ if (c.equals("client_connect")) {
+ if (cls.state == ca_connected) {
+ Com.Printf("Dup connect received. Ignored.\n");
+ return;
+ }
+ Netchan.Setup(NS_CLIENT, cls.netchan, net_from, cls.quakePort);
+ MSG.WriteChar(cls.netchan.message, clc_stringcmd);
+ MSG.WriteString(cls.netchan.message, "new");
+ cls.state = ca_connected;
+ return;
+ }
+
+ // server responding to a status broadcast
+ if (c.equals("info")) {
+ CL.ParseStatusMessage();
+ return;
+ }
+
+ // remote command from gui front end
+ if (c.equals ("cmd")) {
+ if (!NET.IsLocalAddress(net_from)) {
+ Com.Printf("Command packet from remote host. Ignored.\n");
+ return;
+ }
+ s = MSG.ReadString(net_message);
+ Cbuf.AddText(s);
+ Cbuf.AddText("\n");
+ return;
+ }
+ // print command from somewhere
+ if (c.equals("print")) {
+ s = MSG.ReadString(net_message);
+ Com.Printf(s);
+ return;
+ }
+
+ // ping from somewhere
+ if (c.equals("ping")) {
+ Netchan.OutOfBandPrint(NS_CLIENT, net_from, "ack");
+ return;
+ }
+
+ // challenge from the server we are connecting to
+ if (c.equals("challenge")) {
+ cls.challenge = Integer.parseInt(Cmd.Argv(1));
+ CL.SendConnectPacket();
+ return;
+ }
+
+ // echo request from server
+ if (c.equals("echo")) {
+ Netchan.OutOfBandPrint(NS_CLIENT, net_from, Cmd.Argv(1));
+ return;
+ }
+
+ Com.Printf("Unknown command.\n");
+ }
+
+ /*
+ =================
+ CL_DumpPackets
+
+ A vain attempt to help bad TCP stacks that cause problems
+ when they overflow
+ =================
+ */
+ static void DumpPackets() {
+ while (NET.GetPacket(NS_CLIENT, net_from, net_message)) {
+ Com.Printf("dumping a packet\n");
+ }
+ }
+
+ /*
+ =================
+ CL_ReadPackets
+ =================
+ */
+ static void ReadPackets() {
+ while (NET.GetPacket(NS_CLIENT, net_from, net_message)) {
+
+ //
+ // remote command packet
+ //
+ if (net_message.data[0] == -1 && net_message.data[1] == -1
+ && net_message.data[2] == -1 && net_message.data[3] == -1) {
+ // if (*(int *)net_message.data == -1)
+ CL.ConnectionlessPacket();
+ continue;
+ }
+
+ if (cls.state == ca_disconnected || cls.state == ca_connecting)
+ continue; // dump it if not connected
+
+ if (net_message.cursize < 8) {
+ Com.Printf(NET.AdrToString(net_from) + ": Runt packet\n");
+ continue;
+ }
+
+ //
+ // packet from server
+ //
+ if (!NET.CompareAdr(net_from, cls.netchan.remote_address)) {
+ Com.DPrintf(NET.AdrToString(net_from) + ":sequenced packet without connection\n");
+ continue;
+ }
+ if (!Netchan.Process(cls.netchan, net_message))
+ continue; // wasn't accepted for some reason
+ ParseServerMessage();
+ }
+
+ //
+ // check timeout
+ //
+ if (cls.state >= ca_connected && cls.realtime - cls.netchan.last_received > cl_timeout.value * 1000) {
+ if (++cl.timeoutcount > 5) // timeoutcount saves debugger
+ {
+ Com.Printf("\nServer connection timed out.\n");
+ CL.Disconnect();
+ return;
+ }
+ }
+ else
+ cl.timeoutcount = 0;
+ }
+
+ // =============================================================================
+
+ /*
+ ==============
+ CL_FixUpGender_f
+ ==============
+ */
+ static void FixUpGender() {
+
+ String sk;
+
+ if (gender_auto.value != 0.0f) {
+
+ if (gender.modified) {
+ // was set directly, don't override the user
+ gender.modified = false;
+ return;
+ }
+
+ sk = skin.string;
+ if (sk.startsWith("male") || sk.startsWith("cyborg"))
+ Cvar.Set("gender", "male");
+ else if (sk.startsWith("female") || sk.startsWith("crackhor"))
+ Cvar.Set("gender", "female");
+ else
+ Cvar.Set("gender", "none");
+ gender.modified = false;
+ }
+ }
+
+ /*
+ ==============
+ CL_Userinfo_f
+ ==============
+ */
+ static xcommand_t Userinfo_f = new xcommand_t() {
+ public void execute() {
+ Com.Printf("User info settings:\n");
+ Info.Print(Cvar.Userinfo());
+ }
+ };
+
+ /*
+ =================
+ CL_Snd_Restart_f
+
+ Restart the sound subsystem so it can pick up
+ new parameters and flush all sounds
+ =================
+ */
+ static xcommand_t Snd_Restart_f = new xcommand_t() {
+ public void execute() {
+ S.Shutdown();
+ S.Init();
+ CL.RegisterSounds();
+ }
+ };
+
+ static int precache_check; // for autodownload of precache items
+ static int precache_spawncount;
+ static int precache_tex;
+ static int precache_model_skin;
+
+ static byte precache_model[]; // used for skin checking in alias models
+
+ public static final int PLAYER_MULT = 5;
+
+ // ENV_CNT is map load, ENV_CNT+1 is first env map
+ public static final int ENV_CNT = (CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT);
+ public static final int TEXTURE_CNT = (ENV_CNT + 13);
+
+ static String env_suf[] = { "rt", "bk", "lf", "ft", "up", "dn" };
+
+ public static void RequestNextDownload() {
+ int map_checksum = 0; // for detecting cheater maps
+ //char fn[MAX_OSPATH];
+ String fn;
+
+ qfiles.dmdl_t pheader;
+
+ if (cls.state != ca_connected)
+ return;
+
+ if (SV_MAIN.allow_download.value == 0 && precache_check < ENV_CNT)
+ precache_check = ENV_CNT;
+
+ // ZOID
+ if (precache_check == CS_MODELS) { // confirm map
+ precache_check = CS_MODELS + 2; // 0 isn't used
+ if (SV_MAIN.allow_download_maps.value != 0)
+ if (!CheckOrDownloadFile(cl.configstrings[CS_MODELS + 1]))
+ return; // started a download
+ }
+ if (precache_check >= CS_MODELS && precache_check < CS_MODELS + MAX_MODELS) {
+ if (SV_MAIN.allow_download_models.value != 0) {
+ while (precache_check < CS_MODELS + MAX_MODELS && cl.configstrings[precache_check].length() > 0) {
+ if (cl.configstrings[precache_check].charAt(0) == '*' || cl.configstrings[precache_check].charAt(0) == '#') {
+ precache_check++;
+ continue;
+ }
+ if (precache_model_skin == 0) {
+ if (!CheckOrDownloadFile(cl.configstrings[precache_check])) {
+ precache_model_skin = 1;
+ return; // started a download
+ }
+ precache_model_skin = 1;
+ }
+
+ // checking for skins in the model
+ if (precache_model == null) {
+
+ precache_model = FS.LoadFile(cl.configstrings[precache_check]);
+ if (precache_model == null) {
+ precache_model_skin = 0;
+ precache_check++;
+ continue; // couldn't load it
+ }
+ ByteBuffer bb = ByteBuffer.wrap(precache_model);
+ int header = Globals.endian.LittleLong(bb.getInt());
+
+ if (header != qfiles.IDALIASHEADER) {
+ // not an alias model
+ FS.FreeFile(precache_model);
+ precache_model = null;
+ precache_model_skin = 0;
+ precache_check++;
+ continue;
+ }
+ pheader = new qfiles.dmdl_t(ByteBuffer.wrap(precache_model));
+ if (Globals.endian.LittleLong(pheader.version) != ALIAS_VERSION) {
+ precache_check++;
+ precache_model_skin = 0;
+ continue; // couldn't load it
+ }
+ }
+
+ pheader = new qfiles.dmdl_t(ByteBuffer.wrap(precache_model));
+
+ int num_skins = Globals.endian.LittleLong(pheader.num_skins);
+
+ while (precache_model_skin - 1 < num_skins) {
+ Com.Printf("critical code section because of endian mess!");
+
+ String name =
+ new String(
+ precache_model,
+ Globals.endian.LittleLong(pheader.ofs_skins) + (precache_model_skin - 1) * MAX_SKINNAME,
+ MAX_SKINNAME * num_skins);
+
+ if (!CheckOrDownloadFile(name)) {
+ precache_model_skin++;
+ return; // started a download
+ }
+ precache_model_skin++;
+ }
+ if (precache_model != null) {
+ FS.FreeFile(precache_model);
+ precache_model = null;
+ }
+ precache_model_skin = 0;
+ precache_check++;
+ }
+ }
+ precache_check = CS_SOUNDS;
+ }
+ if (precache_check >= CS_SOUNDS && precache_check < CS_SOUNDS + MAX_SOUNDS) {
+ if (SV_MAIN.allow_download_sounds.value != 0) {
+ if (precache_check == CS_SOUNDS)
+ precache_check++; // zero is blank
+ while (precache_check < CS_SOUNDS + MAX_SOUNDS && cl.configstrings[precache_check].length() > 0) {
+ if (cl.configstrings[precache_check].charAt(0) == '*') {
+ precache_check++;
+ continue;
+ }
+ fn = "sound/" + cl.configstrings[precache_check++];
+ if (!CheckOrDownloadFile(fn))
+ return; // started a download
+ }
+ }
+ precache_check = CS_IMAGES;
+ }
+ if (precache_check >= CS_IMAGES && precache_check < CS_IMAGES + MAX_IMAGES) {
+ if (precache_check == CS_IMAGES)
+ precache_check++; // zero is blank
+
+ while (precache_check < CS_IMAGES + MAX_IMAGES && cl.configstrings[precache_check].length() > 0) {
+ fn = "pics/" + cl.configstrings[precache_check++] + ".pcx";
+ if (!CheckOrDownloadFile(fn))
+ return; // started a download
+ }
+ precache_check = CS_PLAYERSKINS;
+ }
+ // skins are special, since a player has three things to download:
+ // model, weapon model and skin
+ // so precache_check is now *3
+ if (precache_check >= CS_PLAYERSKINS && precache_check < CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT) {
+ if (SV_MAIN.allow_download_players.value != 0) {
+ while (precache_check < CS_PLAYERSKINS + MAX_CLIENTS * PLAYER_MULT) {
+
+ int i, n;
+ //char model[MAX_QPATH], skin[MAX_QPATH], * p;
+ String model, skin, p;
+
+ i = (precache_check - CS_PLAYERSKINS) / PLAYER_MULT;
+ n = (precache_check - CS_PLAYERSKINS) % PLAYER_MULT;
+
+ if (cl.configstrings[CS_PLAYERSKINS + i].length() == 0) {
+ precache_check = CS_PLAYERSKINS + (i + 1) * PLAYER_MULT;
+ continue;
+ }
+
+ int pos = cl.configstrings[CS_PLAYERSKINS + i].indexOf('\\');
+ if (pos != -1)
+ pos++;
+ else
+ pos = 0;
+
+ model = cl.configstrings[CS_PLAYERSKINS + i].substring(pos);
+
+ pos = model.indexOf('/');
+
+ if (pos == -1)
+ pos = model.indexOf('\\');
+
+ if (pos != -1) {
+ skin = model.substring(pos + 1);
+ }
+ else
+ skin = "";
+
+ switch (n) {
+ case 0 : // model
+ fn = "players/" + model + "/tris.md2";
+ if (!CheckOrDownloadFile(fn)) {
+ precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 1;
+ return; // started a download
+ }
+ n++;
+ /*FALL THROUGH*/
+
+ case 1 : // weapon model
+ fn = "players/" + model + "/weapon.md2";
+ if (!CheckOrDownloadFile(fn)) {
+ precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 2;
+ return; // started a download
+ }
+ n++;
+ /*FALL THROUGH*/
+
+ case 2 : // weapon skin
+ fn = "players/" + model + "/weapon.pcx";
+ if (!CheckOrDownloadFile(fn)) {
+ precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 3;
+ return; // started a download
+ }
+ n++;
+ /*FALL THROUGH*/
+
+ case 3 : // skin
+ fn = "players/" + model + "/" + skin + ".pcx";
+ if (!CheckOrDownloadFile(fn)) {
+ precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 4;
+ return; // started a download
+ }
+ n++;
+ /*FALL THROUGH*/
+
+ case 4 : // skin_i
+ fn = "players/" + model + "/" + skin + "_i.pcx";
+ if (!CheckOrDownloadFile(fn)) {
+ precache_check = CS_PLAYERSKINS + i * PLAYER_MULT + 5;
+ return; // started a download
+ }
+ // move on to next model
+ precache_check = CS_PLAYERSKINS + (i + 1) * PLAYER_MULT;
+ }
+ }
+ }
+ // precache phase completed
+ precache_check = ENV_CNT;
+ }
+
+ if (precache_check == ENV_CNT) {
+ precache_check = ENV_CNT + 1;
+
+ CM.intwrap iw = new CM.intwrap(map_checksum);
+
+ CM.CM_LoadMap(cl.configstrings[CS_MODELS + 1], true, iw);
+ map_checksum = iw.i;
+// TODO MD4 check abgeklemmt
+// if ((map_checksum ^ atoi(cl.configstrings[CS_MAPCHECKSUM])) != 0) {
+// Com.Error(
+// ERR_DROP,
+// "Local map version differs from server: " + map_checksum + " != '" + cl.configstrings[CS_MAPCHECKSUM] + "'\n");
+// return;
+// }
+ }
+
+ if (precache_check > ENV_CNT && precache_check < TEXTURE_CNT) {
+ if (SV_MAIN.allow_download.value != 0 && SV_MAIN.allow_download_maps.value != 0) {
+ while (precache_check < TEXTURE_CNT) {
+ int n = precache_check++ -ENV_CNT - 1;
+
+ if ((n & 1) != 0)
+ fn = "env/" + cl.configstrings[CS_SKY] + env_suf[n / 2] + ".pcx";
+ else
+ fn = "env/" + cl.configstrings[CS_SKY] + env_suf[n / 2] + ".tga";
+ if (!CheckOrDownloadFile(fn))
+ return; // started a download
+ }
+ }
+ precache_check = TEXTURE_CNT;
+ }
+
+ if (precache_check == TEXTURE_CNT) {
+ precache_check = TEXTURE_CNT + 1;
+ precache_tex = 0;
+ }
+
+ // confirm existance of textures, download any that don't exist
+ if (precache_check == TEXTURE_CNT + 1) {
+ // from qcommon/cmodel.c
+ // extern int numtexinfo;
+ // extern mapsurface_t map_surfaces[];
+
+ if (SV_MAIN.allow_download.value != 0 && SV_MAIN.allow_download_maps.value != 0) {
+ while (precache_tex < CM.numtexinfo) {
+ //char fn[MAX_OSPATH];
+
+ fn = "textures/" + CM.map_surfaces[precache_tex++].rname + ".wal";
+ if (!CheckOrDownloadFile(fn))
+ return; // started a download
+ }
+ }
+ precache_check = TEXTURE_CNT + 999;
+ }
+
+ // ZOID
+ CL.RegisterSounds();
+ PrepRefresh();
+
+ MSG.WriteByte(cls.netchan.message, clc_stringcmd);
+ MSG.WriteString(cls.netchan.message, "begin " + precache_spawncount + "\n");
+ }
+
+ /*
+ =================
+ CL_Precache_f
+
+ The server will send this command right
+ before allowing the client into the server
+ =================
+ */
+ static xcommand_t Precache_f = new xcommand_t() {
+ public void execute() {
+ /* Yet another hack to let old demos work
+ the old precache sequence */
+
+ if (Cmd.Argc() < 2) {
+
+ CM.intwrap iw = new CM.intwrap(0); // for detecting cheater maps
+
+ CM.CM_LoadMap(cl.configstrings[CS_MODELS + 1], true, iw);
+ int mapchecksum = iw.i ;
+ CL.RegisterSounds();
+ CL.PrepRefresh();
+ return;
+ }
+
+ precache_check = CS_MODELS;
+ precache_spawncount = atoi(Cmd.Argv(1));
+ precache_model = null;
+ precache_model_skin = 0;
+
+ RequestNextDownload();
+ }
+ };
+
+ /*
+ =================
+ CL_InitLocal
+ =================
+ */
+ public static void InitLocal() {
+ cls.state = Defines.ca_disconnected;
+ cls.realtime = Sys.Milliseconds();
+
+ InitInput();
+
+ adr0 = Cvar.Get("adr0", "", CVAR_ARCHIVE);
+ adr1 = Cvar.Get("adr0", "", CVAR_ARCHIVE);
+ adr2 = Cvar.Get("adr0", "", CVAR_ARCHIVE);
+ adr3 = Cvar.Get("adr0", "", CVAR_ARCHIVE);
+ adr4 = Cvar.Get("adr0", "", CVAR_ARCHIVE);
+ adr5 = Cvar.Get("adr0", "", CVAR_ARCHIVE);
+ adr6 = Cvar.Get("adr0", "", CVAR_ARCHIVE);
+ adr7 = Cvar.Get("adr0", "", CVAR_ARCHIVE);
+ adr8 = Cvar.Get("adr0", "", CVAR_ARCHIVE);
+
+ //
+ // register our variables
+ //
+ cl_stereo_separation = Cvar.Get("cl_stereo_separation", "0.4", CVAR_ARCHIVE);
+ cl_stereo = Cvar.Get("cl_stereo", "0", 0);
+
+ cl_add_blend = Cvar.Get("cl_blend", "1", 0);
+ cl_add_lights = Cvar.Get("cl_lights", "1", 0);
+ cl_add_particles = Cvar.Get("cl_particles", "1", 0);
+ cl_add_entities = Cvar.Get("cl_entities", "1", 0);
+ cl_gun = Cvar.Get("cl_gun", "1", 0);
+ cl_footsteps = Cvar.Get("cl_footsteps", "1", 0);
+ cl_noskins = Cvar.Get("cl_noskins", "0", 0);
+ cl_autoskins = Cvar.Get("cl_autoskins", "0", 0);
+ cl_predict = Cvar.Get("cl_predict", "1", 0);
+
+ cl_maxfps = Cvar.Get("cl_maxfps", "90", 0);
+
+ cl_upspeed = Cvar.Get("cl_upspeed", "200", 0);
+ cl_forwardspeed = Cvar.Get("cl_forwardspeed", "200", 0);
+ cl_sidespeed = Cvar.Get("cl_sidespeed", "200", 0);
+ cl_yawspeed = Cvar.Get("cl_yawspeed", "140", 0);
+ cl_pitchspeed = Cvar.Get("cl_pitchspeed", "150", 0);
+ cl_anglespeedkey = Cvar.Get("cl_anglespeedkey", "1.5", 0);
+
+ cl_run = Cvar.Get("cl_run", "0", CVAR_ARCHIVE);
+ freelook = Cvar.Get("freelook", "0", CVAR_ARCHIVE);
+ lookspring = Cvar.Get("lookspring", "0", CVAR_ARCHIVE);
+ lookstrafe = Cvar.Get("lookstrafe", "0", CVAR_ARCHIVE);
+ sensitivity = Cvar.Get("sensitivity", "3", CVAR_ARCHIVE);
+
+ m_pitch = Cvar.Get("m_pitch", "0.022", CVAR_ARCHIVE);
+ m_yaw = Cvar.Get("m_yaw", "0.022", 0);
+ m_forward = Cvar.Get("m_forward", "1", 0);
+ m_side = Cvar.Get("m_side", "1", 0);
+
+ cl_shownet = Cvar.Get("cl_shownet", "0", 0);
+ cl_showmiss = Cvar.Get("cl_showmiss", "0", 0);
+ cl_showclamp = Cvar.Get("showclamp", "0", 0);
+ cl_timeout = Cvar.Get("cl_timeout", "120", 0);
+ cl_paused = Cvar.Get("paused", "0", 0);
+ cl_timedemo = Cvar.Get("timedemo", "0", 0);
+
+ rcon_client_password = Cvar.Get("rcon_password", "", 0);
+ rcon_address = Cvar.Get("rcon_address", "", 0);
+
+ cl_lightlevel = Cvar.Get("r_lightlevel", "0", 0);
+
+ //
+ // userinfo
+ //
+ info_password = Cvar.Get("password", "", CVAR_USERINFO);
+ info_spectator = Cvar.Get("spectator", "0", CVAR_USERINFO);
+ name = Cvar.Get("name", "unnamed", CVAR_USERINFO | CVAR_ARCHIVE);
+ skin = Cvar.Get("skin", "male/grunt", CVAR_USERINFO | CVAR_ARCHIVE);
+ rate = Cvar.Get("rate", "25000", CVAR_USERINFO | CVAR_ARCHIVE); // FIXME
+ msg = Cvar.Get("msg", "1", CVAR_USERINFO | CVAR_ARCHIVE);
+ hand = Cvar.Get("hand", "0", CVAR_USERINFO | CVAR_ARCHIVE);
+ fov = Cvar.Get("fov", "90", CVAR_USERINFO | CVAR_ARCHIVE);
+ gender = Cvar.Get("gender", "male", CVAR_USERINFO | CVAR_ARCHIVE);
+ gender_auto = Cvar.Get("gender_auto", "1", CVAR_ARCHIVE);
+ gender.modified = false; // clear this so we know when user sets it manually
+
+ cl_vwep = Cvar.Get("cl_vwep", "1", CVAR_ARCHIVE);
+
+ //
+ // register our commands
+ //
+ Cmd.AddCommand("cmd", ForwardToServer_f);
+ Cmd.AddCommand("pause", Pause_f);
+ Cmd.AddCommand("pingservers", PingServers_f);
+ Cmd.AddCommand("skins", Skins_f);
+
+ Cmd.AddCommand("userinfo", Userinfo_f);
+ Cmd.AddCommand("snd_restart", Snd_Restart_f);
+
+ Cmd.AddCommand("changing", Changing_f);
+ Cmd.AddCommand("disconnect", Disconnect_f);
+ Cmd.AddCommand("record", Record_f);
+ Cmd.AddCommand("stop", Stop_f);
+
+ Cmd.AddCommand("quit", Quit_f);
+
+ Cmd.AddCommand("connect", Connect_f);
+ Cmd.AddCommand("reconnect", Reconnect_f);
+
+ Cmd.AddCommand("rcon", Rcon_f);
+
+ Cmd.AddCommand("precache", Precache_f);
+
+ Cmd.AddCommand("download", Download_f);
+
+ //
+ // forward to server commands
+ //
+ // the only thing this does is allow command completion
+ // to work -- all unknown commands are automatically
+ // forwarded to the server
+ Cmd.AddCommand("wave", null);
+ Cmd.AddCommand("inven", null);
+ Cmd.AddCommand("kill", null);
+ Cmd.AddCommand("use", null);
+ Cmd.AddCommand("drop", null);
+ Cmd.AddCommand("say", null);
+ Cmd.AddCommand("say_team", null);
+ Cmd.AddCommand("info", null);
+ Cmd.AddCommand("prog", null);
+ Cmd.AddCommand("give", null);
+ Cmd.AddCommand("god", null);
+ Cmd.AddCommand("notarget", null);
+ Cmd.AddCommand("noclip", null);
+ Cmd.AddCommand("invuse", null);
+ Cmd.AddCommand("invprev", null);
+ Cmd.AddCommand("invnext", null);
+ Cmd.AddCommand("invdrop", null);
+ Cmd.AddCommand("weapnext", null);
+ Cmd.AddCommand("weapprev", null);
+
+ }
+
+ /*
+ ===============
+ CL_WriteConfiguration
+
+ Writes key bindings and archived cvars to config.cfg
+ ===============
+ */
+ static void WriteConfiguration() {
+ RandomAccessFile f;
+ String path;
+
+ if (cls.state == ca_uninitialized)
+ return;
+
+ path = FS.Gamedir() + "/config.cfg";
+ f = fopen(path, "rw");
+ try
+ {
+ f.seek(0);
+ f.setLength(0);
+ }
+ catch (IOException e1)
+ {}
+ if (f == null) {
+ Com.Printf("Couldn't write config.cfg.\n");
+ return;
+ }
+ try {
+ f.writeBytes("// generated by quake, do not modify\n");
+ }
+ catch (IOException e) {}
+ //fprintf (f, "// generated by quake, do not modify\n");
+ Key.WriteBindings(f);
+ fclose(f);
+ Cvar.WriteVariables(path);
+ }
+
+ /*
+ ==================
+ CL_FixCvarCheats
+
+ ==================
+ */
+ public static class cheatvar_t {
+ String name;
+ String value;
+ cvar_t var;
+ }
+
+ public static String cheatvarsinfo[][] = { { "timescale", "1" }, {
+ "timedemo", "0" }, {
+ "r_drawworld", "1" }, {
+ "cl_testlights", "0" }, {
+ "r_fullbright", "0" }, {
+ "r_drawflat", "0" }, {
+ "paused", "0" }, {
+ "fixedtime", "0" }, {
+ "sw_draworder", "0" }, {
+ "gl_lightmap", "0" }, {
+ "gl_saturatelighting", "0" }, {
+ null, null }
+ };
+ public static cheatvar_t cheatvars[];
+
+ static {
+ cheatvars = new cheatvar_t[cheatvarsinfo.length];
+ for (int n = 0; n < cheatvarsinfo.length; n++) {
+ cheatvars[n] = new cheatvar_t();
+ cheatvars[n].name = cheatvarsinfo[n][0];
+ cheatvars[n].value = cheatvarsinfo[n][1];
+ }
+ }
+
+ static int numcheatvars;
+
+ public static void FixCvarCheats() {
+ int i;
+ cheatvar_t var;
+
+ if (0 == strcmp(cl.configstrings[CS_MAXCLIENTS], "1") || 0 == cl.configstrings[CS_MAXCLIENTS].length())
+ return; // single player can cheat
+
+ // find all the cvars if we haven't done it yet
+ if (0 == numcheatvars) {
+ while (cheatvars[numcheatvars].name != null) {
+ cheatvars[numcheatvars].var = Cvar.Get(cheatvars[numcheatvars].name, cheatvars[numcheatvars].value, 0);
+ numcheatvars++;
+ }
+ }
+
+ // make sure they are all set to the proper values
+ for (i = 0; i < numcheatvars; i++) {
+ var = cheatvars[i];
+ if (0 != strcmp(var.var.string, var.value)) {
+ Cvar.Set(var.name, var.value);
+ }
+ }
+ }
+
+ // ============================================================================
+
+ /*
+ ==================
+ CL_SendCommand
+
+ ==================
+ */
+ public static void SendCommand() {
+ // get new key events
+ Sys.SendKeyEvents();
+
+ // allow mice or other external controllers to add commands
+ IN.Commands();
+
+ // process console commands
+ Cbuf.Execute();
+
+ // fix any cheating cvars
+ FixCvarCheats();
+
+ // send intentions now
+ SendCmd();
+
+ // resend a connection request if necessary
+ CheckForResend();
+ }
+
+ /*
+ ==================
+ CL_Frame
+
+ ==================
+ */
+ private static int extratime;
+ private static int lasttimecalled;
+
+ public static void Frame(int msec) {
+
+ extratime += msec;
+
+ if (cl_timedemo.value == 0.0f) {
+ if (cls.state == ca_connected && extratime < 100) {
+ return; // don't flood packets out while connecting
+ }
+ if (extratime < 1000 / cl_maxfps.value) {
+ return; // framerate is too high
+ }
+ }
+
+ // let the mouse activate or deactivate
+ IN.Frame();
+
+ // decide the simulation time
+ cls.frametime = extratime / 1000.0f;
+ cl.time += extratime;
+ cls.realtime = curtime;
+
+ extratime = 0;
+
+ if (cls.frametime > (1.0f / 5))
+ cls.frametime = (1.0f / 5);
+
+ // if in the debugger last frame, don't timeout
+ if (msec > 5000)
+ cls.netchan.last_received = Sys.Milliseconds();
+
+ // fetch results from server
+ CL.ReadPackets();
+
+ // send a new command message to the server
+ SendCommand();
+
+ // predict all unacknowledged movements
+ CL.PredictMovement();
+
+ // allow rendering DLL change
+ VID.CheckChanges();
+ if (!cl.refresh_prepped && cls.state == ca_active) {
+ CL.PrepRefresh();
+ // TODO force GC after level loading
+ System.gc();
+ System.gc();
+ }
+
+ SCR.UpdateScreen();
+
+ // update audio
+ S.Update(cl.refdef.vieworg, cl.v_forward, cl.v_right, cl.v_up);
+
+ // advance local effects for next frame
+ CL.RunDLights();
+ CL.RunLightStyles();
+
+ SCR.RunConsole();
+
+ cls.framecount++;
+ }
+
+ // ============================================================================
+
+ /*
+ ===============
+ CL_Shutdown
+
+ FIXME: this is a callback from Sys_Quit and Com_Error. It would be better
+ to run quit through here before the final handoff to the sys code.
+ ===============
+ */
+ static boolean isdown = false;
+ public static void Shutdown() {
+
+ if (isdown) {
+ System.out.print("recursive shutdown\n");
+ return;
+ }
+ isdown = true;
+
+ WriteConfiguration();
+
+ S.Shutdown();
+ IN.Shutdown();
+ VID.Shutdown();
+ }
+
+ /**
+ * initialize client subsystem
+ */
+ public static void Init() {
+ if (Globals.dedicated.value != 0.0f)
+ return; // nothing running on the client
+
+ // all archived variables will now be loaded
+
+ Console.Init(); //ok
+
+ S.Init(); //empty
+ VID.Init();
+
+ V.Init();
+
+ Globals.net_message.data = Globals.net_message_buffer;
+ Globals.net_message.maxsize = Globals.net_message_buffer.length;
+
+ Menu.Init();
+
+ SCR.Init();
+ //Globals.cls.disable_screen = 1.0f; // don't draw yet
+
+ CL.InitLocal();
+ IN.Init();
+
+ FS.ExecAutoexec();
+ Cbuf.Execute();
+ }
+
+ /**
+ * Called after an ERR_DROP was thrown.
+ */
+ public static void Drop() {
+ if (Globals.cls.state == Defines.ca_uninitialized)
+ return;
+ if (Globals.cls.state == Defines.ca_disconnected)
+ return;
+
+ CL.Disconnect();
+
+ // drop loading plaque unless this is the initial game start
+ if (Globals.cls.disable_servercount != -1)
+ SCR.EndLoadingPlaque(); // get rid of loading plaque
+ }
+
+}
diff --git a/src/jake2/client/CL_ents.java b/src/jake2/client/CL_ents.java
new file mode 100644
index 0000000..135f3fe
--- /dev/null
+++ b/src/jake2/client/CL_ents.java
@@ -0,0 +1,1287 @@
+/*
+ * CL_ents.java
+ * Copyright (C) 2004
+ *
+ * $Id: CL_ents.java,v 1.1 2004-07-07 19:58:35 hzi Exp $
+ */
+/*
+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.
+
+*/
+package jake2.client;
+
+import jake2.game.entity_state_t;
+import jake2.game.player_state_t;
+import jake2.qcommon.*;
+import jake2.render.model_t;
+
+/**
+ * CL_ents
+ */
+// cl_ents.c -- entity parsing and management
+public class CL_ents extends CL_inv {
+
+ // PGM
+ static int vidref_val;
+ // PGM
+
+ /*
+ =========================================================================
+
+ FRAME PARSING
+
+ =========================================================================
+ */
+
+ /*
+ =================
+ CL_ParseEntityBits
+
+ Returns the entity number and the header bits
+ =================
+ */
+ static int bitcounts[] = new int[32]; /// just for protocol profiling
+ public static int ParseEntityBits(CM.intwrap bits) {
+ int b, total;
+ int i;
+ int number;
+
+ total = MSG.ReadByte(net_message);
+ if ((total & U_MOREBITS1) != 0) {
+ b = MSG.ReadByte(net_message);
+ total |= b << 8;
+ }
+ if ((total & U_MOREBITS2) != 0) {
+ b = MSG.ReadByte(net_message);
+ total |= b << 16;
+ }
+ if ((total & U_MOREBITS3) != 0) {
+ b = MSG.ReadByte(net_message);
+ total |= b << 24;
+ }
+
+ // count the bits for net profiling
+ for (i = 0; i < 32; i++)
+ if ((total & (1 << i)) != 0)
+ bitcounts[i]++;
+
+ if ((total & U_NUMBER16) != 0)
+ number = MSG.ReadShort(net_message);
+ else
+ number = MSG.ReadByte(net_message);
+
+ bits.i = total;
+
+ return number;
+ }
+
+ /*
+ ==================
+ CL_ParseDelta
+
+ Can go from either a baseline or a previous packet_entity
+ ==================
+ */
+ public static void ParseDelta(entity_state_t from, entity_state_t to, int number, int bits) {
+ // set everything to the state we are delta'ing from
+ to.set(from);
+
+ VectorCopy(from.origin, to.old_origin);
+ to.number = number;
+
+ if ((bits & U_MODEL) != 0)
+ to.modelindex = MSG.ReadByte(net_message);
+ if ((bits & U_MODEL2) != 0)
+ to.modelindex2 = MSG.ReadByte(net_message);
+ if ((bits & U_MODEL3) != 0)
+ to.modelindex3 = MSG.ReadByte(net_message);
+ if ((bits & U_MODEL4) != 0)
+ to.modelindex4 = MSG.ReadByte(net_message);
+
+ if ((bits & U_FRAME8) != 0)
+ to.frame = MSG.ReadByte(net_message);
+ if ((bits & U_FRAME16) != 0)
+ to.frame = MSG.ReadShort(net_message);
+
+ if ((bits & U_SKIN8) != 0 && (bits & U_SKIN16) != 0) //used for laser colors
+ to.skinnum = MSG.ReadLong(net_message);
+ else if ((bits & U_SKIN8) != 0)
+ to.skinnum = MSG.ReadByte(net_message);
+ else if ((bits & U_SKIN16) != 0)
+ to.skinnum = MSG.ReadShort(net_message);
+
+ if ((bits & (U_EFFECTS8 | U_EFFECTS16)) == (U_EFFECTS8 | U_EFFECTS16))
+ to.effects = MSG.ReadLong(net_message);
+ else if ((bits & U_EFFECTS8) != 0)
+ to.effects = MSG.ReadByte(net_message);
+ else if ((bits & U_EFFECTS16) != 0)
+ to.effects = MSG.ReadShort(net_message);
+
+ if ((bits & (U_RENDERFX8 | U_RENDERFX16)) == (U_RENDERFX8 | U_RENDERFX16))
+ to.renderfx = MSG.ReadLong(net_message);
+ else if ((bits & U_RENDERFX8) != 0)
+ to.renderfx = MSG.ReadByte(net_message);
+ else if ((bits & U_RENDERFX16) != 0)
+ to.renderfx = MSG.ReadShort(net_message);
+
+ if ((bits & U_ORIGIN1) != 0)
+ to.origin[0] = MSG.ReadCoord(net_message);
+ if ((bits & U_ORIGIN2) != 0)
+ to.origin[1] = MSG.ReadCoord(net_message);
+ if ((bits & U_ORIGIN3) != 0)
+ to.origin[2] = MSG.ReadCoord(net_message);
+
+ if ((bits & U_ANGLE1) != 0)
+ to.angles[0] = MSG.ReadAngle(net_message);
+ if ((bits & U_ANGLE2) != 0)
+ to.angles[1] = MSG.ReadAngle(net_message);
+ if ((bits & U_ANGLE3) != 0)
+ to.angles[2] = MSG.ReadAngle(net_message);
+
+ if ((bits & U_OLDORIGIN) != 0)
+ MSG.ReadPos(net_message, to.old_origin);
+
+ if ((bits & U_SOUND) != 0)
+ to.sound = MSG.ReadByte(net_message);
+
+ if ((bits & U_EVENT) != 0)
+ to.event = MSG.ReadByte(net_message);
+ else
+ to.event = 0;
+
+ if ((bits & U_SOLID) != 0)
+ to.solid = MSG.ReadShort(net_message);
+ }
+
+ /*
+ ==================
+ CL_DeltaEntity
+
+ Parses deltas from the given base and adds the resulting entity
+ to the current frame
+ ==================
+ */
+ public static void DeltaEntity(frame_t frame, int newnum, entity_state_t old, int bits) {
+ centity_t ent;
+ entity_state_t state;
+
+ ent = cl_entities[newnum];
+
+ state = cl_parse_entities[cl.parse_entities & (MAX_PARSE_ENTITIES - 1)];
+ cl.parse_entities++;
+ frame.num_entities++;
+
+ ParseDelta(old, state, newnum, bits);
+
+ // some data changes will force no lerping
+ if (state.modelindex != ent.current.modelindex
+ || state.modelindex2 != ent.current.modelindex2
+ || state.modelindex3 != ent.current.modelindex3
+ || state.modelindex4 != ent.current.modelindex4
+ || Math.abs(state.origin[0] - ent.current.origin[0]) > 512
+ || Math.abs(state.origin[1] - ent.current.origin[1]) > 512
+ || Math.abs(state.origin[2] - ent.current.origin[2]) > 512
+ || state.event == EV_PLAYER_TELEPORT
+ || state.event == EV_OTHER_TELEPORT) {
+ ent.serverframe = -99;
+ }
+
+ if (ent.serverframe != cl.frame.serverframe - 1) { // wasn't in last update, so initialize some things
+ ent.trailcount = 1024; // for diminishing rocket / grenade trails
+ // duplicate the current state so lerping doesn't hurt anything
+ ent.prev.set(state);
+ if (state.event == EV_OTHER_TELEPORT) {
+ VectorCopy(state.origin, ent.prev.origin);
+ VectorCopy(state.origin, ent.lerp_origin);
+ }
+ else {
+ VectorCopy(state.old_origin, ent.prev.origin);
+ VectorCopy(state.old_origin, ent.lerp_origin);
+ }
+ }
+ else { // shuffle the last state to previous
+ // Copy !
+ ent.prev.set(ent.current);
+ }
+
+ ent.serverframe = cl.frame.serverframe;
+ // Copy !
+ ent.current.set(state);
+ }
+
+ /*
+ ==================
+ CL_ParsePacketEntities
+
+ An svc_packetentities has just been parsed, deal with the
+ rest of the data stream.
+ ==================
+ */
+ public static void ParsePacketEntities(frame_t oldframe, frame_t newframe) {
+ int newnum;
+ int bits=0;
+
+ entity_state_t oldstate=null;
+ int oldindex, oldnum;
+
+ newframe.parse_entities = cl.parse_entities;
+ newframe.num_entities = 0;
+
+ // delta from the entities present in oldframe
+ oldindex = 0;
+ if (oldframe == null)
+ oldnum = 99999;
+ else {
+ if (oldindex >= oldframe.num_entities)
+ oldnum = 99999;
+ else {
+ oldstate = cl_parse_entities[(oldframe.parse_entities + oldindex) & (MAX_PARSE_ENTITIES - 1)];
+ oldnum = oldstate.number;
+ }
+ }
+
+ while (true) {
+ CM.intwrap iw = new CM.intwrap(bits);
+ newnum = ParseEntityBits(iw);
+ bits = iw.i;
+
+ if (newnum >= MAX_EDICTS)
+ Com.Error(ERR_DROP, "CL_ParsePacketEntities: bad number:" + newnum);
+
+ if (net_message.readcount > net_message.cursize)
+ Com.Error(ERR_DROP, "CL_ParsePacketEntities: end of message");
+
+ if (0 == newnum)
+ break;
+
+ while (oldnum < newnum) { // one or more entities from the old packet are unchanged
+ if (cl_shownet.value == 3)
+ Com.Printf(" unchanged: " + oldnum + "\n");
+ DeltaEntity(newframe, oldnum, oldstate, 0);
+
+ oldindex++;
+
+ if (oldindex >= oldframe.num_entities)
+ oldnum = 99999;
+ else {
+ oldstate = cl_parse_entities[(oldframe.parse_entities + oldindex) & (MAX_PARSE_ENTITIES - 1)];
+ oldnum = oldstate.number;
+ }
+ }
+
+ if ((bits & U_REMOVE) != 0) { // the entity present in oldframe is not in the current frame
+ if (cl_shownet.value == 3)
+ Com.Printf(" remove: " + newnum + "\n");
+ if (oldnum != newnum)
+ Com.Printf("U_REMOVE: oldnum != newnum\n");
+
+ oldindex++;
+
+ if (oldindex >= oldframe.num_entities)
+ oldnum = 99999;
+ else {
+ oldstate = cl_parse_entities[(oldframe.parse_entities + oldindex) & (MAX_PARSE_ENTITIES - 1)];
+ oldnum = oldstate.number;
+ }
+ continue;
+ }
+
+ if (oldnum == newnum) { // delta from previous state
+ if (cl_shownet.value == 3)
+ Com.Printf(" delta: " + newnum + "\n");
+ DeltaEntity(newframe, newnum, oldstate, bits);
+
+ oldindex++;
+
+ if (oldindex >= oldframe.num_entities)
+ oldnum = 99999;
+ else {
+ oldstate = cl_parse_entities[(oldframe.parse_entities + oldindex) & (MAX_PARSE_ENTITIES - 1)];
+ oldnum = oldstate.number;
+ }
+ continue;
+ }
+
+ if (oldnum > newnum) { // delta from baseline
+ if (cl_shownet.value == 3)
+ Com.Printf(" baseline: " + newnum + "\n");
+ DeltaEntity(newframe, newnum, cl_entities[newnum].baseline, bits);
+ continue;
+ }
+
+ }
+
+ // any remaining entities in the old frame are copied over
+ while (oldnum != 99999) { // one or more entities from the old packet are unchanged
+ if (cl_shownet.value == 3)
+ Com.Printf(" unchanged: " + oldnum + "\n");
+ DeltaEntity(newframe, oldnum, oldstate, 0);
+
+ oldindex++;
+
+ if (oldindex >= oldframe.num_entities)
+ oldnum = 99999;
+ else {
+ oldstate = cl_parse_entities[(oldframe.parse_entities + oldindex) & (MAX_PARSE_ENTITIES - 1)];
+ oldnum = oldstate.number;
+ }
+ }
+ }
+
+ /*
+ ===================
+ CL_ParsePlayerstate
+ ===================
+ */
+ public static void ParsePlayerstate(frame_t oldframe, frame_t newframe) {
+ int flags;
+ player_state_t state;
+ int i;
+ int statbits;
+
+ state = newframe.playerstate;
+
+ // clear to old value before delta parsing
+ if (oldframe != null)
+ state.set(oldframe.playerstate);
+ else
+ //memset (state, 0, sizeof(*state));
+ state.clear();
+
+ flags = MSG.ReadShort(net_message);
+
+ //
+ // parse the pmove_state_t
+ //
+ if ((flags & PS_M_TYPE) != 0)
+ state.pmove.pm_type = MSG.ReadByte(net_message);
+
+ if ((flags & PS_M_ORIGIN) != 0) {
+ state.pmove.origin[0] = MSG.ReadShort(net_message);
+ state.pmove.origin[1] = MSG.ReadShort(net_message);
+ state.pmove.origin[2] = MSG.ReadShort(net_message);
+ }
+
+ if ((flags & PS_M_VELOCITY) != 0) {
+ state.pmove.velocity[0] = MSG.ReadShort(net_message);
+ state.pmove.velocity[1] = MSG.ReadShort(net_message);
+ state.pmove.velocity[2] = MSG.ReadShort(net_message);
+ }
+
+ if ((flags & PS_M_TIME) != 0)
+ {
+ state.pmove.pm_time = (byte) MSG.ReadByte(net_message);
+ }
+
+ if ((flags & PS_M_FLAGS) != 0)
+ state.pmove.pm_flags = (byte) MSG.ReadByte(net_message);
+
+ if ((flags & PS_M_GRAVITY) != 0)
+ state.pmove.gravity = MSG.ReadShort(net_message);
+
+ if ((flags & PS_M_DELTA_ANGLES) != 0) {
+ state.pmove.delta_angles[0] = MSG.ReadShort(net_message);
+ state.pmove.delta_angles[1] = MSG.ReadShort(net_message);
+ state.pmove.delta_angles[2] = MSG.ReadShort(net_message);
+ }
+
+ if (cl.attractloop)
+ state.pmove.pm_type = PM_FREEZE; // demo playback
+
+ //
+ // parse the rest of the player_state_t
+ //
+ if ((flags & PS_VIEWOFFSET) != 0) {
+ state.viewoffset[0] = MSG.ReadChar(net_message) * 0.25f;
+ state.viewoffset[1] = MSG.ReadChar(net_message) * 0.25f;
+ state.viewoffset[2] = MSG.ReadChar(net_message) * 0.25f;
+ }
+
+ if ((flags & PS_VIEWANGLES) != 0) {
+ state.viewangles[0] = MSG.ReadAngle16(net_message);
+ state.viewangles[1] = MSG.ReadAngle16(net_message);
+ state.viewangles[2] = MSG.ReadAngle16(net_message);
+ }
+
+ if ((flags & PS_KICKANGLES) != 0) {
+
+ state.kick_angles[0] = MSG.ReadChar(net_message) * 0.25f;
+ state.kick_angles[1] = MSG.ReadChar(net_message) * 0.25f;
+ state.kick_angles[2] = MSG.ReadChar(net_message) * 0.25f;
+
+ }
+
+ if ((flags & PS_WEAPONINDEX) != 0) {
+ state.gunindex = MSG.ReadByte(net_message);
+ }
+
+ if ((flags & PS_WEAPONFRAME) != 0) {
+ state.gunframe = MSG.ReadByte(net_message);
+ state.gunoffset[0] = MSG.ReadChar(net_message) * 0.25f;
+ state.gunoffset[1] = MSG.ReadChar(net_message) * 0.25f;
+ state.gunoffset[2] = MSG.ReadChar(net_message) * 0.25f;
+ state.gunangles[0] = MSG.ReadChar(net_message) * 0.25f;
+ state.gunangles[1] = MSG.ReadChar(net_message) * 0.25f;
+ state.gunangles[2] = MSG.ReadChar(net_message) * 0.25f;
+ }
+
+ if ((flags & PS_BLEND) != 0) {
+ state.blend[0] = MSG.ReadByte(net_message) / 255.0f;
+ state.blend[1] = MSG.ReadByte(net_message) / 255.0f;
+ state.blend[2] = MSG.ReadByte(net_message) / 255.0f;
+ state.blend[3] = MSG.ReadByte(net_message) / 255.0f;
+ }
+
+ if ((flags & PS_FOV) != 0)
+ state.fov = MSG.ReadByte(net_message);
+
+ if ((flags & PS_RDFLAGS) != 0)
+ state.rdflags = MSG.ReadByte(net_message);
+
+ // parse stats
+ statbits = MSG.ReadLong(net_message);
+ for (i = 0; i < MAX_STATS; i++)
+ if ((statbits & (1 << i))!=0)
+ state.stats[i] = MSG.ReadShort(net_message);
+ }
+
+ /*
+ ==================
+ CL_FireEntityEvents
+
+ ==================
+ */
+ public static void FireEntityEvents(frame_t frame) {
+ entity_state_t s1;
+ int pnum, num;
+
+ for (pnum = 0; pnum < frame.num_entities; pnum++) {
+ num = (frame.parse_entities + pnum) & (MAX_PARSE_ENTITIES - 1);
+ s1 = cl_parse_entities[num];
+ if (s1.event!=0)
+ EntityEvent(s1);
+
+ // EF_TELEPORTER acts like an event, but is not cleared each frame
+ if ((s1.effects & EF_TELEPORTER)!=0)
+ CL_fx.TeleporterParticles(s1);
+ }
+ }
+
+ /*
+ ================
+ CL_ParseFrame
+ ================
+ */
+ public static void ParseFrame() {
+ int cmd;
+ int len;
+ frame_t old;
+
+ //memset( cl.frame, 0, sizeof(cl.frame));
+ cl.frame.reset();
+
+ cl.frame.serverframe = MSG.ReadLong(net_message);
+ cl.frame.deltaframe = MSG.ReadLong(net_message);
+ cl.frame.servertime = cl.frame.serverframe * 100;
+
+ // BIG HACK to let old demos continue to work
+ if (cls.serverProtocol != 26)
+ cl.surpressCount = MSG.ReadByte(net_message);
+
+ if (cl_shownet.value == 3)
+ Com.Printf(" frame:" + cl.frame.serverframe + " delta:" + cl.frame.deltaframe + "\n");
+
+ // If the frame is delta compressed from data that we
+ // no longer have available, we must suck up the rest of
+ // the frame, but not use it, then ask for a non-compressed
+ // message
+ if (cl.frame.deltaframe <= 0) {
+ cl.frame.valid = true; // uncompressed frame
+ old = null;
+ cls.demowaiting = false; // we can start recording now
+ }
+ else {
+ old = cl.frames[cl.frame.deltaframe & UPDATE_MASK];
+ if (!old.valid) { // should never happen
+ Com.Printf("Delta from invalid frame (not supposed to happen!).\n");
+ }
+ if (old.serverframe != cl.frame.deltaframe) { // The frame that the server did the delta from
+ // is too old, so we can't reconstruct it properly.
+ Com.Printf("Delta frame too old.\n");
+ }
+ else if (cl.parse_entities - old.parse_entities > MAX_PARSE_ENTITIES - 128) {
+ Com.Printf("Delta parse_entities too old.\n");
+ }
+ else
+ cl.frame.valid = true; // valid delta parse
+ }
+
+ // clamp time
+ if (cl.time > cl.frame.servertime)
+ cl.time = cl.frame.servertime;
+ else if (cl.time < cl.frame.servertime - 100)
+ cl.time = cl.frame.servertime - 100;
+
+ // read areabits
+ len = MSG.ReadByte(net_message);
+ MSG.ReadData(net_message, cl.frame.areabits, len);
+
+ // read playerinfo
+ cmd = MSG.ReadByte(net_message);
+ CL_parse.SHOWNET(CL_parse.svc_strings[cmd]);
+ if (cmd != svc_playerinfo)
+ Com.Error(ERR_DROP, "CL_ParseFrame: not playerinfo");
+ ParsePlayerstate(old, cl.frame);
+
+ // read packet entities
+ cmd = MSG.ReadByte(net_message);
+ CL_parse.SHOWNET(CL_parse.svc_strings[cmd]);
+ if (cmd != svc_packetentities)
+ Com.Error(ERR_DROP, "CL_ParseFrame: not packetentities");
+
+ ParsePacketEntities(old, cl.frame);
+
+ // save the frame off in the backup array for later delta comparisons
+ cl.frames[cl.frame.serverframe & UPDATE_MASK].set(cl.frame);
+
+ if (cl.frame.valid) {
+ // getting a valid frame message ends the connection process
+ if (cls.state != ca_active) {
+ cls.state = ca_active;
+ cl.force_refdef = true;
+
+ cl.predicted_origin[0] = cl.frame.playerstate.pmove.origin[0] * 0.125f;
+ cl.predicted_origin[1] = cl.frame.playerstate.pmove.origin[1] * 0.125f;
+ cl.predicted_origin[2] = cl.frame.playerstate.pmove.origin[2] * 0.125f;
+
+ VectorCopy(cl.frame.playerstate.viewangles, cl.predicted_angles);
+ if (cls.disable_servercount != cl.servercount && cl.refresh_prepped)
+ SCR.EndLoadingPlaque(); // get rid of loading plaque
+ }
+ cl.sound_prepped = true; // can start mixing ambient sounds
+
+ // fire entity events
+ FireEntityEvents(cl.frame);
+ CL_pred.CheckPredictionError();
+ }
+ }
+
+ /*
+ ==========================================================================
+
+ INTERPOLATE BETWEEN FRAMES TO GET RENDERING PARMS
+
+ ==========================================================================
+ */
+
+ public static model_t S_RegisterSexedModel(entity_state_t ent, String base) {
+ int n;
+ String p;
+ model_t mdl;
+ String model;
+ String buffer;
+
+ // determine what model the client is using
+ model = "";
+
+ n = CS_PLAYERSKINS + ent.number - 1;
+
+ if (cl.configstrings[n].length() >0) {
+
+ int pos = cl.configstrings[n].indexOf('\\');
+ if (pos!=-1) {
+ pos++;
+ model = cl.configstrings[n].substring(pos);
+ pos = model.indexOf('/');
+ if (pos !=-1)
+ model = model.substring(0,pos);
+ }
+ }
+ // if we can't figure it out, they're male
+ if (model.length()==0)
+ model = "male";
+
+ buffer= "players/" + model + "/" + base + 1;
+ mdl = re.RegisterModel(buffer);
+ if (mdl==null) {
+ // not found, try default weapon model
+ buffer = "players/" + model + "/weapon.md2";
+ mdl = re.RegisterModel(buffer);
+ if (mdl==null) {
+ // no, revert to the male model
+ buffer="players/male/" + base + 1;
+ mdl = re.RegisterModel(buffer);
+ if (mdl==null) {
+ // last try, default male weapon.md2
+ buffer = "players/male/weapon.md2";
+ mdl = re.RegisterModel(buffer);
+ }
+ }
+ }
+
+ return mdl;
+ }
+
+ // PMM - used in shell code
+
+ /*
+ ===============
+ CL_AddPacketEntities
+
+ ===============
+ */
+ static int bfg_lightramp[] = { 300, 400, 600, 300, 150, 75 };
+
+ static void AddPacketEntities(frame_t frame) {
+ entity_t ent;
+ entity_state_t s1;
+ float autorotate;
+ int i;
+ int pnum;
+ centity_t cent;
+ int autoanim;
+ clientinfo_t ci;
+ int effects, renderfx;
+
+ // bonus items rotate at a fixed rate
+ autorotate = anglemod(cl.time / 10);
+
+ // brush models can auto animate their frames
+ autoanim = 2 * cl.time / 1000;
+
+ //memset( ent, 0, sizeof(ent));
+ ent = new entity_t();
+
+ for (pnum = 0; pnum < frame.num_entities; pnum++) {
+ s1 = cl_parse_entities[(frame.parse_entities + pnum) & (MAX_PARSE_ENTITIES - 1)];
+
+ cent = cl_entities[s1.number];
+
+ effects = s1.effects;
+ renderfx = s1.renderfx;
+
+ // set frame
+ if ((effects & EF_ANIM01)!=0)
+ ent.frame = autoanim & 1;
+ else if ((effects & EF_ANIM23)!=0)
+ ent.frame = 2 + (autoanim & 1);
+ else if ((effects & EF_ANIM_ALL)!=0)
+ ent.frame = autoanim;
+ else if ((effects & EF_ANIM_ALLFAST)!=0)
+ ent.frame = cl.time / 100;
+ else
+ ent.frame = s1.frame;
+
+ // quad and pent can do different things on client
+ if ((effects & EF_PENT)!=0) {
+ effects &= ~EF_PENT;
+ effects |= EF_COLOR_SHELL;
+ renderfx |= RF_SHELL_RED;
+ }
+
+ if ((effects & EF_QUAD)!=0) {
+ effects &= ~EF_QUAD;
+ effects |= EF_COLOR_SHELL;
+ renderfx |= RF_SHELL_BLUE;
+ }
+ // ======
+ // PMM
+ if ((effects & EF_DOUBLE)!=0) {
+ effects &= ~EF_DOUBLE;
+ effects |= EF_COLOR_SHELL;
+ renderfx |= RF_SHELL_DOUBLE;
+ }
+
+ if ((effects & EF_HALF_DAMAGE) !=0){
+ effects &= ~EF_HALF_DAMAGE;
+ effects |= EF_COLOR_SHELL;
+ renderfx |= RF_SHELL_HALF_DAM;
+ }
+ // pmm
+ // ======
+ ent.oldframe = cent.prev.frame;
+ ent.backlerp = 1.0f - cl.lerpfrac;
+
+ if ((renderfx & (RF_FRAMELERP | RF_BEAM))!=0) { // step origin discretely, because the frames
+ // do the animation properly
+ VectorCopy(cent.current.origin, ent.origin);
+ VectorCopy(cent.current.old_origin, ent.oldorigin);
+ }
+ else { // interpolate origin
+ for (i = 0; i < 3; i++) {
+ ent.origin[i] =
+ ent.oldorigin[i] = cent.prev.origin[i] + cl.lerpfrac * (cent.current.origin[i] - cent.prev.origin[i]);
+ }
+ }
+
+ // create a new entity
+
+ // tweak the color of beams
+ if ((renderfx & RF_BEAM)!=0) { // the four beam colors are encoded in 32 bits of skinnum (hack)
+ ent.alpha = 0.30f;
+ ent.skinnum = (s1.skinnum >> ((rand() % 4) * 8)) & 0xff;
+ ent.model = null;
+ }
+ else {
+ // set skin
+ if (s1.modelindex == 255) { // use custom player skin
+ ent.skinnum = 0;
+ ci = cl.clientinfo[s1.skinnum & 0xff];
+ ent.skin = ci.skin;
+ ent.model = ci.model;
+ if (null==ent.skin || null==ent.model) {
+ ent.skin = cl.baseclientinfo.skin;
+ ent.model = cl.baseclientinfo.model;
+ }
+
+ // ============
+ // PGM
+ if ((renderfx & RF_USE_DISGUISE)!=0) {
+ if (ent.skin.name.startsWith("players/male")) {
+ ent.skin = re.RegisterSkin("players/male/disguise.pcx");
+ ent.model = re.RegisterModel("players/male/tris.md2");
+ }
+ else if (ent.skin.name.startsWith( "players/female")) {
+ ent.skin = re.RegisterSkin("players/female/disguise.pcx");
+ ent.model = re.RegisterModel("players/female/tris.md2");
+ }
+ else if (ent.skin.name.startsWith("players/cyborg")) {
+ ent.skin = re.RegisterSkin("players/cyborg/disguise.pcx");
+ ent.model = re.RegisterModel("players/cyborg/tris.md2");
+ }
+ }
+ // PGM
+ // ============
+ }
+ else {
+ ent.skinnum = s1.skinnum;
+ ent.skin = null;
+ ent.model = cl.model_draw[s1.modelindex];
+ }
+ }
+
+ // only used for black hole model right now, FIXME: do better
+ if (renderfx == RF_TRANSLUCENT)
+ ent.alpha = 0.70f;
+
+ // render effects (fullbright, translucent, etc)
+ if ((effects & EF_COLOR_SHELL)!=0)
+ ent.flags = 0; // renderfx go on color shell entity
+ else
+ ent.flags = renderfx;
+
+ // calculate angles
+ if ((effects & EF_ROTATE)!=0) { // some bonus items auto-rotate
+ ent.angles[0] = 0;
+ ent.angles[1] = autorotate;
+ ent.angles[2] = 0;
+ }
+ // RAFAEL
+ else if ((effects & EF_SPINNINGLIGHTS)!=0) {
+ ent.angles[0] = 0;
+ ent.angles[1] = anglemod(cl.time / 2) + s1.angles[1];
+ ent.angles[2] = 180;
+ {
+ float[] forward={0,0,0};
+ float[] start={0,0,0};
+
+ AngleVectors(ent.angles, forward, null, null);
+ VectorMA(ent.origin, 64, forward, start);
+ V.AddLight(start, 100, 1, 0, 0);
+ }
+ }
+ else { // interpolate angles
+ float a1, a2;
+
+ for (i = 0; i < 3; i++) {
+ a1 = cent.current.angles[i];
+ a2 = cent.prev.angles[i];
+ ent.angles[i] = LerpAngle(a2, a1, cl.lerpfrac);
+ }
+ }
+
+ if (s1.number == cl.playernum + 1) {
+ ent.flags |= RF_VIEWERMODEL; // only draw from mirrors
+ // FIXME: still pass to refresh
+
+ if ((effects & EF_FLAG1)!=0)
+ V.AddLight(ent.origin, 225, 1.0f, 0.1f, 0.1f);
+ else if ((effects & EF_FLAG2)!=0)
+ V.AddLight(ent.origin, 225, 0.1f, 0.1f, 1.0f);
+ else if ((effects & EF_TAGTRAIL)!=0) //PGM
+ V.AddLight(ent.origin, 225, 1.0f, 1.0f, 0.0f); //PGM
+ else if ((effects & EF_TRACKERTRAIL)!=0) //PGM
+ V.AddLight(ent.origin, 225, -1.0f, -1.0f, -1.0f); //PGM
+
+ continue;
+ }
+
+ // if set to invisible, skip
+ if (s1.modelindex==0)
+ continue;
+
+ if ((effects & EF_BFG)!=0) {
+ ent.flags |= RF_TRANSLUCENT;
+ ent.alpha = 0.30f;
+ }
+
+ // RAFAEL
+ if ((effects & EF_PLASMA)!=0) {
+ ent.flags |= RF_TRANSLUCENT;
+ ent.alpha = 0.6f;
+ }
+
+ if ((effects & EF_SPHERETRANS)!=0) {
+ ent.flags |= RF_TRANSLUCENT;
+ // PMM - *sigh* yet more EF overloading
+ if ((effects & EF_TRACKERTRAIL)!=0)
+ ent.alpha = 0.6f;
+ else
+ ent.alpha = 0.3f;
+ }
+ // pmm
+
+ // add to refresh list
+ V.AddEntity( ent);
+
+ // color shells generate a seperate entity for the main model
+ if ((effects & EF_COLOR_SHELL)!=0) {
+ /*
+ PMM - at this point, all of the shells have been handled
+ if we're in the rogue pack, set up the custom mixing, otherwise just
+ keep going
+ if(Developer_searchpath(2) == 2)
+ {
+ all of the solo colors are fine. we need to catch any of the combinations that look bad
+ (double & half) and turn them into the appropriate color, and make double/quad something special
+
+ */
+ if ((renderfx & RF_SHELL_HALF_DAM)!=0) {
+ if (FS.Developer_searchpath(2) == 2) {
+ // ditch the half damage shell if any of red, blue, or double are on
+ if ((renderfx & (RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_DOUBLE))!=0)
+ renderfx &= ~RF_SHELL_HALF_DAM;
+ }
+ }
+
+ if ((renderfx & RF_SHELL_DOUBLE)!=0) {
+ if (FS.Developer_searchpath(2) == 2) {
+ // lose the yellow shell if we have a red, blue, or green shell
+ if ((renderfx & (RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_GREEN))!=0)
+ renderfx &= ~RF_SHELL_DOUBLE;
+ // if we have a red shell, turn it to purple by adding blue
+ if ((renderfx & RF_SHELL_RED)!=0)
+ renderfx |= RF_SHELL_BLUE;
+ // if we have a blue shell (and not a red shell), turn it to cyan by adding green
+ else if ((renderfx & RF_SHELL_BLUE)!=0)
+ // go to green if it's on already, otherwise do cyan (flash green)
+ if ((renderfx & RF_SHELL_GREEN)!=0)
+ renderfx &= ~RF_SHELL_BLUE;
+ else
+ renderfx |= RF_SHELL_GREEN;
+ }
+ }
+ // }
+ // pmm
+ ent.flags = renderfx | RF_TRANSLUCENT;
+ ent.alpha = 0.30f;
+ V.AddEntity( ent);
+ }
+
+ ent.skin = null; // never use a custom skin on others
+ ent.skinnum = 0;
+ ent.flags = 0;
+ ent.alpha = 0;
+
+ // duplicate for linked models
+ if (s1.modelindex2!=0) {
+ if (s1.modelindex2 == 255) { // custom weapon
+ ci = cl.clientinfo[s1.skinnum & 0xff];
+ i = (s1.skinnum >> 8); // 0 is default weapon model
+ if (0==cl_vwep.value || i > MAX_CLIENTWEAPONMODELS - 1)
+ i = 0;
+ ent.model = ci.weaponmodel[i];
+ if (null==ent.model) {
+ if (i != 0)
+ ent.model = ci.weaponmodel[0];
+ if (null==ent.model)
+ ent.model = cl.baseclientinfo.weaponmodel[0];
+ }
+ }
+ else
+ ent.model = cl.model_draw[s1.modelindex2];
+
+ // PMM - check for the defender sphere shell .. make it translucent
+ // replaces the previous version which used the high bit on modelindex2 to determine transparency
+ if (cl.configstrings[CS_MODELS + (s1.modelindex2)].equalsIgnoreCase( "models/items/shell/tris.md2")) {
+ ent.alpha = 0.32f;
+ ent.flags = RF_TRANSLUCENT;
+ }
+ // pmm
+
+ V.AddEntity( ent);
+
+ //PGM - make sure these get reset.
+ ent.flags = 0;
+ ent.alpha = 0;
+ //PGM
+ }
+ if (s1.modelindex3!=0) {
+ ent.model = cl.model_draw[s1.modelindex3];
+ V.AddEntity( ent);
+ }
+ if (s1.modelindex4!=0) {
+ ent.model = cl.model_draw[s1.modelindex4];
+ V.AddEntity( ent);
+ }
+
+ if ((effects & EF_POWERSCREEN)!=0) {
+ ent.model = CL_tent.cl_mod_powerscreen;
+ ent.oldframe = 0;
+ ent.frame = 0;
+ ent.flags |= (RF_TRANSLUCENT | RF_SHELL_GREEN);
+ ent.alpha = 0.30f;
+ V.AddEntity( ent);
+ }
+
+ // add automatic particle trails
+ if ((effects & ~EF_ROTATE)!=0) {
+ if ((effects & EF_ROCKET)!=0) {
+ RocketTrail(cent.lerp_origin, ent.origin, cent);
+ V.AddLight(ent.origin, 200, 1, 1, 0);
+ }
+ // PGM - Do not reorder EF_BLASTER and EF_HYPERBLASTER.
+ // EF_BLASTER | EF_TRACKER is a special case for EF_BLASTER2... Cheese!
+ else if ((effects & EF_BLASTER)!=0) {
+ // CL_BlasterTrail (cent.lerp_origin, ent.origin);
+ // PGM
+ if ((effects & EF_TRACKER)!=0) // lame... problematic?
+ {
+ CL_newfx.BlasterTrail2(cent.lerp_origin, ent.origin);
+ V.AddLight(ent.origin, 200, 0, 1, 0);
+ }
+ else {
+ BlasterTrail(cent.lerp_origin, ent.origin);
+ V.AddLight(ent.origin, 200, 1, 1, 0);
+ }
+ // PGM
+ }
+ else if ((effects & EF_HYPERBLASTER)!=0) {
+ if ((effects & EF_TRACKER)!=0) // PGM overloaded for blaster2.
+ V.AddLight(ent.origin, 200, 0, 1, 0); // PGM
+ else // PGM
+ V.AddLight(ent.origin, 200, 1, 1, 0);
+ }
+ else if ((effects & EF_GIB)!=0) {
+ DiminishingTrail(cent.lerp_origin, ent.origin, cent, effects);
+ }
+ else if ((effects & EF_GRENADE)!=0) {
+ DiminishingTrail(cent.lerp_origin, ent.origin, cent, effects);
+ }
+ else if ((effects & EF_FLIES)!=0) {
+ FlyEffect(cent, ent.origin);
+ }
+ else if ((effects & EF_BFG)!=0) {
+
+
+ if ((effects & EF_ANIM_ALLFAST)!=0) {
+ BfgParticles( ent);
+ i = 200;
+ }
+ else {
+ i = bfg_lightramp[s1.frame];
+ }
+ V.AddLight(ent.origin, i, 0, 1, 0);
+ }
+ // RAFAEL
+ else if ((effects & EF_TRAP)!=0) {
+ ent.origin[2] += 32;
+ TrapParticles( ent);
+ i = (rand() % 100) + 100;
+ V.AddLight(ent.origin, i, 1, 0.8f, 0.1f);
+ }
+ else if ((effects & EF_FLAG1)!=0) {
+ FlagTrail(cent.lerp_origin, ent.origin, 242);
+ V.AddLight(ent.origin, 225, 1, 0.1f, 0.1f);
+ }
+ else if ((effects & EF_FLAG2)!=0) {
+ FlagTrail(cent.lerp_origin, ent.origin, 115);
+ V.AddLight(ent.origin, 225, 0.1f, 0.1f, 1);
+ }
+ // ======
+ // ROGUE
+ else if ((effects & EF_TAGTRAIL)!=0) {
+ CL_newfx.TagTrail(cent.lerp_origin, ent.origin, 220);
+ V.AddLight(ent.origin, 225, 1.0f, 1.0f, 0.0f);
+ }
+ else if ((effects & EF_TRACKERTRAIL)!=0) {
+ if ((effects & EF_TRACKER)!=0) {
+ float intensity;
+
+ intensity = (float) (50 + (500 * (Math.sin(cl.time / 500.0) + 1.0)));
+ // FIXME - check out this effect in rendition
+ if (vidref_val == VIDREF_GL)
+ V.AddLight(ent.origin, intensity, -1.0f, -1.0f, -1.0f);
+ else
+ V.AddLight(ent.origin, -1.0f * intensity, 1.0f, 1.0f, 1.0f);
+ }
+ else {
+ CL_newfx.Tracker_Shell(cent.lerp_origin);
+ V.AddLight(ent.origin, 155, -1.0f, -1.0f, -1.0f);
+ }
+ }
+ else if ((effects & EF_TRACKER)!=0) {
+ CL_newfx.TrackerTrail(cent.lerp_origin, ent.origin, 0);
+ // FIXME - check out this effect in rendition
+ if (vidref_val == VIDREF_GL)
+ V.AddLight(ent.origin, 200, -1, -1, -1);
+ else
+ V.AddLight(ent.origin, -200, 1, 1, 1);
+ }
+ // ROGUE
+ // ======
+ // RAFAEL
+ else if ((effects & EF_GREENGIB)!=0) {
+ DiminishingTrail(cent.lerp_origin, ent.origin, cent, effects);
+ }
+ // RAFAEL
+ else if ((effects & EF_IONRIPPER)!=0) {
+ IonripperTrail(cent.lerp_origin, ent.origin);
+ V.AddLight(ent.origin, 100, 1, 0.5f, 0.5f);
+ }
+ // RAFAEL
+ else if ((effects & EF_BLUEHYPERBLASTER)!=0) {
+ V.AddLight(ent.origin, 200, 0, 0, 1);
+ }
+ // RAFAEL
+ else if ((effects & EF_PLASMA)!=0) {
+ if ((effects & EF_ANIM_ALLFAST)!=0) {
+ BlasterTrail(cent.lerp_origin, ent.origin);
+ }
+ V.AddLight(ent.origin, 130, 1, 0.5f, 0.5f);
+ }
+ }
+
+ VectorCopy(ent.origin, cent.lerp_origin);
+ }
+ }
+
+ /*
+ ==============
+ CL_AddViewWeapon
+ ==============
+ */
+ static void AddViewWeapon(player_state_t ps, player_state_t ops) {
+ entity_t gun; // view model
+ int i;
+
+ // allow the gun to be completely removed
+ if (0==cl_gun.value)
+ return;
+
+ // don't draw gun if in wide angle view
+ if (ps.fov > 90)
+ return;
+
+ //memset( gun, 0, sizeof(gun));
+ gun = new entity_t();
+
+ if (gun_model!=null)
+ gun.model = gun_model; // development tool
+ else
+ gun.model = cl.model_draw[ps.gunindex];
+
+ if (gun.model==null)
+ return;
+
+ // set up gun position
+ for (i = 0; i < 3; i++) {
+ gun.origin[i] = cl.refdef.vieworg[i] + ops.gunoffset[i] + cl.lerpfrac * (ps.gunoffset[i] - ops.gunoffset[i]);
+ gun.angles[i] = cl.refdef.viewangles[i] + LerpAngle(ops.gunangles[i], ps.gunangles[i], cl.lerpfrac);
+ }
+
+ if (gun_frame!=0) {
+ gun.frame = gun_frame; // development tool
+ gun.oldframe = gun_frame; // development tool
+ }
+ else {
+ gun.frame = ps.gunframe;
+ if (gun.frame == 0)
+ gun.oldframe = 0; // just changed weapons, don't lerp from old
+ else
+ gun.oldframe = ops.gunframe;
+ }
+
+ gun.flags = RF_MINLIGHT | RF_DEPTHHACK | RF_WEAPONMODEL;
+ gun.backlerp = 1.0f - cl.lerpfrac;
+ VectorCopy(gun.origin, gun.oldorigin); // don't lerp at all
+ V.AddEntity( gun);
+ }
+
+ /*
+ ===============
+ CL_CalcViewValues
+
+ Sets cl.refdef view values
+ ===============
+ */
+ static void CalcViewValues() {
+ int i;
+ float lerp, backlerp;
+ centity_t ent;
+ frame_t oldframe;
+ player_state_t ps, ops;
+
+ // find the previous frame to interpolate from
+ ps = cl.frame.playerstate;
+
+ i = (cl.frame.serverframe - 1) & UPDATE_MASK;
+ oldframe = cl.frames[i];
+
+ if (oldframe.serverframe != cl.frame.serverframe - 1 || !oldframe.valid)
+ oldframe = cl.frame; // previous frame was dropped or involid
+ ops = oldframe.playerstate;
+
+ // see if the player entity was teleported this frame
+ if (Math.abs(ops.pmove.origin[0] - ps.pmove.origin[0]) > 256 * 8
+ || Math.abs(ops.pmove.origin[1] - ps.pmove.origin[1]) > 256 * 8
+ || Math.abs(ops.pmove.origin[2] - ps.pmove.origin[2]) > 256 * 8)
+ ops = ps; // don't interpolate
+
+ ent = cl_entities[cl.playernum + 1];
+ lerp = cl.lerpfrac;
+
+ // calculate the origin
+ if ((cl_predict.value!=0) && 0==(cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION)) { // use predicted values
+ int delta;
+
+ backlerp = 1.0f - lerp;
+ for (i = 0; i < 3; i++) {
+ cl.refdef.vieworg[i] =
+ cl.predicted_origin[i]
+ + ops.viewoffset[i]
+ + cl.lerpfrac * (ps.viewoffset[i] - ops.viewoffset[i])
+ - backlerp * cl.prediction_error[i];
+ }
+
+ // smooth out stair climbing
+ delta = (int) (cls.realtime - cl.predicted_step_time);
+ if (delta < 100)
+ cl.refdef.vieworg[2] -= cl.predicted_step * (100 - delta) * 0.01;
+ }
+ else { // just use interpolated values
+ for (i = 0; i < 3; i++)
+ cl.refdef.vieworg[i] =
+ ops.pmove.origin[i] * 0.125f
+ + ops.viewoffset[i]
+ + lerp * (ps.pmove.origin[i] * 0.125f + ps.viewoffset[i] - (ops.pmove.origin[i] * 0.125f + ops.viewoffset[i]));
+ }
+
+ // if not running a demo or on a locked frame, add the local angle movement
+ if (cl.frame.playerstate.pmove.pm_type < PM_DEAD) { // use predicted values
+ for (i = 0; i < 3; i++)
+ cl.refdef.viewangles[i] = cl.predicted_angles[i];
+ }
+ else { // just use interpolated values
+ for (i = 0; i < 3; i++)
+ cl.refdef.viewangles[i] = LerpAngle(ops.viewangles[i], ps.viewangles[i], lerp);
+ }
+
+ for (i = 0; i < 3; i++)
+ cl.refdef.viewangles[i] += LerpAngle(ops.kick_angles[i], ps.kick_angles[i], lerp);
+
+ AngleVectors(cl.refdef.viewangles, cl.v_forward, cl.v_right, cl.v_up);
+
+ // interpolate field of view
+ cl.refdef.fov_x = ops.fov + lerp * (ps.fov - ops.fov);
+
+ // don't interpolate blend color
+ for (i = 0; i < 4; i++)
+ cl.refdef.blend[i] = ps.blend[i];
+
+ // add the weapon
+ AddViewWeapon(ps, ops);
+ }
+
+ /*
+ ===============
+ CL_AddEntities
+
+ Emits all entities, particles, and lights to the refresh
+ ===============
+ */
+ static void AddEntities() {
+ if (cls.state != ca_active)
+ return;
+
+ if (cl.time > cl.frame.servertime) {
+ if (cl_showclamp.value!=0)
+ Com.Printf("high clamp " + (cl.time - cl.frame.servertime) + "\n");
+ cl.time = cl.frame.servertime;
+ cl.lerpfrac = 1.0f;
+ }
+ else if (cl.time < cl.frame.servertime - 100) {
+ if (cl_showclamp.value!=0)
+ Com.Printf("low clamp " + (cl.frame.servertime - 100 - cl.time)+"\n");
+ cl.time = cl.frame.servertime - 100;
+ cl.lerpfrac = 0;
+ }
+ else
+ cl.lerpfrac = 1.0f - (cl.frame.servertime - cl.time) * 0.01f;
+
+ if (cl_timedemo.value!=0)
+ cl.lerpfrac = 1.0f;
+
+
+ /* is ok..
+ CL_AddPacketEntities (cl.frame);
+ CL_AddTEnts ();
+ CL_AddParticles ();
+ CL_AddDLights ();
+ CL_AddLightStyles ();
+ */
+
+ CalcViewValues();
+ // PMM - moved this here so the heat beam has the right values for the vieworg, and can lock the beam to the gun
+ AddPacketEntities( cl.frame);
+
+ CL_tent.AddTEnts();
+ AddParticles();
+ CL_fx.AddDLights();
+ AddLightStyles();
+ }
+
+ /*
+ ===============
+ CL_GetEntitySoundOrigin
+
+ Called to get the sound spatialization origin
+ ===============
+ */
+ void GetEntitySoundOrigin(int ent, float[] org) {
+ centity_t old;
+
+ if (ent < 0 || ent >= MAX_EDICTS)
+ Com.Error(ERR_DROP, "CL_GetEntitySoundOrigin: bad ent");
+ old = cl_entities[ent];
+ VectorCopy(old.lerp_origin, org);
+
+ // FIXME: bmodel issues...
+ }
+
+}
diff --git a/src/jake2/client/CL_fx.java b/src/jake2/client/CL_fx.java
new file mode 100644
index 0000000..1ce63ad
--- /dev/null
+++ b/src/jake2/client/CL_fx.java
@@ -0,0 +1,2292 @@
+/*
+ * CL_fx.java
+ * Copyright (C) 2004
+ *
+ * $Id: CL_fx.java,v 1.1 2004-07-07 19:58:36 hzi Exp $
+ */
+/*
+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.
+
+*/
+package jake2.client;
+
+import jake2.game.M_Flash;
+import jake2.game.entity_state_t;
+import jake2.qcommon.Com;
+import jake2.qcommon.MSG;
+
+/**
+ * CL_fx
+ */
+public class CL_fx extends CL_tent {
+
+ static final float INSTANT_PARTICLE = -10000.0f;
+
+ static class cdlight_t {
+ int key; // so entities can reuse same entry
+ float[] color = { 0, 0, 0 };
+ float[] origin = { 0, 0, 0 };
+ float radius;
+ float die; // stop lighting after this time
+ float decay; // drop this each second
+ float minlight; // don't add when contributing less
+ void clear() {
+ radius =
+ decay = die = minlight = color[0] = color[1] = color[2] = origin[0] = origin[1] = origin[2] = key = 0;
+ }
+ }
+
+ static float[][] avelocities = new float[NUMVERTEXNORMALS][3];
+
+ /*
+ ==============================================================
+
+ LIGHT STYLE MANAGEMENT
+
+ ==============================================================
+ */
+
+ static class clightstyle_t {
+ int length;
+ float[] value = new float[3];
+ float[] map = new float[MAX_QPATH];
+ void clear() {
+ value[0] = value[1] = value[2] = length = 0;
+ for (int i = 0; i < map.length; i++)
+ map[i] = 0.0f;
+ }
+ }
+ static clightstyle_t[] cl_lightstyle = new clightstyle_t[MAX_LIGHTSTYLES];
+ static {
+ for(int i=0; i<cl_lightstyle.length; i++) {
+ cl_lightstyle[i] = new clightstyle_t();
+ }
+ }
+ static int lastofs;
+
+ /*
+ ================
+ CL_ClearLightStyles
+ ================
+ */
+ static void ClearLightStyles ()
+ {
+ //memset (cl_lightstyle, 0, sizeof(cl_lightstyle));
+ for (int i = 0; i < cl_lightstyle.length; i++)
+ cl_lightstyle[i].clear();
+ lastofs = -1;
+ }
+
+ /*
+ ================
+ CL_RunLightStyles
+ ================
+ */
+ static void RunLightStyles() {
+ int ofs;
+ int i;
+ clightstyle_t[] ls;
+
+ ofs = cl.time / 100;
+ if (ofs == lastofs)
+ return;
+ lastofs = ofs;
+ ls = cl_lightstyle;
+ for (i = 0; i < ls.length; i++) {
+ if (ls[i].length == 0) {
+ ls[i].value[0] = ls[i].value[1] = ls[i].value[2] = 1.0f;
+ continue;
+ }
+ if (ls.length == 1)
+ ls[i].value[0] = ls[i].value[1] = ls[i].value[2] = ls[i].map[0];
+ else
+ ls[i].value[0] = ls[i].value[1] = ls[i].value[2] = ls[i].map[ofs % ls[i].length];
+ }
+ }
+
+ static void SetLightstyle(int i) {
+ String s;
+ int j, k;
+
+ s = cl.configstrings[i + CS_LIGHTS];
+
+ j = strlen(s);
+ if (j >= MAX_QPATH)
+ Com.Error(ERR_DROP, "svc_lightstyle length=" + j);
+
+ cl_lightstyle[i].length = j;
+
+ for (k = 0; k < j; k++)
+ cl_lightstyle[i].map[k] = (float) (s.charAt(k) - 'a') / (float) ('m' - 'a');
+ }
+
+ /*
+ ================
+ CL_AddLightStyles
+ ================
+ */
+ static void AddLightStyles() {
+ int i;
+ clightstyle_t[] ls;
+
+ ls = cl_lightstyle;
+ for (i = 0; i < ls.length; i++)
+ V.AddLightStyle(i, ls[i].value[0], ls[i].value[1], ls[i].value[2]);
+ }
+
+ /*
+ ==============================================================
+
+ DLIGHT MANAGEMENT
+
+ ==============================================================
+ */
+
+ static cdlight_t[] cl_dlights = new cdlight_t[MAX_DLIGHTS];
+ static {
+ for (int i = 0; i < cl_dlights.length; i++)
+ cl_dlights[i] = new cdlight_t();
+ }
+
+ /*
+ ================
+ CL_ClearDlights
+ ================
+ */
+ static void ClearDlights() {
+ // memset (cl_dlights, 0, sizeof(cl_dlights));
+ for (int i = 0; i < cl_dlights.length; i++) {
+ cl_dlights[i].clear();
+ }
+ }
+
+ /*
+ ===============
+ CL_AllocDlight
+
+ ===============
+ */
+ static cdlight_t AllocDlight(int key) {
+ int i;
+ cdlight_t[] dl;
+
+ // first look for an exact key match
+ if (key != 0) {
+ dl = cl_dlights;
+ for (i = 0; i < MAX_DLIGHTS; i++) {
+ if (dl[i].key == key) {
+ //memset (dl, 0, sizeof(*dl));
+ dl[i].clear();
+ dl[i].key = key;
+ return dl[i];
+ }
+ }
+ }
+
+ // then look for anything else
+ dl = cl_dlights;
+ for (i = 0; i < MAX_DLIGHTS; i++) {
+ if (dl[i].die < cl.time) {
+ //memset (dl, 0, sizeof(*dl));
+ dl[i].clear();
+ dl[i].key = key;
+ return dl[i];
+ }
+ }
+
+ //dl = &cl_dlights[0];
+ //memset (dl, 0, sizeof(*dl));
+ dl[0].clear();
+ dl[0].key = key;
+ return dl[0];
+ }
+
+ /*
+ ===============
+ CL_NewDlight
+ ===============
+ */
+ static void NewDlight(int key, float x, float y, float z, float radius, float time) {
+ cdlight_t dl;
+
+ dl = CL.AllocDlight(key);
+ dl.origin[0] = x;
+ dl.origin[1] = y;
+ dl.origin[2] = z;
+ dl.radius = radius;
+ dl.die = cl.time + time;
+ }
+
+ /*
+ ===============
+ CL_RunDLights
+
+ ===============
+ */
+ static void RunDLights() {
+ int i;
+ cdlight_t[] dl;
+
+ dl = cl_dlights;
+ for (i = 0; i < MAX_DLIGHTS; i++) {
+ if (dl[i].radius == 0.0f)
+ continue;
+
+ if (dl[i].die < cl.time) {
+ dl[i].radius = 0;
+ return;
+ }
+ dl[i].radius -= cls.frametime * dl[i].decay;
+ if (dl[i].radius < 0)
+ dl[i].radius = 0;
+ }
+ }
+
+ /*
+ ==============
+ CL_ParseMuzzleFlash
+ ==============
+ */
+ static void ParseMuzzleFlash() {
+ float[] fv = new float[3];
+ float[] rv = new float[3];
+ cdlight_t dl;
+ int i, weapon;
+ centity_t pl;
+ int silenced;
+ float volume;
+ String soundname;
+
+ i = MSG.ReadShort(net_message);
+ if (i < 1 || i >= MAX_EDICTS)
+ Com.Error(ERR_DROP, "CL_ParseMuzzleFlash: bad entity");
+
+ weapon = MSG.ReadByte(net_message);
+ silenced = weapon & MZ_SILENCED;
+ weapon &= ~MZ_SILENCED;
+
+ pl = cl_entities[i];
+
+ dl = CL.AllocDlight(i);
+ VectorCopy(pl.current.origin, dl.origin);
+ AngleVectors(pl.current.angles, fv, rv, null);
+ VectorMA(dl.origin, 18, fv, dl.origin);
+ VectorMA(dl.origin, 16, rv, dl.origin);
+ if (silenced != 0)
+ dl.radius = 100 + (rand() & 31);
+ else
+ dl.radius = 200 + (rand() & 31);
+ dl.minlight = 32;
+ dl.die = cl.time; // + 0.1;
+
+ if (silenced != 0)
+ volume = 0.2f;
+ else
+ volume = 1;
+
+ switch (weapon) {
+ case MZ_BLASTER :
+ dl.color[0] = 1;
+ dl.color[1] = 1;
+ dl.color[2] = 0;
+ S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound("weapons/blastf1a.wav"), volume, ATTN_NORM, 0);
+ break;
+ case MZ_BLUEHYPERBLASTER :
+ dl.color[0] = 0;
+ dl.color[1] = 0;
+ dl.color[2] = 1;
+ S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound("weapons/hyprbf1a.wav"), volume, ATTN_NORM, 0);
+ break;
+ case MZ_HYPERBLASTER :
+ dl.color[0] = 1;
+ dl.color[1] = 1;
+ dl.color[2] = 0;
+ S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound("weapons/hyprbf1a.wav"), volume, ATTN_NORM, 0);
+ break;
+ case MZ_MACHINEGUN :
+ dl.color[0] = 1;
+ dl.color[1] = 1;
+ dl.color[2] = 0;
+ //Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
+ soundname = "weapons/machgf" + ((rand() % 5) + 1) + "b.wav";
+ S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound(soundname), volume, ATTN_NORM, 0);
+ break;
+ case MZ_SHOTGUN :
+ dl.color[0] = 1;
+ dl.color[1] = 1;
+ dl.color[2] = 0;
+ S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound("weapons/shotgf1b.wav"), volume, ATTN_NORM, 0);
+ S.StartSound(null, i, CHAN_AUTO, S.RegisterSound("weapons/shotgr1b.wav"), volume, ATTN_NORM, 0.1f);
+ break;
+ case MZ_SSHOTGUN :
+ dl.color[0] = 1;
+ dl.color[1] = 1;
+ dl.color[2] = 0;
+ S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound("weapons/sshotf1b.wav"), volume, ATTN_NORM, 0);
+ break;
+ case MZ_CHAINGUN1 :
+ dl.radius = 200 + (rand() & 31);
+ dl.color[0] = 1;
+ dl.color[1] = 0.25f;
+ dl.color[2] = 0;
+ //Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
+ soundname = "weapons/machgf" + ((rand() % 5) + 1) + "b.wav";
+ S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound(soundname), volume, ATTN_NORM, 0);
+ break;
+ case MZ_CHAINGUN2 :
+ dl.radius = 225 + (rand() & 31);
+ dl.color[0] = 1;
+ dl.color[1] = 0.5f;
+ dl.color[2] = 0;
+ dl.die = cl.time + 0.1f; // long delay
+ //Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
+ soundname = "weapons/machgf" + ((rand() % 5) + 1) + "b.wav";
+ S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound(soundname), volume, ATTN_NORM, 0);
+ //Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
+ soundname = "weapons/machgf" + ((rand() % 5) + 1) + "b.wav";
+ S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound(soundname), volume, ATTN_NORM, 0.05f);
+ break;
+ case MZ_CHAINGUN3 :
+ dl.radius = 250 + (rand() & 31);
+ dl.color[0] = 1;
+ dl.color[1] = 1;
+ dl.color[2] = 0;
+ dl.die = cl.time + 0.1f; // long delay
+ //Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
+ soundname = "weapons/machgf" + ((rand() % 5) + 1) + "b.wav";
+ S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound(soundname), volume, ATTN_NORM, 0);
+ //Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
+ soundname = "weapons/machgf" + ((rand() % 5) + 1) + "b.wav";
+ S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound(soundname), volume, ATTN_NORM, 0.033f);
+ //Com_sprintf(soundname, sizeof(soundname), "weapons/machgf%ib.wav", (rand() % 5) + 1);
+ soundname = "weapons/machgf" + ((rand() % 5) + 1) + "b.wav";
+ S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound(soundname), volume, ATTN_NORM, 0.066f);
+ break;
+ case MZ_RAILGUN :
+ dl.color[0] = 0.5f;
+ dl.color[1] = 0.5f;
+ dl.color[2] = 1.0f;
+ S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound("weapons/railgf1a.wav"), volume, ATTN_NORM, 0);
+ break;
+ case MZ_ROCKET :
+ dl.color[0] = 1;
+ dl.color[1] = 0.5f;
+ dl.color[2] = 0.2f;
+ S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound("weapons/rocklf1a.wav"), volume, ATTN_NORM, 0);
+ S.StartSound(null, i, CHAN_AUTO, S.RegisterSound("weapons/rocklr1b.wav"), volume, ATTN_NORM, 0.1f);
+ break;
+ case MZ_GRENADE :
+ dl.color[0] = 1;
+ dl.color[1] = 0.5f;
+ dl.color[2] = 0;
+ S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound("weapons/grenlf1a.wav"), volume, ATTN_NORM, 0);
+ S.StartSound(null, i, CHAN_AUTO, S.RegisterSound("weapons/grenlr1b.wav"), volume, ATTN_NORM, 0.1f);
+ break;
+ case MZ_BFG :
+ dl.color[0] = 0;
+ dl.color[1] = 1;
+ dl.color[2] = 0;
+ S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound("weapons/bfg__f1y.wav"), volume, ATTN_NORM, 0);
+ break;
+
+ case MZ_LOGIN :
+ dl.color[0] = 0;
+ dl.color[1] = 1;
+ dl.color[2] = 0;
+ dl.die = cl.time + 1.0f;
+ S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound("weapons/grenlf1a.wav"), 1, ATTN_NORM, 0);
+ CL.LogoutEffect(pl.current.origin, weapon);
+ break;
+ case MZ_LOGOUT :
+ dl.color[0] = 1;
+ dl.color[1] = 0;
+ dl.color[2] = 0;
+ dl.die = cl.time + 1.0f;
+ S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound("weapons/grenlf1a.wav"), 1, ATTN_NORM, 0);
+ CL.LogoutEffect(pl.current.origin, weapon);
+ break;
+ case MZ_RESPAWN :
+ dl.color[0] = 1;
+ dl.color[1] = 1;
+ dl.color[2] = 0;
+ dl.die = cl.time + 1.0f;
+ S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound("weapons/grenlf1a.wav"), 1, ATTN_NORM, 0);
+ CL.LogoutEffect(pl.current.origin, weapon);
+ break;
+ // RAFAEL
+ case MZ_PHALANX :
+ dl.color[0] = 1;
+ dl.color[1] = 0.5f;
+ dl.color[2] = 0.5f;
+ S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound("weapons/plasshot.wav"), volume, ATTN_NORM, 0);
+ break;
+ // RAFAEL
+ case MZ_IONRIPPER :
+ dl.color[0] = 1;
+ dl.color[1] = 0.5f;
+ dl.color[2] = 0.5f;
+ S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound("weapons/rippfire.wav"), volume, ATTN_NORM, 0);
+ break;
+
+ // ======================
+ // PGM
+ case MZ_ETF_RIFLE :
+ dl.color[0] = 0.9f;
+ dl.color[1] = 0.7f;
+ dl.color[2] = 0;
+ S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound("weapons/nail1.wav"), volume, ATTN_NORM, 0);
+ break;
+ case MZ_SHOTGUN2 :
+ dl.color[0] = 1;
+ dl.color[1] = 1;
+ dl.color[2] = 0;
+ S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound("weapons/shotg2.wav"), volume, ATTN_NORM, 0);
+ break;
+ case MZ_HEATBEAM :
+ dl.color[0] = 1;
+ dl.color[1] = 1;
+ dl.color[2] = 0;
+ dl.die = cl.time + 100;
+ // S.StartSound (null, i, CHAN_WEAPON, S.RegisterSound("weapons/bfg__l1a.wav"), volume, ATTN_NORM, 0);
+ break;
+ case MZ_BLASTER2 :
+ dl.color[0] = 0;
+ dl.color[1] = 1;
+ dl.color[2] = 0;
+ // FIXME - different sound for blaster2 ??
+ S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound("weapons/blastf1a.wav"), volume, ATTN_NORM, 0);
+ break;
+ case MZ_TRACKER :
+ // negative flashes handled the same in gl/soft until CL_AddDLights
+ dl.color[0] = -1;
+ dl.color[1] = -1;
+ dl.color[2] = -1;
+ S.StartSound(null, i, CHAN_WEAPON, S.RegisterSound("weapons/disint2.wav"), volume, ATTN_NORM, 0);
+ break;
+ case MZ_NUKE1 :
+ dl.color[0] = 1;
+ dl.color[1] = 0;
+ dl.color[2] = 0;
+ dl.die = cl.time + 100;
+ break;
+ case MZ_NUKE2 :
+ dl.color[0] = 1;
+ dl.color[1] = 1;
+ dl.color[2] = 0;
+ dl.die = cl.time + 100;
+ break;
+ case MZ_NUKE4 :
+ dl.color[0] = 0;
+ dl.color[1] = 0;
+ dl.color[2] = 1;
+ dl.die = cl.time + 100;
+ break;
+ case MZ_NUKE8 :
+ dl.color[0] = 0;
+ dl.color[1] = 1;
+ dl.color[2] = 1;
+ dl.die = cl.time + 100;
+ break;
+ // PGM
+ // ======================
+ }
+ }
+
+ /*
+ ==============
+ CL_ParseMuzzleFlash2
+ ==============
+ */
+ static void ParseMuzzleFlash2() {
+ int ent;
+ float[] origin = new float[3];
+ int flash_number;
+ cdlight_t dl;
+ float[] forward = new float[3];
+ float[] right = new float[3];
+ String soundname;
+
+ ent = MSG.ReadShort(net_message);
+ if (ent < 1 || ent >= MAX_EDICTS)
+ Com.Error(ERR_DROP, "CL_ParseMuzzleFlash2: bad entity");
+
+ flash_number = MSG.ReadByte(net_message);
+
+ // locate the origin
+ AngleVectors(cl_entities[ent].current.angles, forward, right, null);
+ origin[0] =
+ cl_entities[ent].current.origin[0]
+ + forward[0] * M_Flash.monster_flash_offset[flash_number][0]
+ + right[0] * M_Flash.monster_flash_offset[flash_number][1];
+ origin[1] =
+ cl_entities[ent].current.origin[1]
+ + forward[1] * M_Flash.monster_flash_offset[flash_number][0]
+ + right[1] * M_Flash.monster_flash_offset[flash_number][1];
+ origin[2] =
+ cl_entities[ent].current.origin[2]
+ + forward[2] * M_Flash.monster_flash_offset[flash_number][0]
+ + right[2] * M_Flash.monster_flash_offset[flash_number][1]
+ + M_Flash.monster_flash_offset[flash_number][2];
+
+ dl = CL.AllocDlight(ent);
+ VectorCopy(origin, dl.origin);
+ dl.radius = 200 + (rand() & 31);
+ dl.minlight = 32;
+ dl.die = cl.time; // + 0.1;
+
+ switch (flash_number) {
+ case MZ2_INFANTRY_MACHINEGUN_1 :
+ case MZ2_INFANTRY_MACHINEGUN_2 :
+ case MZ2_INFANTRY_MACHINEGUN_3 :
+ case MZ2_INFANTRY_MACHINEGUN_4 :
+ case MZ2_INFANTRY_MACHINEGUN_5 :
+ case MZ2_INFANTRY_MACHINEGUN_6 :
+ case MZ2_INFANTRY_MACHINEGUN_7 :
+ case MZ2_INFANTRY_MACHINEGUN_8 :
+ case MZ2_INFANTRY_MACHINEGUN_9 :
+ case MZ2_INFANTRY_MACHINEGUN_10 :
+ case MZ2_INFANTRY_MACHINEGUN_11 :
+ case MZ2_INFANTRY_MACHINEGUN_12 :
+ case MZ2_INFANTRY_MACHINEGUN_13 :
+ dl.color[0] = 1;
+ dl.color[1] = 1;
+ dl.color[2] = 0;
+ CL.ParticleEffect(origin, vec3_origin, 0, 40);
+ CL.SmokeAndFlash(origin);
+ S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("infantry/infatck1.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_SOLDIER_MACHINEGUN_1 :
+ case MZ2_SOLDIER_MACHINEGUN_2 :
+ case MZ2_SOLDIER_MACHINEGUN_3 :
+ case MZ2_SOLDIER_MACHINEGUN_4 :
+ case MZ2_SOLDIER_MACHINEGUN_5 :
+ case MZ2_SOLDIER_MACHINEGUN_6 :
+ case MZ2_SOLDIER_MACHINEGUN_7 :
+ case MZ2_SOLDIER_MACHINEGUN_8 :
+ dl.color[0] = 1;
+ dl.color[1] = 1;
+ dl.color[2] = 0;
+ CL.ParticleEffect(origin, vec3_origin, 0, 40);
+ CL.SmokeAndFlash(origin);
+ S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("soldier/solatck3.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_GUNNER_MACHINEGUN_1 :
+ case MZ2_GUNNER_MACHINEGUN_2 :
+ case MZ2_GUNNER_MACHINEGUN_3 :
+ case MZ2_GUNNER_MACHINEGUN_4 :
+ case MZ2_GUNNER_MACHINEGUN_5 :
+ case MZ2_GUNNER_MACHINEGUN_6 :
+ case MZ2_GUNNER_MACHINEGUN_7 :
+ case MZ2_GUNNER_MACHINEGUN_8 :
+ dl.color[0] = 1;
+ dl.color[1] = 1;
+ dl.color[2] = 0;
+ CL.ParticleEffect(origin, vec3_origin, 0, 40);
+ CL.SmokeAndFlash(origin);
+ S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("gunner/gunatck2.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_ACTOR_MACHINEGUN_1 :
+ case MZ2_SUPERTANK_MACHINEGUN_1 :
+ case MZ2_SUPERTANK_MACHINEGUN_2 :
+ case MZ2_SUPERTANK_MACHINEGUN_3 :
+ case MZ2_SUPERTANK_MACHINEGUN_4 :
+ case MZ2_SUPERTANK_MACHINEGUN_5 :
+ case MZ2_SUPERTANK_MACHINEGUN_6 :
+ case MZ2_TURRET_MACHINEGUN : // PGM
+ dl.color[0] = 1;
+ dl.color[1] = 1;
+ dl.color[2] = 0;
+
+ CL.ParticleEffect(origin, vec3_origin, 0, 40);
+ CL.SmokeAndFlash(origin);
+ S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("infantry/infatck1.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_BOSS2_MACHINEGUN_L1 :
+ case MZ2_BOSS2_MACHINEGUN_L2 :
+ case MZ2_BOSS2_MACHINEGUN_L3 :
+ case MZ2_BOSS2_MACHINEGUN_L4 :
+ case MZ2_BOSS2_MACHINEGUN_L5 :
+ case MZ2_CARRIER_MACHINEGUN_L1 : // PMM
+ case MZ2_CARRIER_MACHINEGUN_L2 : // PMM
+ dl.color[0] = 1;
+ dl.color[1] = 1;
+ dl.color[2] = 0;
+
+ CL.ParticleEffect(origin, vec3_origin, 0, 40);
+ CL.SmokeAndFlash(origin);
+ S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("infantry/infatck1.wav"), 1, ATTN_NONE, 0);
+ break;
+
+ case MZ2_SOLDIER_BLASTER_1 :
+ case MZ2_SOLDIER_BLASTER_2 :
+ case MZ2_SOLDIER_BLASTER_3 :
+ case MZ2_SOLDIER_BLASTER_4 :
+ case MZ2_SOLDIER_BLASTER_5 :
+ case MZ2_SOLDIER_BLASTER_6 :
+ case MZ2_SOLDIER_BLASTER_7 :
+ case MZ2_SOLDIER_BLASTER_8 :
+ case MZ2_TURRET_BLASTER : // PGM
+ dl.color[0] = 1;
+ dl.color[1] = 1;
+ dl.color[2] = 0;
+ S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("soldier/solatck2.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_FLYER_BLASTER_1 :
+ case MZ2_FLYER_BLASTER_2 :
+ dl.color[0] = 1;
+ dl.color[1] = 1;
+ dl.color[2] = 0;
+ S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("flyer/flyatck3.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_MEDIC_BLASTER_1 :
+ dl.color[0] = 1;
+ dl.color[1] = 1;
+ dl.color[2] = 0;
+ S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("medic/medatck1.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_HOVER_BLASTER_1 :
+ dl.color[0] = 1;
+ dl.color[1] = 1;
+ dl.color[2] = 0;
+ S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("hover/hovatck1.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_FLOAT_BLASTER_1 :
+ dl.color[0] = 1;
+ dl.color[1] = 1;
+ dl.color[2] = 0;
+ S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("floater/fltatck1.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_SOLDIER_SHOTGUN_1 :
+ case MZ2_SOLDIER_SHOTGUN_2 :
+ case MZ2_SOLDIER_SHOTGUN_3 :
+ case MZ2_SOLDIER_SHOTGUN_4 :
+ case MZ2_SOLDIER_SHOTGUN_5 :
+ case MZ2_SOLDIER_SHOTGUN_6 :
+ case MZ2_SOLDIER_SHOTGUN_7 :
+ case MZ2_SOLDIER_SHOTGUN_8 :
+ dl.color[0] = 1;
+ dl.color[1] = 1;
+ dl.color[2] = 0;
+ CL.SmokeAndFlash(origin);
+ S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("soldier/solatck1.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_TANK_BLASTER_1 :
+ case MZ2_TANK_BLASTER_2 :
+ case MZ2_TANK_BLASTER_3 :
+ dl.color[0] = 1;
+ dl.color[1] = 1;
+ dl.color[2] = 0;
+ S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("tank/tnkatck3.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_TANK_MACHINEGUN_1 :
+ case MZ2_TANK_MACHINEGUN_2 :
+ case MZ2_TANK_MACHINEGUN_3 :
+ case MZ2_TANK_MACHINEGUN_4 :
+ case MZ2_TANK_MACHINEGUN_5 :
+ case MZ2_TANK_MACHINEGUN_6 :
+ case MZ2_TANK_MACHINEGUN_7 :
+ case MZ2_TANK_MACHINEGUN_8 :
+ case MZ2_TANK_MACHINEGUN_9 :
+ case MZ2_TANK_MACHINEGUN_10 :
+ case MZ2_TANK_MACHINEGUN_11 :
+ case MZ2_TANK_MACHINEGUN_12 :
+ case MZ2_TANK_MACHINEGUN_13 :
+ case MZ2_TANK_MACHINEGUN_14 :
+ case MZ2_TANK_MACHINEGUN_15 :
+ case MZ2_TANK_MACHINEGUN_16 :
+ case MZ2_TANK_MACHINEGUN_17 :
+ case MZ2_TANK_MACHINEGUN_18 :
+ case MZ2_TANK_MACHINEGUN_19 :
+ dl.color[0] = 1;
+ dl.color[1] = 1;
+ dl.color[2] = 0;
+ CL.ParticleEffect(origin, vec3_origin, 0, 40);
+ CL.SmokeAndFlash(origin);
+ //Com_sprintf(soundname, sizeof(soundname), "tank/tnkatk2%c.wav", 'a' + rand() % 5);
+ soundname = "tank/tnkatk2" + (char) ('a' + rand() % 5) + ".wav";
+ S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound(soundname), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_CHICK_ROCKET_1 :
+ case MZ2_TURRET_ROCKET : // PGM
+ dl.color[0] = 1;
+ dl.color[1] = 0.5f;
+ dl.color[2] = 0.2f;
+ S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("chick/chkatck2.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_TANK_ROCKET_1 :
+ case MZ2_TANK_ROCKET_2 :
+ case MZ2_TANK_ROCKET_3 :
+ dl.color[0] = 1;
+ dl.color[1] = 0.5f;
+ dl.color[2] = 0.2f;
+ S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("tank/tnkatck1.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_SUPERTANK_ROCKET_1 :
+ case MZ2_SUPERTANK_ROCKET_2 :
+ case MZ2_SUPERTANK_ROCKET_3 :
+ case MZ2_BOSS2_ROCKET_1 :
+ case MZ2_BOSS2_ROCKET_2 :
+ case MZ2_BOSS2_ROCKET_3 :
+ case MZ2_BOSS2_ROCKET_4 :
+ case MZ2_CARRIER_ROCKET_1 :
+ // case MZ2_CARRIER_ROCKET_2:
+ // case MZ2_CARRIER_ROCKET_3:
+ // case MZ2_CARRIER_ROCKET_4:
+ dl.color[0] = 1;
+ dl.color[1] = 0.5f;
+ dl.color[2] = 0.2f;
+ S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("tank/rocket.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_GUNNER_GRENADE_1 :
+ case MZ2_GUNNER_GRENADE_2 :
+ case MZ2_GUNNER_GRENADE_3 :
+ case MZ2_GUNNER_GRENADE_4 :
+ dl.color[0] = 1;
+ dl.color[1] = 0.5f;
+ dl.color[2] = 0;
+ S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("gunner/gunatck3.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_GLADIATOR_RAILGUN_1 :
+ // PMM
+ case MZ2_CARRIER_RAILGUN :
+ case MZ2_WIDOW_RAIL :
+ // pmm
+ dl.color[0] = 0.5f;
+ dl.color[1] = 0.5f;
+ dl.color[2] = 1.0f;
+ break;
+
+ // --- Xian's shit starts ---
+ case MZ2_MAKRON_BFG :
+ dl.color[0] = 0.5f;
+ dl.color[1] = 1;
+ dl.color[2] = 0.5f;
+ //S.StartSound (null, ent, CHAN_WEAPON, S.RegisterSound("makron/bfg_fire.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_MAKRON_BLASTER_1 :
+ case MZ2_MAKRON_BLASTER_2 :
+ case MZ2_MAKRON_BLASTER_3 :
+ case MZ2_MAKRON_BLASTER_4 :
+ case MZ2_MAKRON_BLASTER_5 :
+ case MZ2_MAKRON_BLASTER_6 :
+ case MZ2_MAKRON_BLASTER_7 :
+ case MZ2_MAKRON_BLASTER_8 :
+ case MZ2_MAKRON_BLASTER_9 :
+ case MZ2_MAKRON_BLASTER_10 :
+ case MZ2_MAKRON_BLASTER_11 :
+ case MZ2_MAKRON_BLASTER_12 :
+ case MZ2_MAKRON_BLASTER_13 :
+ case MZ2_MAKRON_BLASTER_14 :
+ case MZ2_MAKRON_BLASTER_15 :
+ case MZ2_MAKRON_BLASTER_16 :
+ case MZ2_MAKRON_BLASTER_17 :
+ dl.color[0] = 1;
+ dl.color[1] = 1;
+ dl.color[2] = 0;
+ S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("makron/blaster.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_JORG_MACHINEGUN_L1 :
+ case MZ2_JORG_MACHINEGUN_L2 :
+ case MZ2_JORG_MACHINEGUN_L3 :
+ case MZ2_JORG_MACHINEGUN_L4 :
+ case MZ2_JORG_MACHINEGUN_L5 :
+ case MZ2_JORG_MACHINEGUN_L6 :
+ dl.color[0] = 1;
+ dl.color[1] = 1;
+ dl.color[2] = 0;
+ CL.ParticleEffect(origin, vec3_origin, 0, 40);
+ CL.SmokeAndFlash(origin);
+ S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("boss3/xfire.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_JORG_MACHINEGUN_R1 :
+ case MZ2_JORG_MACHINEGUN_R2 :
+ case MZ2_JORG_MACHINEGUN_R3 :
+ case MZ2_JORG_MACHINEGUN_R4 :
+ case MZ2_JORG_MACHINEGUN_R5 :
+ case MZ2_JORG_MACHINEGUN_R6 :
+ dl.color[0] = 1;
+ dl.color[1] = 1;
+ dl.color[2] = 0;
+ CL.ParticleEffect(origin, vec3_origin, 0, 40);
+ CL.SmokeAndFlash(origin);
+ break;
+
+ case MZ2_JORG_BFG_1 :
+ dl.color[0] = 0.5f;
+ dl.color[1] = 1;
+ dl.color[2] = 0.5f;
+ break;
+
+ case MZ2_BOSS2_MACHINEGUN_R1 :
+ case MZ2_BOSS2_MACHINEGUN_R2 :
+ case MZ2_BOSS2_MACHINEGUN_R3 :
+ case MZ2_BOSS2_MACHINEGUN_R4 :
+ case MZ2_BOSS2_MACHINEGUN_R5 :
+ case MZ2_CARRIER_MACHINEGUN_R1 : // PMM
+ case MZ2_CARRIER_MACHINEGUN_R2 : // PMM
+
+ dl.color[0] = 1;
+ dl.color[1] = 1;
+ dl.color[2] = 0;
+
+ CL.ParticleEffect(origin, vec3_origin, 0, 40);
+ CL.SmokeAndFlash(origin);
+ break;
+
+ // ======
+ // ROGUE
+ case MZ2_STALKER_BLASTER :
+ case MZ2_DAEDALUS_BLASTER :
+ case MZ2_MEDIC_BLASTER_2 :
+ case MZ2_WIDOW_BLASTER :
+ case MZ2_WIDOW_BLASTER_SWEEP1 :
+ case MZ2_WIDOW_BLASTER_SWEEP2 :
+ case MZ2_WIDOW_BLASTER_SWEEP3 :
+ case MZ2_WIDOW_BLASTER_SWEEP4 :
+ case MZ2_WIDOW_BLASTER_SWEEP5 :
+ case MZ2_WIDOW_BLASTER_SWEEP6 :
+ case MZ2_WIDOW_BLASTER_SWEEP7 :
+ case MZ2_WIDOW_BLASTER_SWEEP8 :
+ case MZ2_WIDOW_BLASTER_SWEEP9 :
+ case MZ2_WIDOW_BLASTER_100 :
+ case MZ2_WIDOW_BLASTER_90 :
+ case MZ2_WIDOW_BLASTER_80 :
+ case MZ2_WIDOW_BLASTER_70 :
+ case MZ2_WIDOW_BLASTER_60 :
+ case MZ2_WIDOW_BLASTER_50 :
+ case MZ2_WIDOW_BLASTER_40 :
+ case MZ2_WIDOW_BLASTER_30 :
+ case MZ2_WIDOW_BLASTER_20 :
+ case MZ2_WIDOW_BLASTER_10 :
+ case MZ2_WIDOW_BLASTER_0 :
+ case MZ2_WIDOW_BLASTER_10L :
+ case MZ2_WIDOW_BLASTER_20L :
+ case MZ2_WIDOW_BLASTER_30L :
+ case MZ2_WIDOW_BLASTER_40L :
+ case MZ2_WIDOW_BLASTER_50L :
+ case MZ2_WIDOW_BLASTER_60L :
+ case MZ2_WIDOW_BLASTER_70L :
+ case MZ2_WIDOW_RUN_1 :
+ case MZ2_WIDOW_RUN_2 :
+ case MZ2_WIDOW_RUN_3 :
+ case MZ2_WIDOW_RUN_4 :
+ case MZ2_WIDOW_RUN_5 :
+ case MZ2_WIDOW_RUN_6 :
+ case MZ2_WIDOW_RUN_7 :
+ case MZ2_WIDOW_RUN_8 :
+ dl.color[0] = 0;
+ dl.color[1] = 1;
+ dl.color[2] = 0;
+ S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("tank/tnkatck3.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_WIDOW_DISRUPTOR :
+ dl.color[0] = -1;
+ dl.color[1] = -1;
+ dl.color[2] = -1;
+ S.StartSound(null, ent, CHAN_WEAPON, S.RegisterSound("weapons/disint2.wav"), 1, ATTN_NORM, 0);
+ break;
+
+ case MZ2_WIDOW_PLASMABEAM :
+ case MZ2_WIDOW2_BEAMER_1 :
+ case MZ2_WIDOW2_BEAMER_2 :
+ case MZ2_WIDOW2_BEAMER_3 :
+ case MZ2_WIDOW2_BEAMER_4 :
+ case MZ2_WIDOW2_BEAMER_5 :
+ case MZ2_WIDOW2_BEAM_SWEEP_1 :
+ case MZ2_WIDOW2_BEAM_SWEEP_2 :
+ case MZ2_WIDOW2_BEAM_SWEEP_3 :
+ case MZ2_WIDOW2_BEAM_SWEEP_4 :
+ case MZ2_WIDOW2_BEAM_SWEEP_5 :
+ case MZ2_WIDOW2_BEAM_SWEEP_6 :
+ case MZ2_WIDOW2_BEAM_SWEEP_7 :
+ case MZ2_WIDOW2_BEAM_SWEEP_8 :
+ case MZ2_WIDOW2_BEAM_SWEEP_9 :
+ case MZ2_WIDOW2_BEAM_SWEEP_10 :
+ case MZ2_WIDOW2_BEAM_SWEEP_11 :
+ dl.radius = 300 + (rand() & 100);
+ dl.color[0] = 1;
+ dl.color[1] = 1;
+ dl.color[2] = 0;
+ dl.die = cl.time + 200;
+ break;
+ // ROGUE
+ // ======
+
+ // --- Xian's shit ends ---
+
+ }
+ }
+
+ /*
+ ===============
+ CL_AddDLights
+
+ ===============
+ */
+ static void AddDLights() {
+ int i;
+ cdlight_t[] dl;
+
+ dl = cl_dlights;
+
+ // =====
+ // PGM
+ if (vidref_val == VIDREF_GL) {
+ for (i = 0; i < MAX_DLIGHTS; i++) {
+ if (dl[i].radius == 0.0f)
+ continue;
+ V.AddLight(dl[i].origin, dl[i].radius, dl[i].color[0], dl[i].color[1], dl[i].color[2]);
+ }
+ } else {
+ for (i = 0; i < MAX_DLIGHTS; i++) {
+ if (dl[i].radius == 0.0f)
+ continue;
+
+ // negative light in software. only black allowed
+ if ((dl[i].color[0] < 0) || (dl[i].color[1] < 0) || (dl[i].color[2] < 0)) {
+ dl[i].radius = - (dl[i].radius);
+ dl[i].color[0] = 1;
+ dl[i].color[1] = 1;
+ dl[i].color[2] = 1;
+ }
+ V.AddLight(dl[i].origin, dl[i].radius, dl[i].color[0], dl[i].color[1], dl[i].color[2]);
+ }
+ }
+ // PGM
+ // =====
+ }
+
+ /*
+ ==============================================================
+
+ PARTICLE MANAGEMENT
+
+ ==============================================================
+ */
+
+ static final int PARTICLE_GRAVITY = 40;
+ static cparticle_t active_particles, free_particles;
+
+ static cparticle_t[] particles = new cparticle_t[MAX_PARTICLES];
+ static {
+ for (int i = 0; i < particles.length; i++)
+ particles[i] = new cparticle_t();
+ }
+ static int cl_numparticles = MAX_PARTICLES;
+
+ /*
+ ===============
+ CL_ClearParticles
+ ===============
+ */
+ static void ClearParticles()
+ {
+ int i;
+
+ free_particles = particles[0];
+ active_particles = null;
+
+ for (i=0 ; i<particles.length - 1; i++)
+ particles[i].next = particles[i+1];
+ particles[particles.length - 1].next = null;
+ }
+
+ /*
+ ===============
+ CL_ParticleEffect
+
+ Wall impact puffs
+ ===============
+ */
+ static void ParticleEffect(float[] org, float[] dir, int color, int count) {
+ int i, j;
+ cparticle_t p;
+ float d;
+
+ for (i = 0; i < count; i++) {
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+
+ p.time = cl.time;
+ p.color = color + (rand() & 7);
+
+ d = rand() & 31;
+ for (j = 0; j < 3; j++) {
+ p.org[j] = org[j] + ((rand() & 7) - 4) + d * dir[j];
+ p.vel[j] = crand() * 20;
+ }
+
+ p.accel[0] = p.accel[1] = 0;
+ p.accel[2] = -PARTICLE_GRAVITY;
+ p.alpha = 1.0f;
+
+ p.alphavel = -1.0f / (0.5f + frand() * 0.3f);
+ }
+ }
+
+ /*
+ ===============
+ CL_ParticleEffect2
+ ===============
+ */
+ static void ParticleEffect2(float[] org, float[] dir, int color, int count) {
+ int i, j;
+ cparticle_t p;
+ float d;
+
+ for (i = 0; i < count; i++) {
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+
+ p.time = cl.time;
+ p.color = color;
+
+ d = rand() & 7;
+ for (j = 0; j < 3; j++) {
+ p.org[j] = org[j] + ((rand() & 7) - 4) + d * dir[j];
+ p.vel[j] = crand() * 20;
+ }
+
+ p.accel[0] = p.accel[1] = 0;
+ p.accel[2] = -PARTICLE_GRAVITY;
+ p.alpha = 1.0f;
+
+ p.alphavel = -1.0f / (0.5f + frand() * 0.3f);
+ }
+ }
+
+ // RAFAEL
+ /*
+ ===============
+ CL_ParticleEffect3
+ ===============
+ */
+ static void ParticleEffect3(float[] org, float[] dir, int color, int count) {
+ int i, j;
+ cparticle_t p;
+ float d;
+
+ for (i = 0; i < count; i++) {
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+
+ p.time = cl.time;
+ p.color = color;
+
+ d = rand() & 7;
+ for (j = 0; j < 3; j++) {
+ p.org[j] = org[j] + ((rand() & 7) - 4) + d * dir[j];
+ p.vel[j] = crand() * 20;
+ }
+
+ p.accel[0] = p.accel[1] = 0;
+ p.accel[2] = PARTICLE_GRAVITY;
+ p.alpha = 1.0f;
+
+ p.alphavel = -1.0f / (0.5f + frand() * 0.3f);
+ }
+ }
+
+ /*
+ ===============
+ CL_TeleporterParticles
+ ===============
+ */
+ static void TeleporterParticles(entity_state_t ent) {
+ int i, j;
+ cparticle_t p;
+
+ for (i = 0; i < 8; i++) {
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+
+ p.time = cl.time;
+ p.color = 0xdb;
+
+ for (j = 0; j < 2; j++) {
+ p.org[j] = ent.origin[j] - 16 + (rand() & 31);
+ p.vel[j] = crand() * 14;
+ }
+
+ p.org[2] = ent.origin[2] - 8 + (rand() & 7);
+ p.vel[2] = 80 + (rand() & 7);
+
+ p.accel[0] = p.accel[1] = 0;
+ p.accel[2] = -PARTICLE_GRAVITY;
+ p.alpha = 1.0f;
+
+ p.alphavel = -0.5f;
+ }
+ }
+
+ /*
+ ===============
+ CL_LogoutEffect
+
+ ===============
+ */
+ static void LogoutEffect(float[] org, int type) {
+ int i, j;
+ cparticle_t p;
+
+ for (i = 0; i < 500; i++) {
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+
+ p.time = cl.time;
+
+ if (type == MZ_LOGIN)
+ p.color = 0xd0 + (rand() & 7); // green
+ else if (type == MZ_LOGOUT)
+ p.color = 0x40 + (rand() & 7); // red
+ else
+ p.color = 0xe0 + (rand() & 7); // yellow
+
+ p.org[0] = org[0] - 16 + frand() * 32;
+ p.org[1] = org[1] - 16 + frand() * 32;
+ p.org[2] = org[2] - 24 + frand() * 56;
+
+ for (j = 0; j < 3; j++)
+ p.vel[j] = crand() * 20;
+
+ p.accel[0] = p.accel[1] = 0;
+ p.accel[2] = -PARTICLE_GRAVITY;
+ p.alpha = 1.0f;
+
+ p.alphavel = -1.0f / (1.0f + frand() * 0.3f);
+ }
+ }
+
+ /*
+ ===============
+ CL_ItemRespawnParticles
+
+ ===============
+ */
+ static void ItemRespawnParticles(float[] org) {
+ int i, j;
+ cparticle_t p;
+
+ for (i = 0; i < 64; i++) {
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+
+ p.time = cl.time;
+
+ p.color = 0xd4 + (rand() & 3); // green
+
+ p.org[0] = org[0] + crand() * 8;
+ p.org[1] = org[1] + crand() * 8;
+ p.org[2] = org[2] + crand() * 8;
+
+ for (j = 0; j < 3; j++)
+ p.vel[j] = crand() * 8;
+
+ p.accel[0] = p.accel[1] = 0;
+ p.accel[2] = -PARTICLE_GRAVITY * 0.2f;
+ p.alpha = 1.0f;
+
+ p.alphavel = -1.0f / (1.0f + frand() * 0.3f);
+ }
+ }
+
+ /*
+ ===============
+ CL_ExplosionParticles
+ ===============
+ */
+ static void ExplosionParticles(float[] org) {
+ int i, j;
+ cparticle_t p;
+
+ for (i = 0; i < 256; i++) {
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+
+ p.time = cl.time;
+ p.color = 0xe0 + (rand() & 7);
+
+ for (j = 0; j < 3; j++) {
+ p.org[j] = org[j] + ((rand() % 32) - 16);
+ p.vel[j] = (rand() % 384) - 192;
+ }
+
+ p.accel[0] = p.accel[1] = 0.0f;
+ p.accel[2] = -PARTICLE_GRAVITY;
+ p.alpha = 1.0f;
+
+ p.alphavel = -0.8f / (0.5f + frand() * 0.3f);
+ }
+ }
+
+ /*
+ ===============
+ CL_BigTeleportParticles
+ ===============
+ */
+ private static int[] colortable = { 2 * 8, 13 * 8, 21 * 8, 18 * 8 };
+ static void BigTeleportParticles(float[] org) {
+ int i;
+ cparticle_t p;
+ float angle, dist;
+
+ for (i = 0; i < 4096; i++) {
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+
+ p.time = cl.time;
+
+ p.color = colortable[rand() & 3];
+
+ angle = (float) (Math.PI * 2 * (rand() & 1023) / 1023.0);
+ dist = rand() & 31;
+ p.org[0] = (float) (org[0] + Math.cos(angle) * dist);
+ p.vel[0] = (float) (Math.cos(angle) * (70 + (rand() & 63)));
+ p.accel[0] = (float) (-Math.cos(angle) * 100);
+
+ p.org[1] = (float) (org[1] + Math.sin(angle) * dist);
+ p.vel[1] = (float) (Math.sin(angle) * (70 + (rand() & 63)));
+ p.accel[1] = (float) (-Math.sin(angle) * 100);
+
+ p.org[2] = org[2] + 8 + (rand() % 90);
+ p.vel[2] = -100 + (rand() & 31);
+ p.accel[2] = PARTICLE_GRAVITY * 4;
+ p.alpha = 1.0f;
+
+ p.alphavel = -0.3f / (0.5f + frand() * 0.3f);
+ }
+ }
+
+ /*
+ ===============
+ CL_BlasterParticles
+
+ Wall impact puffs
+ ===============
+ */
+ static void BlasterParticles(float[] org, float[] dir) {
+ int i, j;
+ cparticle_t p;
+ float d;
+ int count;
+
+ count = 40;
+ for (i = 0; i < count; i++) {
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+
+ p.time = cl.time;
+ p.color = 0xe0 + (rand() & 7);
+
+ d = rand() & 15;
+ for (j = 0; j < 3; j++) {
+ p.org[j] = org[j] + ((rand() & 7) - 4) + d * dir[j];
+ p.vel[j] = dir[j] * 30 + crand() * 40;
+ }
+
+ p.accel[0] = p.accel[1] = 0;
+ p.accel[2] = -PARTICLE_GRAVITY;
+ p.alpha = 1.0f;
+
+ p.alphavel = -1.0f / (0.5f + frand() * 0.3f);
+ }
+ }
+
+ /*
+ ===============
+ CL_BlasterTrail
+
+ ===============
+ */
+ static void BlasterTrail(float[] start, float[] end) {
+ float[] move = new float[3];
+ float[] vec = new float[3];
+ float len;
+ int j;
+ cparticle_t p;
+ int dec;
+
+ VectorCopy(start, move);
+ VectorSubtract(end, start, vec);
+ len = VectorNormalize(vec);
+
+ dec = 5;
+ VectorScale(vec, 5, vec);
+
+ // FIXME: this is a really silly way to have a loop
+ while (len > 0) {
+ len -= dec;
+
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+ VectorClear(p.accel);
+
+ p.time = cl.time;
+
+ p.alpha = 1.0f;
+ p.alphavel = -1.0f / (0.3f + frand() * 0.2f);
+ p.color = 0xe0;
+ for (j = 0; j < 3; j++) {
+ p.org[j] = move[j] + crand();
+ p.vel[j] = crand() * 5;
+ p.accel[j] = 0;
+ }
+
+ VectorAdd(move, vec, move);
+ }
+ }
+
+ /*
+ ===============
+ CL_QuadTrail
+
+ ===============
+ */
+ static void QuadTrail(float[] start, float[] end) {
+ float[] move = new float[3];
+ float[] vec = new float[3];
+ float len;
+ int j;
+ cparticle_t p;
+ int dec;
+
+ VectorCopy(start, move);
+ VectorSubtract(end, start, vec);
+ len = VectorNormalize(vec);
+
+ dec = 5;
+ VectorScale(vec, 5, vec);
+
+ while (len > 0) {
+ len -= dec;
+
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+ VectorClear(p.accel);
+
+ p.time = cl.time;
+
+ p.alpha = 1.0f;
+ p.alphavel = -1.0f / (0.8f + frand() * 0.2f);
+ p.color = 115;
+ for (j = 0; j < 3; j++) {
+ p.org[j] = move[j] + crand() * 16;
+ p.vel[j] = crand() * 5;
+ p.accel[j] = 0;
+ }
+
+ VectorAdd(move, vec, move);
+ }
+ }
+
+ /*
+ ===============
+ CL_FlagTrail
+
+ ===============
+ */
+ static void FlagTrail(float[] start, float[] end, float color) {
+ float[] move = new float[3];
+ float[] vec = new float[3];
+ float len;
+ int j;
+ cparticle_t p;
+ int dec;
+
+ VectorCopy(start, move);
+ VectorSubtract(end, start, vec);
+ len = VectorNormalize(vec);
+
+ dec = 5;
+ VectorScale(vec, 5, vec);
+
+ while (len > 0) {
+ len -= dec;
+
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+ VectorClear(p.accel);
+
+ p.time = cl.time;
+
+ p.alpha = 1.0f;
+ p.alphavel = -1.0f / (0.8f + frand() * 0.2f);
+ p.color = color;
+ for (j = 0; j < 3; j++) {
+ p.org[j] = move[j] + crand() * 16;
+ p.vel[j] = crand() * 5;
+ p.accel[j] = 0;
+ }
+
+ VectorAdd(move, vec, move);
+ }
+ }
+
+ /*
+ ===============
+ CL_DiminishingTrail
+
+ ===============
+ */
+ static void DiminishingTrail(float[] start, float[] end, centity_t old, int flags) {
+ float[] move = new float[3];
+ float[] vec = new float[3];
+ float len;
+ int j;
+ cparticle_t p;
+ float dec;
+ float orgscale;
+ float velscale;
+
+ VectorCopy(start, move);
+ VectorSubtract(end, start, vec);
+ len = VectorNormalize(vec);
+
+ dec = 0.5f;
+ VectorScale(vec, dec, vec);
+
+ if (old.trailcount > 900) {
+ orgscale = 4;
+ velscale = 15;
+ } else if (old.trailcount > 800) {
+ orgscale = 2;
+ velscale = 10;
+ } else {
+ orgscale = 1;
+ velscale = 5;
+ }
+
+ while (len > 0) {
+ len -= dec;
+
+ if (free_particles == null)
+ return;
+
+ // drop less particles as it flies
+ if ((rand() & 1023) < old.trailcount) {
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+ VectorClear(p.accel);
+
+ p.time = cl.time;
+
+ if ((flags & EF_GIB) != 0) {
+ p.alpha = 1.0f;
+ p.alphavel = -1.0f / (1.0f + frand() * 0.4f);
+ p.color = 0xe8 + (rand() & 7);
+ for (j = 0; j < 3; j++) {
+ p.org[j] = move[j] + crand() * orgscale;
+ p.vel[j] = crand() * velscale;
+ p.accel[j] = 0;
+ }
+ p.vel[2] -= PARTICLE_GRAVITY;
+ } else if ((flags & EF_GREENGIB) != 0) {
+ p.alpha = 1.0f;
+ p.alphavel = -1.0f / (1.0f + frand() * 0.4f);
+ p.color = 0xdb + (rand() & 7);
+ for (j = 0; j < 3; j++) {
+ p.org[j] = move[j] + crand() * orgscale;
+ p.vel[j] = crand() * velscale;
+ p.accel[j] = 0;
+ }
+ p.vel[2] -= PARTICLE_GRAVITY;
+ } else {
+ p.alpha = 1.0f;
+ p.alphavel = -1.0f / (1.0f + frand() * 0.2f);
+ p.color = 4 + (rand() & 7);
+ for (j = 0; j < 3; j++) {
+ p.org[j] = move[j] + crand() * orgscale;
+ p.vel[j] = crand() * velscale;
+ }
+ p.accel[2] = 20;
+ }
+ }
+
+ old.trailcount -= 5;
+ if (old.trailcount < 100)
+ old.trailcount = 100;
+ VectorAdd(move, vec, move);
+ }
+ }
+
+ /*
+ ===============
+ CL_RocketTrail
+
+ ===============
+ */
+ static void RocketTrail(float[] start, float[] end, centity_t old) {
+ float[] move = new float[3];
+ float[] vec = new float[3];
+ float len;
+ int j;
+ cparticle_t p;
+ float dec;
+
+ // smoke
+ CL.DiminishingTrail(start, end, old, EF_ROCKET);
+
+ // fire
+ VectorCopy(start, move);
+ VectorSubtract(end, start, vec);
+ len = VectorNormalize(vec);
+
+ dec = 1;
+ VectorScale(vec, dec, vec);
+
+ while (len > 0) {
+ len -= dec;
+
+ if (free_particles == null)
+ return;
+
+ if ((rand() & 7) == 0) {
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+
+ VectorClear(p.accel);
+ p.time = cl.time;
+
+ p.alpha = 1.0f;
+ p.alphavel = -1.0f / (1.0f + frand() * 0.2f);
+ p.color = 0xdc + (rand() & 3);
+ for (j = 0; j < 3; j++) {
+ p.org[j] = move[j] + crand() * 5;
+ p.vel[j] = crand() * 20;
+ }
+ p.accel[2] = -PARTICLE_GRAVITY;
+ }
+ VectorAdd(move, vec, move);
+ }
+ }
+
+ /*
+ ===============
+ CL_RailTrail
+
+ ===============
+ */
+ static void RailTrail(float[] start, float[] end) {
+ float[] move = new float[3];
+ float[] vec = new float[3];
+ float len;
+ int j;
+ cparticle_t p;
+ float dec;
+ float[] right = new float[3];
+ float[] up = new float[3];
+ int i;
+ float d, c, s;
+ float[] dir = new float[3];
+ byte clr = 0x74;
+
+ VectorCopy(start, move);
+ VectorSubtract(end, start, vec);
+ len = VectorNormalize(vec);
+
+ MakeNormalVectors(vec, right, up);
+
+ for (i = 0; i < len; i++) {
+ if (free_particles == null)
+ return;
+
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+
+ p.time = cl.time;
+ VectorClear(p.accel);
+
+ d = i * 0.1f;
+ c = (float)Math.cos(d);
+ s = (float)Math.sin(d);
+
+ VectorScale(right, c, dir);
+ VectorMA(dir, s, up, dir);
+
+ p.alpha = 1.0f;
+ p.alphavel = -1.0f / (1.0f + frand() * 0.2f);
+ p.color = clr + (rand() & 7);
+ for (j = 0; j < 3; j++) {
+ p.org[j] = move[j] + dir[j] * 3;
+ p.vel[j] = dir[j] * 6;
+ }
+
+ VectorAdd(move, vec, move);
+ }
+
+ dec = 0.75f;
+ VectorScale(vec, dec, vec);
+ VectorCopy(start, move);
+
+ while (len > 0) {
+ len -= dec;
+
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+
+ p.time = cl.time;
+ VectorClear(p.accel);
+
+ p.alpha = 1.0f;
+ p.alphavel = -1.0f / (0.6f + frand() * 0.2f);
+ p.color = 0x0 + rand() & 15;
+
+ for (j = 0; j < 3; j++) {
+ p.org[j] = move[j] + crand() * 3;
+ p.vel[j] = crand() * 3;
+ p.accel[j] = 0;
+ }
+
+ VectorAdd(move, vec, move);
+ }
+ }
+
+ // RAFAEL
+ /*
+ ===============
+ CL_IonripperTrail
+ ===============
+ */
+ static void IonripperTrail(float[] start, float[] ent) {
+ float[] move = new float[3];
+ float[] vec = new float[3];
+ float len;
+ int j;
+ cparticle_t p;
+ int dec;
+ int left = 0;
+
+ VectorCopy(start, move);
+ VectorSubtract(ent, start, vec);
+ len = VectorNormalize(vec);
+
+ dec = 5;
+ VectorScale(vec, 5, vec);
+
+ while (len > 0) {
+ len -= dec;
+
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+ VectorClear(p.accel);
+
+ p.time = cl.time;
+ p.alpha = 0.5f;
+ p.alphavel = -1.0f / (0.3f + frand() * 0.2f);
+ p.color = 0xe4 + (rand() & 3);
+
+ for (j = 0; j < 3; j++) {
+ p.org[j] = move[j];
+ p.accel[j] = 0;
+ }
+ if (left != 0) {
+ left = 0;
+ p.vel[0] = 10;
+ } else {
+ left = 1;
+ p.vel[0] = -10;
+ }
+
+ p.vel[1] = 0;
+ p.vel[2] = 0;
+
+ VectorAdd(move, vec, move);
+ }
+ }
+
+ /*
+ ===============
+ CL_BubbleTrail
+
+ ===============
+ */
+ static void BubbleTrail(float[] start, float[] end) {
+ float[] move = new float[3];
+ float[] vec = new float[3];
+ float len;
+ int i, j;
+ cparticle_t p;
+ float dec;
+
+ VectorCopy(start, move);
+ VectorSubtract(end, start, vec);
+ len = VectorNormalize(vec);
+
+ dec = 32;
+ VectorScale(vec, dec, vec);
+
+ for (i = 0; i < len; i += dec) {
+ if (free_particles == null)
+ return;
+
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+
+ VectorClear(p.accel);
+ p.time = cl.time;
+
+ p.alpha = 1.0f;
+ p.alphavel = -1.0f / (1.0f + frand() * 0.2f);
+ p.color = 4 + (rand() & 7);
+ for (j = 0; j < 3; j++) {
+ p.org[j] = move[j] + crand() * 2;
+ p.vel[j] = crand() * 5;
+ }
+ p.vel[2] += 6;
+
+ VectorAdd(move, vec, move);
+ }
+ }
+
+ /*
+ ===============
+ CL_FlyParticles
+ ===============
+ */
+ private static final int BEAMLENGTH = 16;
+ static void FlyParticles (float [] origin, int count)
+ {
+ int i;
+ cparticle_t p;
+ float angle;
+ float sr, sp, sy, cr, cp, cy;
+ float [] forward= new float[3];
+ float dist = 64;
+ float ltime;
+
+
+ if (count > NUMVERTEXNORMALS)
+ count = NUMVERTEXNORMALS;
+
+ if (avelocities[0][0] == 0.0f)
+ {
+ for (i=0 ; i<NUMVERTEXNORMALS ; i++) {
+ avelocities[i][0] = (rand()&255) * 0.01f;
+ avelocities[i][1] = (rand()&255) * 0.01f;
+ avelocities[i][2] = (rand()&255) * 0.01f;
+ }
+ }
+
+
+ ltime = cl.time / 1000.0f;
+ for (i=0 ; i<count ; i+=2)
+ {
+ angle = ltime * avelocities[i][0];
+ sy = (float)Math.sin(angle);
+ cy = (float)Math.cos(angle);
+ angle = ltime * avelocities[i][1];
+ sp = (float)Math.sin(angle);
+ cp = (float)Math.cos(angle);
+ angle = ltime * avelocities[i][2];
+ sr = (float)Math.sin(angle);
+ cr = (float)Math.cos(angle);
+
+ forward[0] = cp*cy;
+ forward[1] = cp*sy;
+ forward[2] = -sp;
+
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+
+ p.time = cl.time;
+
+ dist = (float)Math.sin(ltime + i)*64;
+ p.org[0] = origin[0] + bytedirs[i][0]*dist + forward[0]*BEAMLENGTH;
+ p.org[1] = origin[1] + bytedirs[i][1]*dist + forward[1]*BEAMLENGTH;
+ p.org[2] = origin[2] + bytedirs[i][2]*dist + forward[2]*BEAMLENGTH;
+
+ VectorClear (p.vel);
+ VectorClear (p.accel);
+
+ p.color = 0;
+ //p.colorvel = 0;
+
+ p.alpha = 1;
+ p.alphavel = -100;
+ }
+ }
+
+ static void FlyEffect(centity_t ent, float[] origin) {
+ int n;
+ int count;
+ int starttime;
+
+ if (ent.fly_stoptime < cl.time) {
+ starttime = cl.time;
+ ent.fly_stoptime = cl.time + 60000;
+ } else {
+ starttime = ent.fly_stoptime - 60000;
+ }
+
+ n = cl.time - starttime;
+ if (n < 20000)
+ count = (int) ((n * 162) / 20000.0);
+ else {
+ n = ent.fly_stoptime - cl.time;
+ if (n < 20000)
+ count = (int) ((n * 162) / 20000.0);
+ else
+ count = 162;
+ }
+
+ CL.FlyParticles(origin, count);
+ }
+
+ /*
+ ===============
+ CL_BfgParticles
+ ===============
+ */
+ //#define BEAMLENGTH 16
+ static void BfgParticles(entity_t ent) {
+ int i;
+ cparticle_t p;
+ float angle;
+ float sr, sp, sy, cr, cp, cy;
+ float[] forward = new float[3];
+ float dist = 64;
+ float[] v = new float[3];
+ float ltime;
+
+ if (avelocities[0][0] == 0.0f) {
+ for (i = 0; i < NUMVERTEXNORMALS; i++) {
+ avelocities[i][0] = (rand() & 255) * 0.01f;
+ avelocities[i][1] = (rand() & 255) * 0.01f;
+ avelocities[i][2] = (rand() & 255) * 0.01f;
+ }
+ }
+
+ ltime = cl.time / 1000.0f;
+ for (i = 0; i < NUMVERTEXNORMALS; i++) {
+ angle = ltime * avelocities[i][0];
+ sy = (float)Math.sin(angle);
+ cy = (float)Math.cos(angle);
+ angle = ltime * avelocities[i][1];
+ sp = (float)Math.sin(angle);
+ cp = (float)Math.cos(angle);
+ angle = ltime * avelocities[i][2];
+ sr = (float)Math.sin(angle);
+ cr = (float)Math.cos(angle);
+
+ forward[0] = cp * cy;
+ forward[1] = cp * sy;
+ forward[2] = -sp;
+
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+
+ p.time = cl.time;
+
+ dist = (float) (Math.sin(ltime + i) * 64);
+ p.org[0] = ent.origin[0] + bytedirs[i][0] * dist + forward[0] * BEAMLENGTH;
+ p.org[1] = ent.origin[1] + bytedirs[i][1] * dist + forward[1] * BEAMLENGTH;
+ p.org[2] = ent.origin[2] + bytedirs[i][2] * dist + forward[2] * BEAMLENGTH;
+
+ VectorClear(p.vel);
+ VectorClear(p.accel);
+
+ VectorSubtract(p.org, ent.origin, v);
+ dist = VectorLength(v) / 90.0f;
+ p.color = (float)Math.floor(0xd0 + dist * 7);
+ //p.colorvel = 0;
+
+ p.alpha = 1.0f - dist;
+ p.alphavel = -100;
+ }
+ }
+
+ /*
+ ===============
+ CL_TrapParticles
+ ===============
+ */
+ // RAFAEL
+ static void TrapParticles(entity_t ent) {
+ float[] move = new float[3];
+ float[] vec = new float[3];
+ float[] start = new float[3];
+ float[] end = new float[3];
+ float len;
+ int j;
+ cparticle_t p;
+ int dec;
+
+ ent.origin[2] -= 14;
+ VectorCopy(ent.origin, start);
+ VectorCopy(ent.origin, end);
+ end[2] += 64;
+
+ VectorCopy(start, move);
+ VectorSubtract(end, start, vec);
+ len = VectorNormalize(vec);
+
+ dec = 5;
+ VectorScale(vec, 5, vec);
+
+ // FIXME: this is a really silly way to have a loop
+ while (len > 0) {
+ len -= dec;
+
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+ VectorClear(p.accel);
+
+ p.time = cl.time;
+
+ p.alpha = 1.0f;
+ p.alphavel = -1.0f / (0.3f + frand() * 0.2f);
+ p.color = 0xe0;
+ for (j = 0; j < 3; j++) {
+ p.org[j] = move[j] + crand();
+ p.vel[j] = crand() * 15;
+ p.accel[j] = 0;
+ }
+ p.accel[2] = PARTICLE_GRAVITY;
+
+ VectorAdd(move, vec, move);
+ }
+
+ int i, k;
+ //cparticle_t p;
+ float vel;
+ float[] dir = new float[3];
+ float[] org = new float[3];
+
+ ent.origin[2] += 14;
+ VectorCopy(ent.origin, org);
+
+ for (i = -2; i <= 2; i += 4)
+ for (j = -2; j <= 2; j += 4)
+ for (k = -2; k <= 4; k += 4) {
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+
+ p.time = cl.time;
+ p.color = 0xe0 + (rand() & 3);
+
+ p.alpha = 1.0f;
+ p.alphavel = -1.0f / (0.3f + (rand() & 7) * 0.02f);
+
+ p.org[0] = org[0] + i + ((rand() & 23) * crand());
+ p.org[1] = org[1] + j + ((rand() & 23) * crand());
+ p.org[2] = org[2] + k + ((rand() & 23) * crand());
+
+ dir[0] = j * 8;
+ dir[1] = i * 8;
+ dir[2] = k * 8;
+
+ VectorNormalize(dir);
+ vel = 50 + rand() & 63;
+ VectorScale(dir, vel, p.vel);
+
+ p.accel[0] = p.accel[1] = 0;
+ p.accel[2] = -PARTICLE_GRAVITY;
+ }
+
+ }
+
+
+ /*
+ ===============
+ CL_BFGExplosionParticles
+ ===============
+ */
+ // FIXME combined with CL_ExplosionParticles
+ static void BFGExplosionParticles(float[] org) {
+ int i, j;
+ cparticle_t p;
+
+ for (i = 0; i < 256; i++) {
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+
+ p.time = cl.time;
+ p.color = 0xd0 + (rand() & 7);
+
+ for (j = 0; j < 3; j++) {
+ p.org[j] = org[j] + ((rand() % 32) - 16);
+ p.vel[j] = (rand() % 384) - 192;
+ }
+
+ p.accel[0] = p.accel[1] = 0;
+ p.accel[2] = -PARTICLE_GRAVITY;
+ p.alpha = 1.0f;
+
+ p.alphavel = -0.8f / (0.5f + frand() * 0.3f);
+ }
+ }
+
+ /*
+ ===============
+ CL_TeleportParticles
+
+ ===============
+ */
+ static void TeleportParticles(float[] org) {
+ int i, j, k;
+ cparticle_t p;
+ float vel;
+ float[] dir = new float[3];
+
+ for (i = -16; i <= 16; i += 4)
+ for (j = -16; j <= 16; j += 4)
+ for (k = -16; k <= 32; k += 4) {
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+
+ p.time = cl.time;
+ p.color = 7 + (rand() & 7);
+
+ p.alpha = 1.0f;
+ p.alphavel = -1.0f / (0.3f + (rand() & 7) * 0.02f);
+
+ p.org[0] = org[0] + i + (rand() & 3);
+ p.org[1] = org[1] + j + (rand() & 3);
+ p.org[2] = org[2] + k + (rand() & 3);
+
+ dir[0] = j * 8;
+ dir[1] = i * 8;
+ dir[2] = k * 8;
+
+ VectorNormalize(dir);
+ vel = 50 + (rand() & 63);
+ VectorScale(dir, vel, p.vel);
+
+ p.accel[0] = p.accel[1] = 0;
+ p.accel[2] = -PARTICLE_GRAVITY;
+ }
+ }
+
+ /*
+ ===============
+ CL_AddParticles
+ ===============
+ */
+ static void AddParticles() {
+ cparticle_t p, next;
+ float alpha;
+ float time = 0.0f;
+ float time2;
+ float[] org = new float[3];
+ int color;
+ cparticle_t active, tail;
+
+ active = null;
+ tail = null;
+
+ for (p = active_particles; p != null; p = next) {
+ next = p.next;
+
+ // PMM - added INSTANT_PARTICLE handling for heat beam
+ if (p.alphavel != INSTANT_PARTICLE) {
+ time = (cl.time - p.time) * 0.001f;
+ alpha = p.alpha + time * p.alphavel;
+ if (alpha <= 0) { // faded out
+ p.next = free_particles;
+ free_particles = p;
+ continue;
+ }
+ } else {
+ alpha = p.alpha;
+ }
+
+ p.next = null;
+ if (tail == null)
+ active = tail = p;
+ else {
+ tail.next = p;
+ tail = p;
+ }
+
+ if (alpha > 1.0)
+ alpha = 1;
+ color = (int)p.color;
+
+ time2 = time * time;
+
+ org[0] = p.org[0] + p.vel[0] * time + p.accel[0] * time2;
+ org[1] = p.org[1] + p.vel[1] * time + p.accel[1] * time2;
+ org[2] = p.org[2] + p.vel[2] * time + p.accel[2] * time2;
+
+ V.AddParticle(org, color, alpha);
+ // PMM
+ if (p.alphavel == INSTANT_PARTICLE) {
+ p.alphavel = 0.0f;
+ p.alpha = 0.0f;
+ }
+ }
+
+ active_particles = active;
+ }
+
+ /*
+ ==============
+ CL_EntityEvent
+
+ An entity has just been parsed that has an event value
+
+ the female events are there for backwards compatability
+ ==============
+ */
+ static void EntityEvent(entity_state_t ent) {
+ switch (ent.event) {
+ case EV_ITEM_RESPAWN :
+ S.StartSound(null, ent.number, CHAN_WEAPON, S.RegisterSound("items/respawn1.wav"), 1, ATTN_IDLE, 0);
+ CL.ItemRespawnParticles(ent.origin);
+ break;
+ case EV_PLAYER_TELEPORT :
+ S.StartSound(null, ent.number, CHAN_WEAPON, S.RegisterSound("misc/tele1.wav"), 1, ATTN_IDLE, 0);
+ CL.TeleportParticles(ent.origin);
+ break;
+ case EV_FOOTSTEP :
+ if (cl_footsteps.value != 0.0f)
+ S.StartSound(null, ent.number, CHAN_BODY, cl_sfx_footsteps[rand() & 3], 1, ATTN_NORM, 0);
+ break;
+ case EV_FALLSHORT :
+ S.StartSound(null, ent.number, CHAN_AUTO, S.RegisterSound("player/land1.wav"), 1, ATTN_NORM, 0);
+ break;
+ case EV_FALL :
+ S.StartSound(null, ent.number, CHAN_AUTO, S.RegisterSound("*fall2.wav"), 1, ATTN_NORM, 0);
+ break;
+ case EV_FALLFAR :
+ S.StartSound(null, ent.number, CHAN_AUTO, S.RegisterSound("*fall1.wav"), 1, ATTN_NORM, 0);
+ break;
+ }
+ }
+
+ /*
+ ==============
+ CL_ClearEffects
+
+ ==============
+ */
+ static void ClearEffects() {
+ CL.ClearParticles();
+ CL.ClearDlights();
+ CL.ClearLightStyles();
+ }
+
+}
diff --git a/src/jake2/client/CL_input.java b/src/jake2/client/CL_input.java
new file mode 100644
index 0000000..1b6233c
--- /dev/null
+++ b/src/jake2/client/CL_input.java
@@ -0,0 +1,564 @@
+/*
+ * CL_input.java
+ * Copyright (C) 2004
+ *
+ * $Id: CL_input.java,v 1.1 2004-07-07 19:58:37 hzi Exp $
+ */
+/*
+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.
+
+*/
+package jake2.client;
+
+import jake2.game.*;
+import jake2.game.Cmd;
+import jake2.game.usercmd_t;
+import jake2.qcommon.*;
+import jake2.qcommon.Cvar;
+import jake2.qcommon.xcommand_t;
+import jake2.sys.IN;
+
+/**
+ * CL_input
+ */
+public class CL_input extends CL_ents {
+
+ static long frame_msec;
+ static long old_sys_frame_time;
+
+ static cvar_t cl_nodelta;
+
+ /*
+ ===============================================================================
+
+ KEY BUTTONS
+
+ Continuous button event tracking is complicated by the fact that two different
+ input sources (say, mouse button 1 and the control key) can both press the
+ same button, but the button should only be released when both of the
+ pressing key have been released.
+
+ When a key event issues a button command (+forward, +attack, etc), it appends
+ its key number as a parameter to the command so it can be matched up with
+ the release.
+
+ state bit 0 is the current state of the key
+ state bit 1 is edge triggered on the up to down transition
+ state bit 2 is edge triggered on the down to up transition
+
+
+ Key_Event (int key, qboolean down, unsigned time);
+
+ +mlook src time
+
+ ===============================================================================
+ */
+
+ static kbutton_t in_klook = new kbutton_t();
+ static kbutton_t in_left = new kbutton_t();
+ static kbutton_t in_right = new kbutton_t();
+ static kbutton_t in_forward = new kbutton_t();
+ static kbutton_t in_back = new kbutton_t();
+ static kbutton_t in_lookup = new kbutton_t();
+ static kbutton_t in_lookdown = new kbutton_t();
+ static kbutton_t in_moveleft = new kbutton_t();
+ static kbutton_t in_moveright = new kbutton_t();
+ public static kbutton_t in_strafe = new kbutton_t();
+ static kbutton_t in_speed = new kbutton_t();
+ static kbutton_t in_use = new kbutton_t();
+ static kbutton_t in_attack = new kbutton_t();
+ static kbutton_t in_up = new kbutton_t();
+ static kbutton_t in_down = new kbutton_t();
+
+ static int in_impulse;
+
+ static void KeyDown(kbutton_t b) {
+ int k;
+ String c;
+
+ c = Cmd.Argv(1);
+ if (c.length() > 0)
+ k = Integer.parseInt(c);
+ else
+ k = -1; // typed manually at the console for continuous down
+
+ if (k == b.down[0] || k == b.down[1])
+ return; // repeating key
+
+ if (b.down[0] == 0)
+ b.down[0] = k;
+ else if (b.down[1] == 0)
+ b.down[1] = k;
+ else {
+ Com.Printf("Three keys down for a button!\n");
+ return;
+ }
+
+ if ((b.state & 1) != 0)
+ return; // still down
+
+ // save timestamp
+ c = Cmd.Argv(2);
+ b.downtime = Long.parseLong(c);
+ if (b.downtime == 0)
+ b.downtime = sys_frame_time - 100;
+
+ b.state |= 3; // down + impulse down
+ }
+
+ static void KeyUp(kbutton_t b) {
+ int k;
+ String c;
+ long uptime;
+
+ c = Cmd.Argv(1);
+ if (c.length() > 0)
+ k = Integer.parseInt(c);
+ else {
+ // typed manually at the console, assume for unsticking, so clear all
+ b.down[0] = b.down[1] = 0;
+ b.state = 4; // impulse up
+ return;
+ }
+
+ if (b.down[0] == k)
+ b.down[0] = 0;
+ else if (b.down[1] == k)
+ b.down[1] = 0;
+ else
+ return; // key up without coresponding down (menu pass through)
+ if (b.down[0] != 0 || b.down[1] != 0)
+ return; // some other key is still holding it down
+
+ if ((b.state & 1) == 0)
+ return; // still up (this should not happen)
+
+ // save timestamp
+ c = Cmd.Argv(2);
+ uptime = Long.parseLong(c);
+ if (uptime != 0)
+ b.msec += uptime - b.downtime;
+ else
+ b.msec += 10;
+
+ b.state &= ~1; // now up
+ b.state |= 4; // impulse up
+ }
+
+ static void IN_KLookDown() {KeyDown(in_klook);}
+ static void IN_KLookUp() {KeyUp(in_klook);}
+ static void IN_UpDown() {KeyDown(in_up);}
+ static void IN_UpUp() {KeyUp(in_up);}
+ static void IN_DownDown() {KeyDown(in_down);}
+ static void IN_DownUp() {KeyUp(in_down);}
+ static void IN_LeftDown() {KeyDown(in_left);}
+ static void IN_LeftUp() {KeyUp(in_left);}
+ static void IN_RightDown() {KeyDown(in_right);}
+ static void IN_RightUp() {KeyUp(in_right);}
+ static void IN_ForwardDown() {KeyDown(in_forward);}
+ static void IN_ForwardUp() {KeyUp(in_forward);}
+ static void IN_BackDown() {KeyDown(in_back);}
+ static void IN_BackUp() {KeyUp(in_back);}
+ static void IN_LookupDown() {KeyDown(in_lookup);}
+ static void IN_LookupUp() {KeyUp(in_lookup);}
+ static void IN_LookdownDown() {KeyDown(in_lookdown);}
+ static void IN_LookdownUp() {KeyUp(in_lookdown);}
+ static void IN_MoveleftDown() {KeyDown(in_moveleft);}
+ static void IN_MoveleftUp() {KeyUp(in_moveleft);}
+ static void IN_MoverightDown() {KeyDown(in_moveright);}
+ static void IN_MoverightUp() {KeyUp(in_moveright);}
+
+ static void IN_SpeedDown() {KeyDown(in_speed);}
+ static void IN_SpeedUp() {KeyUp(in_speed);}
+ static void IN_StrafeDown() {KeyDown(in_strafe);}
+ static void IN_StrafeUp() {KeyUp(in_strafe);}
+
+ static void IN_AttackDown() {KeyDown(in_attack);}
+ static void IN_AttackUp() {KeyUp(in_attack);}
+
+ static void IN_UseDown () {KeyDown(in_use);}
+ static void IN_UseUp () {KeyUp(in_use);}
+
+ static void IN_Impulse () {in_impulse=Integer.parseInt(Cmd.Argv(1));}
+
+ /*
+ ===============
+ CL_KeyState
+
+ Returns the fraction of the frame that the key was down
+ ===============
+ */
+ static float KeyState(kbutton_t key) {
+ float val;
+ long msec;
+
+ key.state &= 1; // clear impulses
+
+ msec = key.msec;
+ key.msec = 0;
+
+ if (key.state != 0) {
+ // still down
+ msec += sys_frame_time - key.downtime;
+ key.downtime = sys_frame_time;
+ }
+
+ val = (float)msec / frame_msec;
+ if (val < 0)
+ val = 0;
+ if (val > 1)
+ val = 1;
+
+ return val;
+ }
+
+// ==========================================================================
+
+ /*
+ ================
+ CL_AdjustAngles
+
+ Moves the local angle positions
+ ================
+ */
+ static void AdjustAngles() {
+ float speed;
+ float up, down;
+
+ if ((in_speed.state & 1) != 0)
+ speed = cls.frametime * cl_anglespeedkey.value;
+ else
+ speed = cls.frametime;
+
+ if ((in_strafe.state & 1) == 0) {
+ cl.viewangles[YAW] -= speed * cl_yawspeed.value * CL.KeyState(in_right);
+ cl.viewangles[YAW] += speed * cl_yawspeed.value * CL.KeyState(in_left);
+ }
+ if ((in_klook.state & 1) != 0) {
+ cl.viewangles[PITCH] -= speed * cl_pitchspeed.value * CL.KeyState(in_forward);
+ cl.viewangles[PITCH] += speed * cl_pitchspeed.value * CL.KeyState(in_back);
+ }
+
+ up = CL.KeyState(in_lookup);
+ down = CL.KeyState(in_lookdown);
+
+ cl.viewangles[PITCH] -= speed * cl_pitchspeed.value * up;
+ cl.viewangles[PITCH] += speed * cl_pitchspeed.value * down;
+ }
+
+ /*
+ ================
+ CL_BaseMove
+
+ Send the intended movement message to the server
+ ================
+ */
+ static void BaseMove(usercmd_t cmd) {
+ CL.AdjustAngles();
+
+ //memset (cmd, 0, sizeof(*cmd));
+ cmd.reset();
+
+ VectorCopy(cl.viewangles, cmd.angles);
+ if ((in_strafe.state & 1) != 0) {
+ cmd.sidemove += cl_sidespeed.value * CL.KeyState(in_right);
+ cmd.sidemove -= cl_sidespeed.value * CL.KeyState(in_left);
+ }
+
+ cmd.sidemove += cl_sidespeed.value * CL.KeyState(in_moveright);
+ cmd.sidemove -= cl_sidespeed.value * CL.KeyState(in_moveleft);
+
+ cmd.upmove += cl_upspeed.value * CL.KeyState(in_up);
+ cmd.upmove -= cl_upspeed.value * CL.KeyState(in_down);
+
+ if ((in_klook.state & 1) == 0) {
+ cmd.forwardmove += cl_forwardspeed.value * CL.KeyState(in_forward);
+ cmd.forwardmove -= cl_forwardspeed.value * CL.KeyState(in_back);
+ }
+
+ //
+ // adjust for speed key / running
+ //
+ if (((in_speed.state & 1) ^ (int) (cl_run.value)) != 0) {
+ cmd.forwardmove *= 2;
+ cmd.sidemove *= 2;
+ cmd.upmove *= 2;
+ }
+
+ }
+
+ static void ClampPitch() {
+
+ float pitch;
+
+ pitch = SHORT2ANGLE(cl.frame.playerstate.pmove.delta_angles[PITCH]);
+ if (pitch > 180)
+ pitch -= 360;
+
+ if (cl.viewangles[PITCH] + pitch < -360)
+ cl.viewangles[PITCH] += 360; // wrapped
+ if (cl.viewangles[PITCH] + pitch > 360)
+ cl.viewangles[PITCH] -= 360; // wrapped
+
+ if (cl.viewangles[PITCH] + pitch > 89)
+ cl.viewangles[PITCH] = 89 - pitch;
+ if (cl.viewangles[PITCH] + pitch < -89)
+ cl.viewangles[PITCH] = -89 - pitch;
+ }
+
+ /*
+ ==============
+ CL_FinishMove
+ ==============
+ */
+ static void FinishMove(usercmd_t cmd) {
+ int ms;
+ int i;
+
+ //
+ // figure button bits
+ //
+ if ((in_attack.state & 3) != 0)
+ cmd.buttons |= BUTTON_ATTACK;
+ in_attack.state &= ~2;
+
+ if ((in_use.state & 3) != 0)
+ cmd.buttons |= BUTTON_USE;
+ in_use.state &= ~2;
+
+ if (anykeydown != 0 && cls.key_dest == key_game)
+ cmd.buttons |= BUTTON_ANY;
+
+ // send milliseconds of time to apply the move
+ ms = (int)(cls.frametime * 1000);
+ if (ms > 250)
+ ms = 100; // time was unreasonable
+ cmd.msec = (byte)ms;
+
+ CL.ClampPitch();
+ for (i = 0; i < 3; i++)
+ cmd.angles[i] = (short)ANGLE2SHORT(cl.viewangles[i]);
+
+ cmd.impulse = (byte)in_impulse;
+ in_impulse = 0;
+
+ // send the ambient light level at the player's current position
+ cmd.lightlevel = (byte)cl_lightlevel.value;
+ }
+
+ /*
+ =================
+ CL_CreateCmd
+ =================
+ */
+ static usercmd_t CreateCmd() {
+ usercmd_t cmd = new usercmd_t();
+
+ frame_msec = sys_frame_time - old_sys_frame_time;
+ if (frame_msec < 1)
+ frame_msec = 1;
+ if (frame_msec > 200)
+ frame_msec = 200;
+
+ // get basic movement from keyboard
+ CL.BaseMove(cmd);
+
+ // allow mice or other external controllers to add to the move
+ IN.Move(cmd);
+
+ CL.FinishMove(cmd);
+
+ old_sys_frame_time = sys_frame_time;
+
+ return cmd;
+ }
+
+ /*
+ ============
+ CL_InitInput
+ ============
+ */
+ static void InitInput() {
+ Cmd.AddCommand("centerview", new xcommand_t() {
+ public void execute() {IN.CenterView();}});
+
+ Cmd.AddCommand("+moveup", new xcommand_t() {
+ public void execute() {IN_UpDown();}});
+ Cmd.AddCommand("-moveup", new xcommand_t() {
+ public void execute() {IN_UpUp();}});
+ Cmd.AddCommand("+movedown", new xcommand_t() {
+ public void execute() {IN_DownDown();}});
+ Cmd.AddCommand("-movedown", new xcommand_t() {
+ public void execute() {IN_DownUp();}});
+ Cmd.AddCommand("+left", new xcommand_t() {
+ public void execute() {IN_LeftDown();}});
+ Cmd.AddCommand("-left", new xcommand_t() {
+ public void execute() {IN_LeftUp();}});
+ Cmd.AddCommand("+right", new xcommand_t() {
+ public void execute() {IN_RightDown();}});
+ Cmd.AddCommand("-right", new xcommand_t() {
+ public void execute() {IN_RightUp();}});
+ Cmd.AddCommand("+forward", new xcommand_t() {
+ public void execute() {IN_ForwardDown();}});
+ Cmd.AddCommand("-forward", new xcommand_t() {
+ public void execute() {IN_ForwardUp();}});
+ Cmd.AddCommand("+back", new xcommand_t() {
+ public void execute() {IN_BackDown();}});
+ Cmd.AddCommand("-back", new xcommand_t() {
+ public void execute() {IN_BackUp();}});
+ Cmd.AddCommand("+lookup", new xcommand_t() {
+ public void execute() {IN_LookupDown();}});
+ Cmd.AddCommand("-lookup", new xcommand_t() {
+ public void execute() {IN_LookupUp();}});
+ Cmd.AddCommand("+lookdown", new xcommand_t() {
+ public void execute() {IN_LookdownDown();}});
+ Cmd.AddCommand("-lookdown", new xcommand_t() {
+ public void execute() {IN_LookdownUp();}});
+ Cmd.AddCommand("+strafe", new xcommand_t() {
+ public void execute() {IN_StrafeDown();}});
+ Cmd.AddCommand("-strafe", new xcommand_t() {
+ public void execute() {IN_StrafeUp();}});
+ Cmd.AddCommand("+moveleft", new xcommand_t() {
+ public void execute() {IN_MoveleftDown();}});
+ Cmd.AddCommand("-moveleft", new xcommand_t() {
+ public void execute() {IN_MoveleftUp();}});
+ Cmd.AddCommand("+moveright", new xcommand_t() {
+ public void execute() {IN_MoverightDown();}});
+ Cmd.AddCommand("-moveright", new xcommand_t() {
+ public void execute() {IN_MoverightUp();}});
+ Cmd.AddCommand("+speed", new xcommand_t() {
+ public void execute() {IN_SpeedDown();}});
+ Cmd.AddCommand("-speed", new xcommand_t() {
+ public void execute() {IN_SpeedUp();}});
+ Cmd.AddCommand("+attack", new xcommand_t() {
+ public void execute() {IN_AttackDown();}});
+ Cmd.AddCommand("-attack", new xcommand_t() {
+ public void execute() {IN_AttackUp();}});
+ Cmd.AddCommand("+use", new xcommand_t() {
+ public void execute() {IN_UseDown();}});
+ Cmd.AddCommand("-use", new xcommand_t() {
+ public void execute() {IN_UseUp();}});
+ Cmd.AddCommand("impulse", new xcommand_t() {
+ public void execute() {IN_Impulse();}});
+ Cmd.AddCommand("+klook", new xcommand_t() {
+ public void execute() {IN_KLookDown();}});
+ Cmd.AddCommand("-klook", new xcommand_t() {
+ public void execute() {IN_KLookUp();}});
+
+ // TODO nodelta
+ cl_nodelta = Cvar.Get("cl_nodelta", "1",0);
+ }
+
+ /*
+ =================
+ CL_SendCmd
+ =================
+ */
+ static void SendCmd() {
+ sizebuf_t buf = new sizebuf_t();
+ byte[] data = new byte[128];
+ int i;
+ usercmd_t cmd, oldcmd;
+ usercmd_t nullcmd = new usercmd_t();
+ int checksumIndex;
+
+ // build a command even if not connected
+
+ // save this command off for prediction
+ i = cls.netchan.outgoing_sequence & (CMD_BACKUP - 1);
+ cmd = cl.cmds[i];
+ cl.cmd_time[i] = (int)cls.realtime; // for netgraph ping calculation
+
+ cmd.set(CL.CreateCmd());
+
+ cl.cmd.set(cmd);
+
+ if (cls.state == ca_disconnected || cls.state == ca_connecting)
+ return;
+
+ if (cls.state == ca_connected) {
+ if (cls.netchan.message.cursize != 0 || curtime - cls.netchan.last_sent > 1000)
+ Netchan.Transmit(cls.netchan, 0, new byte[0]);
+ return;
+ }
+
+ // send a userinfo update if needed
+ if (userinfo_modified) {
+ CL.FixUpGender();
+ userinfo_modified = false;
+ MSG.WriteByte(cls.netchan.message, clc_userinfo);
+ MSG.WriteString(cls.netchan.message, Cvar.Userinfo());
+ }
+
+ SZ.Init(buf, data, data.length);
+
+ if (cmd.buttons != 0
+ && cl.cinematictime > 0
+ && !cl.attractloop
+ && cls.realtime - cl.cinematictime > 1000) { // skip the rest of the cinematic
+ SCR.FinishCinematic();
+ }
+
+ // begin a client move command
+ MSG.WriteByte(buf, clc_move);
+
+ // save the position for a checksum byte
+ checksumIndex = buf.cursize;
+ MSG.WriteByte(buf, 0);
+
+ // let the server know what the last frame we
+ // got was, so the next message can be delta compressed
+ if (cl_nodelta.value != 0.0f || !cl.frame.valid || cls.demowaiting)
+ MSG.WriteLong(buf, -1); // no compression
+ else
+ MSG.WriteLong(buf, cl.frame.serverframe);
+
+ // send this and the previous cmds in the message, so
+ // if the last packet was dropped, it can be recovered
+ i = (cls.netchan.outgoing_sequence - 2) & (CMD_BACKUP - 1);
+ cmd = cl.cmds[i];
+ //memset (nullcmd, 0, sizeof(nullcmd));
+ nullcmd.reset();
+
+ MSG.WriteDeltaUsercmd(buf, nullcmd, cmd);
+ oldcmd = cmd;
+
+ i = (cls.netchan.outgoing_sequence - 1) & (CMD_BACKUP - 1);
+ cmd = cl.cmds[i];
+
+ MSG.WriteDeltaUsercmd(buf, oldcmd, cmd);
+ oldcmd = cmd;
+
+ i = (cls.netchan.outgoing_sequence) & (CMD_BACKUP - 1);
+ cmd = cl.cmds[i];
+
+ MSG.WriteDeltaUsercmd(buf, oldcmd, cmd);
+
+ // calculate a checksum over the move commands
+ buf.data[checksumIndex] = 0;
+ /*COM_BlockSequenceCRCByte(
+ buf.data + checksumIndex + 1, buf.cursize - checksumIndex - 1,
+ cls.netchan.outgoing_sequence);*/
+
+ //
+ // deliver the message
+ //
+ Netchan.Transmit(cls.netchan, buf.cursize, buf.data);
+ }
+
+}
diff --git a/src/jake2/client/CL_inv.java b/src/jake2/client/CL_inv.java
new file mode 100644
index 0000000..ba219c7
--- /dev/null
+++ b/src/jake2/client/CL_inv.java
@@ -0,0 +1,152 @@
+/*
+ * CL_fx.java
+ * Copyright (C) 2004
+ *
+ * $Id: CL_inv.java,v 1.1 2004-07-07 19:58:37 hzi Exp $
+ */
+/*
+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 31.01.2004 by RST.
+
+package jake2.client;
+
+import jake2.qcommon.Com;
+import jake2.qcommon.MSG;
+import jake2.util.Vargs;
+
+/**
+ * CL_inv
+ */
+public class CL_inv extends CL_newfx {
+
+ /*
+ ================
+ CL_ParseInventory
+ ================
+ */
+ static void ParseInventory() {
+ int i;
+
+ for (i = 0; i < MAX_ITEMS; i++)
+ cl.inventory[i] = MSG.ReadShort(net_message);
+ }
+
+ /*
+ ================
+ Inv_DrawString
+ ================
+ */
+ static void Inv_DrawString(int x, int y, String string) {
+ for (int i = 0; i < string.length(); i++) {
+ re.DrawChar(x, y, string.charAt(i));
+ x += 8;
+ }
+ }
+
+ static void SetStringHighBit(String s) {
+ byte[] b = s.getBytes();
+ for (int i = 0; i < b.length; i++) {
+ b[i] = (byte) (b[i] | 128);
+ }
+ s = new String(b);
+ }
+
+ /*
+ ================
+ CL_DrawInventory
+ ================
+ */
+ static final int DISPLAY_ITEMS = 17;
+
+ static void DrawInventory() {
+ int i, j;
+ int num, selected_num, item;
+ int[] index = new int[MAX_ITEMS];
+ String string;
+ int x, y;
+ String binding;
+ String bind;
+ int selected;
+ int top;
+
+ selected = cl.frame.playerstate.stats[STAT_SELECTED_ITEM];
+
+ num = 0;
+ selected_num = 0;
+ for (i = 0; i < MAX_ITEMS; i++) {
+ if (i == selected)
+ selected_num = num;
+ if (cl.inventory[i] != 0) {
+ index[num] = i;
+ num++;
+ }
+ }
+
+ // determine scroll point
+ top = selected_num - DISPLAY_ITEMS / 2;
+ if (num - top < DISPLAY_ITEMS)
+ top = num - DISPLAY_ITEMS;
+ if (top < 0)
+ top = 0;
+
+ x = (viddef.width - 256) / 2;
+ y = (viddef.height - 240) / 2;
+
+ // repaint everything next frame
+ SCR.DirtyScreen();
+
+ re.DrawPic(x, y + 8, "inventory");
+
+ y += 24;
+ x += 24;
+ Inv_DrawString(x, y, "hotkey ### item");
+ Inv_DrawString(x, y + 8, "------ --- ----");
+ y += 16;
+ for (i = top; i < num && i < top + DISPLAY_ITEMS; i++) {
+ item = index[i];
+ // search for a binding
+ //Com_sprintf (binding, sizeof(binding), "use %s", cl.configstrings[CS_ITEMS+item]);
+ binding = "use " + cl.configstrings[CS_ITEMS + item];
+ bind = "";
+ for (j = 0; j < 256; j++)
+ if (keybindings[j] != null && keybindings[j].equals(binding)) {
+ bind = Key.KeynumToString(j);
+ break;
+ }
+
+ string =
+ Com.sprintf(
+ "%6s %3i %s",
+ new Vargs(3).add(bind).add(cl.inventory[item]).add(cl.configstrings[CS_ITEMS + item]));
+ if (item != selected)
+ SetStringHighBit(string);
+ else // draw a blinky cursor by the selected item
+ {
+ if (((int) (cls.realtime * 10) & 1) != 0)
+ re.DrawChar(x - 8, y, 15);
+ }
+ Inv_DrawString(x, y, string);
+ y += 8;
+ }
+
+ }
+
+}
diff --git a/src/jake2/client/CL_newfx.java b/src/jake2/client/CL_newfx.java
new file mode 100644
index 0000000..bfa1c71
--- /dev/null
+++ b/src/jake2/client/CL_newfx.java
@@ -0,0 +1,1027 @@
+/*
+ * CL_newfx.java
+ * Copyright (C) 2004
+ *
+ * $Id: CL_newfx.java,v 1.1 2004-07-07 19:58:38 hzi Exp $
+ */
+/*
+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 31.01.2004 by RST.
+
+package jake2.client;
+
+
+/**
+ * CL_newfx
+ */
+public class CL_newfx extends CL_fx {
+
+
+
+ static void Flashlight(int ent, float[] pos) {
+ cdlight_t dl;
+
+ dl = CL.AllocDlight(ent);
+ VectorCopy(pos, dl.origin);
+ dl.radius = 400;
+ dl.minlight = 250;
+ dl.die = cl.time + 100;
+ dl.color[0] = 1;
+ dl.color[1] = 1;
+ dl.color[2] = 1;
+ }
+
+ /*
+ ======
+ CL_ColorFlash - flash of light
+ ======
+ */
+ static void ColorFlash(float[] pos, int ent, int intensity, float r, float g, float b) {
+ cdlight_t dl;
+
+ if ((vidref_val == VIDREF_SOFT) && ((r < 0) || (g < 0) || (b < 0))) {
+ intensity = -intensity;
+ r = -r;
+ g = -g;
+ b = -b;
+ }
+
+ dl = CL.AllocDlight(ent);
+ VectorCopy(pos, dl.origin);
+ dl.radius = intensity;
+ dl.minlight = 250;
+ dl.die = cl.time + 100;
+ dl.color[0] = r;
+ dl.color[1] = g;
+ dl.color[2] = b;
+ }
+
+ /*
+ ======
+ CL_DebugTrail
+ ======
+ */
+ static void DebugTrail(float[] start, float[] end) {
+ float[] move = new float[3];
+ float[] vec = new float[3];
+
+ float len;
+ // int j;
+ cparticle_t p;
+ float dec;
+ float[] right = new float[3];
+ float[] up = new float[3];
+ // int i;
+ // float d, c, s;
+ // float[] dir;
+
+ VectorCopy(start, move);
+ VectorSubtract(end, start, vec);
+ len = VectorNormalize(vec);
+
+ MakeNormalVectors(vec, right, up);
+
+ // VectorScale(vec, RT2_SKIP, vec);
+
+ // dec = 1.0;
+ // dec = 0.75;
+ dec = 3;
+ VectorScale(vec, dec, vec);
+ VectorCopy(start, move);
+
+ while (len > 0) {
+ len -= dec;
+
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+
+ p.time = cl.time;
+ VectorClear(p.accel);
+ VectorClear(p.vel);
+ p.alpha = 1.0f;
+ p.alphavel = -0.1f;
+ // p.alphavel = 0;
+ p.color = 0x74 + (rand() & 7);
+ VectorCopy(move, p.org);
+ /*
+ for (j=0 ; j<3 ; j++)
+ {
+ p.org[j] = move[j] + crand()*2;
+ p.vel[j] = crand()*3;
+ p.accel[j] = 0;
+ }
+ */
+ VectorAdd(move, vec, move);
+ }
+
+ }
+
+ /*
+ ===============
+ CL_SmokeTrail
+ ===============
+ */
+ static void SmokeTrail(float[] start, float[] end, int colorStart, int colorRun, int spacing) {
+ float[] move = new float[3];
+ float[] vec = new float[3];
+ float len;
+ int j;
+ cparticle_t p;
+
+ VectorCopy(start, move);
+ VectorSubtract(end, start, vec);
+ len = VectorNormalize(vec);
+
+ VectorScale(vec, spacing, vec);
+
+ // FIXME: this is a really silly way to have a loop
+ while (len > 0) {
+ len -= spacing;
+
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+ VectorClear(p.accel);
+
+ p.time = cl.time;
+
+ p.alpha = 1.0f;
+ p.alphavel = -1.0f / (1 + frand() * 0.5f);
+ p.color = colorStart + (rand() % colorRun);
+ for (j = 0; j < 3; j++) {
+ p.org[j] = move[j] + crand() * 3;
+ p.accel[j] = 0;
+ }
+ p.vel[2] = 20 + crand() * 5;
+
+ VectorAdd(move, vec, move);
+ }
+ }
+
+ static void ForceWall(float[] start, float[] end, int color) {
+ float[] move = new float[3];
+ float[] vec = new float[3];
+ ;
+ float len;
+ int j;
+ cparticle_t p;
+
+ VectorCopy(start, move);
+ VectorSubtract(end, start, vec);
+ len = VectorNormalize(vec);
+
+ VectorScale(vec, 4, vec);
+
+ // FIXME: this is a really silly way to have a loop
+ while (len > 0) {
+ len -= 4;
+
+ if (free_particles == null)
+ return;
+
+ if (frand() > 0.3) {
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+ VectorClear(p.accel);
+
+ p.time = cl.time;
+
+ p.alpha = 1.0f;
+ p.alphavel = -1.0f / (3.0f + frand() * 0.5f);
+ p.color = color;
+ for (j = 0; j < 3; j++) {
+ p.org[j] = move[j] + crand() * 3;
+ p.accel[j] = 0;
+ }
+ p.vel[0] = 0;
+ p.vel[1] = 0;
+ p.vel[2] = -40 - (crand() * 10);
+ }
+
+ VectorAdd(move, vec, move);
+ }
+ }
+
+ static void FlameEffects(centity_t ent, float[] origin) {
+ int n, count;
+ int j;
+ cparticle_t p;
+
+ count = rand() & 0xF;
+
+ for (n = 0; n < count; n++) {
+ if (free_particles == null)
+ return;
+
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+
+ VectorClear(p.accel);
+ p.time = cl.time;
+
+ p.alpha = 1.0f;
+ p.alphavel = -1.0f / (1 + frand() * 0.2f);
+ p.color = 226 + (rand() % 4);
+ for (j = 0; j < 3; j++) {
+ p.org[j] = origin[j] + crand() * 5;
+ p.vel[j] = crand() * 5;
+ }
+ p.vel[2] = crand() * -10;
+ p.accel[2] = -PARTICLE_GRAVITY;
+ }
+
+ count = rand() & 0x7;
+
+ for (n = 0; n < count; n++) {
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+ VectorClear(p.accel);
+
+ p.time = cl.time;
+
+ p.alpha = 1.0f;
+ p.alphavel = -1.0f / (1 + frand() * 0.5f);
+ p.color = 0 + (rand() % 4);
+ for (j = 0; j < 3; j++) {
+ p.org[j] = origin[j] + crand() * 3;
+ }
+ p.vel[2] = 20 + crand() * 5;
+ }
+
+ }
+
+
+ /*
+ ===============
+ CL_GenericParticleEffect
+ ===============
+ */
+ static void GenericParticleEffect(float[] org, float[] dir, int color, int count, int numcolors, int dirspread, float alphavel) {
+ int i, j;
+ cparticle_t p;
+ float d;
+
+ for (i = 0; i < count; i++) {
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+
+ p.time = cl.time;
+ if (numcolors > 1)
+ p.color = color + (rand() & numcolors);
+ else
+ p.color = color;
+
+ d = rand() & dirspread;
+ for (j = 0; j < 3; j++) {
+ p.org[j] = org[j] + ((rand() & 7) - 4) + d * dir[j];
+ p.vel[j] = crand() * 20;
+ }
+
+ p.accel[0] = p.accel[1] = 0;
+ p.accel[2] = -PARTICLE_GRAVITY;
+ // VectorCopy (accel, p.accel);
+ p.alpha = 1.0f;
+
+ p.alphavel = -1.0f / (0.5f + frand() * alphavel);
+ // p.alphavel = alphavel;
+ }
+ }
+
+ /*
+ ===============
+ CL_BubbleTrail2 (lets you control the # of bubbles by setting the distance between the spawns)
+
+ ===============
+ */
+ static void BubbleTrail2 (float[] start, float[] end, int dist)
+ {
+ float[] move = new float[3];
+ float[] vec = new float[3];;
+ float len;
+ int i, j;
+ cparticle_t p;
+ float dec;
+
+ VectorCopy (start, move);
+ VectorSubtract (end, start, vec);
+ len = VectorNormalize (vec);
+
+ dec = dist;
+ VectorScale (vec, dec, vec);
+
+ for (i=0 ; i<len ; i+=dec)
+ {
+ if (free_particles == null)
+ return;
+
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+
+ VectorClear (p.accel);
+ p.time = cl.time;
+
+ p.alpha = 1.0f;
+ p.alphavel = -1.0f / (1+frand()*0.1f);
+ p.color = 4 + (rand()&7);
+ for (j=0 ; j<3 ; j++)
+ {
+ p.org[j] = move[j] + crand()*2;
+ p.vel[j] = crand()*10;
+ }
+ p.org[2] -= 4;
+// p.vel[2] += 6;
+ p.vel[2] += 20;
+
+ VectorAdd (move, vec, move);
+ }
+ }
+
+ static void Heatbeam(float[] start, float[] forward) {
+ float[] move = new float[3];
+ float[] vec = new float[3];
+ float len;
+ int j;
+ cparticle_t p;
+ float[] right = new float[3];
+ float[] up = new float[3];
+ int i;
+ float c, s;
+ float[] dir = new float[3];
+ float ltime;
+ float step = 32.0f, rstep;
+ float start_pt;
+ float rot;
+ float variance;
+ float[] end = new float[3];
+
+ VectorMA(start, 4096, forward, end);
+
+ VectorCopy(start, move);
+ VectorSubtract(end, start, vec);
+ len = VectorNormalize(vec);
+
+ // FIXME - pmm - these might end up using old values?
+ // MakeNormalVectors (vec, right, up);
+ VectorCopy(cl.v_right, right);
+ VectorCopy(cl.v_up, up);
+ if (vidref_val == VIDREF_GL) { // GL mode
+ VectorMA(move, -0.5f, right, move);
+ VectorMA(move, -0.5f, up, move);
+ }
+ // otherwise assume SOFT
+
+ ltime = (float)cl.time / 1000.0f;
+ start_pt = ltime * 96.0f % step;
+ VectorMA(move, start_pt, vec, move);
+
+ VectorScale(vec, step, vec);
+
+ // Com_Printf ("%f\n", ltime);
+ rstep = (float) (Math.PI / 10.0);
+ float M_PI2 = (float) (Math.PI * 2.0);
+ for (i = (int)start_pt; i < len; i += step) {
+ if (i > step * 5) // don't bother after the 5th ring
+ break;
+
+ for (rot = 0; rot < M_PI2; rot += rstep) {
+
+ if (free_particles == null)
+ return;
+
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+
+ p.time = cl.time;
+ VectorClear(p.accel);
+ // rot+= fmod(ltime, 12.0)*M_PI;
+ // c = cos(rot)/2.0;
+ // s = sin(rot)/2.0;
+ // variance = 0.4 + ((float)rand()/(float)RAND_MAX) *0.2;
+ variance = 0.5f;
+ c = (float) (Math.cos(rot) * variance);
+ s = (float) (Math.sin(rot) * variance);
+
+ // trim it so it looks like it's starting at the origin
+ if (i < 10) {
+ VectorScale(right, c * (i / 10.0f), dir);
+ VectorMA(dir, s * (i / 10.0f), up, dir);
+ } else {
+ VectorScale(right, c, dir);
+ VectorMA(dir, s, up, dir);
+ }
+
+ p.alpha = 0.5f;
+ // p.alphavel = -1.0 / (1+frand()*0.2);
+ p.alphavel = -1000.0f;
+ // p.color = 0x74 + (rand()&7);
+ p.color = 223 - (rand() & 7);
+ for (j = 0; j < 3; j++) {
+ p.org[j] = move[j] + dir[j] * 3;
+ // p.vel[j] = dir[j]*6;
+ p.vel[j] = 0;
+ }
+ }
+ VectorAdd(move, vec, move);
+ }
+ }
+
+ /*
+ ===============
+ CL_ParticleSteamEffect
+
+ Puffs with velocity along direction, with some randomness thrown in
+ ===============
+ */
+ static void ParticleSteamEffect(float[] org, float[] dir, int color, int count, int magnitude) {
+ int i, j;
+ cparticle_t p;
+ float d;
+ float[] r = new float[3];
+ float[] u = new float[3];
+
+ // vectoangles2 (dir, angle_dir);
+ // AngleVectors (angle_dir, f, r, u);
+
+ MakeNormalVectors(dir, r, u);
+
+ for (i = 0; i < count; i++) {
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+
+ p.time = cl.time;
+ p.color = color + (rand() & 7);
+
+ for (j = 0; j < 3; j++) {
+ p.org[j] = org[j] + magnitude * 0.1f * crand();
+ // p.vel[j] = dir[j]*magnitude;
+ }
+ VectorScale(dir, magnitude, p.vel);
+ d = crand() * magnitude / 3;
+ VectorMA(p.vel, d, r, p.vel);
+ d = crand() * magnitude / 3;
+ VectorMA(p.vel, d, u, p.vel);
+
+ p.accel[0] = p.accel[1] = 0;
+ p.accel[2] = -PARTICLE_GRAVITY / 2;
+ p.alpha = 1.0f;
+
+ p.alphavel = -1.0f / (0.5f + frand() * 0.3f);
+ }
+ }
+
+ static void ParticleSteamEffect2(cl_sustain_t self)
+ // float[] org, float[] dir, int color, int count, int magnitude)
+ {
+ int i, j;
+ cparticle_t p;
+ float d;
+ float[] r = new float[3];
+ float[] u = new float[3];
+ float[] dir = new float[3];
+
+ // vectoangles2 (dir, angle_dir);
+ // AngleVectors (angle_dir, f, r, u);
+
+ VectorCopy(self.dir, dir);
+ MakeNormalVectors(dir, r, u);
+
+ for (i = 0; i < self.count; i++) {
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+
+ p.time = cl.time;
+ p.color = self.color + (rand() & 7);
+
+ for (j = 0; j < 3; j++) {
+ p.org[j] = self.org[j] + self.magnitude * 0.1f * crand();
+ // p.vel[j] = dir[j]*magnitude;
+ }
+ VectorScale(dir, self.magnitude, p.vel);
+ d = crand() * self.magnitude / 3;
+ VectorMA(p.vel, d, r, p.vel);
+ d = crand() * self.magnitude / 3;
+ VectorMA(p.vel, d, u, p.vel);
+
+ p.accel[0] = p.accel[1] = 0;
+ p.accel[2] = -PARTICLE_GRAVITY / 2;
+ p.alpha = 1.0f;
+
+ p.alphavel = -1.0f / (0.5f + frand() * 0.3f);
+ }
+ self.nextthink += self.thinkinterval;
+ }
+
+ /*
+ ===============
+ CL_TrackerTrail
+ ===============
+ */
+ static void TrackerTrail(float[] start, float[] end, int particleColor) {
+ float[] move = new float[3];
+ float[] vec = new float[3];
+ float[] forward = new float[3];
+ float[] right = new float[3];
+ float[] up = new float[3];
+ float[] angle_dir = new float[3];
+ float len;
+ cparticle_t p;
+ int dec;
+ float dist;
+
+ VectorCopy(start, move);
+ VectorSubtract(end, start, vec);
+ len = VectorNormalize(vec);
+
+ VectorCopy(vec, forward);
+ vectoangles(forward, angle_dir);
+ AngleVectors(angle_dir, forward, right, up);
+
+ dec = 3;
+ VectorScale(vec, 3, vec);
+
+ // FIXME: this is a really silly way to have a loop
+ while (len > 0) {
+ len -= dec;
+
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+ VectorClear(p.accel);
+
+ p.time = cl.time;
+
+ p.alpha = 1.0f;
+ p.alphavel = -2.0f;
+ p.color = particleColor;
+ dist = DotProduct(move, forward);
+ VectorMA(move, (float)(8 * Math.cos(dist)), up, p.org);
+ for (int j=0 ; j<3 ; j++) {
+ p.vel[j] = 0;
+ p.accel[j] = 0;
+ }
+ p.vel[2] = 5;
+
+ VectorAdd (move, vec, move);
+ }
+ }
+
+ static void Tracker_Shell(float[] origin) {
+ float[] dir = new float[3];
+ int i;
+ cparticle_t p;
+
+ for(i=0;i<300;i++) {
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+ VectorClear(p.accel);
+
+ p.time = cl.time;
+
+ p.alpha = 1.0f;
+ p.alphavel = INSTANT_PARTICLE;
+ p.color = 0;
+
+ dir[0] = crand();
+ dir[1] = crand();
+ dir[2] = crand();
+ VectorNormalize(dir);
+
+ VectorMA(origin, 40, dir, p.org);
+ }
+ }
+
+ static void MonsterPlasma_Shell(float[] origin) {
+ float[] dir = new float[3];
+ int i;
+ cparticle_t p;
+
+ for (i = 0; i < 40; i++) {
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+ VectorClear(p.accel);
+
+ p.time = cl.time;
+
+ p.alpha = 1.0f;
+ p.alphavel = INSTANT_PARTICLE;
+ p.color = 0xe0;
+
+ dir[0] = crand();
+ dir[1] = crand();
+ dir[2] = crand();
+ VectorNormalize(dir);
+
+ VectorMA(origin, 10, dir, p.org);
+ // VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))), dir, p.org);
+ }
+ }
+
+ private static int[] wb_colortable = {2*8,13*8,21*8,18*8};
+ static void Widowbeamout(cl_sustain_t self) {
+ float[] dir = new float[3];
+ int i;
+ cparticle_t p;
+
+ float ratio;
+
+ ratio = 1.0f - (((float)self.endtime - (float)cl.time) / 2100.0f);
+
+ for (i = 0; i < 300; i++) {
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+ VectorClear(p.accel);
+
+ p.time = cl.time;
+
+ p.alpha = 1.0f;
+ p.alphavel = INSTANT_PARTICLE;
+ p.color = wb_colortable[rand() & 3];
+
+ dir[0] = crand();
+ dir[1] = crand();
+ dir[2] = crand();
+ VectorNormalize(dir);
+
+ VectorMA(self.org, (45.0f * ratio), dir, p.org);
+ // VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))), dir, p.org);
+ }
+ }
+
+ private static int[] nb_colortable = {110, 112, 114, 116};
+ static void Nukeblast(cl_sustain_t self) {
+ float[] dir = new float[3];
+ int i;
+ cparticle_t p;
+
+ float ratio;
+
+ ratio = 1.0f - (((float)self.endtime - (float)cl.time) / 1000.0f);
+
+ for (i = 0; i < 700; i++) {
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+ VectorClear(p.accel);
+
+ p.time = cl.time;
+
+ p.alpha = 1.0f;
+ p.alphavel = INSTANT_PARTICLE;
+ p.color = nb_colortable[rand() & 3];
+
+ dir[0] = crand();
+ dir[1] = crand();
+ dir[2] = crand();
+ VectorNormalize(dir);
+
+ VectorMA(self.org, (200.0f * ratio), dir, p.org);
+ // VectorMA(origin, 10*(((rand () & 0x7fff) / ((float)0x7fff))), dir, p.org);
+ }
+ }
+
+ private static int[] ws_colortable = {2*8,13*8,21*8,18*8};
+ static void WidowSplash(float[] org) {
+ int i;
+ cparticle_t p;
+ float[] dir = new float[3];
+
+ for (i = 0; i < 256; i++) {
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+
+ p.time = cl.time;
+ p.color = ws_colortable[rand() & 3];
+
+ dir[0] = crand();
+ dir[1] = crand();
+ dir[2] = crand();
+ VectorNormalize(dir);
+ VectorMA(org, 45.0f, dir, p.org);
+ VectorMA(vec3_origin, 40.0f, dir, p.vel);
+
+ p.accel[0] = p.accel[1] = 0;
+ p.alpha = 1.0f;
+
+ p.alphavel = -0.8f / (0.5f + frand() * 0.3f);
+ }
+
+ }
+
+ static void Tracker_Explode(float[] origin) {
+ float[] dir = new float[3];
+ float[] backdir = new float[3];
+ int i;
+ cparticle_t p;
+
+ for (i = 0; i < 300; i++) {
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+ VectorClear(p.accel);
+
+ p.time = cl.time;
+
+ p.alpha = 1.0f;
+ p.alphavel = -1.0f;
+ p.color = 0;
+
+ dir[0] = crand();
+ dir[1] = crand();
+ dir[2] = crand();
+ VectorNormalize(dir);
+ VectorScale(dir, -1, backdir);
+
+ VectorMA(origin, 64, dir, p.org);
+ VectorScale(backdir, 64, p.vel);
+ }
+
+ }
+
+ /*
+ ===============
+ CL_TagTrail
+
+ ===============
+ */
+ static void TagTrail(float[] start, float[] end, float color) {
+ float[] move = new float[3];
+ float[] vec = new float[3];
+ float len;
+ int j;
+ cparticle_t p;
+ int dec;
+
+ VectorCopy(start, move);
+ VectorSubtract(end, start, vec);
+ len = VectorNormalize(vec);
+
+ dec = 5;
+ VectorScale(vec, 5, vec);
+
+ while (len >= 0) {
+ len -= dec;
+
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+ VectorClear(p.accel);
+
+ p.time = cl.time;
+
+ p.alpha = 1.0f;
+ p.alphavel = -1.0f / (0.8f + frand() * 0.2f);
+ p.color = color;
+ for (j = 0; j < 3; j++) {
+ p.org[j] = move[j] + crand() * 16;
+ p.vel[j] = crand() * 5;
+ p.accel[j] = 0;
+ }
+
+ VectorAdd(move, vec, move);
+ }
+ }
+
+ /*
+ ===============
+ CL_ColorExplosionParticles
+ ===============
+ */
+ static void ColorExplosionParticles(float[] org, int color, int run) {
+ int i, j;
+ cparticle_t p;
+
+ for (i = 0; i < 128; i++) {
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+
+ p.time = cl.time;
+ p.color = color + (rand() % run);
+
+ for (j = 0; j < 3; j++) {
+ p.org[j] = org[j] + ((rand() % 32) - 16);
+ p.vel[j] = (rand() % 256) - 128;
+ }
+
+ p.accel[0] = p.accel[1] = 0;
+ p.accel[2] = -PARTICLE_GRAVITY;
+ p.alpha = 1.0f;
+
+ p.alphavel = -0.4f / (0.6f + frand() * 0.2f);
+ }
+ }
+
+ /*
+ ===============
+ CL_ParticleSmokeEffect - like the steam effect, but unaffected by gravity
+ ===============
+ */
+ static void ParticleSmokeEffect (float[] org, float[] dir, int color, int count, int magnitude)
+ {
+ int i, j;
+ cparticle_t p;
+ float d;
+ float[] r = new float[3];
+ float[] u = new float[3];
+
+ MakeNormalVectors (dir, r, u);
+
+ for (i=0 ; i<count ; i++)
+ {
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+
+ p.time = cl.time;
+ p.color = color + (rand()&7);
+
+ for (j=0 ; j<3 ; j++)
+ {
+ p.org[j] = org[j] + magnitude*0.1f*crand();
+// p.vel[j] = dir[j]*magnitude;
+ }
+ VectorScale (dir, magnitude, p.vel);
+ d = crand()*magnitude/3;
+ VectorMA (p.vel, d, r, p.vel);
+ d = crand()*magnitude/3;
+ VectorMA (p.vel, d, u, p.vel);
+
+ p.accel[0] = p.accel[1] = p.accel[2] = 0;
+ p.alpha = 1.0f;
+
+ p.alphavel = -1.0f / (0.5f + frand()*0.3f);
+ }
+ }
+
+ /*
+ ===============
+ CL_BlasterParticles2
+
+ Wall impact puffs (Green)
+ ===============
+ */
+ static void BlasterParticles2(float[] org, float[] dir, long color) {
+ int i, j;
+ cparticle_t p;
+ float d;
+ int count;
+
+ count = 40;
+ for (i = 0; i < count; i++) {
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+
+ p.time = cl.time;
+ p.color = color + (rand() & 7);
+
+ d = rand() & 15;
+ for (j = 0; j < 3; j++) {
+ p.org[j] = org[j] + ((rand() & 7) - 4) + d * dir[j];
+ p.vel[j] = dir[j] * 30 + crand() * 40;
+ }
+
+ p.accel[0] = p.accel[1] = 0;
+ p.accel[2] = -PARTICLE_GRAVITY;
+ p.alpha = 1.0f;
+
+ p.alphavel = -1.0f / (0.5f + frand() * 0.3f);
+ }
+ }
+
+ /*
+ ===============
+ CL_BlasterTrail2
+
+ Green!
+ ===============
+ */
+ static void BlasterTrail2(float[] start, float[] end) {
+ float[] move = new float[3];
+ float[] vec = new float[3];
+ float len;
+ int j;
+ cparticle_t p;
+ int dec;
+
+ VectorCopy(start, move);
+ VectorSubtract(end, start, vec);
+ len = VectorNormalize(vec);
+
+ dec = 5;
+ VectorScale(vec, 5, vec);
+
+ // FIXME: this is a really silly way to have a loop
+ while (len > 0) {
+ len -= dec;
+
+ if (free_particles == null)
+ return;
+ p = free_particles;
+ free_particles = p.next;
+ p.next = active_particles;
+ active_particles = p;
+ VectorClear(p.accel);
+
+ p.time = cl.time;
+
+ p.alpha = 1.0f;
+ p.alphavel = -1.0f / (0.3f + frand() * 0.2f);
+ p.color = 0xd0;
+ for (j = 0; j < 3; j++) {
+ p.org[j] = move[j] + crand();
+ p.vel[j] = crand() * 5;
+ p.accel[j] = 0;
+ }
+
+ VectorAdd(move, vec, move);
+ }
+ }
+
+}
diff --git a/src/jake2/client/CL_parse.java b/src/jake2/client/CL_parse.java
new file mode 100644
index 0000000..e972ea6
--- /dev/null
+++ b/src/jake2/client/CL_parse.java
@@ -0,0 +1,802 @@
+/*
+ * CL_parse.java
+ * Copyright (C) 2004
+ *
+ * $Id: CL_parse.java,v 1.1 2004-07-07 19:58:38 hzi Exp $
+ */
+/*
+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.
+
+*/
+package jake2.client;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+import jake2.Defines;
+import jake2.game.Cmd;
+import jake2.game.entity_state_t;
+import jake2.qcommon.CM;
+import jake2.qcommon.Cbuf;
+import jake2.qcommon.Com;
+import jake2.qcommon.Cvar;
+import jake2.qcommon.FS;
+import jake2.qcommon.MSG;
+import jake2.qcommon.SZ;
+import jake2.qcommon.xcommand_t;
+import jake2.render.model_t;
+import jake2.sys.Sys;
+import jake2.util.Lib;
+
+/**
+ * CL_parse
+ */
+public class CL_parse extends CL_view {
+
+ //// cl_parse.c -- parse a message received from the server
+
+ public static String svc_strings[] =
+ {
+ "svc_bad",
+ "svc_muzzleflash",
+ "svc_muzzlflash2",
+ "svc_temp_entity",
+ "svc_layout",
+ "svc_inventory",
+ "svc_nop",
+ "svc_disconnect",
+ "svc_reconnect",
+ "svc_sound",
+ "svc_print",
+ "svc_stufftext",
+ "svc_serverdata",
+ "svc_configstring",
+ "svc_spawnbaseline",
+ "svc_centerprint",
+ "svc_download",
+ "svc_playerinfo",
+ "svc_packetentities",
+ "svc_deltapacketentities",
+ "svc_frame" };
+
+ // =============================================================================
+
+ public static String DownloadFileName(String fn) {
+ if ("players".equals(fn))
+ return BASEDIRNAME + "/" + fn;
+ else
+ return FS.Gamedir() + "/" + fn;
+ }
+
+ /*
+ ===============
+ CL_CheckOrDownloadFile
+
+ Returns true if the file exists, otherwise it attempts
+ to start a download from the server.
+ ===============
+ */
+ public static boolean CheckOrDownloadFile(String filename) {
+ RandomAccessFile fp;
+ String name;
+
+ if (filename.indexOf("..") != -1) {
+ Com.Printf("Refusing to download a path with ..\n");
+ return true;
+ }
+
+ if (FS.LoadFile(filename) != null) { // it exists, no need to download
+ return true;
+ }
+
+ cls.downloadname = filename;
+
+ // download to a temp name, and only rename
+ // to the real name when done, so if interrupted
+ // a runt file wont be left
+ Com.StripExtension(cls.downloadname, cls.downloadtempname);
+ cls.downloadtempname += ".tmp";
+
+ // ZOID
+ // check to see if we already have a tmp for this file, if so, try to resume
+ // open the file if not opened yet
+ name = DownloadFileName(cls.downloadtempname);
+
+ fp = fopen(name, "r+b");
+ if (fp != null) { // it exists
+ long len = 0;
+
+ try {
+ len = fp.length();
+ }
+ catch (IOException e) {
+ };
+
+ cls.download = fp;
+
+ // give the server an offset to start the download
+ Com.Printf("Resuming " + cls.downloadname + "\n");
+ MSG.WriteByte(cls.netchan.message, clc_stringcmd);
+ MSG.WriteString(cls.netchan.message, "download " + cls.downloadname + " " + len);
+ }
+ else {
+ // TODO bugfix cwei
+ cls.downloadname = cls.downloadname.toLowerCase();
+
+ Com.Printf("Downloading " + cls.downloadname + "\n");
+ MSG.WriteByte(cls.netchan.message, clc_stringcmd);
+ MSG.WriteString(cls.netchan.message, "download " + cls.downloadname);
+ }
+
+ cls.downloadnumber++;
+
+ return false;
+ }
+
+ /*
+ ===============
+ CL_Download_f
+
+ Request a download from the server
+ ===============
+ */
+ static xcommand_t Download_f = new xcommand_t() {
+ public void execute() {
+ String filename;
+
+ if (Cmd.Argc() != 2) {
+ Com.Printf("Usage: download <filename>\n");
+ return;
+ }
+
+ filename = Cmd.Argv(1);
+
+ if (strstr(filename, "..")) {
+ Com.Printf("Refusing to download a path with ..\n");
+ return;
+ }
+
+ if (FS.LoadFile(filename) != null) { // it exists, no need to download
+ Com.Printf("File already exists.\n");
+ return;
+ }
+
+ cls.downloadname = filename;
+ Com.Printf("Downloading " + cls.downloadname + "\n");
+
+ // download to a temp name, and only rename
+ // to the real name when done, so if interrupted
+ // a runt file wont be left
+ Com.StripExtension(cls.downloadname, cls.downloadtempname);
+ strcat(cls.downloadtempname, ".tmp");
+
+ MSG.WriteByte(cls.netchan.message, clc_stringcmd);
+ MSG.WriteString(cls.netchan.message, "download " + cls.downloadname);
+
+ cls.downloadnumber++;
+ }
+ };
+
+ /*
+ ======================
+ CL_RegisterSounds
+ ======================
+ */
+ static void RegisterSounds() {
+ int i;
+ S.BeginRegistration();
+ CL.RegisterTEntSounds();
+ for (i = 1; i < MAX_SOUNDS; i++) {
+ if (cl.configstrings[CS_SOUNDS + i] == null || cl.configstrings[CS_SOUNDS + i] == "")
+ break;
+ cl.sound_precache[i] = S.RegisterSound(cl.configstrings[CS_SOUNDS + i]);
+ Sys.SendKeyEvents(); // pump message loop
+ }
+ S.EndRegistration();
+ }
+
+ /*
+ =====================
+ CL_ParseDownload
+
+ A download message has been received from the server
+ =====================
+ */
+ public static void ParseDownload() {
+ int size, percent;
+ String name;
+ int r;
+
+ // read the data
+ size = MSG.ReadShort(net_message);
+ percent = MSG.ReadByte(net_message);
+ if (size == -1) {
+ Com.Printf("Server does not have this file.\n");
+ if (cls.download != null) {
+ // if here, we tried to resume a file but the server said no
+ fclose(cls.download);
+ cls.download = null;
+ }
+ CL.RequestNextDownload();
+ return;
+ }
+
+ // open the file if not opened yet
+ if (cls.download == null) {
+ name = DownloadFileName(cls.downloadtempname);
+
+ FS.CreatePath(name);
+
+ cls.download = fopen(name, "rw");
+ if (cls.download == null) {
+ net_message.readcount += size;
+ Com.Printf("Failed to open " + cls.downloadtempname + "\n");
+ CL.RequestNextDownload();
+ return;
+ }
+ }
+
+ //fwrite(net_message.data[net_message.readcount], 1, size, cls.download);
+ try {
+ cls.download.write(net_message.data, net_message.readcount, size);
+ }
+ catch (Exception e) {
+ }
+ net_message.readcount += size;
+
+ if (percent != 100) {
+ // request next block
+ // change display routines by zoid
+
+ MSG.WriteByte(cls.netchan.message, clc_stringcmd);
+ SZ.Print(cls.netchan.message, "nextdl");
+ }
+ else {
+ String oldn, newn;
+ //char oldn[MAX_OSPATH];
+ //char newn[MAX_OSPATH];
+
+ // Com.Printf ("100%%\n");
+
+ fclose(cls.download);
+
+ // rename the temp file to it's final name
+ oldn = DownloadFileName(cls.downloadtempname);
+ newn = DownloadFileName(cls.downloadname);
+ r = Lib.rename(oldn, newn);
+ if (r != 0)
+ Com.Printf("failed to rename.\n");
+
+ cls.download = null;
+ cls.downloadpercent = 0;
+
+ // get another file if needed
+
+ CL.RequestNextDownload();
+ }
+ }
+
+ /*
+ =====================================================================
+
+ SERVER CONNECTING MESSAGES
+
+ =====================================================================
+ */
+
+ /*
+ ==================
+ CL_ParseServerData
+ ==================
+ */
+ //checked once, was ok.
+ public static void ParseServerData() {
+
+ String str;
+ int i;
+
+ Com.DPrintf("Serverdata packet received.\n");
+ //
+ // wipe the client_state_t struct
+ //
+ CL.ClearState();
+ cls.state = ca_connected;
+
+ // parse protocol version number
+ i = MSG.ReadLong(net_message);
+ cls.serverProtocol = i;
+
+ // BIG HACK to let demos from release work with the 3.0x patch!!!
+ if (Com.ServerState() != 0 && PROTOCOL_VERSION == 34) {
+ }
+ else if (i != PROTOCOL_VERSION)
+ Com.Error(ERR_DROP, "Server returned version " + i + ", not " + PROTOCOL_VERSION);
+
+ cl.servercount = MSG.ReadLong(net_message);
+ cl.attractloop = MSG.ReadByte(net_message) != 0;
+
+ // game directory
+ str = MSG.ReadString(net_message);
+ cl.gamedir = str;
+
+ // set gamedir
+ if (str.length() > 0
+ && (FS.fs_gamedirvar.string == null || FS.fs_gamedirvar.string.length() == 0 || FS.fs_gamedirvar.string.equals(str))
+ || (str.length() == 0 && (FS.fs_gamedirvar.string != null || FS.fs_gamedirvar.string.length() == 0)))
+ Cvar.Set("game", str);
+
+ // parse player entity number
+ cl.playernum = MSG.ReadShort(net_message);
+
+ // get the full level name
+ str = MSG.ReadString(net_message);
+
+ if (cl.playernum == -1) { // playing a cinematic or showing a pic, not a level
+ SCR.PlayCinematic(str);
+ }
+ else {
+ // seperate the printfs so the server message can have a color
+// Com.Printf(
+// "\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
+// Com.Printf('\02' + str + "\n");
+ Com.Printf("Levelname:" + str + "\n");
+ // need to prep refresh at next oportunity
+ cl.refresh_prepped = false;
+ }
+ }
+
+ /*
+ ==================
+ CL_ParseBaseline
+ ==================
+ */
+ public static void ParseBaseline() {
+ entity_state_t es;
+ int newnum;
+
+ entity_state_t nullstate = new entity_state_t(null);
+ //memset(nullstate, 0, sizeof(nullstate));
+ CM.intwrap bits = new CM.intwrap(0);
+ newnum = CL_ents.ParseEntityBits(bits);
+ es = cl_entities[newnum].baseline;
+ CL_ents.ParseDelta(nullstate, es, newnum, bits.i);
+ }
+
+ /*
+ ================
+ CL_LoadClientinfo
+
+ ================
+ */
+ public static void LoadClientinfo(clientinfo_t ci, String s) {
+ int i;
+ int t;
+
+ //char model_name[MAX_QPATH];
+ //char skin_name[MAX_QPATH];
+ //char model_filename[MAX_QPATH];
+ //char skin_filename[MAX_QPATH];
+ //char weapon_filename[MAX_QPATH];
+
+ String model_name,skin_name,model_filename, skin_filename, weapon_filename;
+
+ ci.cinfo = s;
+ //ci.cinfo[sizeof(ci.cinfo) - 1] = 0;
+
+ // isolate the player's name
+ ci.name = s;
+ //ci.name[sizeof(ci.name) - 1] = 0;
+
+ t = s.indexOf('\\');
+ //t = strstr(s, "\\");
+
+ if (t!=-1) {
+ ci.name = s.substring(0,t);
+ s = s.substring(t + 1, s.length());
+ //s = t + 1;
+ }
+
+ if (cl_noskins.value!=0 || s.length()!=0) {
+
+ model_filename=("players/male/tris.md2");
+ weapon_filename=("players/male/weapon.md2");
+ skin_filename=("players/male/grunt.pcx");
+ ci.iconname=("/players/male/grunt_i.pcx");
+
+ ci.model = re.RegisterModel(model_filename);
+
+ ci.weaponmodel = new model_t[Defines.MAX_CLIENTWEAPONMODELS];
+ ci.weaponmodel[0] = re.RegisterModel(weapon_filename);
+ ci.skin = re.RegisterSkin(skin_filename);
+ ci.icon = re.RegisterPic(ci.iconname);
+ }
+ else {
+ // isolate the model name
+
+ int pos = s.indexOf('/');
+
+ if (pos == -1)
+ pos = s.indexOf('/');
+ if (pos == -1)
+ {
+ pos =0;
+ Com.Error(Defines.ERR_FATAL, "Invalid model name:" + s);
+ }
+
+ model_name = s.substring(0,pos);
+
+ // isolate the skin name
+ skin_name = s.substring(pos+1, s.length());
+
+ // model file
+ model_filename = "players/" + model_name + "/tris.md2";
+ ci.model = re.RegisterModel(model_filename);
+
+ if (ci.model==null) {
+ model_name = "male";
+ model_filename= "players/male/tris.md2";
+ ci.model = re.RegisterModel(model_filename);
+ }
+
+ // skin file
+ skin_filename = "players/" + model_name +"/"+ skin_name + ".pcx";
+ ci.skin = re.RegisterSkin(skin_filename);
+
+ // if we don't have the skin and the model wasn't male,
+ // see if the male has it (this is for CTF's skins)
+ if (ci.skin==null && !model_name.equalsIgnoreCase("male")) {
+ // change model to male
+ model_name = "male";
+ model_filename= "players/male/tris.md2";
+ ci.model = re.RegisterModel(model_filename);
+
+ // see if the skin exists for the male model
+ skin_filename= "players/" + model_name + "/"+ skin_name+".pcx";
+ ci.skin = re.RegisterSkin(skin_filename);
+ }
+
+ // if we still don't have a skin, it means that the male model didn't have
+ // it, so default to grunt
+ if (ci.skin==null) {
+ // see if the skin exists for the male model
+ skin_filename= "players/" + model_name + "/grunt.pcx";
+ ci.skin = re.RegisterSkin(skin_filename);
+ }
+
+ // weapon file
+ for (i = 0; i < num_cl_weaponmodels; i++) {
+ weapon_filename= "players/"+model_name +"/" + cl_weaponmodels[i];
+ ci.weaponmodel[i] = re.RegisterModel(weapon_filename);
+ if (null==ci.weaponmodel[i] && model_name.equals("cyborg")) {
+ // try male
+ weapon_filename="players/male/" + cl_weaponmodels[i];
+ ci.weaponmodel[i] = re.RegisterModel(weapon_filename);
+ }
+ if (0==cl_vwep.value)
+ break; // only one when vwep is off
+ }
+
+ // icon file
+ ci.iconname= "/players/"+model_name+"/" + skin_name+"_i.pcx";
+ ci.icon = re.RegisterPic(ci.iconname);
+ }
+
+ // must have loaded all data types to be valud
+ if (ci.skin==null || ci.icon==null || ci.model==null || ci.weaponmodel[0]==null) {
+ ci.skin = null;
+ ci.icon = null;
+ ci.model = null;
+ ci.weaponmodel[0] = null;
+ return;
+ }
+ }
+
+ /*
+ ================
+ CL_ParseClientinfo
+
+ Load the skin, icon, and model for a client
+ ================
+ */
+ static void ParseClientinfo(int player) {
+ String s;
+ clientinfo_t ci;
+
+ s = cl.configstrings[player + CS_PLAYERSKINS];
+
+ ci = cl.clientinfo[player];
+
+ LoadClientinfo(ci, s);
+ }
+
+ /*
+ ================
+ CL_ParseConfigString
+ ================
+ */
+ public static void ParseConfigString() {
+ int i;
+ String s;
+ String olds;
+
+ i = MSG.ReadShort(net_message);
+
+ if (i < 0 || i >= MAX_CONFIGSTRINGS)
+ Com.Error(ERR_DROP, "configstring > MAX_CONFIGSTRINGS");
+
+ s = MSG.ReadString(net_message);
+
+ olds=cl.configstrings[i];
+ cl.configstrings[i] = s;
+
+ // do something apropriate
+
+ if (i >= CS_LIGHTS && i < CS_LIGHTS + MAX_LIGHTSTYLES)
+ {
+ SetLightstyle(i - CS_LIGHTS);
+ }
+ else if (i == CS_CDTRACK) {
+ if (cl.refresh_prepped)
+ CDAudio.CDAudio_Play(atoi(cl.configstrings[CS_CDTRACK]), true);
+ }
+ else if (i >= CS_MODELS && i < CS_MODELS + MAX_MODELS) {
+ if (cl.refresh_prepped) {
+ cl.model_draw[i - CS_MODELS] = re.RegisterModel(cl.configstrings[i]);
+ if (cl.configstrings[i].startsWith("*"))
+ cl.model_clip[i - CS_MODELS] = CM.InlineModel(cl.configstrings[i]);
+ else
+ cl.model_clip[i - CS_MODELS] = null;
+ }
+ }
+ else if (i >= CS_SOUNDS && i < CS_SOUNDS + MAX_MODELS) {
+ if (cl.refresh_prepped)
+ cl.sound_precache[i - CS_SOUNDS] = SND_DMA.RegisterSound(cl.configstrings[i]);
+ }
+ else if (i >= CS_IMAGES && i < CS_IMAGES + MAX_MODELS) {
+ if (cl.refresh_prepped)
+ cl.image_precache[i - CS_IMAGES] = re.RegisterPic(cl.configstrings[i]);
+ }
+ else if (i >= CS_PLAYERSKINS && i < CS_PLAYERSKINS + MAX_CLIENTS) {
+ if (cl.refresh_prepped && strcmp(olds, s)!=0)
+ ParseClientinfo(i - CS_PLAYERSKINS);
+ }
+ }
+
+ /*
+ =====================================================================
+
+ ACTION MESSAGES
+
+ =====================================================================
+ */
+
+ /*
+ ==================
+ CL_ParseStartSoundPacket
+ ==================
+ */
+ public static void ParseStartSoundPacket() {
+ float[] pos_v={0,0,0};
+ float pos[];
+ int channel, ent;
+ int sound_num;
+ float volume;
+ float attenuation;
+ int flags;
+ float ofs;
+
+ flags = MSG.ReadByte(net_message);
+ sound_num = MSG.ReadByte(net_message);
+
+ if ((flags & SND_VOLUME) != 0)
+ volume = MSG.ReadByte(net_message) / 255.0f;
+ else
+ volume = DEFAULT_SOUND_PACKET_VOLUME;
+
+ if ((flags & SND_ATTENUATION) != 0)
+ attenuation = MSG.ReadByte(net_message) / 64.0f;
+ else
+ attenuation = DEFAULT_SOUND_PACKET_ATTENUATION;
+
+ if ((flags & SND_OFFSET) != 0)
+ ofs = MSG.ReadByte(net_message) / 1000.0f;
+ else
+ ofs = 0;
+
+ if ((flags & SND_ENT) != 0) { // entity reletive
+ channel = MSG.ReadShort(net_message);
+ ent = channel >> 3;
+ if (ent > MAX_EDICTS)
+ Com.Error(ERR_DROP, "CL_ParseStartSoundPacket: ent = " + ent);
+
+ channel &= 7;
+ }
+ else {
+ ent = 0;
+ channel = 0;
+ }
+
+ if ((flags & SND_POS) != 0) { // positioned in space
+ MSG.ReadPos(net_message, pos_v);
+
+ pos = pos_v;
+ }
+ else // use entity number
+ pos = null;
+
+ if (null==cl.sound_precache[sound_num])
+ return;
+
+ SND_DMA.StartSound(pos, ent, channel, cl.sound_precache[sound_num], volume, attenuation, ofs);
+ }
+
+ public static void SHOWNET(String s) {
+ if (cl_shownet.value >= 2)
+ Com.Printf(net_message.readcount - 1 + ":" + s + "\n");
+ }
+
+ /*
+ =====================
+ CL_ParseServerMessage
+ =====================
+ */
+ public static void ParseServerMessage() {
+ int cmd;
+ String s;
+ int i;
+
+ //
+ // if recording demos, copy the message out
+ //
+ //if (cl_shownet.value == 1)
+ //Com.Printf(net_message.cursize + " ");
+ //else if (cl_shownet.value >= 2)
+ //Com.Printf("------------------\n");
+
+ //
+ // parse the message
+ //
+ while (true) {
+ if (net_message.readcount > net_message.cursize) {
+ Com.Error(ERR_FATAL, "CL_ParseServerMessage: Bad server message:");
+ break;
+ }
+
+ cmd = MSG.ReadByte(net_message);
+
+ if (cmd == -1) {
+ SHOWNET("END OF MESSAGE");
+ break;
+ }
+
+ if (cl_shownet.value >= 2) {
+ if (null == svc_strings[cmd])
+ Com.Printf(net_message.readcount - 1 + ":BAD CMD " + cmd + "\n");
+ else
+ SHOWNET(svc_strings[cmd]);
+ }
+
+ // other commands
+ switch (cmd) {
+ default :
+ Com.Error(ERR_DROP, "CL_ParseServerMessage: Illegible server message\n");
+ break;
+
+ case svc_nop :
+ // Com.Printf ("svc_nop\n");
+ break;
+
+ case svc_disconnect :
+ Com.Error(ERR_DISCONNECT, "Server disconnected\n");
+ break;
+
+ case svc_reconnect :
+ Com.Printf("Server disconnected, reconnecting\n");
+ if (cls.download != null) {
+ //ZOID, close download
+ fclose(cls.download);
+ cls.download = null;
+ }
+ cls.state = ca_connecting;
+ cls.connect_time = -99999; // CL_CheckForResend() will fire immediately
+ break;
+
+ case svc_print :
+ i = MSG.ReadByte(net_message);
+ if (i == PRINT_CHAT) {
+ SND_DMA.StartLocalSound("misc/talk.wav");
+ con.ormask = 128;
+ }
+ Com.Printf(MSG.ReadString(net_message));
+ con.ormask = 0;
+ break;
+
+ case svc_centerprint :
+ SCR.CenterPrint(MSG.ReadString(net_message));
+ break;
+
+ case svc_stufftext :
+ s = MSG.ReadString(net_message);
+ Com.DPrintf("stufftext: " + s + "\n");
+ Cbuf.AddText(s);
+ break;
+
+ case svc_serverdata :
+ Cbuf.Execute(); // make sure any stuffed commands are done
+ ParseServerData();
+ break;
+
+ case svc_configstring :
+ ParseConfigString();
+ break;
+
+ case svc_sound :
+ ParseStartSoundPacket();
+ break;
+
+ case svc_spawnbaseline :
+ ParseBaseline();
+ break;
+
+ case svc_temp_entity :
+ ParseTEnt();
+ break;
+
+ case svc_muzzleflash :
+ CL_fx.ParseMuzzleFlash();
+ break;
+
+ case svc_muzzleflash2 :
+ ParseMuzzleFlash2();
+ break;
+
+ case svc_download :
+ ParseDownload();
+ break;
+
+ case svc_frame :
+ ParseFrame();
+ break;
+
+ case svc_inventory :
+ CL_inv.ParseInventory();
+ break;
+
+ case svc_layout :
+ s = MSG.ReadString(net_message);
+ cl.layout = s;
+ break;
+
+ case svc_playerinfo :
+ case svc_packetentities :
+ case svc_deltapacketentities :
+ Com.Error(ERR_DROP, "Out of place frame data");
+ break;
+ }
+ }
+
+ CL_view.AddNetgraph();
+
+ //
+ // we don't know if it is ok to save a demo message until
+ // after we have parsed the frame
+ //
+ if (cls.demorecording && !cls.demowaiting)
+ CL.WriteDemoMessage();
+ }
+}
diff --git a/src/jake2/client/CL_pred.java b/src/jake2/client/CL_pred.java
new file mode 100644
index 0000000..cc8061f
--- /dev/null
+++ b/src/jake2/client/CL_pred.java
@@ -0,0 +1,347 @@
+/*
+ * CL_pred.java
+ * Copyright (C) 2004
+ *
+ * $Id: CL_pred.java,v 1.1 2004-07-07 19:58:39 hzi Exp $
+ */
+/*
+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.
+
+*/
+package jake2.client;
+
+import jake2.game.*;
+import jake2.qcommon.*;
+
+/**
+ * CL_pred
+ */
+public class CL_pred extends CL_parse
+{
+
+ /*
+ ===================
+ CL_CheckPredictionError
+ ===================
+ */
+ static void CheckPredictionError()
+ {
+ int frame;
+ int[] delta = new int[3];
+ int i;
+ int len;
+
+ if (cl_predict.value == 0.0f
+ || (cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION) != 0)
+ return;
+
+ // calculate the last usercmd_t we sent that the server has processed
+ frame = cls.netchan.incoming_acknowledged;
+ frame &= (CMD_BACKUP - 1);
+
+ // compare what the server returned with what we had predicted it to be
+ VectorSubtract(
+ cl.frame.playerstate.pmove.origin,
+ cl.predicted_origins[frame],
+ delta);
+
+ // save the prediction error for interpolation
+ len = Math.abs(delta[0]) + Math.abs(delta[1]) + Math.abs(delta[2]);
+ if (len > 640) // 80 world units
+ { // a teleport or something
+ VectorClear(cl.prediction_error);
+ }
+ else
+ {
+ if (cl_showmiss.value != 0.0f
+ && (delta[0] != 0 || delta[1] != 0 || delta[2] != 0))
+ Com.Printf(
+ "prediction miss on "
+ + cl.frame.serverframe
+ + ": "
+ + (delta[0] + delta[1] + delta[2])
+ + "\n");
+
+ VectorCopy(
+ cl.frame.playerstate.pmove.origin,
+ cl.predicted_origins[frame]);
+
+ // save for error itnerpolation
+ for (i = 0; i < 3; i++)
+ cl.prediction_error[i] = delta[i] * 0.125f;
+ }
+ }
+
+ /*
+ ====================
+ CL_ClipMoveToEntities
+
+ ====================
+ */
+ static void ClipMoveToEntities(
+ float[] start,
+ float[] mins,
+ float[] maxs,
+ float[] end,
+ trace_t tr)
+ {
+ int i, x, zd, zu;
+ trace_t trace;
+ int headnode;
+ float[] angles;
+ entity_state_t ent;
+ int num;
+ cmodel_t cmodel;
+ float[] bmins = new float[3];
+ float[] bmaxs = new float[3];
+
+ for (i = 0; i < cl.frame.num_entities; i++)
+ {
+ num = (cl.frame.parse_entities + i) & (MAX_PARSE_ENTITIES - 1);
+ ent = cl_parse_entities[num];
+
+ if (ent.solid == 0)
+ continue;
+
+ if (ent.number == cl.playernum + 1)
+ continue;
+
+ if (ent.solid == 31)
+ { // special value for bmodel
+ cmodel = cl.model_clip[ent.modelindex];
+ if (cmodel == null)
+ continue;
+ headnode = cmodel.headnode;
+ angles = ent.angles;
+ }
+ else
+ { // encoded bbox
+ x = 8 * (ent.solid & 31);
+ zd = 8 * ((ent.solid >>> 5) & 31);
+ zu = 8 * ((ent.solid >>> 10) & 63) - 32;
+
+ bmins[0] = bmins[1] = -x;
+ bmaxs[0] = bmaxs[1] = x;
+ bmins[2] = -zd;
+ bmaxs[2] = zu;
+
+ headnode = CM.HeadnodeForBox(bmins, bmaxs);
+ angles = vec3_origin; // boxes don't rotate
+ }
+
+ if (tr.allsolid)
+ return;
+
+ trace =
+ CM.TransformedBoxTrace(
+ start,
+ end,
+ mins,
+ maxs,
+ headnode,
+ MASK_PLAYERSOLID,
+ ent.origin,
+ angles);
+
+ if (trace.allsolid
+ || trace.startsolid
+ || trace.fraction < tr.fraction)
+ {
+ // TODO bugfix cwei
+ //if (trace.ent == null) trace.ent = new edict_t(0);
+ trace.ent = ent.surrounding_ent;
+ if (tr.startsolid)
+ {
+ tr = trace;
+ tr.startsolid = true;
+ }
+ else
+ tr = trace;
+ }
+ else if (trace.startsolid)
+ tr.startsolid = true;
+ }
+ }
+
+ /*
+ ================
+ CL_PMTrace
+ ================
+ */
+
+ static edict_t DUMMY_ENT = new edict_t(-1);
+
+ static trace_t PMTrace(float[] start, float[] mins, float[] maxs, float[] end) {
+ trace_t t;
+
+ // check against world
+ t = CM.BoxTrace(start, end, mins, maxs, 0, MASK_PLAYERSOLID);
+
+ if (t.fraction < 1.0f) {
+ t.ent = DUMMY_ENT;
+ }
+
+ // check all other solid models
+ CL.ClipMoveToEntities(start, mins, maxs, end, t);
+
+ return t;
+ }
+
+ static int PMpointcontents(float[] point)
+ {
+ int i;
+ entity_state_t ent;
+ int num;
+ cmodel_t cmodel;
+ int contents;
+
+ contents = CM.PointContents(point, 0);
+
+ for (i = 0; i < cl.frame.num_entities; i++)
+ {
+ num = (cl.frame.parse_entities + i) & (MAX_PARSE_ENTITIES - 1);
+ ent = cl_parse_entities[num];
+
+ if (ent.solid != 31) // special value for bmodel
+ continue;
+
+ cmodel = cl.model_clip[ent.modelindex];
+ if (cmodel == null)
+ continue;
+
+ contents
+ |= CM.TransformedPointContents(
+ point,
+ cmodel.headnode,
+ ent.origin,
+ ent.angles);
+ }
+
+ return contents;
+ }
+
+ /*
+ =================
+ CL_PredictMovement
+
+ Sets cl.predicted_origin and cl.predicted_angles
+ =================
+ */
+ static void PredictMovement()
+ {
+ int ack, current;
+ int frame;
+ int oldframe;
+ usercmd_t cmd;
+ pmove_t pm;
+ int i;
+ int step;
+ int oldz;
+
+ if (cls.state != ca_active)
+ return;
+
+ if (cl_paused.value != 0.0f)
+ return;
+
+ if (cl_predict.value == 0.0f
+ || (cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION) != 0)
+ { // just set angles
+ for (i = 0; i < 3; i++)
+ {
+ cl.predicted_angles[i] =
+ cl.viewangles[i]
+ + SHORT2ANGLE(cl.frame.playerstate.pmove.delta_angles[i]);
+ }
+ return;
+ }
+
+ ack = cls.netchan.incoming_acknowledged;
+ current = cls.netchan.outgoing_sequence;
+
+ // if we are too far out of date, just freeze
+ if (current - ack >= CMD_BACKUP)
+ {
+ if (cl_showmiss.value != 0.0f)
+ Com.Printf("exceeded CMD_BACKUP\n");
+ return;
+ }
+
+ // copy current state to pmove
+ //memset (pm, 0, sizeof(pm));
+ pm = new pmove_t();
+
+ pm.trace = new pmove_t.TraceAdapter()
+ {
+ public trace_t trace(
+ float[] start,
+ float[] mins,
+ float[] maxs,
+ float[] end)
+ {
+ return CL.PMTrace(start, mins, maxs, end);
+ }
+ };
+ pm.pointcontents = new pmove_t.PointContentsAdapter()
+ {
+ public int pointcontents(float[] point)
+ {
+ return CL.PMpointcontents(point);
+ }
+ };
+
+ PMove.pm_airaccelerate = atof(cl.configstrings[CS_AIRACCEL]);
+
+ // bugfix (rst) yeah !!!!!!!! found the B E W E G U N G S P R O B L E M.
+ pm.s.set(cl.frame.playerstate.pmove);
+
+ // SCR_DebugGraph (current - ack - 1, 0);
+ frame = 0;
+
+ // run frames
+ while (++ack < current)
+ {
+ frame = ack & (CMD_BACKUP - 1);
+ cmd = cl.cmds[frame];
+
+ pm.cmd.set(cmd);
+
+ PMove.Pmove(pm);
+
+ // save for debug checking
+ VectorCopy(pm.s.origin, cl.predicted_origins[frame]);
+ }
+
+ oldframe = (ack - 2) & (CMD_BACKUP - 1);
+ oldz = cl.predicted_origins[oldframe][2];
+ step = pm.s.origin[2] - oldz;
+ if (step > 63 && step < 160 && (pm.s.pm_flags & PMF_ON_GROUND) != 0)
+ {
+ cl.predicted_step = step * 0.125f;
+ cl.predicted_step_time = (int) (cls.realtime - cls.frametime * 500);
+ }
+
+ // copy results out for rendering
+ cl.predicted_origin[0] = pm.s.origin[0] * 0.125f;
+ cl.predicted_origin[1] = pm.s.origin[1] * 0.125f;
+ cl.predicted_origin[2] = pm.s.origin[2] * 0.125f;
+
+ VectorCopy(pm.viewangles, cl.predicted_angles);
+ }
+
+}
diff --git a/src/jake2/client/CL_tent.java b/src/jake2/client/CL_tent.java
new file mode 100644
index 0000000..7430a45
--- /dev/null
+++ b/src/jake2/client/CL_tent.java
@@ -0,0 +1,1720 @@
+/*
+ * CL_tent.java
+ * Copyright (C) 2004
+ *
+ * $Id: CL_tent.java,v 1.1 2004-07-07 19:58:40 hzi Exp $
+ */
+/*
+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.
+
+*/
+package jake2.client;
+
+import jake2.Globals;
+import jake2.game.player_state_t;
+import jake2.qcommon.Com;
+import jake2.qcommon.MSG;
+import jake2.render.model_t;
+
+/**
+ * CL_tent
+ */
+public class CL_tent extends Globals {
+
+ static final int ex_free = 0;
+ static final int ex_explosion = 1;
+ static final int ex_misc = 2;
+ static final int ex_flash = 3;
+ static final int ex_mflash = 4;
+ static final int ex_poly = 5;
+ static final int ex_poly2 = 6;
+
+
+ static class explosion_t {
+ int type;
+ entity_t ent = new entity_t();
+
+ int frames;
+ float light;
+ float[] lightcolor = new float[3];
+ float start;
+ int baseframe;
+ void clear() {
+ lightcolor[0] = lightcolor[1] = lightcolor[2] =
+ light = start = type = frames = baseframe = 0;
+ ent = new entity_t();
+ }
+ }
+
+ static final int MAX_EXPLOSIONS = 32;
+ static explosion_t[] cl_explosions = new explosion_t[MAX_EXPLOSIONS];
+ static {
+ for (int i = 0; i < cl_explosions.length; i++)
+ cl_explosions[i] = new explosion_t();
+ }
+
+ static final int MAX_BEAMS = 32;
+
+ static class beam_t {
+ int entity;
+ int dest_entity;
+ model_t model;
+ int endtime;
+ float[] offset = new float[3];
+ float[] start = new float[3];
+ float[] end = new float[3];
+ void clear() {
+ offset[0] = offset[1] = offset[2] =
+ start[0] = start[1] = start[2] =
+ end[0] = end[1] = end[2] =
+ entity = dest_entity = endtime = 0;
+ model = null;
+ }
+ }
+ static beam_t[] cl_beams = new beam_t[MAX_BEAMS];
+ // PMM - added this for player-linked beams. Currently only used by the plasma beam
+ static beam_t[] cl_playerbeams = new beam_t[MAX_BEAMS];
+ static {
+ for (int i = 0; i < cl_beams.length; i++)
+ cl_beams[i] = new beam_t();
+ for (int i = 0; i < cl_playerbeams.length; i++)
+ cl_playerbeams[i] = new beam_t();
+ }
+
+ static final int MAX_LASERS = 32;
+
+ static class laser_t {
+ entity_t ent = new entity_t();
+ int endtime;
+ void clear() {
+ endtime = 0;
+ ent = new entity_t();
+ }
+ }
+ static laser_t[] cl_lasers = new laser_t[MAX_LASERS];
+ static {
+ for (int i = 0; i < cl_lasers.length; i++)
+ cl_lasers[i] = new laser_t();
+ }
+
+// ROGUE
+ static final int MAX_SUSTAINS = 32;
+ static cl_sustain_t[] cl_sustains = new cl_sustain_t[MAX_SUSTAINS];
+ static {
+ for (int i = 0; i < cl_sustains.length; i++)
+ cl_sustains[i] = new cl_sustain_t();
+ }
+// ROGUE
+
+ // all are references;
+ static sfx_t cl_sfx_ric1;
+ static sfx_t cl_sfx_ric2;
+ static sfx_t cl_sfx_ric3;
+ static sfx_t cl_sfx_lashit;
+ static sfx_t cl_sfx_spark5;
+ static sfx_t cl_sfx_spark6;
+ static sfx_t cl_sfx_spark7;
+ static sfx_t cl_sfx_railg;
+ static sfx_t cl_sfx_rockexp;
+ static sfx_t cl_sfx_grenexp;
+ static sfx_t cl_sfx_watrexp;
+ // RAFAEL
+ static sfx_t cl_sfx_plasexp;
+ static sfx_t cl_sfx_footsteps[] = new sfx_t[4];
+
+ static model_t cl_mod_explode;
+ static model_t cl_mod_smoke;
+ static model_t cl_mod_flash;
+ static model_t cl_mod_parasite_segment;
+ static model_t cl_mod_grapple_cable;
+ static model_t cl_mod_parasite_tip;
+ static model_t cl_mod_explo4;
+ static model_t cl_mod_bfg_explo;
+ static model_t cl_mod_powerscreen;
+ // RAFAEL
+ static model_t cl_mod_plasmaexplo;
+
+ // ROGUE
+ static sfx_t cl_sfx_lightning;
+ static sfx_t cl_sfx_disrexp;
+ static model_t cl_mod_lightning;
+ static model_t cl_mod_heatbeam;
+ static model_t cl_mod_monster_heatbeam;
+ static model_t cl_mod_explo4_big;
+
+// ROGUE
+ /*
+ =================
+ CL_RegisterTEntSounds
+ =================
+ */
+ static void RegisterTEntSounds() {
+ int i;
+ String name;
+
+ // PMM - version stuff
+ // Com_Printf ("%s\n", ROGUE_VERSION_STRING);
+ // PMM
+ cl_sfx_ric1 = S.RegisterSound("world/ric1.wav");
+ cl_sfx_ric2 = S.RegisterSound("world/ric2.wav");
+ cl_sfx_ric3 = S.RegisterSound("world/ric3.wav");
+ cl_sfx_lashit = S.RegisterSound("weapons/lashit.wav");
+ cl_sfx_spark5 = S.RegisterSound("world/spark5.wav");
+ cl_sfx_spark6 = S.RegisterSound("world/spark6.wav");
+ cl_sfx_spark7 = S.RegisterSound("world/spark7.wav");
+ cl_sfx_railg = S.RegisterSound("weapons/railgf1a.wav");
+ cl_sfx_rockexp = S.RegisterSound("weapons/rocklx1a.wav");
+ cl_sfx_grenexp = S.RegisterSound("weapons/grenlx1a.wav");
+ cl_sfx_watrexp = S.RegisterSound("weapons/xpld_wat.wav");
+ // RAFAEL
+ // cl_sfx_plasexp = S.RegisterSound ("weapons/plasexpl.wav");
+ S.RegisterSound("player/land1.wav");
+
+ S.RegisterSound("player/fall2.wav");
+ S.RegisterSound("player/fall1.wav");
+
+ for (i = 0; i < 4; i++) {
+ //Com_sprintf (name, sizeof(name), "player/step%i.wav", i+1);
+ name = "player/step" + (i + 1) + ".wav";
+ cl_sfx_footsteps[i] = S.RegisterSound(name);
+ }
+
+ // PGM
+ cl_sfx_lightning = S.RegisterSound("weapons/tesla.wav");
+ cl_sfx_disrexp = S.RegisterSound("weapons/disrupthit.wav");
+ // version stuff
+ // sprintf (name, "weapons/sound%d.wav", ROGUE_VERSION_ID);
+ // if (name[0] == 'w')
+ // name[0] = 'W';
+ // PGM
+ }
+
+ /*
+ =================
+ CL_RegisterTEntModels
+ =================
+ */
+ static void RegisterTEntModels() {
+ cl_mod_explode = re.RegisterModel("models/objects/explode/tris.md2");
+ cl_mod_smoke = re.RegisterModel("models/objects/smoke/tris.md2");
+ cl_mod_flash = re.RegisterModel("models/objects/flash/tris.md2");
+ cl_mod_parasite_segment = re.RegisterModel("models/monsters/parasite/segment/tris.md2");
+ cl_mod_grapple_cable = re.RegisterModel("models/ctf/segment/tris.md2");
+ cl_mod_parasite_tip = re.RegisterModel("models/monsters/parasite/tip/tris.md2");
+ cl_mod_explo4 = re.RegisterModel("models/objects/r_explode/tris.md2");
+ cl_mod_bfg_explo = re.RegisterModel("sprites/s_bfg2.sp2");
+ cl_mod_powerscreen = re.RegisterModel("models/items/armor/effect/tris.md2");
+
+ re.RegisterModel("models/objects/laser/tris.md2");
+ re.RegisterModel("models/objects/grenade2/tris.md2");
+ re.RegisterModel("models/weapons/v_machn/tris.md2");
+ re.RegisterModel("models/weapons/v_handgr/tris.md2");
+ re.RegisterModel("models/weapons/v_shotg2/tris.md2");
+ re.RegisterModel("models/objects/gibs/bone/tris.md2");
+ re.RegisterModel("models/objects/gibs/sm_meat/tris.md2");
+ re.RegisterModel("models/objects/gibs/bone2/tris.md2");
+ // RAFAEL
+ // re.RegisterModel ("models/objects/blaser/tris.md2");
+
+ re.RegisterPic("w_machinegun");
+ re.RegisterPic("a_bullets");
+ re.RegisterPic("i_health");
+ re.RegisterPic("a_grenades");
+
+ // ROGUE
+ cl_mod_explo4_big = re.RegisterModel("models/objects/r_explode2/tris.md2");
+ cl_mod_lightning = re.RegisterModel("models/proj/lightning/tris.md2");
+ cl_mod_heatbeam = re.RegisterModel("models/proj/beam/tris.md2");
+ cl_mod_monster_heatbeam = re.RegisterModel("models/proj/widowbeam/tris.md2");
+ // ROGUE
+ }
+
+ /*
+ =================
+ CL_ClearTEnts
+ =================
+ */
+ static void ClearTEnts() {
+ // memset (cl_beams, 0, sizeof(cl_beams));
+ for (int i = 0; i < cl_beams.length; i++)
+ cl_beams[i].clear();
+ // memset (cl_explosions, 0, sizeof(cl_explosions));
+ for (int i = 0; i < cl_explosions.length; i++)
+ cl_explosions[i].clear();
+ // memset (cl_lasers, 0, sizeof(cl_lasers));
+ for (int i = 0; i < cl_lasers.length; i++)
+ cl_lasers[i].clear();
+ //
+ // ROGUE
+ // memset (cl_playerbeams, 0, sizeof(cl_playerbeams));
+ for (int i = 0; i < cl_playerbeams.length; i++)
+ cl_playerbeams[i].clear();
+ // memset (cl_sustains, 0, sizeof(cl_sustains));
+ for (int i = 0; i < cl_sustains.length; i++)
+ cl_sustains[i].clear();
+ // ROGUE
+ }
+
+ /*
+ =================
+ CL_AllocExplosion
+ =================
+ */
+ static explosion_t AllocExplosion() {
+ int i;
+ int time;
+ int index;
+
+ for (i = 0; i < MAX_EXPLOSIONS; i++) {
+ if (cl_explosions[i].type == ex_free) {
+ //memset (&cl_explosions[i], 0, sizeof (cl_explosions[i]));
+ cl_explosions[i].clear();
+ return cl_explosions[i];
+ }
+ }
+ // find the oldest explosion
+ time = cl.time;
+ index = 0;
+
+ for (i = 0; i < MAX_EXPLOSIONS; i++)
+ if (cl_explosions[i].start < time) {
+ time = (int)cl_explosions[i].start;
+ index = i;
+ }
+ //memset (&cl_explosions[index], 0, sizeof (cl_explosions[index]));
+ cl_explosions[index].clear();
+ return cl_explosions[index];
+ }
+
+ /*
+ =================
+ CL_SmokeAndFlash
+ =================
+ */
+ static void SmokeAndFlash(float[] origin) {
+ explosion_t ex;
+
+ ex = CL.AllocExplosion();
+ VectorCopy(origin, ex.ent.origin);
+ ex.type = ex_misc;
+ ex.frames = 4;
+ ex.ent.flags = RF_TRANSLUCENT;
+ ex.start = cl.frame.servertime - 100;
+ ex.ent.model = cl_mod_smoke;
+
+ ex = CL.AllocExplosion();
+ VectorCopy(origin, ex.ent.origin);
+ ex.type = ex_flash;
+ ex.ent.flags = RF_FULLBRIGHT;
+ ex.frames = 2;
+ ex.start = cl.frame.servertime - 100;
+ ex.ent.model = cl_mod_flash;
+ }
+
+ /*
+ =================
+ CL_ParseParticles
+ =================
+ */
+ static void ParseParticles() {
+ int color, count;
+ float[] pos = new float[3];
+ float[] dir = new float[3];
+
+ MSG.ReadPos(net_message, pos);
+ MSG.ReadDir(net_message, dir);
+
+ color = MSG.ReadByte(net_message);
+
+ count = MSG.ReadByte(net_message);
+
+ CL.ParticleEffect(pos, dir, color, count);
+ }
+
+ /*
+ =================
+ CL_ParseBeam
+ =================
+ */
+ static int ParseBeam(model_t model) {
+ int ent;
+ float[] start = new float[3];
+ float[] end = new float[3];
+ beam_t[] b;
+ int i;
+
+ ent = MSG.ReadShort(net_message);
+
+ MSG.ReadPos(net_message, start);
+ MSG.ReadPos(net_message, end);
+
+ // override any beam with the same entity
+ b = cl_beams;
+ for (i = 0; i < MAX_BEAMS; i++)
+ if (b[i].entity == ent) {
+ b[i].entity = ent;
+ b[i].model = model;
+ b[i].endtime = cl.time + 200;
+ VectorCopy(start, b[i].start);
+ VectorCopy(end, b[i].end);
+ VectorClear(b[i].offset);
+ return ent;
+ }
+
+ // find a free beam
+ b = cl_beams;
+ for (i = 0; i < MAX_BEAMS; i++) {
+ if (b[i].model == null || b[i].endtime < cl.time) {
+ b[i].entity = ent;
+ b[i].model = model;
+ b[i].endtime = cl.time + 200;
+ VectorCopy(start, b[i].start);
+ VectorCopy(end, b[i].end);
+ VectorClear(b[i].offset);
+ return ent;
+ }
+ }
+ Com.Printf("beam list overflow!\n");
+ return ent;
+ }
+
+ /*
+ =================
+ CL_ParseBeam2
+ =================
+ */
+ static int ParseBeam2(model_t model) {
+ int ent;
+ float[] start = new float[3];
+ float[] end = new float[3];
+ float[] offset = new float[3];
+ beam_t[] b;
+ int i;
+
+ ent = MSG.ReadShort(net_message);
+
+ MSG.ReadPos(net_message, start);
+ MSG.ReadPos(net_message, end);
+ MSG.ReadPos(net_message, offset);
+
+ // Com_Printf ("end- %f %f %f\n", end[0], end[1], end[2]);
+
+ // override any beam with the same entity
+ b = cl_beams;
+ for (i = 0; i < MAX_BEAMS; i++)
+ if (b[i].entity == ent) {
+ b[i].entity = ent;
+ b[i].model = model;
+ b[i].endtime = cl.time + 200;
+ VectorCopy(start, b[i].start);
+ VectorCopy(end, b[i].end);
+ VectorCopy(offset, b[i].offset);
+ return ent;
+ }
+
+ // find a free beam
+ b = cl_beams;
+ for (i = 0; i < MAX_BEAMS; i++) {
+ if (b[i].model == null || b[i].endtime < cl.time) {
+ b[i].entity = ent;
+ b[i].model = model;
+ b[i].endtime = cl.time + 200;
+ VectorCopy(start, b[i].start);
+ VectorCopy(end, b[i].end);
+ VectorCopy(offset, b[i].offset);
+ return ent;
+ }
+ }
+ Com.Printf("beam list overflow!\n");
+ return ent;
+ }
+
+ // ROGUE
+ /*
+ =================
+ CL_ParsePlayerBeam
+ - adds to the cl_playerbeam array instead of the cl_beams array
+ =================
+ */
+ static int ParsePlayerBeam(model_t model) {
+ int ent;
+ float[] start = new float[3];
+ float[] end = new float[3];
+ float[] offset = new float[3];
+ beam_t[] b;
+ int i;
+
+ ent = MSG.ReadShort(net_message);
+
+ MSG.ReadPos(net_message, start);
+ MSG.ReadPos(net_message, end);
+ // PMM - network optimization
+ if (model == cl_mod_heatbeam)
+ VectorSet(offset, 2, 7, -3);
+ else if (model == cl_mod_monster_heatbeam) {
+ model = cl_mod_heatbeam;
+ VectorSet(offset, 0, 0, 0);
+ } else
+ MSG.ReadPos(net_message, offset);
+
+ // Com_Printf ("end- %f %f %f\n", end[0], end[1], end[2]);
+
+ // override any beam with the same entity
+ // PMM - For player beams, we only want one per player (entity) so..
+ b = cl_playerbeams;
+ for (i = 0; i < MAX_BEAMS; i++) {
+ if (b[i].entity == ent) {
+ b[i].entity = ent;
+ b[i].model = model;
+ b[i].endtime = cl.time + 200;
+ VectorCopy(start, b[i].start);
+ VectorCopy(end, b[i].end);
+ VectorCopy(offset, b[i].offset);
+ return ent;
+ }
+ }
+
+ // find a free beam
+ b = cl_playerbeams;
+ for (i = 0; i < MAX_BEAMS; i++) {
+ if (b[i].model == null || b[i].endtime < cl.time) {
+ b[i].entity = ent;
+ b[i].model = model;
+ b[i].endtime = cl.time + 100; // PMM - this needs to be 100 to prevent multiple heatbeams
+ VectorCopy(start, b[i].start);
+ VectorCopy(end, b[i].end);
+ VectorCopy(offset, b[i].offset);
+ return ent;
+ }
+ }
+ Com.Printf("beam list overflow!\n");
+ return ent;
+ }
+// rogue
+
+ /*
+ =================
+ CL_ParseLightning
+ =================
+ */
+ static int ParseLightning(model_t model) {
+ int srcEnt, destEnt;
+ float[] start = new float[3];
+ float[] end = new float[3];
+ beam_t[] b;
+ int i;
+
+ srcEnt = MSG.ReadShort(net_message);
+ destEnt = MSG.ReadShort(net_message);
+
+ MSG.ReadPos(net_message, start);
+ MSG.ReadPos(net_message, end);
+
+ // override any beam with the same source AND destination entities
+ b = cl_beams;
+ for (i = 0; i < MAX_BEAMS; i++)
+ if (b[i].entity == srcEnt && b[i].dest_entity == destEnt) {
+ // Com_Printf("%d: OVERRIDE %d . %d\n", cl.time, srcEnt, destEnt);
+ b[i].entity = srcEnt;
+ b[i].dest_entity = destEnt;
+ b[i].model = model;
+ b[i].endtime = cl.time + 200;
+ VectorCopy(start, b[i].start);
+ VectorCopy(end, b[i].end);
+ VectorClear(b[i].offset);
+ return srcEnt;
+ }
+
+ // find a free beam
+ b = cl_beams;
+ for (i = 0; i < MAX_BEAMS; i++) {
+ if (b[i].model == null || b[i].endtime < cl.time) {
+ // Com_Printf("%d: NORMAL %d . %d\n", cl.time, srcEnt, destEnt);
+ b[i].entity = srcEnt;
+ b[i].dest_entity = destEnt;
+ b[i].model = model;
+ b[i].endtime = cl.time + 200;
+ VectorCopy(start, b[i].start);
+ VectorCopy(end, b[i].end);
+ VectorClear(b[i].offset);
+ return srcEnt;
+ }
+ }
+ Com.Printf("beam list overflow!\n");
+ return srcEnt;
+ }
+
+ /*
+ =================
+ CL_ParseLaser
+ =================
+ */
+ static void ParseLaser(int colors) {
+ float[] start = new float[3];
+ float[] end = new float[3];
+ laser_t[] l;
+ int i;
+
+ MSG.ReadPos(net_message, start);
+ MSG.ReadPos(net_message, end);
+
+ l = cl_lasers;
+ for (i = 0; i < MAX_LASERS; i++) {
+ if (l[i].endtime < cl.time) {
+ l[i].ent.flags = RF_TRANSLUCENT | RF_BEAM;
+ VectorCopy(start, l[i].ent.origin);
+ VectorCopy(end, l[i].ent.oldorigin);
+ l[i].ent.alpha = 0.30f;
+ l[i].ent.skinnum = (colors >> ((rand() % 4) * 8)) & 0xff;
+ l[i].ent.model = null;
+ l[i].ent.frame = 4;
+ l[i].endtime = cl.time + 100;
+ return;
+ }
+ }
+ }
+
+// =============
+// ROGUE
+ static void ParseSteam() {
+ float[] pos = new float[3];
+ float[] dir = new float[3];
+ int id, i;
+ int r;
+ int cnt;
+ int color;
+ int magnitude;
+ cl_sustain_t[] s;
+ cl_sustain_t free_sustain;
+
+ id = MSG.ReadShort(net_message); // an id of -1 is an instant effect
+ if (id != -1) // sustains
+ {
+ // Com_Printf ("Sustain effect id %d\n", id);
+ free_sustain = null;
+ s = cl_sustains;
+ for (i = 0; i < MAX_SUSTAINS; i++) {
+ if (s[i].id == 0) {
+ free_sustain = s[i];
+ break;
+ }
+ }
+ if (free_sustain != null) {
+ s[i].id = id;
+ s[i].count = MSG.ReadByte(net_message);
+ MSG.ReadPos(net_message, s[i].org);
+ MSG.ReadDir(net_message, s[i].dir);
+ r = MSG.ReadByte(net_message);
+ s[i].color = r & 0xff;
+ s[i].magnitude = MSG.ReadShort(net_message);
+ s[i].endtime = cl.time + MSG.ReadLong(net_message);
+ s[i].think = new cl_sustain_t.ThinkAdapter() {
+ void think(cl_sustain_t self) {
+ CL.ParticleSteamEffect2(self);
+ }
+ };
+ s[i].thinkinterval = 100;
+ s[i].nextthink = cl.time;
+ } else {
+ // Com_Printf ("No free sustains!\n");
+ // FIXME - read the stuff anyway
+ cnt = MSG.ReadByte(net_message);
+ MSG.ReadPos(net_message, pos);
+ MSG.ReadDir(net_message, dir);
+ r = MSG.ReadByte(net_message);
+ magnitude = MSG.ReadShort(net_message);
+ magnitude = MSG.ReadLong(net_message); // really interval
+ }
+ } else // instant
+ {
+ cnt = MSG.ReadByte(net_message);
+ MSG.ReadPos(net_message, pos);
+ MSG.ReadDir(net_message, dir);
+ r = MSG.ReadByte(net_message);
+ magnitude = MSG.ReadShort(net_message);
+ color = r & 0xff;
+ CL.ParticleSteamEffect(pos, dir, color, cnt, magnitude);
+ // S_StartSound (pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+ }
+ }
+
+ static void ParseWidow() {
+ float[] pos = new float[3];
+ int id, i;
+ cl_sustain_t[] s;
+ cl_sustain_t free_sustain;
+
+ id = MSG.ReadShort(net_message);
+
+ free_sustain = null;
+ s = cl_sustains;
+ for (i = 0; i < MAX_SUSTAINS; i++) {
+ if (s[i].id == 0) {
+ free_sustain = s[i];
+ break;
+ }
+ }
+ if (free_sustain != null) {
+ s[i].id = id;
+ MSG.ReadPos(net_message, s[i].org);
+ s[i].endtime = cl.time + 2100;
+ s[i].think = new cl_sustain_t.ThinkAdapter() {
+ void think(cl_sustain_t self) {
+ CL.Widowbeamout(self);
+ }
+ };
+ s[i].thinkinterval = 1;
+ s[i].nextthink = cl.time;
+ } else // no free sustains
+ {
+ // FIXME - read the stuff anyway
+ MSG.ReadPos(net_message, pos);
+ }
+ }
+
+ static void ParseNuke() {
+ float[] pos = new float[3];
+ int i;
+ cl_sustain_t[] s;
+ cl_sustain_t free_sustain;
+
+ free_sustain = null;
+ s = cl_sustains;
+ for (i = 0; i < MAX_SUSTAINS; i++) {
+ if (s[i].id == 0) {
+ free_sustain = s[i];
+ break;
+ }
+ }
+ if (free_sustain != null) {
+ s[i].id = 21000;
+ MSG.ReadPos(net_message, s[i].org);
+ s[i].endtime = cl.time + 1000;
+ s[i].think = new cl_sustain_t.ThinkAdapter() {
+ void think(cl_sustain_t self) {
+ CL.Nukeblast(self);
+ }
+ };
+ s[i].thinkinterval = 1;
+ s[i].nextthink = cl.time;
+ } else // no free sustains
+ {
+ // FIXME - read the stuff anyway
+ MSG.ReadPos(net_message, pos);
+ }
+ }
+
+// ROGUE
+// =============
+
+
+ /*
+ =================
+ CL_ParseTEnt
+ =================
+ */
+ static int[] splash_color = {0x00, 0xe0, 0xb0, 0x50, 0xd0, 0xe0, 0xe8};
+ static void ParseTEnt() {
+ int type;
+ float[] pos = new float[3];
+ float[] pos2 = new float[3];
+ float[] dir = new float[3];
+ explosion_t ex;
+ int cnt;
+ int color;
+ int r;
+ int ent;
+ int magnitude;
+
+ type = MSG.ReadByte(net_message);
+
+ switch (type) {
+ case TE_BLOOD : // bullet hitting flesh
+ MSG.ReadPos(net_message, pos);
+ MSG.ReadDir(net_message, dir);
+ CL.ParticleEffect(pos, dir, 0xe8, 60);
+ break;
+
+ case TE_GUNSHOT : // bullet hitting wall
+ case TE_SPARKS :
+ case TE_BULLET_SPARKS :
+ MSG.ReadPos(net_message, pos);
+ MSG.ReadDir(net_message, dir);
+ if (type == TE_GUNSHOT)
+ CL.ParticleEffect(pos, dir, 0, 40);
+ else
+ CL.ParticleEffect(pos, dir, 0xe0, 6);
+
+ if (type != TE_SPARKS) {
+ CL.SmokeAndFlash(pos);
+
+ // impact sound
+ cnt = rand() & 15;
+ if (cnt == 1)
+ S.StartSound(pos, 0, 0, cl_sfx_ric1, 1, ATTN_NORM, 0);
+ else if (cnt == 2)
+ S.StartSound(pos, 0, 0, cl_sfx_ric2, 1, ATTN_NORM, 0);
+ else if (cnt == 3)
+ S.StartSound(pos, 0, 0, cl_sfx_ric3, 1, ATTN_NORM, 0);
+ }
+
+ break;
+
+ case TE_SCREEN_SPARKS :
+ case TE_SHIELD_SPARKS :
+ MSG.ReadPos(net_message, pos);
+ MSG.ReadDir(net_message, dir);
+ if (type == TE_SCREEN_SPARKS)
+ CL.ParticleEffect(pos, dir, 0xd0, 40);
+ else
+ CL.ParticleEffect(pos, dir, 0xb0, 40);
+ //FIXME : replace or remove this sound
+ S.StartSound(pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+ break;
+
+ case TE_SHOTGUN : // bullet hitting wall
+ MSG.ReadPos(net_message, pos);
+ MSG.ReadDir(net_message, dir);
+ CL.ParticleEffect(pos, dir, 0, 20);
+ CL.SmokeAndFlash(pos);
+ break;
+
+ case TE_SPLASH : // bullet hitting water
+ cnt = MSG.ReadByte(net_message);
+ MSG.ReadPos(net_message, pos);
+ MSG.ReadDir(net_message, dir);
+ r = MSG.ReadByte(net_message);
+ if (r > 6)
+ color = 0x00;
+ else
+ color = splash_color[r];
+ CL.ParticleEffect(pos, dir, color, cnt);
+
+ if (r == SPLASH_SPARKS) {
+ r = rand() & 3;
+ if (r == 0)
+ S.StartSound(pos, 0, 0, cl_sfx_spark5, 1, ATTN_STATIC, 0);
+ else if (r == 1)
+ S.StartSound(pos, 0, 0, cl_sfx_spark6, 1, ATTN_STATIC, 0);
+ else
+ S.StartSound(pos, 0, 0, cl_sfx_spark7, 1, ATTN_STATIC, 0);
+ }
+ break;
+
+ case TE_LASER_SPARKS :
+ cnt = MSG.ReadByte(net_message);
+ MSG.ReadPos(net_message, pos);
+ MSG.ReadDir(net_message, dir);
+ color = MSG.ReadByte(net_message);
+ CL.ParticleEffect2(pos, dir, color, cnt);
+ break;
+
+ // RAFAEL
+ case TE_BLUEHYPERBLASTER :
+ MSG.ReadPos(net_message, pos);
+ MSG.ReadPos(net_message, dir);
+ CL.BlasterParticles(pos, dir);
+ break;
+
+ case TE_BLASTER : // blaster hitting wall
+ MSG.ReadPos(net_message, pos);
+ MSG.ReadDir(net_message, dir);
+ CL.BlasterParticles(pos, dir);
+
+ ex = CL.AllocExplosion();
+ VectorCopy(pos, ex.ent.origin);
+ ex.ent.angles[0] = (float) (Math.acos(dir[2]) / Math.PI * 180);
+ // PMM - fixed to correct for pitch of 0
+ if (dir[0] != 0.0f)
+ ex.ent.angles[1] = (float) (Math.atan2(dir[1], dir[0]) / Math.PI * 180);
+ else if (dir[1] > 0)
+ ex.ent.angles[1] = 90;
+ else if (dir[1] < 0)
+ ex.ent.angles[1] = 270;
+ else
+ ex.ent.angles[1] = 0;
+
+ ex.type = ex_misc;
+ ex.ent.flags = RF_FULLBRIGHT | RF_TRANSLUCENT;
+ ex.start = cl.frame.servertime - 100;
+ ex.light = 150;
+ ex.lightcolor[0] = 1;
+ ex.lightcolor[1] = 1;
+ ex.ent.model = cl_mod_explode;
+ ex.frames = 4;
+ S.StartSound(pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+ break;
+
+ case TE_RAILTRAIL : // railgun effect
+ MSG.ReadPos(net_message, pos);
+ MSG.ReadPos(net_message, pos2);
+ CL.RailTrail(pos, pos2);
+ S.StartSound(pos2, 0, 0, cl_sfx_railg, 1, ATTN_NORM, 0);
+ break;
+
+ case TE_EXPLOSION2 :
+ case TE_GRENADE_EXPLOSION :
+ case TE_GRENADE_EXPLOSION_WATER :
+ MSG.ReadPos(net_message, pos);
+
+ ex = CL.AllocExplosion();
+ VectorCopy(pos, ex.ent.origin);
+ ex.type = ex_poly;
+ ex.ent.flags = RF_FULLBRIGHT;
+ ex.start = cl.frame.servertime - 100;
+ ex.light = 350;
+ ex.lightcolor[0] = 1.0f;
+ ex.lightcolor[1] = 0.5f;
+ ex.lightcolor[2] = 0.5f;
+ ex.ent.model = cl_mod_explo4;
+ ex.frames = 19;
+ ex.baseframe = 30;
+ ex.ent.angles[1] = rand() % 360;
+ CL.ExplosionParticles(pos);
+ if (type == TE_GRENADE_EXPLOSION_WATER)
+ S.StartSound(pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
+ else
+ S.StartSound(pos, 0, 0, cl_sfx_grenexp, 1, ATTN_NORM, 0);
+ break;
+
+ // RAFAEL
+ case TE_PLASMA_EXPLOSION :
+ MSG.ReadPos(net_message, pos);
+ ex = CL.AllocExplosion();
+ VectorCopy(pos, ex.ent.origin);
+ ex.type = ex_poly;
+ ex.ent.flags = RF_FULLBRIGHT;
+ ex.start = cl.frame.servertime - 100;
+ ex.light = 350;
+ ex.lightcolor[0] = 1.0f;
+ ex.lightcolor[1] = 0.5f;
+ ex.lightcolor[2] = 0.5f;
+ ex.ent.angles[1] = rand() % 360;
+ ex.ent.model = cl_mod_explo4;
+ if (frand() < 0.5)
+ ex.baseframe = 15;
+ ex.frames = 15;
+ CL.ExplosionParticles(pos);
+ S.StartSound(pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
+ break;
+
+ case TE_EXPLOSION1 :
+ case TE_EXPLOSION1_BIG : // PMM
+ case TE_ROCKET_EXPLOSION :
+ case TE_ROCKET_EXPLOSION_WATER :
+ case TE_EXPLOSION1_NP : // PMM
+ MSG.ReadPos(net_message, pos);
+
+ ex = CL.AllocExplosion();
+ VectorCopy(pos, ex.ent.origin);
+ ex.type = ex_poly;
+ ex.ent.flags = RF_FULLBRIGHT;
+ ex.start = cl.frame.servertime - 100;
+ ex.light = 350;
+ ex.lightcolor[0] = 1.0f;
+ ex.lightcolor[1] = 0.5f;
+ ex.lightcolor[2] = 0.5f;
+ ex.ent.angles[1] = rand() % 360;
+ if (type != TE_EXPLOSION1_BIG) // PMM
+ ex.ent.model = cl_mod_explo4; // PMM
+ else
+ ex.ent.model = cl_mod_explo4_big;
+ if (frand() < 0.5)
+ ex.baseframe = 15;
+ ex.frames = 15;
+ if ((type != TE_EXPLOSION1_BIG) && (type != TE_EXPLOSION1_NP)) // PMM
+ CL.ExplosionParticles(pos); // PMM
+ if (type == TE_ROCKET_EXPLOSION_WATER)
+ S.StartSound(pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
+ else
+ S.StartSound(pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
+ break;
+
+ case TE_BFG_EXPLOSION :
+ MSG.ReadPos(net_message, pos);
+ ex = CL.AllocExplosion();
+ VectorCopy(pos, ex.ent.origin);
+ ex.type = ex_poly;
+ ex.ent.flags = RF_FULLBRIGHT;
+ ex.start = cl.frame.servertime - 100;
+ ex.light = 350;
+ ex.lightcolor[0] = 0.0f;
+ ex.lightcolor[1] = 1.0f;
+ ex.lightcolor[2] = 0.0f;
+ ex.ent.model = cl_mod_bfg_explo;
+ ex.ent.flags |= RF_TRANSLUCENT;
+ ex.ent.alpha = 0.30f;
+ ex.frames = 4;
+ break;
+
+ case TE_BFG_BIGEXPLOSION :
+ MSG.ReadPos(net_message, pos);
+ CL.BFGExplosionParticles(pos);
+ break;
+
+ case TE_BFG_LASER :
+ CL.ParseLaser(0xd0d1d2d3);
+ break;
+
+ case TE_BUBBLETRAIL :
+ MSG.ReadPos(net_message, pos);
+ MSG.ReadPos(net_message, pos2);
+ CL.BubbleTrail(pos, pos2);
+ break;
+
+ case TE_PARASITE_ATTACK :
+ case TE_MEDIC_CABLE_ATTACK :
+ ent = CL.ParseBeam(cl_mod_parasite_segment);
+ break;
+
+ case TE_BOSSTPORT : // boss teleporting to station
+ MSG.ReadPos(net_message, pos);
+ CL.BigTeleportParticles(pos);
+ S.StartSound(pos, 0, 0, S.RegisterSound("misc/bigtele.wav"), 1, ATTN_NONE, 0);
+ break;
+
+ case TE_GRAPPLE_CABLE :
+ ent = CL.ParseBeam2(cl_mod_grapple_cable);
+ break;
+
+ // RAFAEL
+ case TE_WELDING_SPARKS :
+ cnt = MSG.ReadByte(net_message);
+ MSG.ReadPos(net_message, pos);
+ MSG.ReadDir(net_message, dir);
+ color = MSG.ReadByte(net_message);
+ CL.ParticleEffect2(pos, dir, color, cnt);
+
+ ex = CL.AllocExplosion();
+ VectorCopy(pos, ex.ent.origin);
+ ex.type = ex_flash;
+ // note to self
+ // we need a better no draw flag
+ ex.ent.flags = RF_BEAM;
+ ex.start = cl.frame.servertime - 0.1f;
+ ex.light = 100 + (rand() % 75);
+ ex.lightcolor[0] = 1.0f;
+ ex.lightcolor[1] = 1.0f;
+ ex.lightcolor[2] = 0.3f;
+ ex.ent.model = cl_mod_flash;
+ ex.frames = 2;
+ break;
+
+ case TE_GREENBLOOD :
+ MSG.ReadPos(net_message, pos);
+ MSG.ReadDir(net_message, dir);
+ CL.ParticleEffect2(pos, dir, 0xdf, 30);
+ break;
+
+ // RAFAEL
+ case TE_TUNNEL_SPARKS :
+ cnt = MSG.ReadByte(net_message);
+ MSG.ReadPos(net_message, pos);
+ MSG.ReadDir(net_message, dir);
+ color = MSG.ReadByte(net_message);
+ CL.ParticleEffect3(pos, dir, color, cnt);
+ break;
+
+ // =============
+ // PGM
+ // PMM -following code integrated for flechette (different color)
+ case TE_BLASTER2 : // green blaster hitting wall
+ case TE_FLECHETTE : // flechette
+ MSG.ReadPos(net_message, pos);
+ MSG.ReadDir(net_message, dir);
+
+ // PMM
+ if (type == TE_BLASTER2)
+ CL.BlasterParticles2(pos, dir, 0xd0);
+ else
+ CL.BlasterParticles2(pos, dir, 0x6f); // 75
+
+ ex = CL.AllocExplosion();
+ VectorCopy(pos, ex.ent.origin);
+ ex.ent.angles[0] = (float) (Math.acos(dir[2]) / Math.PI * 180);
+ // PMM - fixed to correct for pitch of 0
+ if (dir[0] != 0.0f)
+ ex.ent.angles[1] = (float) (Math.atan2(dir[1], dir[0]) / Math.PI * 180);
+ else if (dir[1] > 0)
+ ex.ent.angles[1] = 90;
+ else if (dir[1] < 0)
+ ex.ent.angles[1] = 270;
+ else
+ ex.ent.angles[1] = 0;
+
+ ex.type = ex_misc;
+ ex.ent.flags = RF_FULLBRIGHT | RF_TRANSLUCENT;
+
+ // PMM
+ if (type == TE_BLASTER2)
+ ex.ent.skinnum = 1;
+ else // flechette
+ ex.ent.skinnum = 2;
+
+ ex.start = cl.frame.servertime - 100;
+ ex.light = 150;
+ // PMM
+ if (type == TE_BLASTER2)
+ ex.lightcolor[1] = 1;
+ else // flechette
+ {
+ ex.lightcolor[0] = 0.19f;
+ ex.lightcolor[1] = 0.41f;
+ ex.lightcolor[2] = 0.75f;
+ }
+ ex.ent.model = cl_mod_explode;
+ ex.frames = 4;
+ S.StartSound(pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+ break;
+
+ case TE_LIGHTNING :
+ ent = CL.ParseLightning(cl_mod_lightning);
+ S.StartSound(null, ent, CHAN_WEAPON, cl_sfx_lightning, 1, ATTN_NORM, 0);
+ break;
+
+ case TE_DEBUGTRAIL :
+ MSG.ReadPos(net_message, pos);
+ MSG.ReadPos(net_message, pos2);
+ CL.DebugTrail(pos, pos2);
+ break;
+
+ case TE_PLAIN_EXPLOSION :
+ MSG.ReadPos(net_message, pos);
+
+ ex = CL.AllocExplosion();
+ VectorCopy(pos, ex.ent.origin);
+ ex.type = ex_poly;
+ ex.ent.flags = RF_FULLBRIGHT;
+ ex.start = cl.frame.servertime - 100;
+ ex.light = 350;
+ ex.lightcolor[0] = 1.0f;
+ ex.lightcolor[1] = 0.5f;
+ ex.lightcolor[2] = 0.5f;
+ ex.ent.angles[1] = rand() % 360;
+ ex.ent.model = cl_mod_explo4;
+ if (frand() < 0.5)
+ ex.baseframe = 15;
+ ex.frames = 15;
+ if (type == TE_ROCKET_EXPLOSION_WATER)
+ S.StartSound(pos, 0, 0, cl_sfx_watrexp, 1, ATTN_NORM, 0);
+ else
+ S.StartSound(pos, 0, 0, cl_sfx_rockexp, 1, ATTN_NORM, 0);
+ break;
+
+ case TE_FLASHLIGHT :
+ MSG.ReadPos(net_message, pos);
+ ent = MSG.ReadShort(net_message);
+ CL.Flashlight(ent, pos);
+ break;
+
+ case TE_FORCEWALL :
+ MSG.ReadPos(net_message, pos);
+ MSG.ReadPos(net_message, pos2);
+ color = MSG.ReadByte(net_message);
+ CL.ForceWall(pos, pos2, color);
+ break;
+
+ case TE_HEATBEAM :
+ ent = CL.ParsePlayerBeam(cl_mod_heatbeam);
+ break;
+
+ case TE_MONSTER_HEATBEAM :
+ ent = CL.ParsePlayerBeam(cl_mod_monster_heatbeam);
+ break;
+
+ case TE_HEATBEAM_SPARKS :
+ // cnt = MSG.ReadByte (net_message);
+ cnt = 50;
+ MSG.ReadPos(net_message, pos);
+ MSG.ReadDir(net_message, dir);
+ // r = MSG.ReadByte (net_message);
+ // magnitude = MSG.ReadShort (net_message);
+ r = 8;
+ magnitude = 60;
+ color = r & 0xff;
+ CL.ParticleSteamEffect(pos, dir, color, cnt, magnitude);
+ S.StartSound(pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+ break;
+
+ case TE_HEATBEAM_STEAM :
+ // cnt = MSG.ReadByte (net_message);
+ cnt = 20;
+ MSG.ReadPos(net_message, pos);
+ MSG.ReadDir(net_message, dir);
+ // r = MSG.ReadByte (net_message);
+ // magnitude = MSG.ReadShort (net_message);
+ // color = r & 0xff;
+ color = 0xe0;
+ magnitude = 60;
+ CL.ParticleSteamEffect(pos, dir, color, cnt, magnitude);
+ S.StartSound(pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+ break;
+
+ case TE_STEAM :
+ CL.ParseSteam();
+ break;
+
+ case TE_BUBBLETRAIL2 :
+ // cnt = MSG.ReadByte (net_message);
+ cnt = 8;
+ MSG.ReadPos(net_message, pos);
+ MSG.ReadPos(net_message, pos2);
+ CL.BubbleTrail2(pos, pos2, cnt);
+ S.StartSound(pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+ break;
+
+ case TE_MOREBLOOD :
+ MSG.ReadPos(net_message, pos);
+ MSG.ReadDir(net_message, dir);
+ CL.ParticleEffect(pos, dir, 0xe8, 250);
+ break;
+
+ case TE_CHAINFIST_SMOKE :
+ dir[0] = 0;
+ dir[1] = 0;
+ dir[2] = 1;
+ MSG.ReadPos(net_message, pos);
+ CL.ParticleSmokeEffect(pos, dir, 0, 20, 20);
+ break;
+
+ case TE_ELECTRIC_SPARKS :
+ MSG.ReadPos(net_message, pos);
+ MSG.ReadDir(net_message, dir);
+ // CL_ParticleEffect (pos, dir, 109, 40);
+ CL.ParticleEffect(pos, dir, 0x75, 40);
+ //FIXME : replace or remove this sound
+ S.StartSound(pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0);
+ break;
+
+ case TE_TRACKER_EXPLOSION :
+ MSG.ReadPos(net_message, pos);
+ CL.ColorFlash(pos, 0, 150, -1, -1, -1);
+ CL.ColorExplosionParticles(pos, 0, 1);
+ // CL_Tracker_Explode (pos);
+ S.StartSound(pos, 0, 0, cl_sfx_disrexp, 1, ATTN_NORM, 0);
+ break;
+
+ case TE_TELEPORT_EFFECT :
+ case TE_DBALL_GOAL :
+ MSG.ReadPos(net_message, pos);
+ CL.TeleportParticles(pos);
+ break;
+
+ case TE_WIDOWBEAMOUT :
+ CL.ParseWidow();
+ break;
+
+ case TE_NUKEBLAST :
+ ParseNuke();
+ break;
+
+ case TE_WIDOWSPLASH :
+ MSG.ReadPos(net_message, pos);
+ CL.WidowSplash(pos);
+ break;
+ // PGM
+ // ==============
+
+ default :
+ Com.Error(ERR_DROP, "CL_ParseTEnt: bad type");
+ }
+ }
+
+ /*
+ =================
+ CL_AddBeams
+ =================
+ */
+ static void AddBeams() {
+ int i, j;
+ beam_t[] b;
+ float[] dist = new float[3];
+ float[] org = new float[3];
+ float d;
+ entity_t ent = new entity_t();
+ float yaw, pitch;
+ float forward;
+ float len, steps;
+ float model_length;
+
+ // update beams
+ b = cl_beams;
+ for (i = 0; i < MAX_BEAMS; i++) {
+ if (b[i].model == null || b[i].endtime < cl.time)
+ continue;
+
+ // if coming from the player, update the start position
+ if (b[i].entity == cl.playernum + 1) // entity 0 is the world
+ {
+ VectorCopy(cl.refdef.vieworg, b[i].start);
+ b[i].start[2] -= 22; // adjust for view height
+ }
+ VectorAdd(b[i].start, b[i].offset, org);
+
+ // calculate pitch and yaw
+ VectorSubtract(b[i].end, org, dist);
+
+ if (dist[1] == 0 && dist[0] == 0) {
+ yaw = 0;
+ if (dist[2] > 0)
+ pitch = 90;
+ else
+ pitch = 270;
+ } else {
+ // PMM - fixed to correct for pitch of 0
+ if (dist[0] != 0.0f)
+ yaw = (float) (Math.atan2(dist[1], dist[0]) * 180 / Math.PI);
+ else if (dist[1] > 0)
+ yaw = 90;
+ else
+ yaw = 270;
+ if (yaw < 0)
+ yaw += 360;
+
+ forward = (float)Math.sqrt(dist[0] * dist[0] + dist[1] * dist[1]);
+ pitch = (float) (Math.atan2(dist[2], forward) * -180.0 / Math.PI);
+ if (pitch < 0)
+ pitch += 360.0;
+ }
+
+ // add new entities for the beams
+ d = VectorNormalize(dist);
+
+ //memset (&ent, 0, sizeof(ent));
+ ent = new entity_t();
+ if (b[i].model == cl_mod_lightning) {
+ model_length = 35.0f;
+ d -= 20.0; // correction so it doesn't end in middle of tesla
+ } else {
+ model_length = 30.0f;
+ }
+ steps = (float)Math.ceil(d / model_length);
+ len = (d - model_length) / (steps - 1);
+
+ // PMM - special case for lightning model .. if the real length is shorter than the model,
+ // flip it around & draw it from the end to the start. This prevents the model from going
+ // through the tesla mine (instead it goes through the target)
+ if ((b[i].model == cl_mod_lightning) && (d <= model_length)) {
+ // Com_Printf ("special case\n");
+ VectorCopy(b[i].end, ent.origin);
+ // offset to push beam outside of tesla model (negative because dist is from end to start
+ // for this beam)
+ // for (j=0 ; j<3 ; j++)
+ // ent.origin[j] -= dist[j]*10.0;
+ ent.model = b[i].model;
+ ent.flags = RF_FULLBRIGHT;
+ ent.angles[0] = pitch;
+ ent.angles[1] = yaw;
+ ent.angles[2] = rand() % 360;
+ V.AddEntity(ent);
+ return;
+ }
+ while (d > 0) {
+ VectorCopy(org, ent.origin);
+ ent.model = b[i].model;
+ if (b[i].model == cl_mod_lightning) {
+ ent.flags = RF_FULLBRIGHT;
+ ent.angles[0] = -pitch;
+ ent.angles[1] = yaw + 180.0f;
+ ent.angles[2] = rand() % 360;
+ } else {
+ ent.angles[0] = pitch;
+ ent.angles[1] = yaw;
+ ent.angles[2] = rand() % 360;
+ }
+
+ // Com_Printf("B: %d . %d\n", b[i].entity, b[i].dest_entity);
+ V.AddEntity(ent);
+
+ for (j = 0; j < 3; j++)
+ org[j] += dist[j] * len;
+ d -= model_length;
+ }
+ }
+ }
+
+ //extern cvar_t *hand;
+
+ /*
+ =================
+ ROGUE - draw player locked beams
+ CL_AddPlayerBeams
+ =================
+ */
+ static void AddPlayerBeams() {
+ int i, j;
+ beam_t[] b;
+ float[] dist = new float[3];
+ float[] org = new float[3];
+ float d;
+ entity_t ent = new entity_t();
+ float yaw, pitch;
+ float forward;
+ float len, steps;
+ int framenum = 0;
+ float model_length;
+
+ float hand_multiplier;
+ frame_t oldframe;
+ player_state_t ps, ops;
+
+ // PMM
+ if (hand != null) {
+ if (hand.value == 2)
+ hand_multiplier = 0;
+ else if (hand.value == 1)
+ hand_multiplier = -1;
+ else
+ hand_multiplier = 1;
+ } else {
+ hand_multiplier = 1;
+ }
+ // PMM
+
+ // update beams
+ b = cl_playerbeams;
+ for (i = 0; i < MAX_BEAMS; i++) {
+ float[] f = new float[3];
+ float[] u = new float[3];
+ float[] r = new float[3];
+ if (b[i].model == null || b[i].endtime < cl.time)
+ continue;
+
+ if (cl_mod_heatbeam != null && (b[i].model == cl_mod_heatbeam)) {
+
+ // if coming from the player, update the start position
+ if (b[i].entity == cl.playernum + 1) // entity 0 is the world
+ {
+ // set up gun position
+ // code straight out of CL_AddViewWeapon
+ ps = cl.frame.playerstate;
+ j = (cl.frame.serverframe - 1) & UPDATE_MASK;
+ oldframe = cl.frames[j];
+
+ if (oldframe.serverframe != cl.frame.serverframe - 1 || !oldframe.valid)
+ oldframe = cl.frame; // previous frame was dropped or involid
+
+ ops = oldframe.playerstate;
+ for (j = 0; j < 3; j++) {
+ b[i].start[j] =
+ cl.refdef.vieworg[j]
+ + ops.gunoffset[j]
+ + cl.lerpfrac * (ps.gunoffset[j] - ops.gunoffset[j]);
+ }
+ VectorMA(b[i].start, (hand_multiplier * b[i].offset[0]), cl.v_right, org);
+ VectorMA(org, b[i].offset[1], cl.v_forward, org);
+ VectorMA(org, b[i].offset[2], cl.v_up, org);
+ if ((hand != null) && (hand.value == 2)) {
+ VectorMA(org, -1, cl.v_up, org);
+ }
+ // FIXME - take these out when final
+ VectorCopy(cl.v_right, r);
+ VectorCopy(cl.v_forward, f);
+ VectorCopy(cl.v_up, u);
+
+ } else
+ VectorCopy(b[i].start, org);
+ } else {
+ // if coming from the player, update the start position
+ if (b[i].entity == cl.playernum + 1) // entity 0 is the world
+ {
+ VectorCopy(cl.refdef.vieworg, b[i].start);
+ b[i].start[2] -= 22; // adjust for view height
+ }
+ VectorAdd(b[i].start, b[i].offset, org);
+ }
+
+ // calculate pitch and yaw
+ VectorSubtract(b[i].end, org, dist);
+
+ // PMM
+ if (cl_mod_heatbeam != null && (b[i].model == cl_mod_heatbeam) && (b[i].entity == cl.playernum + 1)) {
+
+ len = VectorLength(dist);
+ VectorScale(f, len, dist);
+ VectorMA(dist, (hand_multiplier * b[i].offset[0]), r, dist);
+ VectorMA(dist, b[i].offset[1], f, dist);
+ VectorMA(dist, b[i].offset[2], u, dist);
+ if ((hand != null) && (hand.value == 2)) {
+ VectorMA(org, -1, cl.v_up, org);
+ }
+ }
+ // PMM
+
+ if (dist[1] == 0 && dist[0] == 0) {
+ yaw = 0;
+ if (dist[2] > 0)
+ pitch = 90;
+ else
+ pitch = 270;
+ } else {
+ // PMM - fixed to correct for pitch of 0
+ if (dist[0] != 0.0f)
+ yaw = (float) (Math.atan2(dist[1], dist[0]) * 180 / Math.PI);
+ else if (dist[1] > 0)
+ yaw = 90;
+ else
+ yaw = 270;
+ if (yaw < 0)
+ yaw += 360;
+
+ forward = (float)Math.sqrt(dist[0] * dist[0] + dist[1] * dist[1]);
+ pitch = (float) (Math.atan2(dist[2], forward) * -180.0 / Math.PI);
+ if (pitch < 0)
+ pitch += 360.0;
+ }
+
+ if (cl_mod_heatbeam != null && (b[i].model == cl_mod_heatbeam)) {
+ if (b[i].entity != cl.playernum + 1) {
+ framenum = 2;
+ // Com_Printf ("Third person\n");
+ ent.angles[0] = -pitch;
+ ent.angles[1] = yaw + 180.0f;
+ ent.angles[2] = 0;
+ // Com_Printf ("%f %f - %f %f %f\n", -pitch, yaw+180.0, b[i].offset[0], b[i].offset[1], b[i].offset[2]);
+ AngleVectors(ent.angles, f, r, u);
+
+ // if it's a non-origin offset, it's a player, so use the hardcoded player offset
+ if (VectorCompare(b[i].offset, vec3_origin) == 0) {
+ VectorMA(org, - (b[i].offset[0]) + 1, r, org);
+ VectorMA(org, - (b[i].offset[1]), f, org);
+ VectorMA(org, - (b[i].offset[2]) - 10, u, org);
+ } else {
+ // if it's a monster, do the particle effect
+ CL.MonsterPlasma_Shell(b[i].start);
+ }
+ } else {
+ framenum = 1;
+ }
+ }
+
+ // if it's the heatbeam, draw the particle effect
+ if ((cl_mod_heatbeam != null && (b[i].model == cl_mod_heatbeam) && (b[i].entity == cl.playernum + 1))) {
+ CL.Heatbeam(org, dist);
+ }
+
+ // add new entities for the beams
+ d = VectorNormalize(dist);
+
+ //memset (&ent, 0, sizeof(ent));
+ ent = new entity_t();
+ if (b[i].model == cl_mod_heatbeam) {
+ model_length = 32.0f;
+ } else if (b[i].model == cl_mod_lightning) {
+ model_length = 35.0f;
+ d -= 20.0; // correction so it doesn't end in middle of tesla
+ } else {
+ model_length = 30.0f;
+ }
+ steps = (float)Math.ceil(d / model_length);
+ len = (d - model_length) / (steps - 1);
+
+ // PMM - special case for lightning model .. if the real length is shorter than the model,
+ // flip it around & draw it from the end to the start. This prevents the model from going
+ // through the tesla mine (instead it goes through the target)
+ if ((b[i].model == cl_mod_lightning) && (d <= model_length)) {
+ // Com_Printf ("special case\n");
+ VectorCopy(b[i].end, ent.origin);
+ // offset to push beam outside of tesla model (negative because dist is from end to start
+ // for this beam)
+ // for (j=0 ; j<3 ; j++)
+ // ent.origin[j] -= dist[j]*10.0;
+ ent.model = b[i].model;
+ ent.flags = RF_FULLBRIGHT;
+ ent.angles[0] = pitch;
+ ent.angles[1] = yaw;
+ ent.angles[2] = rand() % 360;
+ V.AddEntity(ent);
+ return;
+ }
+ while (d > 0) {
+ VectorCopy(org, ent.origin);
+ ent.model = b[i].model;
+ if (cl_mod_heatbeam != null && (b[i].model == cl_mod_heatbeam)) {
+ // ent.flags = RF_FULLBRIGHT|RF_TRANSLUCENT;
+ // ent.alpha = 0.3;
+ ent.flags = RF_FULLBRIGHT;
+ ent.angles[0] = -pitch;
+ ent.angles[1] = yaw + 180.0f;
+ ent.angles[2] = (cl.time) % 360;
+ // ent.angles[2] = rand()%360;
+ ent.frame = framenum;
+ } else if (b[i].model == cl_mod_lightning) {
+ ent.flags = RF_FULLBRIGHT;
+ ent.angles[0] = -pitch;
+ ent.angles[1] = yaw + 180.0f;
+ ent.angles[2] = rand() % 360;
+ } else {
+ ent.angles[0] = pitch;
+ ent.angles[1] = yaw;
+ ent.angles[2] = rand() % 360;
+ }
+
+ // Com_Printf("B: %d . %d\n", b[i].entity, b[i].dest_entity);
+ V.AddEntity(ent);
+
+ for (j = 0; j < 3; j++)
+ org[j] += dist[j] * len;
+ d -= model_length;
+ }
+ }
+ }
+
+ /*
+ =================
+ CL_AddExplosions
+ =================
+ */
+ static void AddExplosions() {
+ entity_t ent;
+ int i;
+ explosion_t[] ex;
+ float frac;
+ int f;
+
+ //memset (&ent, 0, sizeof(ent)); Pointer!
+ ent = null;
+ ex = cl_explosions;
+ for (i = 0; i < MAX_EXPLOSIONS; i++) {
+ if (ex[i].type == ex_free)
+ continue;
+ frac = (cl.time - ex[i].start) / 100.0f;
+ f = (int)Math.floor(frac);
+
+ ent = ex[i].ent;
+
+ switch (ex[i].type) {
+ case ex_mflash :
+ if (f >= ex[i].frames - 1)
+ ex[i].type = ex_free;
+ break;
+ case ex_misc :
+ if (f >= ex[i].frames - 1) {
+ ex[i].type = ex_free;
+ break;
+ }
+ ent.alpha = 1.0f - frac / (ex[i].frames - 1);
+ break;
+ case ex_flash :
+ if (f >= 1) {
+ ex[i].type = ex_free;
+ break;
+ }
+ ent.alpha = 1.0f;
+ break;
+ case ex_poly :
+ if (f >= ex[i].frames - 1) {
+ ex[i].type = ex_free;
+ break;
+ }
+
+ ent.alpha = (16.0f - (float)f) / 16.0f;
+
+ if (f < 10) {
+ ent.skinnum = (f >> 1);
+ if (ent.skinnum < 0)
+ ent.skinnum = 0;
+ } else {
+ ent.flags |= RF_TRANSLUCENT;
+ if (f < 13)
+ ent.skinnum = 5;
+ else
+ ent.skinnum = 6;
+ }
+ break;
+ case ex_poly2 :
+ if (f >= ex[i].frames - 1) {
+ ex[i].type = ex_free;
+ break;
+ }
+
+ ent.alpha = (5.0f - (float)f) / 5.0f;
+ ent.skinnum = 0;
+ ent.flags |= RF_TRANSLUCENT;
+ break;
+ }
+
+ if (ex[i].type == ex_free)
+ continue;
+ if (ex[i].light != 0.0f) {
+ V.AddLight(
+ ent.origin,
+ ex[i].light * ent.alpha,
+ ex[i].lightcolor[0],
+ ex[i].lightcolor[1],
+ ex[i].lightcolor[2]);
+ }
+
+ VectorCopy(ent.origin, ent.oldorigin);
+
+ if (f < 0)
+ f = 0;
+ ent.frame = ex[i].baseframe + f + 1;
+ ent.oldframe = ex[i].baseframe + f;
+ ent.backlerp = 1.0f - cl.lerpfrac;
+
+ V.AddEntity(ent);
+ }
+ }
+
+ /*
+ =================
+ CL_AddLasers
+ =================
+ */
+ static void AddLasers() {
+ laser_t[] l;
+ int i;
+
+ l = cl_lasers;
+ for (i = 0; i < MAX_LASERS; i++) {
+ if (l[i].endtime >= cl.time)
+ V.AddEntity(l[i].ent);
+ }
+ }
+
+ /* PMM - CL_Sustains */
+ static void ProcessSustain() {
+ cl_sustain_t[] s;
+ int i;
+
+ s = cl_sustains;
+ for (i = 0; i < MAX_SUSTAINS; i++) {
+ if (s[i].id != 0)
+ if ((s[i].endtime >= cl.time) && (cl.time >= s[i].nextthink)) {
+ s[i].think.think(s[i]);
+ } else if (s[i].endtime < cl.time)
+ s[i].id = 0;
+ }
+ }
+
+ /*
+ =================
+ CL_AddTEnts
+ =================
+ */
+ static void AddTEnts() {
+ CL.AddBeams();
+ // PMM - draw plasma beams
+ CL.AddPlayerBeams();
+ CL.AddExplosions();
+ CL.AddLasers();
+ // PMM - set up sustain
+ CL.ProcessSustain();
+ }
+}
diff --git a/src/jake2/client/CL_view.java b/src/jake2/client/CL_view.java
new file mode 100644
index 0000000..2d2e7ab
--- /dev/null
+++ b/src/jake2/client/CL_view.java
@@ -0,0 +1,189 @@
+/*
+ * CL_view.java
+ * Copyright (C) 2004
+ *
+ * $Id: CL_view.java,v 1.1 2004-07-07 19:58:40 hzi Exp $
+ */
+/*
+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.
+
+*/
+package jake2.client;
+
+import java.util.StringTokenizer;
+
+import jake2.qcommon.CM;
+import jake2.qcommon.Com;
+import jake2.qcommon.xcommand_t;
+import jake2.sys.Sys;
+import jake2.util.Vargs;
+
+
+
+
+
+public class CL_view extends CL_input {
+
+ static int num_cl_weaponmodels;
+ static String[] cl_weaponmodels = new String[MAX_CLIENTWEAPONMODELS];
+
+
+ /*
+ =================
+ CL_PrepRefresh
+
+ Call before entering a new level, or after changing dlls
+ =================
+ */
+
+ static void PrepRefresh() {
+ re.updateScreen(new xcommand_t() {
+ public void execute() {
+ PrepRefresh2();
+ }
+ });
+ }
+
+ static void PrepRefresh2() {
+ String mapname;
+ int i;
+ String name;
+ float rotate;
+ float[] axis = new float[3];
+
+ if ((i=cl.configstrings[CS_MODELS+1].length()) == 0)
+ return; // no map loaded
+
+ SCR.AddDirtyPoint(0, 0);
+ SCR.AddDirtyPoint(viddef.width-1, viddef.height-1);
+
+ // let the render dll load the map
+ mapname = cl.configstrings[CS_MODELS+1].substring(5, i - 4); // skip "maps/"
+ // cut off ".bsp"
+
+ // register models, pics, and skins
+ Com.Printf("Map: " + mapname + "\r");
+ SCR.UpdateScreen2();
+ re.BeginRegistration(mapname);
+ Com.Printf(" \r");
+
+ // precache status bar pics
+ Com.Printf("pics\r");
+ SCR.UpdateScreen2();
+ SCR.TouchPics();
+ Com.Printf(" \r");
+
+ CL.RegisterTEntModels();
+
+ num_cl_weaponmodels = 1;
+ cl_weaponmodels[0] = "weapon.md2";
+
+ for (i=1 ; i<MAX_MODELS && cl.configstrings[CS_MODELS+i].length() != 0 ; i++) {
+ name = new String(cl.configstrings[CS_MODELS+i]);
+ if (name.length() > 37) name = name.substring(0, 36);
+
+ /*
+ if (name.charAt(0) != '*')
+ Com.Printf("name" + "\r");
+ */
+ SCR.UpdateScreen2();
+ Sys.SendKeyEvents(); // pump message loop
+ if (name.charAt(0) == '#') {
+ // special player weapon model
+ if (num_cl_weaponmodels < MAX_CLIENTWEAPONMODELS) {
+ cl_weaponmodels[num_cl_weaponmodels] = cl.configstrings[CS_MODELS+i].substring(1);
+ num_cl_weaponmodels++;
+ }
+ } else {
+ cl.model_draw[i] = re.RegisterModel(cl.configstrings[CS_MODELS+i]);
+ if (name.charAt(0) == '*')
+ cl.model_clip[i] = CM.InlineModel(cl.configstrings[CS_MODELS+i]);
+ else
+ cl.model_clip[i] = null;
+ }
+ if (name.charAt(0) != '*')
+ Com.Printf(" \r");
+ }
+
+ Com.Printf("images\r");
+ SCR.UpdateScreen2();
+ for (i=1 ; i<MAX_IMAGES && cl.configstrings[CS_IMAGES+i].length() > 0 ; i++) {
+ cl.image_precache[i] = re.RegisterPic(cl.configstrings[CS_IMAGES+i]);
+ Sys.SendKeyEvents(); // pump message loop
+ }
+
+ Com.Printf(" \r");
+ for (i=0 ; i<MAX_CLIENTS ; i++) {
+ if (cl.configstrings[CS_PLAYERSKINS+i].length() == 0)
+ continue;
+ Com.Printf("client %i\r", new Vargs(1).add(i));
+ SCR.UpdateScreen2();
+ Sys.SendKeyEvents(); // pump message loop
+ CL.ParseClientinfo(i);
+ Com.Printf(" \r");
+ }
+
+ CL_parse.LoadClientinfo(cl.baseclientinfo, "unnamed\\male/grunt");
+
+ // set sky textures and speed
+ Com.Printf("sky\r");
+ SCR.UpdateScreen2();
+ rotate = Float.parseFloat(cl.configstrings[CS_SKYROTATE]);
+ StringTokenizer st = new StringTokenizer(cl.configstrings[CS_SKYAXIS]);
+ axis[0] = Float.parseFloat(st.nextToken());
+ axis[1] = Float.parseFloat(st.nextToken());
+ axis[2] = Float.parseFloat(st.nextToken());
+ re.SetSky(cl.configstrings[CS_SKY], rotate, axis);
+ Com.Printf(" \r");
+
+ // the renderer can now free unneeded stuff
+ re.EndRegistration ();
+
+ // clear any lines of console text
+ Console.ClearNotify();
+
+ SCR.UpdateScreen2();
+ cl.refresh_prepped = true;
+ cl.force_refdef = true; // make sure we have a valid refdef
+ }
+
+ public static void AddNetgraph() {
+ int i;
+ int in;
+ int ping;
+
+ // if using the debuggraph for something else, don't
+ // add the net lines
+ if (SCR.scr_debuggraph.value == 0.0f || SCR.scr_timegraph.value == 0.0f)
+ return;
+
+ for (i=0 ; i<cls.netchan.dropped ; i++)
+ SCR.DebugGraph(30, 0x40);
+
+ for (i=0 ; i<cl.surpressCount ; i++)
+ SCR.DebugGraph(30, 0xdf);
+
+ // see what the latency was on this packet
+ in = cls.netchan.incoming_acknowledged & (CMD_BACKUP-1);
+ ping = (int)(cls.realtime - cl.cmd_time[in]);
+ ping /= 30;
+ if (ping > 30)
+ ping = 30;
+ SCR.DebugGraph (ping, 0xd0);
+ }
+}
diff --git a/src/jake2/client/Console.java b/src/jake2/client/Console.java
new file mode 100644
index 0000000..d37bf5c
--- /dev/null
+++ b/src/jake2/client/Console.java
@@ -0,0 +1,610 @@
+/*
+ * Con.java
+ * Copyright (C) 2003
+ *
+ * $Id: Console.java,v 1.1 2004-07-07 19:58:41 hzi Exp $
+ */
+/*
+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.
+
+*/
+package jake2.client;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.Arrays;
+
+import jake2.Defines;
+import jake2.Globals;
+import jake2.game.Cmd;
+import jake2.qcommon.*;
+import jake2.util.Vargs;
+
+/**
+ * Console
+ */
+public final class Console extends Globals {
+
+ public static xcommand_t ToggleConsole_f = new xcommand_t() {
+ public void execute() {
+ SCR.EndLoadingPlaque(); // get rid of loading plaque
+
+ if (Globals.cl.attractloop) {
+ Cbuf.AddText("killserver\n");
+ return;
+ }
+
+ if (Globals.cls.state == Defines.ca_disconnected) {
+ // start the demo loop again
+ Cbuf.AddText("d1\n");
+ return;
+ }
+
+ Key.ClearTyping();
+ Console.ClearNotify();
+
+ if (Globals.cls.key_dest == Defines.key_console) {
+ Menu.ForceMenuOff();
+ Cvar.Set("paused", "0");
+ }
+ else {
+ Menu.ForceMenuOff();
+ Globals.cls.key_dest = Defines.key_console;
+
+ if (Cvar.VariableValue("maxclients") == 1 && Com.ServerState()!= 0)
+ Cvar.Set("paused", "1");
+ }
+ }
+ };
+
+ public static xcommand_t Clear_f = new xcommand_t() {
+ public void execute() {
+ Arrays.fill(Globals.con.text, (byte)' ');
+ }
+ };
+ public static xcommand_t Dump_f = new xcommand_t() {
+ public void execute() {
+
+ int l, x;
+ int line;
+ RandomAccessFile f;
+ byte[] buffer = new byte[1024];
+ String name;
+
+ if (Cmd.Argc() != 2) {
+ Com.Printf("usage: condump <filename>\n");
+ return;
+ }
+
+ //Com_sprintf (name, sizeof(name), "%s/%s.txt", FS_Gamedir(), Cmd_Argv(1));
+ name = FS.Gamedir() + "/" + Cmd.Argv(1) + ".txt";
+
+ Com.Printf("Dumped console text to " + name + ".\n");
+ FS.CreatePath(name);
+ f = fopen(name, "rw");
+ if (f == null) {
+ Com.Printf("ERROR: couldn't open.\n");
+ return;
+ }
+
+ // skip empty lines
+ for (l = con.current - con.totallines + 1; l <= con.current; l++) {
+ line = (l % con.totallines) * con.linewidth;
+ for (x = 0; x < con.linewidth; x++)
+ if (con.text[line + x] != ' ')
+ break;
+ if (x != con.linewidth)
+ break;
+ }
+
+ // write the remaining lines
+ buffer[con.linewidth] = 0;
+ for (; l <= con.current; l++) {
+ line = (l % con.totallines) * con.linewidth;
+ //strncpy (buffer, line, con.linewidth);
+ System.arraycopy(con.text, line, buffer, 0, con.linewidth);
+ for (x = con.linewidth - 1; x >= 0; x--) {
+ if (buffer[x] == ' ')
+ buffer[x] = 0;
+ else
+ break;
+ }
+ for (x = 0; buffer[x] != 0; x++)
+ buffer[x] &= 0x7f;
+
+ buffer[x] = '\n';
+ // fprintf (f, "%s\n", buffer);
+ try {
+ f.write(buffer, 0, x+1);
+ } catch (IOException e) {}
+ }
+
+ fclose(f);
+
+ }
+ };
+
+ /**
+ *
+ */
+ public static void Init() {
+ Globals.con.linewidth = -1;
+
+ CheckResize();
+
+ Com.Printf("Console initialized.\n");
+
+ //
+ // register our commands
+ //
+ Globals.con_notifytime = Cvar.Get("con_notifytime", "3", 0);
+
+ Cmd.AddCommand("toggleconsole", ToggleConsole_f);
+ Cmd.AddCommand("togglechat", ToggleChat_f);
+ Cmd.AddCommand("messagemode", MessageMode_f);
+ Cmd.AddCommand("messagemode2", MessageMode2_f);
+ Cmd.AddCommand("clear", Clear_f);
+ Cmd.AddCommand("condump", Dump_f);
+ Globals.con.initialized = true;
+ }
+
+ /**
+ * If the line width has changed, reformat the buffer.
+ */
+ public static void CheckResize() {
+ int i, j, width, oldwidth, oldtotallines, numlines, numchars;
+ byte[] tbuf = new byte[Defines.CON_TEXTSIZE];
+
+ width = (Globals.viddef.width >> 3) - 2;
+
+ if (width == Globals.con.linewidth)
+ return;
+
+ if (width < 1) { // video hasn't been initialized yet
+ width = 38;
+ Globals.con.linewidth = width;
+ Globals.con.totallines = Defines.CON_TEXTSIZE / Globals.con.linewidth;
+ Arrays.fill(Globals.con.text, (byte)' ');
+ }
+ else {
+ oldwidth = Globals.con.linewidth;
+ Globals.con.linewidth = width;
+ oldtotallines = Globals.con.totallines;
+ Globals.con.totallines = Defines.CON_TEXTSIZE / Globals.con.linewidth;
+ numlines = oldtotallines;
+
+ if (Globals.con.totallines < numlines)
+ numlines = Globals.con.totallines;
+
+ numchars = oldwidth;
+
+ if (Globals.con.linewidth < numchars)
+ numchars = Globals.con.linewidth;
+
+ System.arraycopy(Globals.con.text, 0, tbuf, 0, Defines.CON_TEXTSIZE);
+ Arrays.fill(Globals.con.text, (byte)' ');
+
+ for (i=0 ; i<numlines ; i++) {
+ for (j=0 ; j<numchars ; j++) {
+ Globals.con.text[(Globals.con.totallines - 1 - i) * Globals.con.linewidth + j] =
+ tbuf[((Globals.con.current - i + oldtotallines) % oldtotallines) * oldwidth + j];
+ }
+ }
+
+ Console.ClearNotify();
+ }
+
+ Globals.con.current = Globals.con.totallines - 1;
+ Globals.con.display = Globals.con.current;
+ }
+
+ public static void ClearNotify() {
+ int i;
+ for (i=0 ; i<Defines.NUM_CON_TIMES ; i++)
+ Globals.con.times[i] = 0;
+ }
+
+ static void DrawString(int x, int y, String s) {
+ for (int i = 0; i < s.length(); i++) {
+ Globals.re.DrawChar(x, y, s.charAt(i));
+ x+=8;
+ }
+ }
+
+ static void DrawAltString(int x, int y, String s) {
+ for (int i = 0; i < s.length(); i++) {
+ Globals.re.DrawChar(x, y, s.charAt(i) ^ 0x80);
+ x+=8;
+ }
+ }
+
+
+ /*
+ ================
+ Con_ToggleChat_f
+ ================
+ */
+ static xcommand_t ToggleChat_f = new xcommand_t() {
+ public void execute() {
+ Key.ClearTyping();
+
+ if (cls.key_dest == key_console) {
+ if (cls.state == ca_active) {
+ Menu.ForceMenuOff();
+ cls.key_dest = key_game;
+ }
+ } else
+ cls.key_dest = key_console;
+
+ ClearNotify();
+ }
+ };
+
+ /*
+ ================
+ Con_MessageMode_f
+ ================
+ */
+ static xcommand_t MessageMode_f = new xcommand_t() {
+ public void execute() {
+ chat_team = false;
+ cls.key_dest = key_message;
+ }
+ };
+
+ /*
+ ================
+ Con_MessageMode2_f
+ ================
+ */
+ static xcommand_t MessageMode2_f = new xcommand_t() {
+ public void execute() {
+ chat_team = true;
+ cls.key_dest = key_message;
+ }
+ };
+
+ /*
+ ===============
+ Con_Linefeed
+ ===============
+ */
+ static void Linefeed() {
+ Globals.con.x = 0;
+ if (Globals.con.display == Globals.con.current)
+ Globals.con.display++;
+ Globals.con.current++;
+ int i = (Globals.con.current%Globals.con.totallines)*Globals.con.linewidth;
+ int e = i + Globals.con.linewidth;
+ while (i++ < e) Globals.con.text[i] = ' ';
+ }
+
+ /*
+ ================
+ Con_Print
+
+ Handles cursor positioning, line wrapping, etc
+ All console printing must go through this in order to be logged to disk
+ If no console is visible, the text will appear at the top of the game window
+ ================
+ */
+ private static int cr;
+ public static void Print(String txt) {
+ int y;
+ int c, l;
+ int mask;
+ int txtpos = 0;
+
+ if (!con.initialized) return;
+
+ if (txt.charAt(0) == 1 || txt.charAt(0) == 2) {
+ mask = 128; // go to colored text
+ txtpos++;
+ } else mask = 0;
+
+ while ( txtpos < txt.length() ) {
+ c = txt.charAt(txtpos);
+ // count word length
+ for (l=0 ; l < con.linewidth && l < (txt.length() - txtpos) ; l++)
+ if ( txt.charAt(l + txtpos) <= ' ') break;
+
+ // word wrap
+ if (l != con.linewidth && (con.x + l > con.linewidth) )
+ con.x = 0;
+
+ txtpos++;
+
+ if (cr != 0) {
+ con.current--;
+ cr = 0;
+ }
+
+ if (con.x == 0) {
+ Console.Linefeed();
+ // mark time for transparent overlay
+ if (con.current >= 0)
+ con.times[con.current % NUM_CON_TIMES] = cls.realtime;
+ }
+
+ switch (c) {
+ case '\n':
+ con.x = 0;
+ break;
+
+ case '\r':
+ con.x = 0;
+ cr = 1;
+ break;
+
+ default: // display character and advance
+ y = con.current % con.totallines;
+ con.text[y*con.linewidth+con.x] = (byte)(c | mask | con.ormask);
+ con.x++;
+ if (con.x >= con.linewidth)
+ con.x = 0;
+ break;
+ }
+ }
+ }
+
+ /*
+ ==============
+ Con_CenteredPrint
+ ==============
+ */
+ static void CenteredPrint(String text) {
+ int l = text.length();
+ l = (con.linewidth-l)/2;
+ if (l < 0) l = 0;
+
+ StringBuffer sb = new StringBuffer(1024);
+ for (int i = 0; i < l; i++) sb.append(' ');
+ sb.append(text);
+ sb.append('\n');
+
+ sb.setLength(1024);
+
+ Console.Print(sb.toString());
+ }
+
+ /*
+ ==============================================================================
+
+ DRAWING
+
+ ==============================================================================
+ */
+
+ /*
+ ================
+ Con_DrawInput
+
+ The input line scrolls horizontally if typing goes beyond the right edge
+ ================
+ */
+ static void DrawInput() {
+ int y;
+ int i;
+ byte[] text;
+ int start = 0;
+
+ if (cls.key_dest == key_menu)
+ return;
+ if (cls.key_dest != key_console && cls.state == ca_active)
+ return; // don't draw anything (always draw if not active)
+
+ text = key_lines[edit_line];
+
+ // add the cursor frame
+ text[key_linepos] = (byte)(10+((int)(cls.realtime>>8)&1));
+
+ // fill out remainder with spaces
+ for (i=key_linepos+1 ; i< con.linewidth ; i++)
+ text[i] = ' ';
+
+ // prestep if horizontally scrolling
+ if (key_linepos >= con.linewidth)
+ start += 1 + key_linepos - con.linewidth;
+
+ // draw it
+ y = con.vislines-16;
+
+ for (i=0 ; i<con.linewidth ; i++)
+ re.DrawChar ( (i+1)<<3, con.vislines - 22, text[i]);
+
+ // remove cursor
+ key_lines[edit_line][key_linepos] = 0;
+ }
+
+
+ /*
+ ================
+ Con_DrawNotify
+
+ Draws the last few lines of output transparently over the game top
+ ================
+ */
+ static void DrawNotify() {
+ int x, v;
+ int text;
+ int i;
+ int time;
+ String s;
+ int skip;
+
+ v = 0;
+ for (i= con.current-NUM_CON_TIMES+1 ; i<=con.current ; i++) {
+ if (i < 0) continue;
+
+ time = (int)con.times[i % NUM_CON_TIMES];
+ if (time == 0) continue;
+
+ time = (int)(cls.realtime - time);
+ if (time > con_notifytime.value*1000) continue;
+
+ text = (i % con.totallines)*con.linewidth;
+
+ for (x = 0 ; x < con.linewidth ; x++)
+ re.DrawChar( (x+1)<<3, v, con.text[text+x]);
+
+ v += 8;
+ }
+
+ if (cls.key_dest == key_message) {
+ if (chat_team) {
+ DrawString(8, v, "say_team:");
+ skip = 11;
+ } else {
+ DrawString (8, v, "say:");
+ skip = 5;
+ }
+
+ s = chat_buffer;
+ if (chat_bufferlen > (viddef.width>>3)-(skip+1))
+ s = s.substring(chat_bufferlen - ((viddef.width>>3)-(skip+1)));
+
+ for (x = 0; x < s.length(); x++) {
+ re.DrawChar( (x+skip)<<3, v, s.charAt(x));
+ }
+ re.DrawChar( (x+skip)<<3, v, (int)(10+((cls.realtime>>8)&1)));
+ v += 8;
+ }
+
+ if (v != 0) {
+ SCR.AddDirtyPoint(0,0);
+ SCR.AddDirtyPoint(viddef.width-1, v);
+ }
+ }
+
+ /*
+ ================
+ Con_DrawConsole
+
+ Draws the console with the solid background
+ ================
+ */
+ static void DrawConsole(float frac) {
+ int i, j, x, y, n;
+ int rows;
+ int text;
+ int row;
+ int lines;
+ String version;
+ String dlbar;
+
+ lines = (int)(viddef.height * frac);
+ if (lines <= 0)
+ return;
+
+ if (lines > viddef.height)
+ lines = viddef.height;
+
+ // draw the background
+ re.DrawStretchPic(0, -viddef.height+lines, viddef.width, viddef.height, "conback");
+ SCR.AddDirtyPoint(0,0);
+ SCR.AddDirtyPoint(viddef.width-1,lines-1);
+
+ version = Com.sprintf("v%4.2f", new Vargs(1).add(VERSION));
+ for (x=0 ; x<5 ; x++)
+ re.DrawChar (viddef.width-44+x*8, lines-12, 128 + version.charAt(x));
+
+ // draw the text
+ con.vislines = lines;
+
+ rows = (lines-22)>>3; // rows of text to draw
+
+ y = lines - 30;
+
+ // draw from the bottom up
+ if (con.display != con.current) {
+ // draw arrows to show the buffer is backscrolled
+ for (x=0 ; x<con.linewidth ; x+=4)
+ re.DrawChar ( (x+1)<<3, y, '^');
+
+ y -= 8;
+ rows--;
+ }
+
+ row = con.display;
+ for (i=0 ; i<rows ; i++, y-=8, row--) {
+ if (row < 0)
+ break;
+ if (con.current - row >= con.totallines)
+ break; // past scrollback wrap point
+
+ int first = (row % con.totallines)*con.linewidth;
+
+ for (x=0 ; x<con.linewidth ; x++)
+ re.DrawChar( (x+1)<<3, y, con.text[x+first]);
+ }
+
+ //ZOID
+ // draw the download bar
+ // figure out width
+ if (cls.download != null) {
+ if ((text = cls.downloadname.lastIndexOf('/')) != 0)
+ text++;
+ else
+ text = 0;
+
+ x = con.linewidth - ((con.linewidth * 7) / 40);
+ y = x - (cls.downloadname.length()-text) - 8;
+ i = con.linewidth/3;
+ if (cls.downloadname.length()-text > i) {
+ y = x - i - 11;
+ int end = text + i - 1;;
+ dlbar = cls.downloadname.substring(text, end);
+ dlbar += "...";
+ } else {
+ dlbar = cls.downloadname.substring(text);
+ }
+ dlbar += ": ";
+ i = strlen(dlbar);
+ dlbar += (char)0x80;
+ i++;
+
+ // where's the dot go?
+ if (cls.downloadpercent == 0)
+ n = 0;
+ else
+ n = y * cls.downloadpercent / 100;
+
+ StringBuffer sb = new StringBuffer(dlbar);
+ sb.ensureCapacity(1024);
+ for (j = 0; j < y; j++) {
+ if (j == n)
+ sb.append((char)0x83);
+ else
+ sb.append((char)0x81);
+ }
+ sb.append((char)0x82);
+
+ dlbar = sb.toString();
+ dlbar += Com.sprintf(" %02d%%", new Vargs(1).add(cls.downloadpercent));
+
+ // draw it
+ y = con.vislines-12;
+ for (i = 0; i < dlbar.length(); i++)
+ re.DrawChar ( (i+1)<<3, y, dlbar.charAt(i));
+ }
+ //ZOID
+
+ // draw the input prompt, user text, and cursor if desired
+ DrawInput();
+ }
+}
diff --git a/src/jake2/client/Key.java b/src/jake2/client/Key.java
new file mode 100644
index 0000000..33b25a2
--- /dev/null
+++ b/src/jake2/client/Key.java
@@ -0,0 +1,812 @@
+/*
+ * Key.java
+ * Copyright (C) 2003
+ *
+ * $Id: Key.java,v 1.1 2004-07-07 19:58:42 hzi Exp $
+ */
+/*
+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.
+
+*/
+package jake2.client;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+import jake2.Defines;
+import jake2.Globals;
+import jake2.game.Cmd;
+import jake2.qcommon.*;
+import jake2.qcommon.Cbuf;
+import jake2.qcommon.Com;
+import jake2.util.Lib;
+
+/**
+ * Key
+ */
+public class Key extends Globals {
+ //
+ // these are the key numbers that should be passed to Key_Event
+ //
+ public static final int K_TAB = 9;
+ public static final int K_ENTER = 13;
+ public static final int K_ESCAPE = 27;
+ public static final int K_SPACE = 32;
+
+ // normal keys should be passed as lowercased ascii
+
+ public static final int K_BACKSPACE = 127;
+ public static final int K_UPARROW = 128;
+ public static final int K_DOWNARROW = 129;
+ public static final int K_LEFTARROW = 130;
+ public static final int K_RIGHTARROW = 131;
+
+ public static final int K_ALT = 132;
+ public static final int K_CTRL = 133;
+ public static final int K_SHIFT = 134;
+ public static final int K_F1 = 135;
+ public static final int K_F2 = 136;
+ public static final int K_F3 = 137;
+ public static final int K_F4 = 138;
+ public static final int K_F5 = 139;
+ public static final int K_F6 = 140;
+ public static final int K_F7 = 141;
+ public static final int K_F8 = 142;
+ public static final int K_F9 = 143;
+ public static final int K_F10 = 144;
+ public static final int K_F11 = 145;
+ public static final int K_F12 = 146;
+ public static final int K_INS = 147;
+ public static final int K_DEL = 148;
+ public static final int K_PGDN = 149;
+ public static final int K_PGUP = 150;
+ public static final int K_HOME = 151;
+ public static final int K_END = 152;
+
+ public static final int K_KP_HOME = 160;
+ public static final int K_KP_UPARROW = 161;
+ public static final int K_KP_PGUP = 162;
+ public static final int K_KP_LEFTARROW = 163;
+ public static final int K_KP_5 = 164;
+ public static final int K_KP_RIGHTARROW = 165;
+ public static final int K_KP_END = 166;
+ public static final int K_KP_DOWNARROW = 167;
+ public static final int K_KP_PGDN = 168;
+ public static final int K_KP_ENTER = 169;
+ public static final int K_KP_INS = 170;
+ public static final int K_KP_DEL = 171;
+ public static final int K_KP_SLASH = 172;
+ public static final int K_KP_MINUS = 173;
+ public static final int K_KP_PLUS = 174;
+
+ public static final int K_PAUSE = 255;
+
+ //
+ // mouse buttons generate virtual keys
+ //
+ public static final int K_MOUSE1 = 200;
+ public static final int K_MOUSE2 = 201;
+ public static final int K_MOUSE3 = 202;
+
+ //
+ // joystick buttons
+ //
+ public static final int K_JOY1 = 203;
+ public static final int K_JOY2 = 204;
+ public static final int K_JOY3 = 205;
+ public static final int K_JOY4 = 206;
+
+ public static final int K_MWHEELDOWN = 239;
+ public static final int K_MWHEELUP = 240;
+
+ static int key_waiting;
+ static int history_line = 0;
+ static boolean shift_down = false;
+ static int[] key_repeats = new int[256];
+ static int[] keyshift = new int[256];
+ static boolean[] menubound = new boolean[256];
+ static boolean[] consolekeys = new boolean[256];
+
+ static String[] keynames = new String[256];
+
+ static {
+ keynames[K_TAB] = "TAB";
+ keynames[K_ENTER] = "ENTER";
+ keynames[K_ESCAPE] = "ESCAPE";
+ keynames[K_SPACE] = "SPACE";
+ keynames[K_BACKSPACE] = "BACKSPACE";
+ keynames[K_UPARROW] = "UPARROW";
+ keynames[K_DOWNARROW] = "DOWNARROW";
+ keynames[K_LEFTARROW] = "LEFTARROW";
+ keynames[K_RIGHTARROW] = "RIGHTARROW";
+ keynames[K_ALT] = "ALT";
+ keynames[K_CTRL] = "CTRL";
+ keynames[K_SHIFT] = "SHIFT";
+
+ keynames[K_F1] = "F1";
+ keynames[K_F2] = "F2";
+ keynames[K_F3] = "F3";
+ keynames[K_F4] = "F4";
+ keynames[K_F5] = "F5";
+ keynames[K_F6] = "F6";
+ keynames[K_F7] = "F7";
+ keynames[K_F8] = "F8";
+ keynames[K_F9] = "F9";
+ keynames[K_F10] = "F10";
+ keynames[K_F11] = "F11";
+ keynames[K_F12] = "F12";
+
+ keynames[K_INS] = "INS";
+ keynames[K_DEL] = "DEL";
+ keynames[K_PGDN] = "PGDN";
+ keynames[K_PGUP] = "PGUP";
+ keynames[K_HOME] = "HOME";
+ keynames[K_END] = "END";
+
+ keynames[K_MOUSE1] = "MOUSE1";
+ keynames[K_MOUSE2] = "MOUSE2";
+ keynames[K_MOUSE3] = "MOUSE3";
+
+ // 00092 {"JOY1", K_JOY1},
+ // 00093 {"JOY2", K_JOY2},
+ // 00094 {"JOY3", K_JOY3},
+ // 00095 {"JOY4", K_JOY4},
+
+ keynames[K_KP_HOME] = "KP_HOME";
+ keynames[K_KP_UPARROW] = "KP_UPARROW";
+ keynames[K_KP_PGUP] = "KP_PGUP";
+ keynames[K_KP_LEFTARROW] = "KP_LEFTARROW";
+ keynames[K_KP_5] = "KP_5";
+ keynames[K_KP_RIGHTARROW] = "KP_RIGHTARROW";
+ keynames[K_KP_END] = "KP_END";
+ keynames[K_KP_DOWNARROW] = "KP_DOWNARROW";
+ keynames[K_KP_PGDN] = "KP_PGDN";
+ keynames[K_KP_ENTER] = "KP_ENTER";
+ keynames[K_KP_INS] = "KP_INS";
+ keynames[K_KP_DEL] = "KP_DEL";
+ keynames[K_KP_SLASH] = "KP_SLASH";
+
+ keynames[K_KP_PLUS] = "KP_PLUS";
+ keynames[K_KP_MINUS] = "KP_MINUS";
+
+ keynames[K_MWHEELUP] = "MWHEELUP";
+ keynames[K_MWHEELDOWN] = "MWHEELDOWN";
+
+ keynames[K_PAUSE] = "PAUSE";
+ keynames[';'] = "SEMICOLON"; // because a raw semicolon seperates commands
+
+ keynames[0] = "NULL";
+ }
+
+ /**
+ *
+ */
+ public static void Init() {
+ for (int i = 0; i < 32; i++) {
+ Globals.key_lines[i][0] = ']';
+ Globals.key_lines[i][1] = 0;
+ }
+ Globals.key_linepos = 1;
+
+ //
+ // init ascii characters in console mode
+ //
+ for (int i = 32; i < 128; i++)
+ consolekeys[i] = true;
+ consolekeys[K_ENTER] = true;
+ consolekeys[K_KP_ENTER] = true;
+ consolekeys[K_TAB] = true;
+ consolekeys[K_LEFTARROW] = true;
+ consolekeys[K_KP_LEFTARROW] = true;
+ consolekeys[K_RIGHTARROW] = true;
+ consolekeys[K_KP_RIGHTARROW] = true;
+ consolekeys[K_UPARROW] = true;
+ consolekeys[K_KP_UPARROW] = true;
+ consolekeys[K_DOWNARROW] = true;
+ consolekeys[K_KP_DOWNARROW] = true;
+ consolekeys[K_BACKSPACE] = true;
+ consolekeys[K_HOME] = true;
+ consolekeys[K_KP_HOME] = true;
+ consolekeys[K_END] = true;
+ consolekeys[K_KP_END] = true;
+ consolekeys[K_PGUP] = true;
+ consolekeys[K_KP_PGUP] = true;
+ consolekeys[K_PGDN] = true;
+ consolekeys[K_KP_PGDN] = true;
+ consolekeys[K_SHIFT] = true;
+ consolekeys[K_INS] = true;
+ consolekeys[K_KP_INS] = true;
+ consolekeys[K_KP_DEL] = true;
+ consolekeys[K_KP_SLASH] = true;
+ consolekeys[K_KP_PLUS] = true;
+ consolekeys[K_KP_MINUS] = true;
+ consolekeys[K_KP_5] = true;
+
+ consolekeys['`'] = false;
+ consolekeys['~'] = false;
+
+ for (int i = 0; i < 256; i++)
+ keyshift[i] = i;
+ for (int i = 'a'; i <= 'z'; i++)
+ keyshift[i] = i - 'a' + 'A';
+ keyshift['1'] = '!';
+ keyshift['2'] = '@';
+ keyshift['3'] = '#';
+ keyshift['4'] = '$';
+ keyshift['5'] = '%';
+ keyshift['6'] = '^';
+ keyshift['7'] = '&';
+ keyshift['8'] = '*';
+ keyshift['9'] = '(';
+ keyshift['0'] = ')';
+ keyshift['-'] = '_';
+ keyshift['='] = '+';
+ keyshift[','] = '<';
+ keyshift['.'] = '>';
+ keyshift['/'] = '?';
+ keyshift[';'] = ':';
+ keyshift['\''] = '"';
+ keyshift['['] = '{';
+ keyshift[']'] = '}';
+ keyshift['`'] = '~';
+ keyshift['\\'] = '|';
+
+ menubound[K_ESCAPE] = true;
+ for (int i = 0; i < 12; i++)
+ menubound[K_F1 + i] = true;
+
+ //
+ // register our functions
+ //
+ Cmd.AddCommand("bind", Key.Bind_f);
+ Cmd.AddCommand("unbind", Key.Unbind_f);
+ Cmd.AddCommand("unbindall", Key.Unbindall_f);
+ Cmd.AddCommand("bindlist", Key.Bindlist_f);
+ }
+
+ public static void ClearTyping() {
+ Globals.key_lines[Globals.edit_line][1] = 0; // clear any typing
+ Globals.key_linepos = 1;
+ }
+
+ /**
+ * Called by the system between frames for both key up and key down events.
+ */
+ public static void Event(int key, boolean down, long time) {
+ //System.out.println(key + " " + down);
+ //return;
+ String kb;
+ String cmd;
+
+ // hack for modal presses
+ if (key_waiting == -1) {
+ if (down)
+ key_waiting = key;
+ return;
+ }
+
+ // update auto-repeat status
+ if (down) {
+ key_repeats[key]++;
+ if (key != K_BACKSPACE
+ && key != K_PAUSE
+ && key != K_PGUP
+ && key != K_KP_PGUP
+ && key != K_PGDN
+ && key != K_KP_PGDN
+ && key_repeats[key] > 1)
+ return; // ignore most autorepeats
+
+ if (key >= 200 && Globals.keybindings[key] == null)
+ Com.Printf(Key.KeynumToString(key) + " is unbound, hit F4 to set.\n");
+ }
+ else {
+ key_repeats[key] = 0;
+ }
+
+ if (key == K_SHIFT)
+ shift_down = down;
+
+ // console key is hardcoded, so the user can never unbind it
+ if (key == '`' || key == '~') {
+ if (!down)
+ return;
+ try {
+ Console.ToggleConsole_f.execute();
+ }
+ catch (Exception e) {
+ }
+ return;
+ }
+
+ // any key during the attract mode will bring up the menu
+ if (Globals.cl.attractloop && Globals.cls.key_dest != Defines.key_menu && !(key >= K_F1 && key <= K_F12))
+ key = K_ESCAPE;
+
+ // menu key is hardcoded, so the user can never unbind it
+ if (key == K_ESCAPE) {
+ if (!down)
+ return;
+
+ if (Globals.cl.frame.playerstate.stats[Defines.STAT_LAYOUTS] != 0 && Globals.cls.key_dest == Defines.key_game) {
+ // put away help computer / inventory
+ Cbuf.AddText("cmd putaway\n");
+ return;
+ }
+ switch (Globals.cls.key_dest) {
+ case Defines.key_message :
+ Key.Message(key);
+ break;
+ case Defines.key_menu :
+ Menu.Keydown(key);
+ break;
+ case Defines.key_game :
+ case Defines.key_console :
+ Menu.Menu_Main_f();
+ break;
+ default :
+ Com.Error(Defines.ERR_FATAL, "Bad cls.key_dest");
+ }
+ return;
+ }
+
+ // track if any key is down for BUTTON_ANY
+ Globals.keydown[key] = down;
+ if (down) {
+ if (key_repeats[key] == 1)
+ Globals.anykeydown++;
+ }
+ else {
+ Globals.anykeydown--;
+ if (Globals.anykeydown < 0)
+ Globals.anykeydown = 0;
+ }
+
+ //
+ // key up events only generate commands if the game key binding is
+ // a button command (leading + sign). These will occur even in console mode,
+ // to keep the character from continuing an action started before a console
+ // switch. Button commands include the kenum as a parameter, so multiple
+ // downs can be matched with ups
+ //
+ if (!down) {
+ kb = Globals.keybindings[key];
+ if (kb != null && kb.length()>0 && kb.charAt(0) == '+') {
+ cmd = "-" + kb.substring(1) + " " + key + " " + time + "\n";
+ Cbuf.AddText(cmd);
+ }
+ if (keyshift[key] != key) {
+ kb = Globals.keybindings[keyshift[key]];
+ if (kb != null && kb.length()>0 && kb.charAt(0) == '+') {
+ cmd = "-" + kb.substring(1) + " " + key + " " + time + "\n";
+ Cbuf.AddText(cmd);
+ }
+ }
+ return;
+ }
+
+ //
+ // if not a consolekey, send to the interpreter no matter what mode is
+ //
+ if ((Globals.cls.key_dest == Defines.key_menu && menubound[key])
+ || (Globals.cls.key_dest == Defines.key_console && !consolekeys[key])
+ || (Globals.cls.key_dest == Defines.key_game && (Globals.cls.state == Defines.ca_active || !consolekeys[key]))) {
+ kb = Globals.keybindings[key];
+ if (kb != null) {
+ if (kb.length()>0 && kb.charAt(0) == '+') {
+ // button commands add keynum and time as a parm
+ cmd = kb + " " + key + " " + time + "\n";
+ Cbuf.AddText(cmd);
+ }
+ else {
+ Cbuf.AddText(kb + "\n");
+ }
+ }
+ return;
+ }
+
+ if (!down)
+ return; // other systems only care about key down events
+
+ if (shift_down)
+ key = keyshift[key];
+
+ switch (Globals.cls.key_dest) {
+ case Defines.key_message :
+ Key.Message(key);
+ break;
+ case Defines.key_menu :
+ Menu.Keydown(key);
+ break;
+
+ case Defines.key_game :
+ case Defines.key_console :
+ Key.Console(key);
+ break;
+ default :
+ Com.Error(Defines.ERR_FATAL, "Bad cls.key_dest");
+ }
+ }
+
+ /**
+ * Returns a string (either a single ascii char, or a K_* name) for the
+ * given keynum.
+ */
+ public static String KeynumToString(int keynum) {
+ if (keynum < 0 || keynum > 255)
+ return "<KEY NOT FOUND>";
+ if (keynum > 32 && keynum < 127)
+ return Character.toString((char) keynum);
+
+ if (keynames[keynum] != null)
+ return keynames[keynum];
+
+ return "<UNKNOWN KEYNUM>";
+ }
+
+ /**
+ * Returns a key number to be used to index keybindings[] by looking at
+ * the given string. Single ascii characters return themselves, while
+ * the K_* names are matched up.
+ */
+ static int StringToKeynum(String str) {
+
+ if (str == null)
+ return -1;
+
+ if (str.length() == 1)
+ return str.charAt(0);
+
+ for (int i = 0; i < keynames.length; i++) {
+ if (str.equalsIgnoreCase(keynames[i]))
+ return i;
+ }
+
+ return -1;
+ }
+
+ public static void Message(int key) {
+
+ if (key == K_ENTER || key == K_KP_ENTER) {
+ if (Globals.chat_team)
+ Cbuf.AddText("say_team \"");
+ else
+ Cbuf.AddText("say \"");
+
+ Cbuf.AddText(Globals.chat_buffer);
+ Cbuf.AddText("\"\n");
+
+ Globals.cls.key_dest = Defines.key_game;
+ Globals.chat_buffer = "";
+ return;
+ }
+
+ if (key == K_ESCAPE) {
+ Globals.cls.key_dest = Defines.key_game;
+ Globals.chat_buffer = "";
+ return;
+ }
+
+ if (key < 32 || key > 127)
+ return; // non printable
+
+ if (key == K_BACKSPACE) {
+ if (Globals.chat_buffer.length() > 2) {
+ Globals.chat_buffer = Globals.chat_buffer.substring(0, Globals.chat_buffer.length() - 2);
+ }
+ else
+ Globals.chat_buffer = "";
+ return;
+ }
+
+ if (Globals.chat_buffer.length() > Defines.MAXCMDLINE)
+ return; // all full
+
+ Globals.chat_buffer += (char) key;
+ }
+
+ /**
+ * Interactive line editing and console scrollback.
+ */
+ public static void Console(int key) {
+
+ switch (key) {
+ case K_KP_SLASH :
+ key = '/';
+ break;
+ case K_KP_MINUS :
+ key = '-';
+ break;
+ case K_KP_PLUS :
+ key = '+';
+ break;
+ case K_KP_HOME :
+ key = '7';
+ break;
+ case K_KP_UPARROW :
+ key = '8';
+ break;
+ case K_KP_PGUP :
+ key = '9';
+ break;
+ case K_KP_LEFTARROW :
+ key = '4';
+ break;
+ case K_KP_5 :
+ key = '5';
+ break;
+ case K_KP_RIGHTARROW :
+ key = '6';
+ break;
+ case K_KP_END :
+ key = '1';
+ break;
+ case K_KP_DOWNARROW :
+ key = '2';
+ break;
+ case K_KP_PGDN :
+ key = '3';
+ break;
+ case K_KP_INS :
+ key = '0';
+ break;
+ case K_KP_DEL :
+ key = '.';
+ break;
+ }
+
+ if (key == 'l') {
+ if (Globals.keydown[K_CTRL]) {
+ Cbuf.AddText("clear\n");
+ return;
+ }
+ }
+
+ if (key == K_ENTER || key == K_KP_ENTER) {
+ // backslash text are commands, else chat
+ if (Globals.key_lines[Globals.edit_line][1] == '\\' || Globals.key_lines[Globals.edit_line][1] == '/')
+ Cbuf.AddText(
+ new String(Globals.key_lines[Globals.edit_line], 2, Lib.strlen(Globals.key_lines[Globals.edit_line]) - 2));
+ else
+ Cbuf.AddText(
+ new String(Globals.key_lines[Globals.edit_line], 1, Lib.strlen(Globals.key_lines[Globals.edit_line]) - 1));
+
+ Cbuf.AddText("\n");
+ Com.Printf(new String(Globals.key_lines[Globals.edit_line], 0, Lib.strlen(Globals.key_lines[Globals.edit_line])));
+ Globals.edit_line = (Globals.edit_line + 1) & 31;
+ history_line = Globals.edit_line;
+ Globals.key_lines[Globals.edit_line][0] = ']';
+ Globals.key_linepos = 1;
+ if (Globals.cls.state == Defines.ca_disconnected)
+ SCR.UpdateScreen(); // force an update, because the command
+ // may take some time
+ return;
+ }
+
+ if (key == K_TAB) {
+ // command completion
+ CompleteCommand();
+ return;
+ }
+
+ if ((key == K_BACKSPACE) || (key == K_LEFTARROW) || (key == K_KP_LEFTARROW) || ((key == 'h') && (Globals.keydown[K_CTRL]))) {
+ if (Globals.key_linepos > 1)
+ Globals.key_linepos--;
+ return;
+ }
+
+ if ((key == K_UPARROW) || (key == K_KP_UPARROW) || ((key == 'p') && Globals.keydown[K_CTRL])) {
+ do {
+ history_line = (history_line - 1) & 31;
+ }
+ while (history_line != Globals.edit_line && Globals.key_lines[history_line][1] == 0);
+ if (history_line == Globals.edit_line)
+ history_line = (Globals.edit_line + 1) & 31;
+ Lib.strcpy(Globals.key_lines[Globals.edit_line], Globals.key_lines[history_line]);
+ Globals.key_linepos = Lib.strlen(Globals.key_lines[Globals.edit_line]);
+ return;
+ }
+
+ if ((key == K_DOWNARROW) || (key == K_KP_DOWNARROW) || ((key == 'n') && Globals.keydown[K_CTRL])) {
+ if (history_line == Globals.edit_line)
+ return;
+ do {
+ history_line = (history_line + 1) & 31;
+ }
+ while (history_line != Globals.edit_line && Globals.key_lines[history_line][1] == 0);
+ if (history_line == Globals.edit_line) {
+ Globals.key_lines[Globals.edit_line][0] = ']';
+ Globals.key_linepos = 1;
+ }
+ else {
+ Lib.strcpy(Globals.key_lines[Globals.edit_line], Globals.key_lines[history_line]);
+ Globals.key_linepos = Lib.strlen(Globals.key_lines[Globals.edit_line]);
+ }
+ return;
+ }
+
+ if (key == K_PGUP || key == K_KP_PGUP) {
+ Globals.con.display -= 2;
+ return;
+ }
+
+ if (key == K_PGDN || key == K_KP_PGDN) {
+ Globals.con.display += 2;
+ if (Globals.con.display > Globals.con.current)
+ Globals.con.display = Globals.con.current;
+ return;
+ }
+
+ if (key == K_HOME || key == K_KP_HOME) {
+ Globals.con.display = Globals.con.current - Globals.con.totallines + 10;
+ return;
+ }
+
+ if (key == K_END || key == K_KP_END) {
+ Globals.con.display = Globals.con.current;
+ return;
+ }
+
+ if (key < 32 || key > 127)
+ return; // non printable
+
+ if (Globals.key_linepos < Defines.MAXCMDLINE - 1) {
+ Globals.key_lines[Globals.edit_line][Globals.key_linepos] = (byte) key;
+ Globals.key_linepos++;
+ Globals.key_lines[Globals.edit_line][Globals.key_linepos] = 0;
+ }
+
+ }
+
+ static void CompleteCommand() {
+ // 00166 char *cmd, *s;
+ // 00167
+ // 00168 s = key_lines[edit_line]+1;
+ // 00169 if (*s == '\\' || *s == '/')
+ // 00170 s++;
+ // 00171
+ // 00172 cmd = Cmd_CompleteCommand (s);
+ // 00173 if (!cmd)
+ // 00174 cmd = Cvar_CompleteVariable (s);
+ // 00175 if (cmd)
+ // 00176 {
+ // 00177 key_lines[edit_line][1] = '/';
+ // 00178 strcpy (key_lines[edit_line]+2, cmd);
+ // 00179 key_linepos = strlen(cmd)+2;
+ // 00180 key_lines[edit_line][key_linepos] = ' ';
+ // 00181 key_linepos++;
+ // 00182 key_lines[edit_line][key_linepos] = 0;
+ // 00183 return;
+ // 00184 }
+ }
+
+ public static xcommand_t Bind_f = new xcommand_t() {
+ public void execute() {
+ Key_Bind_f();
+ }
+ };
+
+ static void Key_Bind_f() {
+ int c = Cmd.Argc();
+
+ if (c < 2) {
+ Com.Printf("bind <key> [command] : attach a command to a key\n");
+ return;
+ }
+ int b = StringToKeynum(Cmd.Argv(1));
+ if (b == -1) {
+ Com.Printf("\"" + Cmd.Argv(1) + "\" isn't a valid key\n");
+ return;
+ }
+
+ if (c == 2) {
+ if (Globals.keybindings[b] != null)
+ Com.Printf("\"" + Cmd.Argv(1) + "\" = \"" + Globals.keybindings[b] + "\"\n");
+ else
+ Com.Printf("\"" + Cmd.Argv(1) + "\" is not bound\n");
+ return;
+ }
+
+ // copy the rest of the command line
+ String cmd = ""; // start out with a null string
+ for (int i = 2; i < c; i++) {
+ cmd += Cmd.Argv(i);
+ if (i != (c - 1))
+ cmd += " ";
+ }
+
+ SetBinding(b, cmd);
+ }
+
+ static void SetBinding(int keynum, String binding) {
+ if (keynum == -1)
+ return;
+
+ // free old bindings
+ Globals.keybindings[keynum] = null;
+
+ Globals.keybindings[keynum] = binding;
+ }
+
+ static xcommand_t Unbind_f = new xcommand_t() {
+ public void execute() {
+ Key_Unbind_f();
+ }
+ };
+
+ static void Key_Unbind_f() {
+
+ if (Cmd.Argc() != 2) {
+ Com.Printf("unbind <key> : remove commands from a key\n");
+ return;
+ }
+
+ int b = Key.StringToKeynum(Cmd.Argv(1));
+ if (b == -1) {
+ Com.Printf("\"" + Cmd.Argv(1) + "\" isn't a valid key\n");
+ return;
+ }
+
+ Key.SetBinding(b, null);
+ }
+
+ static xcommand_t Unbindall_f = new xcommand_t() {
+ public void execute() {
+ Key_Unbindall_f();
+ }
+ };
+
+ static void Key_Unbindall_f() {
+ for (int i = 0; i < 256; i++)
+ Key.SetBinding(i, null);
+ }
+
+ static xcommand_t Bindlist_f = new xcommand_t() {
+ public void execute() {
+ Key_Bindlist_f();
+ }
+ };
+
+ static void Key_Bindlist_f() {
+ for (int i = 0; i < 256; i++)
+ if (Globals.keybindings[i] != null && Globals.keybindings[i].length() != 0)
+ Com.Printf(Key.KeynumToString(i) + " \"" + Globals.keybindings[i] + "\"\n");
+ }
+
+ static void ClearStates() {
+ int i;
+
+ anykeydown = 0;
+
+ for (i = 0; i < 256; i++) {
+ if (keydown[i] || key_repeats[i]!=0)
+ Event(i, false, 0);
+ keydown[i] = false;
+ key_repeats[i] = 0;
+ }
+ }
+
+ public static void WriteBindings(RandomAccessFile f) {
+ for (int i = 0; i < 256; i++)
+ if (keybindings[i] != null && keybindings[i].length() > 0)
+ try {
+ f.writeBytes("bind " + KeynumToString(i) + " \"" + keybindings[i] + "\"\n");
+ } catch (IOException e) {}
+ }
+
+}
diff --git a/src/jake2/client/M.java b/src/jake2/client/M.java
new file mode 100644
index 0000000..ebd9ebd
--- /dev/null
+++ b/src/jake2/client/M.java
@@ -0,0 +1,573 @@
+/*
+ * M.java
+ * Copyright (C) 2003
+ *
+ * $Id: M.java,v 1.1 2004-07-07 19:58:42 hzi Exp $
+ */
+/*
+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.
+
+*/
+package jake2.client;
+
+import jake2.Defines;
+import jake2.game.*;
+import jake2.server.SV;
+import jake2.util.Lib;
+import jake2.util.Math3D;
+
+/**
+ * M
+ */
+public final class M {
+
+ public static void M_CheckGround(edict_t ent) {
+ float[] point = { 0, 0, 0 };
+ trace_t trace;
+
+ if ((ent.flags & (Defines.FL_SWIM | Defines.FL_FLY)) != 0)
+ return;
+
+ if (ent.velocity[2] > 100) {
+ ent.groundentity = null;
+ return;
+ }
+
+ // if the hull point one-quarter unit down is solid the entity is on ground
+ point[0] = ent.s.origin[0];
+ point[1] = ent.s.origin[1];
+ point[2] = ent.s.origin[2] - 0.25f;
+
+ trace = GameBase.gi.trace(ent.s.origin, ent.mins, ent.maxs, point, ent, Defines.MASK_MONSTERSOLID);
+
+ // check steepness
+ if (trace.plane.normal[2] < 0.7 && !trace.startsolid) {
+ ent.groundentity = null;
+ return;
+ }
+
+ // ent.groundentity = trace.ent;
+ // ent.groundentity_linkcount = trace.ent.linkcount;
+ // if (!trace.startsolid && !trace.allsolid)
+ // VectorCopy (trace.endpos, ent.s.origin);
+ if (!trace.startsolid && !trace.allsolid) {
+ Math3D.VectorCopy(trace.endpos, ent.s.origin);
+ ent.groundentity = trace.ent;
+ ent.groundentity_linkcount = trace.ent.linkcount;
+ ent.velocity[2] = 0;
+ }
+ }
+
+ public static boolean M_CheckBottom(edict_t ent) {
+ float[] mins = { 0, 0, 0 };
+ float[] maxs = { 0, 0, 0 };
+ float[] start = { 0, 0, 0 };
+ float[] stop = { 0, 0, 0 };
+
+ trace_t trace;
+ int x, y;
+ float mid, bottom;
+
+ Math3D.VectorAdd(ent.s.origin, ent.mins, mins);
+ Math3D.VectorAdd(ent.s.origin, ent.maxs, maxs);
+
+ // if all of the points under the corners are solid world, don't bother
+ // with the tougher checks
+ // the corners must be within 16 of the midpoint
+ start[2] = mins[2] - 1;
+ for (x = 0; x <= 1; x++)
+ for (y = 0; y <= 1; y++) {
+ start[0] = x != 0 ? maxs[0] : mins[0];
+ start[1] = y != 0 ? maxs[1] : mins[1];
+ if (GameBase.gi.pointcontents.pointcontents(start) != Defines.CONTENTS_SOLID) {
+ GameBase.c_no++;
+ //
+ // check it for real...
+ //
+ start[2] = mins[2];
+
+ // the midpoint must be within 16 of the bottom
+ start[0] = stop[0] = (mins[0] + maxs[0]) * 0.5f;
+ start[1] = stop[1] = (mins[1] + maxs[1]) * 0.5f;
+ stop[2] = start[2] - 2 * GameBase.STEPSIZE;
+ trace = GameBase.gi.trace(start, GameBase.vec3_origin, GameBase.vec3_origin, stop, ent, Defines.MASK_MONSTERSOLID);
+
+ if (trace.fraction == 1.0)
+ return false;
+ mid = bottom = trace.endpos[2];
+
+ // the corners must be within 16 of the midpoint
+ for (x = 0; x <= 1; x++)
+ for (y = 0; y <= 1; y++) {
+ start[0] = stop[0] = x != 0 ? maxs[0] : mins[0];
+ start[1] = stop[1] = y != 0 ? maxs[1] : mins[1];
+
+ trace =
+ GameBase.gi.trace(
+ start,
+ GameBase.vec3_origin,
+ GameBase.vec3_origin,
+ stop,
+ ent,
+ Defines.MASK_MONSTERSOLID);
+
+ if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
+ bottom = trace.endpos[2];
+ if (trace.fraction == 1.0 || mid - trace.endpos[2] > GameBase.STEPSIZE)
+ return false;
+ }
+
+ GameBase.c_yes++;
+ return true;
+ }
+ }
+
+ GameBase.c_yes++;
+ return true; // we got out easy
+ }
+
+ /*
+ ===============
+ M_ChangeYaw
+
+ ===============
+ *///ok
+ public static void M_ChangeYaw(edict_t ent) {
+ float ideal;
+ float current;
+ float move;
+ float speed;
+
+ current = Math3D.anglemod(ent.s.angles[Defines.YAW]);
+ ideal = ent.ideal_yaw;
+
+ if (current == ideal)
+ return;
+
+ move = ideal - current;
+ speed = ent.yaw_speed;
+ if (ideal > current) {
+ if (move >= 180)
+ move = move - 360;
+ }
+ else {
+ if (move <= -180)
+ move = move + 360;
+ }
+ if (move > 0) {
+ if (move > speed)
+ move = speed;
+ }
+ else {
+ if (move < -speed)
+ move = -speed;
+ }
+
+ ent.s.angles[Defines.YAW] = Math3D.anglemod(current + move);
+ }
+
+ /*
+ ======================
+ M_MoveToGoal
+ ======================
+ */
+ public static void M_MoveToGoal(edict_t ent, float dist) {
+ edict_t goal = ent.goalentity;
+
+ if (ent.groundentity == null && (ent.flags & (Defines.FL_FLY | Defines.FL_SWIM)) == 0)
+ return;
+
+ // if the next step hits the enemy, return immediately
+ if (ent.enemy != null && SV.SV_CloseEnough(ent, ent.enemy, dist))
+ return;
+
+ // bump around...
+ if ((Lib.rand() & 3) == 1 || !SV.SV_StepDirection(ent, ent.ideal_yaw, dist)) {
+ if (ent.inuse)
+ SV.SV_NewChaseDir(ent, goal, dist);
+ }
+ }
+
+ /*
+ ===============
+ M_walkmove
+ ===============
+ */
+ public static boolean M_walkmove(edict_t ent, float yaw, float dist) {
+ float[] move = { 0, 0, 0 };
+
+ if ((ent.groundentity == null) && (ent.flags & (Defines.FL_FLY | Defines.FL_SWIM)) == 0)
+ return false;
+
+ yaw = (float) (yaw * Math.PI * 2 / 360);
+
+ move[0] = (float) Math.cos(yaw) * dist;
+ move[1] = (float) Math.sin(yaw) * dist;
+ move[2] = 0;
+
+ return SV.SV_movestep(ent, move, true);
+ }
+
+ public static void M_CatagorizePosition(edict_t ent) {
+ float[] point = { 0, 0, 0 };
+ int cont;
+
+ //
+ // get waterlevel
+ //
+ point[0] = ent.s.origin[0];
+ point[1] = ent.s.origin[1];
+ point[2] = ent.s.origin[2] + ent.mins[2] + 1;
+ cont = Game.gi.pointcontents.pointcontents(point);
+
+ if (0 == (cont & Defines.MASK_WATER)) {
+ ent.waterlevel = 0;
+ ent.watertype = 0;
+ return;
+ }
+
+ ent.watertype = cont;
+ ent.waterlevel = 1;
+ point[2] += 26;
+ cont = GameBase.gi.pointcontents.pointcontents(point);
+ if (0 == (cont & Defines.MASK_WATER))
+ return;
+
+ ent.waterlevel = 2;
+ point[2] += 22;
+ cont = GameBase.gi.pointcontents.pointcontents(point);
+ if (0 != (cont & Defines.MASK_WATER))
+ ent.waterlevel = 3;
+ }
+
+ public static void M_WorldEffects(edict_t ent) {
+ int dmg;
+
+ if (ent.health > 0) {
+ if (0 == (ent.flags & Defines.FL_SWIM)) {
+ if (ent.waterlevel < 3) {
+ ent.air_finished = GameBase.level.time + 12;
+ }
+ else if (ent.air_finished < GameBase.level.time) {
+ // drown!
+ if (ent.pain_debounce_time < GameBase.level.time) {
+ dmg = (int) (2f + 2f * Math.floor(GameBase.level.time - ent.air_finished));
+ if (dmg > 15)
+ dmg = 15;
+ GameUtil.T_Damage(
+ ent,
+ GameBase.g_edicts[0],
+ GameBase.g_edicts[0],
+ GameBase.vec3_origin,
+ ent.s.origin,
+ GameBase.vec3_origin,
+ dmg,
+ 0,
+ Defines.DAMAGE_NO_ARMOR,
+ Defines.MOD_WATER);
+ ent.pain_debounce_time = GameBase.level.time + 1;
+ }
+ }
+ }
+ else {
+ if (ent.waterlevel > 0) {
+ ent.air_finished = GameBase.level.time + 9;
+ }
+ else if (ent.air_finished < GameBase.level.time) {
+ // suffocate!
+ if (ent.pain_debounce_time < GameBase.level.time) {
+ dmg = (int) (2 + 2 * Math.floor(GameBase.level.time - ent.air_finished));
+ if (dmg > 15)
+ dmg = 15;
+ GameUtil.T_Damage(
+ ent,
+ GameBase.g_edicts[0],
+ GameBase.g_edicts[0],
+ GameBase.vec3_origin,
+ ent.s.origin,
+ GameBase.vec3_origin,
+ dmg,
+ 0,
+ Defines.DAMAGE_NO_ARMOR,
+ Defines.MOD_WATER);
+ ent.pain_debounce_time = GameBase.level.time + 1;
+ }
+ }
+ }
+ }
+
+ if (ent.waterlevel == 0) {
+ if ((ent.flags & Defines.FL_INWATER) != 0) {
+ GameBase.gi.sound(ent, Defines.CHAN_BODY, GameBase.gi.soundindex("player/watr_out.wav"), 1, Defines.ATTN_NORM, 0);
+ ent.flags &= ~Defines.FL_INWATER;
+ }
+ return;
+ }
+
+ if ((ent.watertype & Defines.CONTENTS_LAVA) != 0 && 0 == (ent.flags & Defines.FL_IMMUNE_LAVA)) {
+ if (ent.damage_debounce_time < GameBase.level.time) {
+ ent.damage_debounce_time = GameBase.level.time + 0.2f;
+ GameUtil.T_Damage(
+ ent,
+ GameBase.g_edicts[0],
+ GameBase.g_edicts[0],
+ GameBase.vec3_origin,
+ ent.s.origin,
+ GameBase.vec3_origin,
+ 10 * ent.waterlevel,
+ 0,
+ 0,
+ Defines.MOD_LAVA);
+ }
+ }
+ if ((ent.watertype & Defines.CONTENTS_SLIME) != 0 && 0 == (ent.flags & Defines.FL_IMMUNE_SLIME)) {
+ if (ent.damage_debounce_time < GameBase.level.time) {
+ ent.damage_debounce_time = GameBase.level.time + 1;
+ GameUtil.T_Damage(
+ ent,
+ GameBase.g_edicts[0],
+ GameBase.g_edicts[0],
+ GameBase.vec3_origin,
+ ent.s.origin,
+ GameBase.vec3_origin,
+ 4 * ent.waterlevel,
+ 0,
+ 0,
+ Defines.MOD_SLIME);
+ }
+ }
+
+ if (0 == (ent.flags & Defines.FL_INWATER)) {
+ if (0 == (ent.svflags & Defines.SVF_DEADMONSTER)) {
+ if ((ent.watertype & Defines.CONTENTS_LAVA) != 0)
+ if (Lib.random() <= 0.5)
+ GameBase.gi.sound(ent, Defines.CHAN_BODY, GameBase.gi.soundindex("player/lava1.wav"), 1, Defines.ATTN_NORM, 0);
+ else
+ GameBase.gi.sound(ent, Defines.CHAN_BODY, GameBase.gi.soundindex("player/lava2.wav"), 1, Defines.ATTN_NORM, 0);
+ else if ((ent.watertype & Defines.CONTENTS_SLIME) != 0)
+ GameBase.gi.sound(ent, Defines.CHAN_BODY, GameBase.gi.soundindex("player/watr_in.wav"), 1, Defines.ATTN_NORM, 0);
+ else if ((ent.watertype & Defines.CONTENTS_WATER) != 0)
+ GameBase.gi.sound(ent, Defines.CHAN_BODY, GameBase.gi.soundindex("player/watr_in.wav"), 1, Defines.ATTN_NORM, 0);
+ }
+
+ ent.flags |= Defines.FL_INWATER;
+ ent.damage_debounce_time = 0;
+ }
+ }
+
+ public static EntThinkAdapter M_droptofloor = new EntThinkAdapter() {
+ public boolean think(edict_t ent) {
+ float[] end = { 0, 0, 0 };
+ trace_t trace;
+
+ ent.s.origin[2] += 1;
+ Math3D.VectorCopy(ent.s.origin, end);
+ end[2] -= 256;
+
+ trace = GameBase.gi.trace(ent.s.origin, ent.mins, ent.maxs, end, ent, Defines.MASK_MONSTERSOLID);
+
+ if (trace.fraction == 1 || trace.allsolid)
+ return true;
+
+ Math3D.VectorCopy(trace.endpos, ent.s.origin);
+
+ GameBase.gi.linkentity(ent);
+ M.M_CheckGround(ent);
+ M_CatagorizePosition(ent);
+ return true;
+ }
+ };
+
+ public static void M_SetEffects(edict_t ent) {
+ ent.s.effects &= ~(Defines.EF_COLOR_SHELL | Defines.EF_POWERSCREEN);
+ ent.s.renderfx &= ~(Defines.RF_SHELL_RED | Defines.RF_SHELL_GREEN | Defines.RF_SHELL_BLUE);
+
+ if ((ent.monsterinfo.aiflags & Defines.AI_RESURRECTING) != 0) {
+ ent.s.effects |= Defines.EF_COLOR_SHELL;
+ ent.s.renderfx |= Defines.RF_SHELL_RED;
+ }
+
+ if (ent.health <= 0)
+ return;
+
+ if (ent.powerarmor_time > GameBase.level.time) {
+ if (ent.monsterinfo.power_armor_type == Defines.POWER_ARMOR_SCREEN) {
+ ent.s.effects |= Defines.EF_POWERSCREEN;
+ }
+ else if (ent.monsterinfo.power_armor_type == Defines.POWER_ARMOR_SHIELD) {
+ ent.s.effects |= Defines.EF_COLOR_SHELL;
+ ent.s.renderfx |= Defines.RF_SHELL_GREEN;
+ }
+ }
+ };
+
+ public static void M_MoveFrame(edict_t self) {
+ mmove_t move;
+ int index;
+
+ move = self.monsterinfo.currentmove;
+ self.nextthink = GameBase.level.time + Defines.FRAMETIME;
+
+ if ((self.monsterinfo.nextframe != 0)
+ && (self.monsterinfo.nextframe >= move.firstframe)
+ && (self.monsterinfo.nextframe <= move.lastframe)) {
+ self.s.frame = self.monsterinfo.nextframe;
+ self.monsterinfo.nextframe = 0;
+ }
+ else {
+ if (self.s.frame == move.lastframe) {
+ if (move.endfunc != null) {
+ move.endfunc.think(self);
+
+ // regrab move, endfunc is very likely to change it
+ move = self.monsterinfo.currentmove;
+
+ // check for death
+ if ((self.svflags & Defines.SVF_DEADMONSTER) != 0)
+ return;
+ }
+ }
+
+ if (self.s.frame < move.firstframe || self.s.frame > move.lastframe) {
+ self.monsterinfo.aiflags &= ~Defines.AI_HOLD_FRAME;
+ self.s.frame = move.firstframe;
+ }
+ else {
+ if (0 == (self.monsterinfo.aiflags & Defines.AI_HOLD_FRAME)) {
+ self.s.frame++;
+ if (self.s.frame > move.lastframe)
+ self.s.frame = move.firstframe;
+ }
+ }
+ }
+
+ index = self.s.frame - move.firstframe;
+ if (move.frame[index].ai != null)
+ if (0 == (self.monsterinfo.aiflags & Defines.AI_HOLD_FRAME))
+ move.frame[index].ai.ai(self, move.frame[index].dist * self.monsterinfo.scale);
+ else
+ move.frame[index].ai.ai(self, 0);
+
+ if (move.frame[index].think != null)
+ move.frame[index].think.think(self);
+ }
+
+ public static void M_ReactToDamage(edict_t targ, edict_t attacker) {
+ if ((null != attacker.client) && 0 != (attacker.svflags & Defines.SVF_MONSTER))
+ return;
+
+ if (attacker == targ || attacker == targ.enemy)
+ return;
+
+ // if we are a good guy monster and our attacker is a player
+ // or another good guy, do not get mad at them
+ if (0 != (targ.monsterinfo.aiflags & Defines.AI_GOOD_GUY)) {
+ if (attacker.client != null || (attacker.monsterinfo.aiflags & Defines.AI_GOOD_GUY) != 0)
+ return;
+ }
+
+ // we now know that we are not both good guys
+
+ // if attacker is a client, get mad at them because he's good and we're not
+ if (attacker.client != null) {
+ targ.monsterinfo.aiflags &= ~Defines.AI_SOUND_TARGET;
+
+ // this can only happen in coop (both new and old enemies are clients)
+ // only switch if can't see the current enemy
+ if (targ.enemy != null && targ.enemy.client != null) {
+ if (GameUtil.visible(targ, targ.enemy)) {
+ targ.oldenemy = attacker;
+ return;
+ }
+ targ.oldenemy = targ.enemy;
+ }
+ targ.enemy = attacker;
+ if (0 != (targ.monsterinfo.aiflags & Defines.AI_DUCKED))
+ GameUtil.FoundTarget(targ);
+ return;
+ }
+
+ // it's the same base (walk/swim/fly) type and a different classname and it's not a tank
+ // (they spray too much), get mad at them
+ if (((targ.flags & (Defines.FL_FLY | Defines.FL_SWIM)) == (attacker.flags & (Defines.FL_FLY | Defines.FL_SWIM)))
+ && (Lib.strcmp(targ.classname, attacker.classname) != 0)
+ && (Lib.strcmp(attacker.classname, "monster_tank") != 0)
+ && (Lib.strcmp(attacker.classname, "monster_supertank") != 0)
+ && (Lib.strcmp(attacker.classname, "monster_makron") != 0)
+ && (Lib.strcmp(attacker.classname, "monster_jorg") != 0)) {
+ if (targ.enemy != null && targ.enemy.client != null)
+ targ.oldenemy = targ.enemy;
+ targ.enemy = attacker;
+ if (0 == (targ.monsterinfo.aiflags & Defines.AI_DUCKED))
+ GameUtil.FoundTarget(targ);
+ }
+ // if they *meant* to shoot us, then shoot back
+ else if (attacker.enemy == targ) {
+ if (targ.enemy != null && targ.enemy.client != null)
+ targ.oldenemy = targ.enemy;
+ targ.enemy = attacker;
+ if (0 == (targ.monsterinfo.aiflags & Defines.AI_DUCKED))
+ GameUtil.FoundTarget(targ);
+ }
+ // otherwise get mad at whoever they are mad at (help our buddy) unless it is us!
+ else if (attacker.enemy != null && attacker.enemy != targ) {
+ if (targ.enemy != null && targ.enemy.client != null)
+ targ.oldenemy = targ.enemy;
+ targ.enemy = attacker.enemy;
+ if (0 == (targ.monsterinfo.aiflags & Defines.AI_DUCKED))
+ GameUtil.FoundTarget(targ);
+ }
+ }
+ /** Stops the Flies. */
+ public static EntThinkAdapter M_FliesOff = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ self.s.effects &= ~Defines.EF_FLIES;
+ self.s.sound = 0;
+ return true;
+ }
+ };
+ /** Starts the Flies as setting the animation flag in the entity. */
+ public static EntThinkAdapter M_FliesOn = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+ if (self.waterlevel != 0)
+ return true;
+
+ self.s.effects |= Defines.EF_FLIES;
+ self.s.sound = GameBase.gi.soundindex("infantry/inflies1.wav");
+ self.think = M_FliesOff;
+ self.nextthink = GameBase.level.time + 60;
+ return true;
+ }
+ };
+ /** Adds some flies after a random time */
+ public static EntThinkAdapter M_FlyCheck = new EntThinkAdapter() {
+ public boolean think(edict_t self) {
+
+ if (self.waterlevel != 0)
+ return true;
+
+ if (Lib.random() > 0.5)
+ return true;
+
+ self.think = M_FliesOn;
+ self.nextthink = GameBase.level.time + 5 + 10 * Lib.random();
+ return true;
+ }
+ };
+
+}
diff --git a/src/jake2/client/Menu.java b/src/jake2/client/Menu.java
new file mode 100644
index 0000000..264d38f
--- /dev/null
+++ b/src/jake2/client/Menu.java
@@ -0,0 +1,4977 @@
+/*
+ * Menu.java
+ * Copyright (C) 2004
+ *
+ * $Id: Menu.java,v 1.1 2004-07-07 19:58:51 hzi Exp $
+ */
+/*
+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.
+
+*/
+package jake2.client;
+
+import jake2.Globals;
+import jake2.game.Cmd;
+import jake2.game.cvar_t;
+import jake2.qcommon.*;
+import jake2.sys.NET;
+import jake2.sys.Sys;
+import jake2.util.Lib;
+import jake2.util.Math3D;
+
+import java.awt.Dimension;
+import java.io.RandomAccessFile;
+import java.util.Arrays;
+import java.util.Comparator;
+
+/**
+ * Menu
+ *
+ *
+ */
+
+abstract class keyfunc_t {
+ abstract String execute(int key);
+}
+
+public final class Menu extends Key {
+
+ static int m_main_cursor;
+ static final int NUM_CURSOR_FRAMES = 15;
+
+ static final String menu_in_sound = "misc/menu1.wav";
+ static final String menu_move_sound = "misc/menu2.wav";
+ static final String menu_out_sound = "misc/menu3.wav";
+
+ static boolean m_entersound; // play after drawing a frame, so caching
+ // won't disrupt the sound
+
+ static xcommand_t m_drawfunc;
+
+ static keyfunc_t m_keyfunc;
+
+ // =============================================================================
+ /* Support Routines */
+
+ public final static int MAX_MENU_DEPTH = 8;
+
+ public static class menulayer_t {
+ xcommand_t draw;
+ keyfunc_t key;
+ }
+
+ static class menuframework_s {
+ int x, y;
+ int cursor;
+
+ int nitems;
+ int nslots;
+ menucommon_s items[] = new menucommon_s[64];
+
+ String statusbar;
+
+ //void (*cursordraw)( struct _tag_menuframework *m );
+ mcallback cursordraw;
+
+ }
+
+ static class mcallback {
+ public void execute(Object self) {
+ }
+ }
+
+ static class menucommon_s {
+ int type;
+ String name;
+ int x, y;
+ menuframework_s parent;
+ int cursor_offset;
+ int localdata[] = { 0, 0, 0, 0 };
+ int flags;
+ int n = -1; //position in an array.
+
+ String statusbar;
+
+ mcallback callback;
+ mcallback statusbarfunc;
+ mcallback ownerdraw;
+ mcallback cursordraw;
+ }
+
+ static class menufield_s extends menucommon_s {
+ //char buffer[80];
+ StringBuffer buffer; //allow deletion.
+
+ int cursor;
+ int length;
+ int visible_length;
+ int visible_offset;
+ }
+
+ static class menuslider_s extends menucommon_s {
+
+ float minvalue;
+ float maxvalue;
+ float curvalue;
+
+ float range;
+ }
+
+ static class menulist_s extends menucommon_s {
+ int curvalue;
+ String itemnames[];
+ }
+
+ static class menuaction_s extends menucommon_s {
+
+ }
+
+ static class menuseparator_s extends menucommon_s {
+
+ }
+
+ public static menulayer_t m_layers[] = new menulayer_t[MAX_MENU_DEPTH];
+ public static int m_menudepth;
+
+ static void Banner(String name) {
+ int w, h;
+
+ Dimension dim = new Dimension();
+ Globals.re.DrawGetPicSize(dim, name);
+
+ Globals.re.DrawPic(viddef.width / 2 - dim.width / 2, viddef.height / 2 - 110, name);
+ }
+
+ static void PushMenu(xcommand_t draw, keyfunc_t key) { //, String(*key) (int k) ) {
+ int i;
+
+ if (Cvar.VariableValue("maxclients") == 1 && Com.ServerState() != 0)
+ Cvar.Set("paused", "1");
+
+ // if this menu is already present, drop back to that level
+ // to avoid stacking menus by hotkeys
+ for (i = 0; i < m_menudepth; i++)
+ if (m_layers[i].draw == draw && m_layers[i].key == key) {
+ m_menudepth = i;
+ }
+
+ if (i == m_menudepth) {
+ if (m_menudepth >= MAX_MENU_DEPTH)
+ Com.Error(ERR_FATAL, "PushMenu: MAX_MENU_DEPTH");
+
+ m_layers[m_menudepth].draw = m_drawfunc;
+ m_layers[m_menudepth].key = m_keyfunc;
+ m_menudepth++;
+ }
+
+ m_drawfunc = draw;
+ m_keyfunc = key;
+
+ m_entersound = true;
+
+ cls.key_dest = key_menu;
+ }
+
+ static void ForceMenuOff() {
+ m_drawfunc = null;
+ m_keyfunc = null;
+ cls.key_dest = key_game;
+ m_menudepth = 0;
+ Key.ClearStates();
+ Cvar.Set("paused", "0");
+ }
+
+ static void PopMenu() {
+ S.StartLocalSound(menu_out_sound);
+ if (m_menudepth < 1)
+ Com.Error(ERR_FATAL, "PopMenu: depth < 1");
+ m_menudepth--;
+
+ m_drawfunc = m_layers[m_menudepth].draw;
+ m_keyfunc = m_layers[m_menudepth].key;
+
+ if (0 == m_menudepth)
+ ForceMenuOff();
+ }
+
+ static String Default_MenuKey(menuframework_s m, int key) {
+ String sound = null;
+ menucommon_s item;
+
+ if (m != null) {
+ if ((item = ((menucommon_s) Menu_ItemAtCursor(m))) != null) {
+ if (item.type == MTYPE_FIELD) {
+ if (Field_Key((menufield_s) item, key))
+ return null;
+ }
+ }
+ }
+
+ switch (key) {
+ case K_ESCAPE :
+ PopMenu();
+ return menu_out_sound;
+ case K_KP_UPARROW :
+ case K_UPARROW :
+ if (m != null) {
+ m.cursor--;
+ Menu_AdjustCursor(m, -1);
+ sound = menu_move_sound;
+ }
+ break;
+ case K_TAB :
+ if (m != null) {
+ m.cursor++;
+ Menu_AdjustCursor(m, 1);
+ sound = menu_move_sound;
+ }
+ break;
+ case K_KP_DOWNARROW :
+ case K_DOWNARROW :
+ if (m != null) {
+ m.cursor++;
+ Menu_AdjustCursor(m, 1);
+ sound = menu_move_sound;
+ }
+ break;
+ case K_KP_LEFTARROW :
+ case K_LEFTARROW :
+ if (m != null) {
+ Menu_SlideItem(m, -1);
+ sound = menu_move_sound;
+ }
+ break;
+ case K_KP_RIGHTARROW :
+ case K_RIGHTARROW :
+ if (m != null) {
+ Menu_SlideItem(m, 1);
+ sound = menu_move_sound;
+ }
+ break;
+
+ case K_MOUSE1 :
+ case K_MOUSE2 :
+ case K_MOUSE3 :
+ case K_JOY1 :
+ case K_JOY2 :
+ case K_JOY3 :
+ case K_JOY4 :
+ /*
+ case K_AUX1 :
+ case K_AUX2 :
+ case K_AUX3 :
+ case K_AUX4 :
+ case K_AUX5 :
+ case K_AUX6 :
+ case K_AUX7 :
+ case K_AUX8 :
+ case K_AUX9 :
+ case K_AUX10 :
+ case K_AUX11 :
+ case K_AUX12 :
+ case K_AUX13 :
+ case K_AUX14 :
+ case K_AUX15 :
+ case K_AUX16 :
+ case K_AUX17 :
+ case K_AUX18 :
+ case K_AUX19 :
+ case K_AUX20 :
+ case K_AUX21 :
+ case K_AUX22 :
+ case K_AUX23 :
+ case K_AUX24 :
+ case K_AUX25 :
+ case K_AUX26 :
+ case K_AUX27 :
+ case K_AUX28 :
+ case K_AUX29 :
+ case K_AUX30 :
+ case K_AUX31 :
+ case K_AUX32 :
+ */
+ case K_KP_ENTER :
+ case K_ENTER :
+ if (m != null)
+ Menu_SelectItem(m);
+ sound = menu_move_sound;
+ break;
+ }
+
+ return sound;
+ }
+
+ /*
+ ================
+ DrawCharacter
+
+ Draws one solid graphics character
+ cx and cy are in 320*240 coordinates, and will be centered on
+ higher res screens.
+ ================
+ */
+ public static void DrawCharacter(int cx, int cy, int num) {
+ re.DrawChar(cx + ((viddef.width - 320) >> 1), cy + ((viddef.height - 240) >> 1), num);
+ }
+
+ public static void Print(int cx, int cy, String str) {
+ //while (*str)
+ for (int n = 0; n < str.length(); n++) {
+ DrawCharacter(cx, cy, str.charAt(n) + 128);
+ //str++;
+ cx += 8;
+ }
+ }
+
+ public static void PrintWhite(int cx, int cy, String str) {
+ for (int n = 0; n < str.length(); n++) {
+ DrawCharacter(cx, cy, str.charAt(n));
+ //str++;
+ cx += 8;
+ }
+ }
+
+ public static void DrawPic(int x, int y, String pic) {
+ re.DrawPic(x + ((viddef.width - 320) >> 1), y + ((viddef.height - 240) >> 1), pic);
+ }
+
+ /*
+ =============
+ DrawCursor
+
+ Draws an animating cursor with the point at
+ x,y. The pic will extend to the left of x,
+ and both above and below y.
+ =============
+ */
+ static boolean cached;
+ static void DrawCursor(int x, int y, int f) {
+ //char cursorname[80];
+ String cursorname;
+
+ assert(f >= 0) : "negative time and cursor bug";
+
+ f = Math.abs(f);
+
+ if (!cached) {
+ int i;
+
+ for (i = 0; i < NUM_CURSOR_FRAMES; i++) {
+ cursorname = "m_cursor" + i;
+
+ re.RegisterPic(cursorname);
+ }
+ cached = true;
+ }
+
+ cursorname = "m_cursor" + f;
+ re.DrawPic(x, y, cursorname);
+ }
+
+ public static void DrawTextBox(int x, int y, int width, int lines) {
+ int cx, cy;
+ int n;
+
+ // draw left side
+ cx = x;
+ cy = y;
+ DrawCharacter(cx, cy, 1);
+
+ for (n = 0; n < lines; n++) {
+ cy += 8;
+ DrawCharacter(cx, cy, 4);
+ }
+ DrawCharacter(cx, cy + 8, 7);
+
+ // draw middle
+ cx += 8;
+ while (width > 0) {
+ cy = y;
+ DrawCharacter(cx, cy, 2);
+
+ for (n = 0; n < lines; n++) {
+ cy += 8;
+ DrawCharacter(cx, cy, 5);
+ }
+ DrawCharacter(cx, cy + 8, 8);
+
+ width -= 1;
+ cx += 8;
+ }
+
+ // draw right side
+ cy = y;
+ DrawCharacter(cx, cy, 3);
+ for (n = 0; n < lines; n++) {
+ cy += 8;
+ DrawCharacter(cx, cy, 6);
+
+ }
+ DrawCharacter(cx, cy + 8, 9);
+
+ }
+
+ /*
+ =======================================================================
+
+ MAIN MENU
+
+ =======================================================================
+ */
+ static final int MAIN_ITEMS = 5;
+
+ static xcommand_t Main_Draw = new xcommand_t() {
+ public void execute() {
+ Main_Draw();
+ }
+ };
+ static void Main_Draw() {
+ int i;
+ int w, h;
+ int ystart;
+ int xoffset;
+ int widest = -1;
+ int totalheight = 0;
+ String litname;
+ String[] names = { "m_main_game", "m_main_multiplayer", "m_main_options", "m_main_video", "m_main_quit" };
+ Dimension dim = new Dimension();
+
+ for (i = 0; i < names.length; i++) {
+ Globals.re.DrawGetPicSize(dim, names[i]);
+ w = dim.width;
+ h = dim.height;
+
+ if (w > widest)
+ widest = w;
+ totalheight += (h + 12);
+ }
+
+ ystart = (Globals.viddef.height / 2 - 110);
+ xoffset = (Globals.viddef.width - widest + 70) / 2;
+
+ for (i = 0; i < names.length; i++) {
+ if (i != m_main_cursor)
+ Globals.re.DrawPic(xoffset, ystart + i * 40 + 13, names[i]);
+ }
+
+ //strcat(litname, "_sel");
+ litname = names[m_main_cursor] + "_sel";
+ Globals.re.DrawPic(xoffset, ystart + m_main_cursor * 40 + 13, litname);
+
+ DrawCursor(xoffset - 25, ystart + m_main_cursor * 40 + 11, (int) ((Globals.cls.realtime / 100)) % NUM_CURSOR_FRAMES);
+
+ Globals.re.DrawGetPicSize(dim, "m_main_plaque");
+ w = dim.width;
+ h = dim.height;
+ Globals.re.DrawPic(xoffset - 30 - w, ystart, "m_main_plaque");
+
+ Globals.re.DrawPic(xoffset - 30 - w, ystart + h + 5, "m_main_logo");
+ }
+
+ static keyfunc_t Main_Key = new keyfunc_t() {
+ public String execute(int key) {
+ return Main_Key(key);
+ }
+ };
+
+ static String Main_Key(int key) {
+ String sound = menu_move_sound;
+
+ switch (key) {
+ case Key.K_ESCAPE :
+ PopMenu();
+ break;
+
+ case Key.K_KP_DOWNARROW :
+ case Key.K_DOWNARROW :
+ if (++m_main_cursor >= MAIN_ITEMS)
+ m_main_cursor = 0;
+ return sound;
+
+ case Key.K_KP_UPARROW :
+ case Key.K_UPARROW :
+ if (--m_main_cursor < 0)
+ m_main_cursor = MAIN_ITEMS - 1;
+ return sound;
+
+ case Key.K_KP_ENTER :
+ case Key.K_ENTER :
+ m_entersound = true;
+
+ switch (m_main_cursor) {
+ case 0 :
+ Menu_Game_f();
+ break;
+
+ case 1 :
+ Menu_Multiplayer_f();
+ break;
+
+ case 2 :
+ Menu_Options_f();
+ break;
+
+ case 3 :
+ Menu_Video_f();
+ break;
+
+ case 4 :
+ Menu_Quit_f();
+ break;
+ }
+ }
+
+ return null;
+ }
+
+ static xcommand_t Menu_Main = new xcommand_t() {
+ public void execute() {
+ Menu_Main_f();
+ }
+ };
+
+ static void Menu_Main_f() {
+ PushMenu(new xcommand_t() {
+ public void execute() {
+ Main_Draw();
+ }
+ }, new keyfunc_t() {
+ public String execute(int key) {
+ return Main_Key(key);
+ }
+ });
+ }
+
+ /*
+ =======================================================================
+
+ MULTIPLAYER MENU
+
+ =======================================================================
+ */
+ static menuframework_s s_multiplayer_menu = new menuframework_s();
+ static menuaction_s s_join_network_server_action = new menuaction_s();
+ static menuaction_s s_start_network_server_action = new menuaction_s();
+ static menuaction_s s_player_setup_action = new menuaction_s();
+
+ static void Multiplayer_MenuDraw() {
+ Banner("m_banner_multiplayer");
+
+ Menu_AdjustCursor(s_multiplayer_menu, 1);
+ Menu_Draw(s_multiplayer_menu);
+ }
+
+ static void PlayerSetupFunc(Object unused) {
+ Menu_PlayerConfig_f();
+ }
+
+ static void JoinNetworkServerFunc(Object unused) {
+ Menu_JoinServer_f();
+ }
+
+ static void StartNetworkServerFunc(Object unused) {
+ Menu_StartServer_f();
+ }
+
+ static void Multiplayer_MenuInit() {
+ s_multiplayer_menu.x = (int) (viddef.width * 0.50f - 64);
+ s_multiplayer_menu.nitems = 0;
+
+ s_join_network_server_action.type = MTYPE_ACTION;
+ s_join_network_server_action.flags = QMF_LEFT_JUSTIFY;
+ s_join_network_server_action.x = 0;
+ s_join_network_server_action.y = 0;
+ s_join_network_server_action.name = " join network server";
+ s_join_network_server_action.callback = new mcallback() {
+ public void execute(Object o) {
+ JoinNetworkServerFunc(o);
+ };
+ };
+
+ s_start_network_server_action.type = MTYPE_ACTION;
+ s_start_network_server_action.flags = QMF_LEFT_JUSTIFY;
+ s_start_network_server_action.x = 0;
+ s_start_network_server_action.y = 10;
+ s_start_network_server_action.name = " start network server";
+ s_start_network_server_action.callback = new mcallback() {
+ public void execute(Object o) {
+ StartNetworkServerFunc(o);
+ }
+ };
+
+ s_player_setup_action.type = MTYPE_ACTION;
+ s_player_setup_action.flags = QMF_LEFT_JUSTIFY;
+ s_player_setup_action.x = 0;
+ s_player_setup_action.y = 20;
+ s_player_setup_action.name = " player setup";
+ s_player_setup_action.callback = new mcallback() {
+ public void execute(Object o) {
+ PlayerSetupFunc(o);
+ }
+ };
+
+ Menu_AddItem(s_multiplayer_menu, s_join_network_server_action);
+ Menu_AddItem(s_multiplayer_menu, s_start_network_server_action);
+ Menu_AddItem(s_multiplayer_menu, s_player_setup_action);
+
+ Menu_SetStatusBar(s_multiplayer_menu, null);
+
+ Menu_Center(s_multiplayer_menu);
+ }
+
+ static String Multiplayer_MenuKey(int key) {
+ return Default_MenuKey(s_multiplayer_menu, key);
+ }
+
+ static xcommand_t Menu_Multiplayer = new xcommand_t() {
+ public void execute() {
+ Menu_Multiplayer_f();
+ }
+ };
+
+ static void Menu_Multiplayer_f() {
+ Multiplayer_MenuInit();
+ PushMenu(new xcommand_t() {
+ public void execute() {
+ Multiplayer_MenuDraw();
+ }
+ }, new keyfunc_t() {
+ public String execute(int key) {
+ return Multiplayer_MenuKey(key);
+ }
+ });
+ }
+
+ /*
+ =======================================================================
+
+ KEYS MENU
+
+ =======================================================================
+ */
+ static String bindnames[][] = { { "+attack", "attack" }, {
+ "weapnext", "next weapon" }, {
+ "+forward", "walk forward" }, {
+ "+back", "backpedal" }, {
+ "+left", "turn left" }, {
+ "+right", "turn right" }, {
+ "+speed", "run" }, {
+ "+moveleft", "step left" }, {
+ "+moveright", "step right" }, {
+ "+strafe", "sidestep" }, {
+ "+lookup", "look up" }, {
+ "+lookdown", "look down" }, {
+ "centerview", "center view" }, {
+ "+mlook", "mouse look" }, {
+ "+klook", "keyboard look" }, {
+ "+moveup", "up / jump" }, {
+ "+movedown", "down / crouch" }, {
+
+ "inven", "inventory" }, {
+ "invuse", "use item" }, {
+ "invdrop", "drop item" }, {
+ "invprev", "prev item" }, {
+ "invnext", "next item" }, {
+
+ "cmd help", "help computer" }, {
+ null, null }
+ };
+
+ int keys_cursor;
+ static boolean bind_grab;
+
+ static menuframework_s s_keys_menu = new menuframework_s();
+ static menuaction_s s_keys_attack_action = new menuaction_s();
+ static menuaction_s s_keys_change_weapon_action = new menuaction_s();
+ static menuaction_s s_keys_walk_forward_action = new menuaction_s();
+ static menuaction_s s_keys_backpedal_action = new menuaction_s();
+ static menuaction_s s_keys_turn_left_action = new menuaction_s();
+ static menuaction_s s_keys_turn_right_action = new menuaction_s();
+ static menuaction_s s_keys_run_action = new menuaction_s();
+ static menuaction_s s_keys_step_left_action = new menuaction_s();
+ static menuaction_s s_keys_step_right_action = new menuaction_s();
+ static menuaction_s s_keys_sidestep_action = new menuaction_s();
+ static menuaction_s s_keys_look_up_action = new menuaction_s();
+ static menuaction_s s_keys_look_down_action = new menuaction_s();
+ static menuaction_s s_keys_center_view_action = new menuaction_s();
+ static menuaction_s s_keys_mouse_look_action = new menuaction_s();
+ static menuaction_s s_keys_keyboard_look_action = new menuaction_s();
+ static menuaction_s s_keys_move_up_action = new menuaction_s();
+ static menuaction_s s_keys_move_down_action = new menuaction_s();
+ static menuaction_s s_keys_inventory_action = new menuaction_s();
+ static menuaction_s s_keys_inv_use_action = new menuaction_s();
+ static menuaction_s s_keys_inv_drop_action = new menuaction_s();
+ static menuaction_s s_keys_inv_prev_action = new menuaction_s();
+ static menuaction_s s_keys_inv_next_action = new menuaction_s();
+
+ static menuaction_s s_keys_help_computer_action = new menuaction_s();
+
+ static void UnbindCommand(String command) {
+ int j;
+ int l;
+ String b;
+
+ for (j = 0; j < 256; j++) {
+ b = keybindings[j];
+ if (b == null)
+ continue;
+ if (b.equals(command))
+ Key.SetBinding(j, "");
+ }
+ }
+
+ static void FindKeysForCommand(String command, int twokeys[]) {
+ int count;
+ int j;
+ int l;
+ String b;
+
+ twokeys[0] = twokeys[1] = -1;
+ count = 0;
+
+ for (j = 0; j < 256; j++) {
+ b = keybindings[j];
+ if (b == null)
+ continue;
+
+ if (b.equals(command)) {
+ twokeys[count] = j;
+ count++;
+ if (count == 2)
+ break;
+ }
+ }
+ }
+
+ static void KeyCursorDrawFunc(menuframework_s menu) {
+ if (bind_grab)
+ re.DrawChar(menu.x, menu.y + menu.cursor * 9, '=');
+ else
+ re.DrawChar(menu.x, menu.y + menu.cursor * 9, 12 + ((int) (Sys.Milliseconds() / 250) & 1));
+ }
+
+ static void DrawKeyBindingFunc(Object self) {
+ int keys[] = { 0, 0 };
+ menuaction_s a = (menuaction_s) self;
+
+ FindKeysForCommand(bindnames[a.localdata[0]][0], keys);
+
+ if (keys[0] == -1) {
+ Menu_DrawString(a.x + a.parent.x + 16, a.y + a.parent.y, "???");
+ }
+ else {
+ int x;
+ String name;
+
+ name = Key.KeynumToString(keys[0]);
+
+ Menu_DrawString(a.x + a.parent.x + 16, a.y + a.parent.y, name);
+
+ x = strlen(name) * 8;
+
+ if (keys[1] != -1) {
+ Menu_DrawString(a.x + a.parent.x + 24 + x, a.y + a.parent.y, "or");
+ Menu_DrawString(a.x + a.parent.x + 48 + x, a.y + a.parent.y, Key.KeynumToString(keys[1]));
+ }
+ }
+ }
+
+ static void KeyBindingFunc(Object self) {
+ menuaction_s a = (menuaction_s) self;
+ int keys[] = { 0, 0 };
+
+ FindKeysForCommand(bindnames[a.localdata[0]][0], keys);
+
+ if (keys[1] != -1)
+ UnbindCommand(bindnames[a.localdata[0]][0]);
+
+ bind_grab = true;
+
+ Menu_SetStatusBar(s_keys_menu, "press a key or button for this action");
+ }
+
+ static void Keys_MenuInit() {
+ int y = 0;
+ int i = 0;
+
+ s_keys_menu.x = (int) (viddef.width * 0.50);
+ s_keys_menu.nitems = 0;
+ s_keys_menu.cursordraw = new mcallback() {
+ public void execute(Object o) {
+ KeyCursorDrawFunc((menuframework_s) o);
+ }
+ };
+
+ s_keys_attack_action.type = MTYPE_ACTION;
+ s_keys_attack_action.flags = QMF_GRAYED;
+ s_keys_attack_action.x = 0;
+ s_keys_attack_action.y = y;
+ s_keys_attack_action.ownerdraw = new mcallback() {
+ public void execute(Object o) {
+ DrawKeyBindingFunc(o);
+ }
+ };
+ s_keys_attack_action.localdata[0] = i;
+ s_keys_attack_action.name = bindnames[s_keys_attack_action.localdata[0]][1];
+
+ s_keys_change_weapon_action.type = MTYPE_ACTION;
+ s_keys_change_weapon_action.flags = QMF_GRAYED;
+ s_keys_change_weapon_action.x = 0;
+ s_keys_change_weapon_action.y = y += 9;
+ s_keys_change_weapon_action.ownerdraw = new mcallback() {
+ public void execute(Object o) {
+ DrawKeyBindingFunc(o);
+ }
+ };
+
+ s_keys_change_weapon_action.localdata[0] = ++i;
+ s_keys_change_weapon_action.name = bindnames[s_keys_change_weapon_action.localdata[0]][1];
+
+ s_keys_walk_forward_action.type = MTYPE_ACTION;
+ s_keys_walk_forward_action.flags = QMF_GRAYED;
+ s_keys_walk_forward_action.x = 0;
+ s_keys_walk_forward_action.y = y += 9;
+ s_keys_walk_forward_action.ownerdraw = new mcallback() {
+ public void execute(Object o) {
+ DrawKeyBindingFunc(o);
+ }
+ };
+ s_keys_walk_forward_action.localdata[0] = ++i;
+ s_keys_walk_forward_action.name = bindnames[s_keys_walk_forward_action.localdata[0]][1];
+
+ s_keys_backpedal_action.type = MTYPE_ACTION;
+ s_keys_backpedal_action.flags = QMF_GRAYED;
+ s_keys_backpedal_action.x = 0;
+ s_keys_backpedal_action.y = y += 9;
+ s_keys_backpedal_action.ownerdraw = new mcallback() {
+ public void execute(Object o) {
+ DrawKeyBindingFunc(o);
+ }
+ };
+ s_keys_backpedal_action.localdata[0] = ++i;
+ s_keys_backpedal_action.name = bindnames[s_keys_backpedal_action.localdata[0]][1];
+
+ s_keys_turn_left_action.type = MTYPE_ACTION;
+ s_keys_turn_left_action.flags = QMF_GRAYED;
+ s_keys_turn_left_action.x = 0;
+ s_keys_turn_left_action.y = y += 9;
+ s_keys_turn_left_action.ownerdraw = new mcallback() {
+ public void execute(Object o) {
+ DrawKeyBindingFunc(o);
+ }
+ };
+ s_keys_turn_left_action.localdata[0] = ++i;
+ s_keys_turn_left_action.name = bindnames[s_keys_turn_left_action.localdata[0]][1];
+
+ s_keys_turn_right_action.type = MTYPE_ACTION;
+ s_keys_turn_right_action.flags = QMF_GRAYED;
+ s_keys_turn_right_action.x = 0;
+ s_keys_turn_right_action.y = y += 9;
+ s_keys_turn_right_action.ownerdraw = new mcallback() {
+ public void execute(Object o) {
+ DrawKeyBindingFunc(o);
+ }
+ };
+ s_keys_turn_right_action.localdata[0] = ++i;
+ s_keys_turn_right_action.name = bindnames[s_keys_turn_right_action.localdata[0]][1];
+
+ s_keys_run_action.type = MTYPE_ACTION;
+ s_keys_run_action.flags = QMF_GRAYED;
+ s_keys_run_action.x = 0;
+ s_keys_run_action.y = y += 9;
+ s_keys_run_action.ownerdraw = new mcallback() {
+ public void execute(Object o) {
+ DrawKeyBindingFunc(o);
+ }
+ };
+ s_keys_run_action.localdata[0] = ++i;
+ s_keys_run_action.name = bindnames[s_keys_run_action.localdata[0]][1];
+
+ s_keys_step_left_action.type = MTYPE_ACTION;
+ s_keys_step_left_action.flags = QMF_GRAYED;
+ s_keys_step_left_action.x = 0;
+ s_keys_step_left_action.y = y += 9;
+ s_keys_step_left_action.ownerdraw = new mcallback() {
+ public void execute(Object o) {
+ DrawKeyBindingFunc(o);
+ }
+ };
+ s_keys_step_left_action.localdata[0] = ++i;
+ s_keys_step_left_action.name = bindnames[s_keys_step_left_action.localdata[0]][1];
+
+ s_keys_step_right_action.type = MTYPE_ACTION;
+ s_keys_step_right_action.flags = QMF_GRAYED;
+ s_keys_step_right_action.x = 0;
+ s_keys_step_right_action.y = y += 9;
+ s_keys_step_right_action.ownerdraw = new mcallback() {
+ public void execute(Object o) {
+ DrawKeyBindingFunc(o);
+ }
+ };
+
+ s_keys_step_right_action.localdata[0] = ++i;
+ s_keys_step_right_action.name = bindnames[s_keys_step_right_action.localdata[0]][1];
+
+ s_keys_sidestep_action.type = MTYPE_ACTION;
+ s_keys_sidestep_action.flags = QMF_GRAYED;
+ s_keys_sidestep_action.x = 0;
+ s_keys_sidestep_action.y = y += 9;
+ s_keys_sidestep_action.ownerdraw = new mcallback() {
+ public void execute(Object o) {
+ DrawKeyBindingFunc(o);
+ }
+ };
+
+ s_keys_sidestep_action.localdata[0] = ++i;
+ s_keys_sidestep_action.name = bindnames[s_keys_sidestep_action.localdata[0]][1];
+
+ s_keys_look_up_action.type = MTYPE_ACTION;
+ s_keys_look_up_action.flags = QMF_GRAYED;
+ s_keys_look_up_action.x = 0;
+ s_keys_look_up_action.y = y += 9;
+ s_keys_look_up_action.ownerdraw = new mcallback() {
+ public void execute(Object o) {
+ DrawKeyBindingFunc(o);
+ }
+ };
+
+ s_keys_look_up_action.localdata[0] = ++i;
+ s_keys_look_up_action.name = bindnames[s_keys_look_up_action.localdata[0]][1];
+
+ s_keys_look_down_action.type = MTYPE_ACTION;
+ s_keys_look_down_action.flags = QMF_GRAYED;
+ s_keys_look_down_action.x = 0;
+ s_keys_look_down_action.y = y += 9;
+ s_keys_look_down_action.ownerdraw = new mcallback() {
+ public void execute(Object o) {
+ DrawKeyBindingFunc(o);
+ }
+ };
+
+ s_keys_look_down_action.localdata[0] = ++i;
+ s_keys_look_down_action.name = bindnames[s_keys_look_down_action.localdata[0]][1];
+
+ s_keys_center_view_action.type = MTYPE_ACTION;
+ s_keys_center_view_action.flags = QMF_GRAYED;
+ s_keys_center_view_action.x = 0;
+ s_keys_center_view_action.y = y += 9;
+ s_keys_center_view_action.ownerdraw = new mcallback() {
+ public void execute(Object o) {
+ DrawKeyBindingFunc(o);
+ }
+ };
+
+ s_keys_center_view_action.localdata[0] = ++i;
+ s_keys_center_view_action.name = bindnames[s_keys_center_view_action.localdata[0]][1];
+
+ s_keys_mouse_look_action.type = MTYPE_ACTION;
+ s_keys_mouse_look_action.flags = QMF_GRAYED;
+ s_keys_mouse_look_action.x = 0;
+ s_keys_mouse_look_action.y = y += 9;
+ s_keys_mouse_look_action.ownerdraw = new mcallback() {
+ public void execute(Object o) {
+ DrawKeyBindingFunc(o);
+ }
+ };
+
+ s_keys_mouse_look_action.localdata[0] = ++i;
+ s_keys_mouse_look_action.name = bindnames[s_keys_mouse_look_action.localdata[0]][1];
+
+ s_keys_keyboard_look_action.type = MTYPE_ACTION;
+ s_keys_keyboard_look_action.flags = QMF_GRAYED;
+ s_keys_keyboard_look_action.x = 0;
+ s_keys_keyboard_look_action.y = y += 9;
+ s_keys_keyboard_look_action.ownerdraw = new mcallback() {
+ public void execute(Object o) {
+ DrawKeyBindingFunc(o);
+ }
+ };
+
+ s_keys_keyboard_look_action.localdata[0] = ++i;
+ s_keys_keyboard_look_action.name = bindnames[s_keys_keyboard_look_action.localdata[0]][1];
+
+ s_keys_move_up_action.type = MTYPE_ACTION;
+ s_keys_move_up_action.flags = QMF_GRAYED;
+ s_keys_move_up_action.x = 0;
+ s_keys_move_up_action.y = y += 9;
+ s_keys_move_up_action.ownerdraw = new mcallback() {
+ public void execute(Object o) {
+ DrawKeyBindingFunc(o);
+ }
+ };
+
+ s_keys_move_up_action.localdata[0] = ++i;
+ s_keys_move_up_action.name = bindnames[s_keys_move_up_action.localdata[0]][1];
+
+ s_keys_move_down_action.type = MTYPE_ACTION;
+ s_keys_move_down_action.flags = QMF_GRAYED;
+ s_keys_move_down_action.x = 0;
+ s_keys_move_down_action.y = y += 9;
+ s_keys_move_down_action.ownerdraw = new mcallback() {
+ public void execute(Object o) {
+ DrawKeyBindingFunc(o);
+ }
+ };
+
+ s_keys_move_down_action.localdata[0] = ++i;
+ s_keys_move_down_action.name = bindnames[s_keys_move_down_action.localdata[0]][1];
+
+ s_keys_inventory_action.type = MTYPE_ACTION;
+ s_keys_inventory_action.flags = QMF_GRAYED;
+ s_keys_inventory_action.x = 0;
+ s_keys_inventory_action.y = y += 9;
+ s_keys_inventory_action.ownerdraw = new mcallback() {
+ public void execute(Object o) {
+ DrawKeyBindingFunc(o);
+ }
+ };
+
+ s_keys_inventory_action.localdata[0] = ++i;
+ s_keys_inventory_action.name = bindnames[s_keys_inventory_action.localdata[0]][1];
+
+ s_keys_inv_use_action.type = MTYPE_ACTION;
+ s_keys_inv_use_action.flags = QMF_GRAYED;
+ s_keys_inv_use_action.x = 0;
+ s_keys_inv_use_action.y = y += 9;
+ s_keys_inv_use_action.ownerdraw = new mcallback() {
+ public void execute(Object o) {
+ DrawKeyBindingFunc(o);
+ }
+ };
+
+ s_keys_inv_use_action.localdata[0] = ++i;
+ s_keys_inv_use_action.name = bindnames[s_keys_inv_use_action.localdata[0]][1];
+
+ s_keys_inv_drop_action.type = MTYPE_ACTION;
+ s_keys_inv_drop_action.flags = QMF_GRAYED;
+ s_keys_inv_drop_action.x = 0;
+ s_keys_inv_drop_action.y = y += 9;
+ s_keys_inv_drop_action.ownerdraw = new mcallback() {
+ public void execute(Object o) {
+ DrawKeyBindingFunc(o);
+ }
+ };
+
+ s_keys_inv_drop_action.localdata[0] = ++i;
+ s_keys_inv_drop_action.name = bindnames[s_keys_inv_drop_action.localdata[0]][1];
+
+ s_keys_inv_prev_action.type = MTYPE_ACTION;
+ s_keys_inv_prev_action.flags = QMF_GRAYED;
+ s_keys_inv_prev_action.x = 0;
+ s_keys_inv_prev_action.y = y += 9;
+ s_keys_inv_prev_action.ownerdraw = new mcallback() {
+ public void execute(Object o) {
+ DrawKeyBindingFunc(o);
+ }
+ };
+
+ s_keys_inv_prev_action.localdata[0] = ++i;
+ s_keys_inv_prev_action.name = bindnames[s_keys_inv_prev_action.localdata[0]][1];
+
+ s_keys_inv_next_action.type = MTYPE_ACTION;
+ s_keys_inv_next_action.flags = QMF_GRAYED;
+ s_keys_inv_next_action.x = 0;
+ s_keys_inv_next_action.y = y += 9;
+ s_keys_inv_next_action.ownerdraw = new mcallback() {
+ public void execute(Object o) {
+ DrawKeyBindingFunc(o);
+ }
+ };
+
+ s_keys_inv_next_action.localdata[0] = ++i;
+ s_keys_inv_next_action.name = bindnames[s_keys_inv_next_action.localdata[0]][1];
+
+ s_keys_help_computer_action.type = MTYPE_ACTION;
+ s_keys_help_computer_action.flags = QMF_GRAYED;
+ s_keys_help_computer_action.x = 0;
+ s_keys_help_computer_action.y = y += 9;
+ s_keys_help_computer_action.ownerdraw = new mcallback() {
+ public void execute(Object o) {
+ DrawKeyBindingFunc(o);
+ }
+ };
+
+ s_keys_help_computer_action.localdata[0] = ++i;
+ s_keys_help_computer_action.name = bindnames[s_keys_help_computer_action.localdata[0]][1];
+
+ Menu_AddItem(s_keys_menu, s_keys_attack_action);
+ Menu_AddItem(s_keys_menu, s_keys_change_weapon_action);
+ Menu_AddItem(s_keys_menu, s_keys_walk_forward_action);
+ Menu_AddItem(s_keys_menu, s_keys_backpedal_action);
+ Menu_AddItem(s_keys_menu, s_keys_turn_left_action);
+ Menu_AddItem(s_keys_menu, s_keys_turn_right_action);
+ Menu_AddItem(s_keys_menu, s_keys_run_action);
+ Menu_AddItem(s_keys_menu, s_keys_step_left_action);
+ Menu_AddItem(s_keys_menu, s_keys_step_right_action);
+ Menu_AddItem(s_keys_menu, s_keys_sidestep_action);
+ Menu_AddItem(s_keys_menu, s_keys_look_up_action);
+ Menu_AddItem(s_keys_menu, s_keys_look_down_action);
+ Menu_AddItem(s_keys_menu, s_keys_center_view_action);
+ Menu_AddItem(s_keys_menu, s_keys_mouse_look_action);
+ Menu_AddItem(s_keys_menu, s_keys_keyboard_look_action);
+ Menu_AddItem(s_keys_menu, s_keys_move_up_action);
+ Menu_AddItem(s_keys_menu, s_keys_move_down_action);
+
+ Menu_AddItem(s_keys_menu, s_keys_inventory_action);
+ Menu_AddItem(s_keys_menu, s_keys_inv_use_action);
+ Menu_AddItem(s_keys_menu, s_keys_inv_drop_action);
+ Menu_AddItem(s_keys_menu, s_keys_inv_prev_action);
+ Menu_AddItem(s_keys_menu, s_keys_inv_next_action);
+
+ Menu_AddItem(s_keys_menu, s_keys_help_computer_action);
+
+ Menu_SetStatusBar(s_keys_menu, "enter to change, backspace to clear");
+ Menu_Center(s_keys_menu);
+ }
+
+ static xcommand_t Keys_MenuDraw = new xcommand_t() {
+ public void execute() {
+ Keys_MenuDraw_f();
+ }
+ };
+
+ static void Keys_MenuDraw_f() {
+ Menu_AdjustCursor(s_keys_menu, 1);
+ Menu_Draw(s_keys_menu);
+ }
+
+ static keyfunc_t Keys_MenuKey = new keyfunc_t() {
+ public String execute(int key) {
+ return Keys_MenuKey_f(key);
+ }
+ };
+ static String Keys_MenuKey_f(int key) {
+ menuaction_s item = (menuaction_s) Menu_ItemAtCursor(s_keys_menu);
+
+ if (bind_grab) {
+ if (key != K_ESCAPE && key != '`') {
+ //char cmd[1024];
+ String cmd;
+
+ //Com_sprintf(cmd, sizeof(cmd), "bind \"%s\" \"%s\"\n", Key_KeynumToString(key), bindnames[item.localdata[0]][0]);
+ cmd = "bind \"" + Key.KeynumToString(key) + "\" \"" + bindnames[item.localdata[0]][0] + "\"";
+ Cbuf.InsertText(cmd);
+ }
+
+ Menu_SetStatusBar(s_keys_menu, "enter to change, backspace to clear");
+ bind_grab = false;
+ return menu_out_sound;
+ }
+
+ switch (key) {
+ case K_KP_ENTER :
+ case K_ENTER :
+ KeyBindingFunc(item);
+ return menu_in_sound;
+ case K_BACKSPACE : // delete bindings
+ case K_DEL : // delete bindings
+ case K_KP_DEL :
+ UnbindCommand(bindnames[item.localdata[0]][0]);
+ return menu_out_sound;
+ default :
+ return Default_MenuKey(s_keys_menu, key);
+ }
+ }
+
+ static xcommand_t Menu_Keys = new xcommand_t() {
+ public void execute() {
+ Menu_Keys_f();
+ }
+ };
+ static void Menu_Keys_f() {
+ Keys_MenuInit();
+ PushMenu(new xcommand_t() {
+ public void execute() {
+ Keys_MenuDraw_f();
+ }
+ }, new keyfunc_t() {
+ public String execute(int key) {
+ return Keys_MenuKey_f(key);
+ }
+ });
+ }
+
+ /*
+ =======================================================================
+
+ CONTROLS MENU
+
+ =======================================================================
+ */
+ static cvar_t win_noalttab;
+
+ static menuframework_s s_options_menu = new menuframework_s();
+ static menuaction_s s_options_defaults_action = new menuaction_s();
+ static menuaction_s s_options_customize_options_action = new menuaction_s();
+ static menuslider_s s_options_sensitivity_slider = new menuslider_s();
+ static menulist_s s_options_freelook_box = new menulist_s();
+ static menulist_s s_options_noalttab_box = new menulist_s();
+ static menulist_s s_options_alwaysrun_box = new menulist_s();
+ static menulist_s s_options_invertmouse_box = new menulist_s();
+ static menulist_s s_options_lookspring_box = new menulist_s();
+ static menulist_s s_options_lookstrafe_box = new menulist_s();
+ static menulist_s s_options_crosshair_box = new menulist_s();
+ static menuslider_s s_options_sfxvolume_slider = new menuslider_s();
+ static menulist_s s_options_joystick_box = new menulist_s();
+ static menulist_s s_options_cdvolume_box = new menulist_s();
+ static menulist_s s_options_quality_list = new menulist_s();
+ static menulist_s s_options_compatibility_list = new menulist_s();
+ static menuaction_s s_options_console_action = new menuaction_s();
+
+ static void CrosshairFunc(Object unused) {
+ Cvar.SetValue("crosshair", s_options_crosshair_box.curvalue);
+ }
+
+ static void JoystickFunc(Object unused) {
+ Cvar.SetValue("in_joystick", s_options_joystick_box.curvalue);
+ }
+
+ static void CustomizeControlsFunc(Object unused) {
+ Menu_Keys_f();
+ }
+
+ static void AlwaysRunFunc(Object unused) {
+ Cvar.SetValue("cl_run", s_options_alwaysrun_box.curvalue);
+ }
+
+ static void FreeLookFunc(Object unused) {
+ Cvar.SetValue("freelook", s_options_freelook_box.curvalue);
+ }
+
+ static void MouseSpeedFunc(Object unused) {
+ Cvar.SetValue("sensitivity", s_options_sensitivity_slider.curvalue / 2.0F);
+ }
+
+ static void NoAltTabFunc(Object unused) {
+ Cvar.SetValue("win_noalttab", s_options_noalttab_box.curvalue);
+ }
+
+ static float ClampCvar(float min, float max, float value) {
+ if (value < min)
+ return min;
+ if (value > max)
+ return max;
+ return value;
+ }
+
+ static void ControlsSetMenuItemValues() {
+ s_options_sfxvolume_slider.curvalue = Cvar.VariableValue("s_volume") * 10;
+ s_options_cdvolume_box.curvalue = 1 - ((int) Cvar.VariableValue("cd_nocd"));
+ s_options_quality_list.curvalue = 1 - ((int) Cvar.VariableValue("s_loadas8bit"));
+ s_options_sensitivity_slider.curvalue = (sensitivity.value) * 2;
+
+ Cvar.SetValue("cl_run", ClampCvar(0, 1, cl_run.value));
+ s_options_alwaysrun_box.curvalue = (int) cl_run.value;
+
+ s_options_invertmouse_box.curvalue = m_pitch.value < 0 ? 1 : 0;
+
+ Cvar.SetValue("lookspring", ClampCvar(0, 1, lookspring.value));
+ s_options_lookspring_box.curvalue = (int) lookspring.value;
+
+ Cvar.SetValue("lookstrafe", ClampCvar(0, 1, lookstrafe.value));
+ s_options_lookstrafe_box.curvalue = (int) lookstrafe.value;
+
+ Cvar.SetValue("freelook", ClampCvar(0, 1, freelook.value));
+ s_options_freelook_box.curvalue = (int) freelook.value;
+
+ Cvar.SetValue("crosshair", ClampCvar(0, 3, Globals.crosshair.value));
+ s_options_crosshair_box.curvalue = (int) Globals.crosshair.value;
+
+ Cvar.SetValue("in_joystick", ClampCvar(0, 1, in_joystick.value));
+ s_options_joystick_box.curvalue = (int) in_joystick.value;
+
+ s_options_noalttab_box.curvalue = (int) win_noalttab.value;
+ }
+
+ static void ControlsResetDefaultsFunc(Object unused) {
+ Cbuf.AddText("exec default.cfg\n");
+ Cbuf.Execute();
+
+ ControlsSetMenuItemValues();
+ }
+
+ static void InvertMouseFunc(Object unused) {
+ Cvar.SetValue("m_pitch", -m_pitch.value);
+ }
+
+ static void LookspringFunc(Object unused) {
+ Cvar.SetValue("lookspring", 1 - lookspring.value);
+ }
+
+ static void LookstrafeFunc(Object unused) {
+ Cvar.SetValue("lookstrafe", 1 - lookstrafe.value);
+ }
+
+ static void UpdateVolumeFunc(Object unused) {
+ Cvar.SetValue("s_volume", s_options_sfxvolume_slider.curvalue / 10);
+ }
+
+ static void UpdateCDVolumeFunc(Object unused) {
+ Cvar.SetValue("cd_nocd", 1 - s_options_cdvolume_box.curvalue);
+ }
+
+ static void ConsoleFunc(Object unused) {
+ /*
+ ** the proper way to do this is probably to have ToggleConsole_f accept a parameter
+ */
+
+ if (cl.attractloop) {
+ Cbuf.AddText("killserver\n");
+ return;
+ }
+
+ Key.ClearTyping();
+ Console.ClearNotify();
+
+ ForceMenuOff();
+ cls.key_dest = key_console;
+ }
+
+ static void UpdateSoundQualityFunc(Object unused) {
+ if (s_options_quality_list.curvalue != 0) {
+ Cvar.SetValue("s_khz", 22);
+ Cvar.SetValue("s_loadas8bit", 0);
+ }
+ else {
+ Cvar.SetValue("s_khz", 11);
+ Cvar.SetValue("s_loadas8bit", 1);
+ }
+
+ Cvar.SetValue("s_primary", s_options_compatibility_list.curvalue);
+
+ DrawTextBox(8, 120 - 48, 36, 3);
+ Print(16 + 16, 120 - 48 + 8, "Restarting the sound system. This");
+ Print(16 + 16, 120 - 48 + 16, "could take up to a minute, so");
+ Print(16 + 16, 120 - 48 + 24, "please be patient.");
+
+ // the text box won't show up unless we do a buffer swap
+ re.EndFrame();
+
+ CL.Snd_Restart_f.execute();
+ }
+
+ static String cd_music_items[] = { "disabled", "enabled", null };
+ static String quality_items[] = { "low", "high", null };
+
+ static String compatibility_items[] = { "max compatibility", "max performance", null };
+
+ static String yesno_names[] = { "no", "yes", null };
+
+ static String crosshair_names[] = { "none", "cross", "dot", "angle", null };
+
+ static void Options_MenuInit() {
+
+ win_noalttab = Cvar.Get("win_noalttab", "0", CVAR_ARCHIVE);
+
+ /*
+ ** configure controls menu and menu items
+ */
+ s_options_menu.x = viddef.width / 2;
+ s_options_menu.y = viddef.height / 2 - 58;
+ s_options_menu.nitems = 0;
+
+ s_options_sfxvolume_slider.type = MTYPE_SLIDER;
+ s_options_sfxvolume_slider.x = 0;
+ s_options_sfxvolume_slider.y = 0;
+ s_options_sfxvolume_slider.name = "effects volume";
+ s_options_sfxvolume_slider.callback = new mcallback() {
+ public void execute(Object o) {
+ UpdateVolumeFunc(o);
+ }
+ };
+ s_options_sfxvolume_slider.minvalue = 0;
+ s_options_sfxvolume_slider.maxvalue = 10;
+ s_options_sfxvolume_slider.curvalue = Cvar.VariableValue("s_volume") * 10;
+
+ s_options_cdvolume_box.type = MTYPE_SPINCONTROL;
+ s_options_cdvolume_box.x = 0;
+ s_options_cdvolume_box.y = 10;
+ s_options_cdvolume_box.name = "CD music";
+ s_options_cdvolume_box.callback = new mcallback() {
+ public void execute(Object o) {
+ UpdateCDVolumeFunc(o);
+ }
+ };
+ s_options_cdvolume_box.itemnames = cd_music_items;
+ s_options_cdvolume_box.curvalue = 1 - (int) Cvar.VariableValue("cd_nocd");
+
+ s_options_quality_list.type = MTYPE_SPINCONTROL;
+ s_options_quality_list.x = 0;
+ s_options_quality_list.y = 20;
+ ;
+ s_options_quality_list.name = "sound quality";
+ s_options_quality_list.callback = new mcallback() {
+ public void execute(Object o) {
+ UpdateSoundQualityFunc(o);
+ }
+ };
+ s_options_quality_list.itemnames = quality_items;
+ s_options_quality_list.curvalue = 1 - (int) Cvar.VariableValue("s_loadas8bit");
+
+ s_options_compatibility_list.type = MTYPE_SPINCONTROL;
+ s_options_compatibility_list.x = 0;
+ s_options_compatibility_list.y = 30;
+ s_options_compatibility_list.name = "sound compatibility";
+ s_options_compatibility_list.callback = new mcallback() {
+ public void execute(Object o) {
+ UpdateSoundQualityFunc(o);
+ }
+ };
+ s_options_compatibility_list.itemnames = compatibility_items;
+ s_options_compatibility_list.curvalue = (int) Cvar.VariableValue("s_primary");
+
+ s_options_sensitivity_slider.type = MTYPE_SLIDER;
+ s_options_sensitivity_slider.x = 0;
+ s_options_sensitivity_slider.y = 50;
+ s_options_sensitivity_slider.name = "mouse speed";
+ s_options_sensitivity_slider.callback = new mcallback() {
+ public void execute(Object o) {
+ MouseSpeedFunc(o);
+ }
+ };
+ s_options_sensitivity_slider.minvalue = 2;
+ s_options_sensitivity_slider.maxvalue = 22;
+
+ s_options_alwaysrun_box.type = MTYPE_SPINCONTROL;
+ s_options_alwaysrun_box.x = 0;
+ s_options_alwaysrun_box.y = 60;
+ s_options_alwaysrun_box.name = "always run";
+ s_options_alwaysrun_box.callback = new mcallback() {
+ public void execute(Object o) {
+ AlwaysRunFunc(o);
+ }
+ };
+ s_options_alwaysrun_box.itemnames = yesno_names;
+
+ s_options_invertmouse_box.type = MTYPE_SPINCONTROL;
+ s_options_invertmouse_box.x = 0;
+ s_options_invertmouse_box.y = 70;
+ s_options_invertmouse_box.name = "invert mouse";
+ s_options_invertmouse_box.callback = new mcallback() {
+ public void execute(Object o) {
+ InvertMouseFunc(o);
+ }
+ };
+ s_options_invertmouse_box.itemnames = yesno_names;
+
+ s_options_lookspring_box.type = MTYPE_SPINCONTROL;
+ s_options_lookspring_box.x = 0;
+ s_options_lookspring_box.y = 80;
+ s_options_lookspring_box.name = "lookspring";
+ s_options_lookspring_box.callback = new mcallback() {
+ public void execute(Object o) {
+ LookspringFunc(o);
+ }
+ };
+ s_options_lookspring_box.itemnames = yesno_names;
+
+ s_options_lookstrafe_box.type = MTYPE_SPINCONTROL;
+ s_options_lookstrafe_box.x = 0;
+ s_options_lookstrafe_box.y = 90;
+ s_options_lookstrafe_box.name = "lookstrafe";
+ s_options_lookstrafe_box.callback = new mcallback() {
+ public void execute(Object o) {
+ LookstrafeFunc(o);
+ }
+ };
+ s_options_lookstrafe_box.itemnames = yesno_names;
+
+ s_options_freelook_box.type = MTYPE_SPINCONTROL;
+ s_options_freelook_box.x = 0;
+ s_options_freelook_box.y = 100;
+ s_options_freelook_box.name = "free look";
+ s_options_freelook_box.callback = new mcallback() {
+ public void execute(Object o) {
+ FreeLookFunc(o);
+ }
+ };
+ s_options_freelook_box.itemnames = yesno_names;
+
+ s_options_crosshair_box.type = MTYPE_SPINCONTROL;
+ s_options_crosshair_box.x = 0;
+ s_options_crosshair_box.y = 110;
+ s_options_crosshair_box.name = "crosshair";
+ s_options_crosshair_box.callback = new mcallback() {
+ public void execute(Object o) {
+ CrosshairFunc(o);
+ }
+ };
+ s_options_crosshair_box.itemnames = crosshair_names;
+ /*
+ s_options_noalttab_box.type = MTYPE_SPINCONTROL;
+ s_options_noalttab_box.x = 0;
+ s_options_noalttab_box.y = 110;
+ s_options_noalttab_box.name = "disable alt-tab";
+ s_options_noalttab_box.callback = NoAltTabFunc;
+ s_options_noalttab_box.itemnames = yesno_names;
+ */
+ s_options_joystick_box.type = MTYPE_SPINCONTROL;
+ s_options_joystick_box.x = 0;
+ s_options_joystick_box.y = 120;
+ s_options_joystick_box.name = "use joystick";
+ s_options_joystick_box.callback = new mcallback() {
+ public void execute(Object o) {
+ JoystickFunc(o);
+ }
+ };
+ s_options_joystick_box.itemnames = yesno_names;
+
+ s_options_customize_options_action.type = MTYPE_ACTION;
+ s_options_customize_options_action.x = 0;
+ s_options_customize_options_action.y = 140;
+ s_options_customize_options_action.name = "customize controls";
+ s_options_customize_options_action.callback = new mcallback() {
+ public void execute(Object o) {
+ CustomizeControlsFunc(o);
+ }
+ };
+
+ s_options_defaults_action.type = MTYPE_ACTION;
+ s_options_defaults_action.x = 0;
+ s_options_defaults_action.y = 150;
+ s_options_defaults_action.name = "reset defaults";
+ s_options_defaults_action.callback = new mcallback() {
+ public void execute(Object o) {
+ ControlsResetDefaultsFunc(o);
+ }
+ };
+
+ s_options_console_action.type = MTYPE_ACTION;
+ s_options_console_action.x = 0;
+ s_options_console_action.y = 160;
+ s_options_console_action.name = "go to console";
+ s_options_console_action.callback = new mcallback() {
+ public void execute(Object o) {
+ ConsoleFunc(o);
+ }
+ };
+
+ ControlsSetMenuItemValues();
+
+ Menu_AddItem(s_options_menu, s_options_sfxvolume_slider);
+
+ Menu_AddItem(s_options_menu, s_options_cdvolume_box);
+ Menu_AddItem(s_options_menu, s_options_quality_list);
+ Menu_AddItem(s_options_menu, s_options_compatibility_list);
+ Menu_AddItem(s_options_menu, s_options_sensitivity_slider);
+ Menu_AddItem(s_options_menu, s_options_alwaysrun_box);
+ Menu_AddItem(s_options_menu, s_options_invertmouse_box);
+ Menu_AddItem(s_options_menu, s_options_lookspring_box);
+ Menu_AddItem(s_options_menu, s_options_lookstrafe_box);
+ Menu_AddItem(s_options_menu, s_options_freelook_box);
+ Menu_AddItem(s_options_menu, s_options_crosshair_box);
+// Menu_AddItem(s_options_menu, s_options_joystick_box);
+ Menu_AddItem(s_options_menu, s_options_customize_options_action);
+ Menu_AddItem(s_options_menu, s_options_defaults_action);
+ Menu_AddItem(s_options_menu, s_options_console_action);
+ }
+
+ static void Options_MenuDraw() {
+ Banner("m_banner_options");
+ Menu_AdjustCursor(s_options_menu, 1);
+ Menu_Draw(s_options_menu);
+ }
+
+ static String Options_MenuKey(int key) {
+ return Default_MenuKey(s_options_menu, key);
+ }
+
+ static xcommand_t Menu_Options = new xcommand_t() {
+ public void execute() {
+ Menu_Options_f();
+ }
+ };
+
+ static void Menu_Options_f() {
+ Options_MenuInit();
+ PushMenu(new xcommand_t() {
+ public void execute() {
+ Options_MenuDraw();
+ }
+ }, new keyfunc_t() {
+ public String execute(int key) {
+ return Options_MenuKey(key);
+ }
+ });
+ }
+
+ /*
+ =======================================================================
+
+ VIDEO MENU
+
+ =======================================================================
+ */
+
+ static xcommand_t Menu_Video = new xcommand_t() {
+ public void execute() {
+ Menu_Video_f();
+ }
+ };
+
+ static void Menu_Video_f() {
+ VID.MenuInit();
+ PushMenu(new xcommand_t() {
+ public void execute() {
+ VID.MenuDraw();
+ }
+ }, new keyfunc_t() {
+ public String execute(int key) {
+ return VID.MenuKey(key);
+ }
+ });
+ }
+
+ /*
+ =============================================================================
+
+ END GAME MENU
+
+ =============================================================================
+ */
+ static int credits_start_time;
+
+ static String creditsIndex[] = new String[256];
+ static String creditsBuffer;
+ static String idcredits[] =
+ {
+ "+QUAKE II BY ID SOFTWARE",
+ "",
+ "+PROGRAMMING",
+ "John Carmack",
+ "John Cash",
+ "Brian Hook",
+ "",
+ "+JAVA PORT BY JTEAM",
+ "CWEI",
+ "HOZ",
+ "RST",
+ "",
+ "+ART",
+ "Adrian Carmack",
+ "Kevin Cloud",
+ "Paul Steed",
+ "",
+ "+LEVEL DESIGN",
+ "Tim Willits",
+ "American McGee",
+ "Christian Antkow",
+ "Paul Jaquays",
+ "Brandon James",
+ "",
+ "+BIZ",
+ "Todd Hollenshead",
+ "Barrett (Bear) Alexander",
+ "Donna Jackson",
+ "",
+ "",
+ "+SPECIAL THANKS",
+ "Ben Donges for beta testing",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "+ADDITIONAL SUPPORT",
+ "",
+ "+LINUX PORT AND CTF",
+ "Dave \"Zoid\" Kirsch",
+ "",
+ "+CINEMATIC SEQUENCES",
+ "Ending Cinematic by Blur Studio - ",
+ "Venice, CA",
+ "",
+ "Environment models for Introduction",
+ "Cinematic by Karl Dolgener",
+ "",
+ "Assistance with environment design",
+ "by Cliff Iwai",
+ "",
+ "+SOUND EFFECTS AND MUSIC",
+ "Sound Design by Soundelux Media Labs.",
+ "Music Composed and Produced by",
+ "Soundelux Media Labs. Special thanks",
+ "to Bill Brown, Tom Ozanich, Brian",
+ "Celano, Jeff Eisner, and The Soundelux",
+ "Players.",
+ "",
+ "\"Level Music\" by Sonic Mayhem",
+ "www.sonicmayhem.com",
+ "",
+ "\"Quake II Theme Song\"",
+ "(C) 1997 Rob Zombie. All Rights",
+ "Reserved.",
+ "",
+ "Track 10 (\"Climb\") by Jer Sypult",
+ "",
+ "Voice of computers by",
+ "Carly Staehlin-Taylor",
+ "",
+ "+THANKS TO ACTIVISION",
+ "+IN PARTICULAR:",
+ "",
+ "John Tam",
+ "Steve Rosenthal",
+ "Marty Stratton",
+ "Henk Hartong",
+ "",
+ "Quake II(tm) (C)1997 Id Software, Inc.",
+ "All Rights Reserved. Distributed by",
+ "Activision, Inc. under license.",
+ "Quake II(tm), the Id Software name,",
+ "the \"Q II\"(tm) logo and id(tm)",
+ "logo are trademarks of Id Software,",
+ "Inc. Activision(R) is a registered",
+ "trademark of Activision, Inc. All",
+ "other trademarks and trade names are",
+ "properties of their respective owners.",
+ null };
+ static String credits[] = idcredits;
+ static String xatcredits[] =
+ {
+ "+QUAKE II MISSION PACK: THE RECKONING",
+ "+BY",
+ "+XATRIX ENTERTAINMENT, INC.",
+ "",
+ "+DESIGN AND DIRECTION",
+ "Drew Markham",
+ "",
+ "+PRODUCED BY",
+ "Greg Goodrich",
+ "",
+ "+PROGRAMMING",
+ "Rafael Paiz",
+ "",
+ "+LEVEL DESIGN / ADDITIONAL GAME DESIGN",
+ "Alex Mayberry",
+ "",
+ "+LEVEL DESIGN",
+ "Mal Blackwell",
+ "Dan Koppel",
+ "",
+ "+ART DIRECTION",
+ "Michael \"Maxx\" Kaufman",
+ "",
+ "+COMPUTER GRAPHICS SUPERVISOR AND",
+ "+CHARACTER ANIMATION DIRECTION",
+ "Barry Dempsey",
+ "",
+ "+SENIOR ANIMATOR AND MODELER",
+ "Jason Hoover",
+ "",
+ "+CHARACTER ANIMATION AND",
+ "+MOTION CAPTURE SPECIALIST",
+ "Amit Doron",
+ "",
+ "+ART",
+ "Claire Praderie-Markham",
+ "Viktor Antonov",
+ "Corky Lehmkuhl",
+ "",
+ "+INTRODUCTION ANIMATION",
+ "Dominique Drozdz",
+ "",
+ "+ADDITIONAL LEVEL DESIGN",
+ "Aaron Barber",
+ "Rhett Baldwin",
+ "",
+ "+3D CHARACTER ANIMATION TOOLS",
+ "Gerry Tyra, SA Technology",
+ "",
+ "+ADDITIONAL EDITOR TOOL PROGRAMMING",
+ "Robert Duffy",
+ "",
+ "+ADDITIONAL PROGRAMMING",
+ "Ryan Feltrin",
+ "",
+ "+PRODUCTION COORDINATOR",
+ "Victoria Sylvester",
+ "",
+ "+SOUND DESIGN",
+ "Gary Bradfield",
+ "",
+ "+MUSIC BY",
+ "Sonic Mayhem",
+ "",
+ "",
+ "",
+ "+SPECIAL THANKS",
+ "+TO",
+ "+OUR FRIENDS AT ID SOFTWARE",
+ "",
+ "John Carmack",
+ "John Cash",
+ "Brian Hook",
+ "Adrian Carmack",
+ "Kevin Cloud",
+ "Paul Steed",
+ "Tim Willits",
+ "Christian Antkow",
+ "Paul Jaquays",
+ "Brandon James",
+ "Todd Hollenshead",
+ "Barrett (Bear) Alexander",
+ "Dave \"Zoid\" Kirsch",
+ "Donna Jackson",
+ "",
+ "",
+ "",
+ "+THANKS TO ACTIVISION",
+ "+IN PARTICULAR:",
+ "",
+ "Marty Stratton",
+ "Henk \"The Original Ripper\" Hartong",
+ "Kevin Kraff",
+ "Jamey Gottlieb",
+ "Chris Hepburn",
+ "",
+ "+AND THE GAME TESTERS",
+ "",
+ "Tim Vanlaw",
+ "Doug Jacobs",
+ "Steven Rosenthal",
+ "David Baker",
+ "Chris Campbell",
+ "Aaron Casillas",
+ "Steve Elwell",
+ "Derek Johnstone",
+ "Igor Krinitskiy",
+ "Samantha Lee",
+ "Michael Spann",
+ "Chris Toft",
+ "Juan Valdes",
+ "",
+ "+THANKS TO INTERGRAPH COMPUTER SYTEMS",
+ "+IN PARTICULAR:",
+ "",
+ "Michael T. Nicolaou",
+ "",
+ "",
+ "Quake II Mission Pack: The Reckoning",
+ "(tm) (C)1998 Id Software, Inc. All",
+ "Rights Reserved. Developed by Xatrix",
+ "Entertainment, Inc. for Id Software,",
+ "Inc. Distributed by Activision Inc.",
+ "under license. Quake(R) is a",
+ "registered trademark of Id Software,",
+ "Inc. Quake II Mission Pack: The",
+ "Reckoning(tm), Quake II(tm), the Id",
+ "Software name, the \"Q II\"(tm) logo",
+ "and id(tm) logo are trademarks of Id",
+ "Software, Inc. Activision(R) is a",
+ "registered trademark of Activision,",
+ "Inc. Xatrix(R) is a registered",
+ "trademark of Xatrix Entertainment,",
+ "Inc. All other trademarks and trade",
+ "names are properties of their",
+ "respective owners.",
+ null };
+
+ static String roguecredits[] =
+ {
+ "+QUAKE II MISSION PACK 2: GROUND ZERO",
+ "+BY",
+ "+ROGUE ENTERTAINMENT, INC.",
+ "",
+ "+PRODUCED BY",
+ "Jim Molinets",
+ "",
+ "+PROGRAMMING",
+ "Peter Mack",
+ "Patrick Magruder",
+ "",
+ "+LEVEL DESIGN",
+ "Jim Molinets",
+ "Cameron Lamprecht",
+ "Berenger Fish",
+ "Robert Selitto",
+ "Steve Tietze",
+ "Steve Thoms",
+ "",
+ "+ART DIRECTION",
+ "Rich Fleider",
+ "",
+ "+ART",
+ "Rich Fleider",
+ "Steve Maines",
+ "Won Choi",
+ "",
+ "+ANIMATION SEQUENCES",
+ "Creat Studios",
+ "Steve Maines",
+ "",
+ "+ADDITIONAL LEVEL DESIGN",
+ "Rich Fleider",
+ "Steve Maines",
+ "Peter Mack",
+ "",
+ "+SOUND",
+ "James Grunke",
+ "",
+ "+GROUND ZERO THEME",
+ "+AND",
+ "+MUSIC BY",
+ "Sonic Mayhem",
+ "",
+ "+VWEP MODELS",
+ "Brent \"Hentai\" Dill",
+ "",
+ "",
+ "",
+ "+SPECIAL THANKS",
+ "+TO",
+ "+OUR FRIENDS AT ID SOFTWARE",
+ "",
+ "John Carmack",
+ "John Cash",
+ "Brian Hook",
+ "Adrian Carmack",
+ "Kevin Cloud",
+ "Paul Steed",
+ "Tim Willits",
+ "Christian Antkow",
+ "Paul Jaquays",
+ "Brandon James",
+ "Todd Hollenshead",
+ "Barrett (Bear) Alexander",
+ "Katherine Anna Kang",
+ "Donna Jackson",
+ "Dave \"Zoid\" Kirsch",
+ "",
+ "",
+ "",
+ "+THANKS TO ACTIVISION",
+ "+IN PARTICULAR:",
+ "",
+ "Marty Stratton",
+ "Henk Hartong",
+ "Mitch Lasky",
+ "Steve Rosenthal",
+ "Steve Elwell",
+ "",
+ "+AND THE GAME TESTERS",
+ "",
+ "The Ranger Clan",
+ "Dave \"Zoid\" Kirsch",
+ "Nihilistic Software",
+ "Robert Duffy",
+ "",
+ "And Countless Others",
+ "",
+ "",
+ "",
+ "Quake II Mission Pack 2: Ground Zero",
+ "(tm) (C)1998 Id Software, Inc. All",
+ "Rights Reserved. Developed by Rogue",
+ "Entertainment, Inc. for Id Software,",
+ "Inc. Distributed by Activision Inc.",
+ "under license. Quake(R) is a",
+ "registered trademark of Id Software,",
+ "Inc. Quake II Mission Pack 2: Ground",
+ "Zero(tm), Quake II(tm), the Id",
+ "Software name, the \"Q II\"(tm) logo",
+ "and id(tm) logo are trademarks of Id",
+ "Software, Inc. Activision(R) is a",
+ "registered trademark of Activision,",
+ "Inc. Rogue(R) is a registered",
+ "trademark of Rogue Entertainment,",
+ "Inc. All other trademarks and trade",
+ "names are properties of their",
+ "respective owners.",
+ null };
+
+ public static void Credits_MenuDraw() {
+ int i, y;
+
+ /*
+ ** draw the credits
+ */
+ for (i = 0, y = (int) (viddef.height - ((cls.realtime - credits_start_time) / 40.0F));
+ credits[i] != null && y < viddef.height;
+ y += 10, i++) {
+ int j, stringoffset = 0;
+ boolean bold = false;
+
+ if (y <= -8)
+ continue;
+
+ if (credits[i].length() > 0 && credits[i].charAt(0) == '+') {
+ bold = true;
+ stringoffset = 1;
+ }
+ else {
+ bold = false;
+ stringoffset = 0;
+ }
+
+ for (j = 0; j + stringoffset < credits[i].length(); j++) {
+ int x;
+
+ x = (viddef.width - strlen(credits[i]) * 8 - stringoffset * 8) / 2 + (j + stringoffset) * 8;
+
+ if (bold)
+ re.DrawChar(x, y, credits[i].charAt(j + stringoffset) + 128);
+ else
+ re.DrawChar(x, y, credits[i].charAt(j + stringoffset));
+ }
+ }
+
+ if (y < 0)
+ credits_start_time = cls.realtime;
+ }
+
+ public static String Credits_Key(int key) {
+ switch (key) {
+ case K_ESCAPE :
+ if (creditsBuffer != null)
+ //FS.FreeFile(creditsBuffer);
+ ;
+ PopMenu();
+ break;
+ }
+
+ return menu_out_sound;
+
+ }
+
+ static xcommand_t Menu_Credits = new xcommand_t() {
+ public void execute() {
+ Menu_Credits_f();
+ }
+ };
+ static void Menu_Credits_f() {
+ int n;
+ int count;
+ String p;
+ int isdeveloper = 0;
+
+ byte b[] = FS.LoadFile("credits");
+
+ if (b != null) {
+ creditsBuffer = new String(b);
+ String line[] = Lib.linesplit(creditsBuffer);
+
+ for (n = 0; n < line.length; n++) {
+ creditsIndex[n] = line[n];
+ }
+
+ creditsIndex[n] = null;
+ credits = creditsIndex;
+ }
+ else {
+ isdeveloper = FS.Developer_searchpath(1);
+
+ if (isdeveloper == 1) // xatrix
+ credits = xatcredits;
+ else if (isdeveloper == 2) // ROGUE
+ credits = roguecredits;
+ else {
+ credits = idcredits;
+ }
+
+ }
+
+ credits_start_time = cls.realtime;
+ PushMenu(new xcommand_t() {
+ public void execute() {
+ Credits_MenuDraw();
+ }
+ }, new keyfunc_t() {
+ public String execute(int key) {
+ return Credits_Key(key);
+ }
+ });
+ }
+
+ /*
+ =============================================================================
+
+ GAME MENU
+
+ =============================================================================
+ */
+
+ static int m_game_cursor;
+
+ static menuframework_s s_game_menu = new menuframework_s();
+ static menuaction_s s_easy_game_action = new menuaction_s();
+ static menuaction_s s_medium_game_action = new menuaction_s();
+ static menuaction_s s_hard_game_action = new menuaction_s();
+ static menuaction_s s_load_game_action = new menuaction_s();
+ static menuaction_s s_save_game_action = new menuaction_s();
+ static menuaction_s s_credits_action = new menuaction_s();
+ static menuseparator_s s_blankline = new menuseparator_s();
+
+ static void StartGame() {
+ // disable updates and start the cinematic going
+ cl.servercount = -1;
+ ForceMenuOff();
+ Cvar.SetValue("deathmatch", 0);
+ Cvar.SetValue("coop", 0);
+
+ Cvar.SetValue("gamerules", 0); //PGM
+
+ Cbuf.AddText("loading ; killserver ; wait ; newgame\n");
+ cls.key_dest = key_game;
+ }
+
+ static void EasyGameFunc(Object data) {
+ Cvar.ForceSet("skill", "0");
+ StartGame();
+ }
+
+ static void MediumGameFunc(Object data) {
+ Cvar.ForceSet("skill", "1");
+ StartGame();
+ }
+
+ static void HardGameFunc(Object data) {
+ Cvar.ForceSet("skill", "2");
+ StartGame();
+ }
+
+ static void LoadGameFunc(Object unused) {
+ Menu_LoadGame_f();
+ }
+
+ static void SaveGameFunc(Object unused) {
+ Menu_SaveGame_f();
+ }
+
+ static void CreditsFunc(Object unused) {
+ Menu_Credits_f();
+ }
+
+ static String difficulty_names[] = { "easy", "medium", "fuckin shitty hard", null };
+ static void Game_MenuInit() {
+
+ s_game_menu.x = (int) (viddef.width * 0.50);
+ s_game_menu.nitems = 0;
+
+ s_easy_game_action.type = MTYPE_ACTION;
+ s_easy_game_action.flags = QMF_LEFT_JUSTIFY;
+ s_easy_game_action.x = 0;
+ s_easy_game_action.y = 0;
+ s_easy_game_action.name = "easy";
+ s_easy_game_action.callback = new mcallback() {
+ public void execute(Object o) {
+ EasyGameFunc(o);
+ }
+ };
+
+ s_medium_game_action.type = MTYPE_ACTION;
+ s_medium_game_action.flags = QMF_LEFT_JUSTIFY;
+ s_medium_game_action.x = 0;
+ s_medium_game_action.y = 10;
+ s_medium_game_action.name = "medium";
+ s_medium_game_action.callback = new mcallback() {
+ public void execute(Object o) {
+ MediumGameFunc(o);
+ }
+ };
+
+ s_hard_game_action.type = MTYPE_ACTION;
+ s_hard_game_action.flags = QMF_LEFT_JUSTIFY;
+ s_hard_game_action.x = 0;
+ s_hard_game_action.y = 20;
+ s_hard_game_action.name = "hard";
+ s_hard_game_action.callback = new mcallback() {
+ public void execute(Object o) {
+ HardGameFunc(o);
+ }
+ };
+
+ s_blankline.type = MTYPE_SEPARATOR;
+
+ s_load_game_action.type = MTYPE_ACTION;
+ s_load_game_action.flags = QMF_LEFT_JUSTIFY;
+ s_load_game_action.x = 0;
+ s_load_game_action.y = 40;
+ s_load_game_action.name = "load game";
+ s_load_game_action.callback = new mcallback() {
+ public void execute(Object o) {
+ LoadGameFunc(o);
+ }
+ };
+
+ s_save_game_action.type = MTYPE_ACTION;
+ s_save_game_action.flags = QMF_LEFT_JUSTIFY;
+ s_save_game_action.x = 0;
+ s_save_game_action.y = 50;
+ s_save_game_action.name = "save game";
+ s_save_game_action.callback = new mcallback() {
+ public void execute(Object o) {
+ SaveGameFunc(o);
+ }
+ };
+
+ s_credits_action.type = MTYPE_ACTION;
+ s_credits_action.flags = QMF_LEFT_JUSTIFY;
+ s_credits_action.x = 0;
+ s_credits_action.y = 60;
+ s_credits_action.name = "credits";
+ s_credits_action.callback = new mcallback() {
+ public void execute(Object o) {
+ CreditsFunc(o);
+ }
+ };
+
+ Menu_AddItem(s_game_menu, s_easy_game_action);
+ Menu_AddItem(s_game_menu, s_medium_game_action);
+ Menu_AddItem(s_game_menu, s_hard_game_action);
+ Menu_AddItem(s_game_menu, s_blankline);
+ Menu_AddItem(s_game_menu, s_load_game_action);
+ Menu_AddItem(s_game_menu, s_save_game_action);
+ Menu_AddItem(s_game_menu, s_blankline);
+ Menu_AddItem(s_game_menu, s_credits_action);
+
+ Menu_Center(s_game_menu);
+ }
+
+ static void Game_MenuDraw() {
+ Banner("m_banner_game");
+ Menu_AdjustCursor(s_game_menu, 1);
+ Menu_Draw(s_game_menu);
+ }
+
+ static String Game_MenuKey(int key) {
+ return Default_MenuKey(s_game_menu, key);
+ }
+
+ static xcommand_t Menu_Game = new xcommand_t() {
+ public void execute() {
+ Menu_Game_f();
+ }
+ };
+
+ static void Menu_Game_f() {
+ Game_MenuInit();
+ PushMenu(new xcommand_t() {
+ public void execute() {
+ Game_MenuDraw();
+ }
+ }, new keyfunc_t() {
+ public String execute(int key) {
+ return Game_MenuKey(key);
+ }
+ });
+ m_game_cursor = 1;
+ }
+
+ /*
+ =============================================================================
+
+ LOADGAME MENU
+
+ =============================================================================
+ */
+
+ public final static int MAX_SAVEGAMES = 15;
+
+ static menuframework_s s_savegame_menu = new menuframework_s();
+ static menuframework_s s_loadgame_menu = new menuframework_s();
+
+ static menuaction_s s_loadgame_actions[] = new menuaction_s[MAX_SAVEGAMES];
+
+ static {
+ for (int n = 0; n < MAX_SAVEGAMES; n++)
+ s_loadgame_actions[n] = new menuaction_s();
+ }
+
+ //String m_savestrings[] = new String [MAX_SAVEGAMES][32];
+ static String m_savestrings[] = new String[MAX_SAVEGAMES];
+
+ static {
+ for (int n = 0; n < MAX_SAVEGAMES; n++)
+ m_savestrings[n] = "";
+ }
+
+ static boolean m_savevalid[] = new boolean[MAX_SAVEGAMES];
+
+ static void Create_Savestrings() {
+ int i;
+ RandomAccessFile f;
+ //char name[MAX_OSPATH];
+ String name;
+
+ for (i = 0; i < MAX_SAVEGAMES; i++) {
+ name = FS.Gamedir() + "/save/save" + i + "/server.ssv";
+ f = fopen(name, "r");
+ if (f == null) {
+ m_savestrings[i] = "<EMPTY>";
+ m_savevalid[i] = false;
+ }
+ else {
+ m_savestrings[i] = freadString(f, 32);
+ fclose(f);
+ m_savevalid[i] = true;
+ }
+ }
+ }
+
+ static void LoadGameCallback(Object self) {
+ menuaction_s a = (menuaction_s) self;
+
+ if (m_savevalid[a.localdata[0]])
+ Cbuf.AddText("load save" + a.localdata[0] + "\n");
+ ForceMenuOff();
+ }
+
+ static void LoadGame_MenuInit() {
+ int i;
+
+ s_loadgame_menu.x = viddef.width / 2 - 120;
+ s_loadgame_menu.y = viddef.height / 2 - 58;
+ s_loadgame_menu.nitems = 0;
+
+ Create_Savestrings();
+
+ for (i = 0; i < MAX_SAVEGAMES; i++) {
+ s_loadgame_actions[i].name = m_savestrings[i];
+ s_loadgame_actions[i].flags = QMF_LEFT_JUSTIFY;
+ s_loadgame_actions[i].localdata[0] = i;
+ s_loadgame_actions[i].callback = new mcallback() {
+ public void execute(Object o) {
+ LoadGameCallback(o);
+ }
+ };
+
+ s_loadgame_actions[i].x = 0;
+ s_loadgame_actions[i].y = (i) * 10;
+ if (i > 0) // separate from autosave
+ s_loadgame_actions[i].y += 10;
+
+ s_loadgame_actions[i].type = MTYPE_ACTION;
+
+ Menu_AddItem(s_loadgame_menu, s_loadgame_actions[i]);
+ }
+ }
+
+ static void LoadGame_MenuDraw() {
+ Banner("m_banner_load_game");
+ // Menu_AdjustCursor( &s_loadgame_menu, 1 );
+ Menu_Draw(s_loadgame_menu);
+ }
+
+ static String LoadGame_MenuKey(int key) {
+ if (key == K_ESCAPE || key == K_ENTER) {
+ s_savegame_menu.cursor = s_loadgame_menu.cursor - 1;
+ if (s_savegame_menu.cursor < 0)
+ s_savegame_menu.cursor = 0;
+ }
+ return Default_MenuKey(s_loadgame_menu, key);
+ }
+
+ static xcommand_t Menu_LoadGame = new xcommand_t() {
+ public void execute() {
+ Menu_LoadGame_f();
+ }
+ };
+ static void Menu_LoadGame_f() {
+ LoadGame_MenuInit();
+ PushMenu(new xcommand_t() {
+ public void execute() {
+ LoadGame_MenuDraw();
+ }
+ }, new keyfunc_t() {
+ public String execute(int key) {
+ return LoadGame_MenuKey(key);
+ }
+ });
+ }
+
+ /*
+ =============================================================================
+
+ SAVEGAME MENU
+
+ =============================================================================
+ */
+ //static menuframework_s s_savegame_menu;
+ static menuaction_s s_savegame_actions[] = new menuaction_s[MAX_SAVEGAMES];
+
+ static void SaveGameCallback(Object self) {
+ menuaction_s a = (menuaction_s) self;
+
+ Cbuf.AddText("save save" + a.localdata[0] + "\n");
+ ForceMenuOff();
+ }
+
+ static void SaveGame_MenuDraw() {
+ Banner("m_banner_save_game");
+ Menu_AdjustCursor(s_savegame_menu, 1);
+ Menu_Draw(s_savegame_menu);
+ }
+
+ static void SaveGame_MenuInit() {
+ int i;
+
+ s_savegame_menu.x = viddef.width / 2 - 120;
+ s_savegame_menu.y = viddef.height / 2 - 58;
+ s_savegame_menu.nitems = 0;
+
+ Create_Savestrings();
+
+ // don't include the autosave slot
+ for (i = 0; i < MAX_SAVEGAMES - 1; i++) {
+ s_savegame_actions[i].name = m_savestrings[i + 1];
+ s_savegame_actions[i].localdata[0] = i + 1;
+ s_savegame_actions[i].flags = QMF_LEFT_JUSTIFY;
+ s_savegame_actions[i].callback = new mcallback() {
+ public void execute(Object o) {
+ SaveGameCallback(o);
+ }
+ };
+
+ s_savegame_actions[i].x = 0;
+ s_savegame_actions[i].y = (i) * 10;
+
+ s_savegame_actions[i].type = MTYPE_ACTION;
+
+ Menu_AddItem(s_savegame_menu, s_savegame_actions[i]);
+ }
+ }
+
+ static String SaveGame_MenuKey(int key) {
+ if (key == K_ENTER || key == K_ESCAPE) {
+ s_loadgame_menu.cursor = s_savegame_menu.cursor - 1;
+ if (s_loadgame_menu.cursor < 0)
+ s_loadgame_menu.cursor = 0;
+ }
+ return Default_MenuKey(s_savegame_menu, key);
+ }
+
+ static xcommand_t Menu_SaveGame = new xcommand_t() {
+ public void execute() {
+ Menu_SaveGame_f();
+ }
+ };
+ static void Menu_SaveGame_f() {
+ if (0 == Com.ServerState())
+ return; // not playing a game
+
+ SaveGame_MenuInit();
+ PushMenu(new xcommand_t() {
+ public void execute() {
+ SaveGame_MenuDraw();
+ }
+ }, new keyfunc_t() {
+ public String execute(int key) {
+ return SaveGame_MenuKey(key);
+ }
+ });
+ Create_Savestrings();
+ }
+
+ /*
+ =============================================================================
+
+ JOIN SERVER MENU
+
+ =============================================================================
+ */
+
+ static menuframework_s s_joinserver_menu = new menuframework_s();
+ static menuseparator_s s_joinserver_server_title = new menuseparator_s();
+ static menuaction_s s_joinserver_search_action = new menuaction_s();
+ static menuaction_s s_joinserver_address_book_action = new menuaction_s();
+
+ static netadr_t local_server_netadr[] = new netadr_t[MAX_LOCAL_SERVERS];
+ static String local_server_names[] = new String[MAX_LOCAL_SERVERS]; //[80];
+ static menuaction_s s_joinserver_server_actions[] = new menuaction_s[MAX_LOCAL_SERVERS];
+
+ // user readable information
+ // network address
+ static {
+ for (int n = 0; n < MAX_LOCAL_SERVERS; n++) {
+ local_server_netadr[n] = new netadr_t();
+ local_server_names[n] = "";
+ s_joinserver_server_actions[n] = new menuaction_s();
+ s_joinserver_server_actions[n].n = n;
+ }
+ }
+
+ static int m_num_servers;
+
+ static void AddToServerList(netadr_t adr, String info) {
+ int i;
+
+ if (m_num_servers == MAX_LOCAL_SERVERS)
+ return;
+
+ String x = info.trim();
+
+ // ignore if duplicated
+ for (i = 0; i < m_num_servers; i++)
+ if (0 == strcmp(x, local_server_names[i]))
+ return;
+
+ local_server_netadr[m_num_servers] = adr;
+ local_server_names[m_num_servers] = x;
+ m_num_servers++;
+ }
+
+ static void JoinServerFunc(Object self) {
+ String buffer;
+ int index;
+
+ index = ((menucommon_s) self).n;
+
+ if (Q_stricmp(local_server_names[index], NO_SERVER_STRING) == 0)
+ return;
+
+ if (index >= m_num_servers)
+ return;
+
+ buffer = "connect " + NET.AdrToString(local_server_netadr[index]) + "\n";
+ Cbuf.AddText(buffer);
+ ForceMenuOff();
+ }
+
+ static void AddressBookFunc(Object self) {
+ Menu_AddressBook_f();
+ }
+
+ static void NullCursorDraw(Object self) {
+ }
+
+ static void SearchLocalGames() {
+ int i;
+
+ m_num_servers = 0;
+ for (i = 0; i < MAX_LOCAL_SERVERS; i++)
+ local_server_names[i] = NO_SERVER_STRING;
+
+ DrawTextBox(8, 120 - 48, 36, 3);
+ Print(16 + 16, 120 - 48 + 8, "Searching for local servers, this");
+ Print(16 + 16, 120 - 48 + 16, "could take up to a minute, so");
+ Print(16 + 16, 120 - 48 + 24, "please be patient.");
+
+ // the text box won't show up unless we do a buffer swap
+ re.EndFrame();
+
+ // send out info packets
+ CL.PingServers_f.execute();
+ }
+
+ static void SearchLocalGamesFunc(Object self) {
+ SearchLocalGames();
+ }
+
+ static void JoinServer_MenuInit() {
+ int i;
+
+ s_joinserver_menu.x = (int) (viddef.width * 0.50 - 120);
+ s_joinserver_menu.nitems = 0;
+
+ s_joinserver_address_book_action.type = MTYPE_ACTION;
+ s_joinserver_address_book_action.name = "address book";
+ s_joinserver_address_book_action.flags = QMF_LEFT_JUSTIFY;
+ s_joinserver_address_book_action.x = 0;
+ s_joinserver_address_book_action.y = 0;
+ s_joinserver_address_book_action.callback = new mcallback() {
+ public void execute(Object o) {
+ AddressBookFunc(o);
+ }
+ };
+
+ s_joinserver_search_action.type = MTYPE_ACTION;
+ s_joinserver_search_action.name = "refresh server list";
+ s_joinserver_search_action.flags = QMF_LEFT_JUSTIFY;
+ s_joinserver_search_action.x = 0;
+ s_joinserver_search_action.y = 10;
+ s_joinserver_search_action.callback = new mcallback() {
+ public void execute(Object o) {
+ SearchLocalGamesFunc(o);
+ }
+ };
+ s_joinserver_search_action.statusbar = "search for servers";
+
+ s_joinserver_server_title.type = MTYPE_SEPARATOR;
+ s_joinserver_server_title.name = "connect to...";
+ s_joinserver_server_title.x = 80;
+ s_joinserver_server_title.y = 30;
+
+ for (i = 0; i < MAX_LOCAL_SERVERS; i++) {
+ s_joinserver_server_actions[i].type = MTYPE_ACTION;
+ local_server_names[i] = NO_SERVER_STRING;
+ s_joinserver_server_actions[i].name = local_server_names[i];
+ s_joinserver_server_actions[i].flags = QMF_LEFT_JUSTIFY;
+ s_joinserver_server_actions[i].x = 0;
+ s_joinserver_server_actions[i].y = 40 + i * 10;
+ s_joinserver_server_actions[i].callback = new mcallback() {
+ public void execute(Object o) {
+ JoinServerFunc(o);
+ }
+ };
+ s_joinserver_server_actions[i].statusbar = "press ENTER to connect";
+ }
+
+ Menu_AddItem(s_joinserver_menu, s_joinserver_address_book_action);
+ Menu_AddItem(s_joinserver_menu, s_joinserver_server_title);
+ Menu_AddItem(s_joinserver_menu, s_joinserver_search_action);
+
+ for (i = 0; i < 8; i++)
+ Menu_AddItem(s_joinserver_menu, s_joinserver_server_actions[i]);
+
+ Menu_Center(s_joinserver_menu);
+
+ SearchLocalGames();
+ }
+
+ static void JoinServer_MenuDraw() {
+ Banner("m_banner_join_server");
+ Menu_Draw(s_joinserver_menu);
+ }
+
+ static String JoinServer_MenuKey(int key) {
+ return Default_MenuKey(s_joinserver_menu, key);
+ }
+
+ static xcommand_t Menu_JoinServer = new xcommand_t() {
+ public void execute() {
+ Menu_JoinServer_f();
+ }
+ };
+ static void Menu_JoinServer_f() {
+ JoinServer_MenuInit();
+ PushMenu(new xcommand_t() {
+ public void execute() {
+ JoinServer_MenuDraw();
+ }
+ }, new keyfunc_t() {
+ public String execute(int key) {
+ return JoinServer_MenuKey(key);
+ }
+ });
+ }
+
+ /*
+ =============================================================================
+
+ START SERVER MENU
+
+ =============================================================================
+ */
+ static menuframework_s s_startserver_menu = new menuframework_s();
+ static String mapnames[];
+ static int nummaps;
+
+ static menuaction_s s_startserver_start_action = new menuaction_s();
+ static menuaction_s s_startserver_dmoptions_action = new menuaction_s();
+ static menufield_s s_timelimit_field = new menufield_s();
+ static menufield_s s_fraglimit_field = new menufield_s();
+ static menufield_s s_maxclients_field = new menufield_s();
+ static menufield_s s_hostname_field = new menufield_s();
+ static menulist_s s_startmap_list = new menulist_s();
+ static menulist_s s_rules_box = new menulist_s();
+
+ static void DMOptionsFunc(Object self) {
+ if (s_rules_box.curvalue == 1)
+ return;
+ Menu_DMOptions_f();
+ }
+
+ static void RulesChangeFunc(Object self) {
+ // DM
+ if (s_rules_box.curvalue == 0) {
+ s_maxclients_field.statusbar = null;
+ s_startserver_dmoptions_action.statusbar = null;
+ }
+ else if (s_rules_box.curvalue == 1)
+ // coop // PGM
+ {
+ s_maxclients_field.statusbar = "4 maximum for cooperative";
+ if (atoi(s_maxclients_field.buffer.toString()) > 4)
+ s_maxclients_field.buffer = new StringBuffer("4");
+ s_startserver_dmoptions_action.statusbar = "N/A for cooperative";
+ }
+ // =====
+ // PGM
+ // ROGUE GAMES
+ else if (FS.Developer_searchpath(2) == 2) {
+ if (s_rules_box.curvalue == 2) // tag
+ {
+ s_maxclients_field.statusbar = null;
+ s_startserver_dmoptions_action.statusbar = null;
+ }
+ /*
+ else if(s_rules_box.curvalue == 3) // deathball
+ {
+ s_maxclients_field.statusbar = null;
+ s_startserver_dmoptions_action.statusbar = null;
+ }
+ */
+ }
+ // PGM
+ // =====
+ }
+
+ static void StartServerActionFunc(Object self) {
+ //char startmap[1024];
+ String startmap;
+ int timelimit;
+ int fraglimit;
+ int maxclients;
+ String spot;
+
+ //strcpy(startmap, strchr(mapnames[s_startmap_list.curvalue], '\n') + 1);
+ String x = mapnames[s_startmap_list.curvalue];
+
+ int pos = x.indexOf('\n');
+ if (pos == -1)
+ startmap = x;
+ else
+ startmap = x.substring(pos + 1, x.length());
+
+ maxclients = atoi(s_maxclients_field.buffer.toString());
+ timelimit = atoi(s_timelimit_field.buffer.toString());
+ fraglimit = atoi(s_fraglimit_field.buffer.toString());
+
+ Cvar.SetValue("maxclients", ClampCvar(0, maxclients, maxclients));
+ Cvar.SetValue("timelimit", ClampCvar(0, timelimit, timelimit));
+ Cvar.SetValue("fraglimit", ClampCvar(0, fraglimit, fraglimit));
+ Cvar.Set("hostname", s_hostname_field.buffer.toString());
+ // Cvar.SetValue ("deathmatch", !s_rules_box.curvalue );
+ // Cvar.SetValue ("coop", s_rules_box.curvalue );
+
+ // PGM
+ if ((s_rules_box.curvalue < 2) || (FS.Developer_searchpath(2) != 2)) {
+ Cvar.SetValue("deathmatch", 1 - (int) (s_rules_box.curvalue));
+ Cvar.SetValue("coop", s_rules_box.curvalue);
+ Cvar.SetValue("gamerules", 0);
+ }
+ else {
+ Cvar.SetValue("deathmatch", 1);
+ // deathmatch is always true for rogue games, right?
+ Cvar.SetValue("coop", 0);
+ // FIXME - this might need to depend on which game we're running
+ Cvar.SetValue("gamerules", s_rules_box.curvalue);
+ }
+ // PGM
+
+ spot = null;
+ if (s_rules_box.curvalue == 1) // PGM
+ {
+ if (Q_stricmp(startmap, "bunk1") == 0)
+ spot = "start";
+ else if (Q_stricmp(startmap, "mintro") == 0)
+ spot = "start";
+ else if (Q_stricmp(startmap, "fact1") == 0)
+ spot = "start";
+ else if (Q_stricmp(startmap, "power1") == 0)
+ spot = "pstart";
+ else if (Q_stricmp(startmap, "biggun") == 0)
+ spot = "bstart";
+ else if (Q_stricmp(startmap, "hangar1") == 0)
+ spot = "unitstart";
+ else if (Q_stricmp(startmap, "city1") == 0)
+ spot = "unitstart";
+ else if (Q_stricmp(startmap, "boss1") == 0)
+ spot = "bosstart";
+ }
+
+ if (spot != null) {
+ if (Com.ServerState() != 0)
+ Cbuf.AddText("disconnect\n");
+ Cbuf.AddText("gamemap \"*" + startmap + "$" + spot + "\"\n");
+ }
+ else {
+ Cbuf.AddText("map " + startmap + "\n");
+ }
+
+ ForceMenuOff();
+ }
+
+ static String dm_coop_names[] = { "deathmatch", "cooperative", null };
+ static String dm_coop_names_rogue[] = { "deathmatch", "cooperative", "tag",
+ // "deathball",
+ null };
+
+ static void StartServer_MenuInit() {
+
+ // =======
+ // PGM
+ // =======
+
+ byte[] buffer = null;
+ //char mapsname[1024];
+ String mapsname;
+ String s;
+ int length;
+ int i;
+ RandomAccessFile fp;
+
+ /*
+ ** load the list of map names
+ */
+ mapsname = FS.Gamedir() + "/maps.lst";
+
+ if ((fp = fopen(mapsname, "r")) == null) {
+ buffer = FS.LoadFile("maps.lst");
+ if (buffer == null)
+ //if ((length = FS_LoadFile("maps.lst", (Object *) & buffer)) == -1)
+ Com.Error(ERR_DROP, "couldn't find maps.lst\n");
+ }
+ else {
+ try {
+ int len = (int) fp.length();
+ buffer = new byte[len];
+ fp.readFully(buffer);
+ }
+ catch (Exception e) {
+ Com.Error(ERR_DROP, "couldn't load maps.lst\n");
+ }
+ }
+
+ s = new String(buffer);
+ String lines[] = Lib.linesplit(s);
+
+ nummaps = lines.length;
+
+ if (nummaps == 0)
+ Com.Error(ERR_DROP, "no maps in maps.lst\n");
+
+ mapnames = new String[nummaps + 1];
+
+ for (i = 0; i < nummaps; i++) {
+ String shortname, longname, scratch;
+
+ Com.ParseHelp ph = new Com.ParseHelp(lines[i]);
+
+ shortname = Com.Parse(ph).toUpperCase();
+ longname = Com.Parse(ph);
+ scratch = longname + "\n" + shortname;
+ mapnames[i] = scratch;
+ }
+ mapnames[nummaps] = null;
+
+ if (fp != null) {
+ fclose(fp);
+ fp = null;
+
+ }
+ else {
+ FS.FreeFile(buffer);
+ }
+
+ /*
+ ** initialize the menu stuff
+ */
+ s_startserver_menu.x = (int) (viddef.width * 0.50);
+ s_startserver_menu.nitems = 0;
+
+ s_startmap_list.type = MTYPE_SPINCONTROL;
+ s_startmap_list.x = 0;
+ s_startmap_list.y = 0;
+ s_startmap_list.name = "initial map";
+ s_startmap_list.itemnames = mapnames;
+
+ s_rules_box.type = MTYPE_SPINCONTROL;
+ s_rules_box.x = 0;
+ s_rules_box.y = 20;
+ s_rules_box.name = "rules";
+
+ // PGM - rogue games only available with rogue DLL.
+ if (FS.Developer_searchpath(2) == 2)
+ s_rules_box.itemnames = dm_coop_names_rogue;
+ else
+ s_rules_box.itemnames = dm_coop_names;
+ // PGM
+
+ if (Cvar.VariableValue("coop") != 0)
+ s_rules_box.curvalue = 1;
+ else
+ s_rules_box.curvalue = 0;
+ s_rules_box.callback = new mcallback() {
+ public void execute(Object o) {
+ RulesChangeFunc(o);
+ }
+ };
+
+ s_timelimit_field.type = MTYPE_FIELD;
+ s_timelimit_field.name = "time limit";
+ s_timelimit_field.flags = QMF_NUMBERSONLY;
+ s_timelimit_field.x = 0;
+ s_timelimit_field.y = 36;
+ s_timelimit_field.statusbar = "0 = no limit";
+ s_timelimit_field.length = 3;
+ s_timelimit_field.visible_length = 3;
+ s_timelimit_field.buffer = new StringBuffer(Cvar.VariableString("timelimit"));
+
+ s_fraglimit_field.type = MTYPE_FIELD;
+ s_fraglimit_field.name = "frag limit";
+ s_fraglimit_field.flags = QMF_NUMBERSONLY;
+ s_fraglimit_field.x = 0;
+ s_fraglimit_field.y = 54;
+ s_fraglimit_field.statusbar = "0 = no limit";
+ s_fraglimit_field.length = 3;
+ s_fraglimit_field.visible_length = 3;
+ s_fraglimit_field.buffer = new StringBuffer(Cvar.VariableString("fraglimit"));
+
+ /*
+ ** maxclients determines the maximum number of players that can join
+ ** the game. If maxclients is only "1" then we should default the menu
+ ** option to 8 players, otherwise use whatever its current value is.
+ ** Clamping will be done when the server is actually started.
+ */
+ s_maxclients_field.type = MTYPE_FIELD;
+ s_maxclients_field.name = "max players";
+ s_maxclients_field.flags = QMF_NUMBERSONLY;
+ s_maxclients_field.x = 0;
+ s_maxclients_field.y = 72;
+ s_maxclients_field.statusbar = null;
+ s_maxclients_field.length = 3;
+ s_maxclients_field.visible_length = 3;
+ if (Cvar.VariableValue("maxclients") == 1)
+ s_maxclients_field.buffer = new StringBuffer("8");
+ else
+ s_maxclients_field.buffer = new StringBuffer(Cvar.VariableString("maxclients"));
+
+ s_hostname_field.type = MTYPE_FIELD;
+ s_hostname_field.name = "hostname";
+ s_hostname_field.flags = 0;
+ s_hostname_field.x = 0;
+ s_hostname_field.y = 90;
+ s_hostname_field.statusbar = null;
+ s_hostname_field.length = 12;
+ s_hostname_field.visible_length = 12;
+ s_hostname_field.buffer = new StringBuffer(Cvar.VariableString("hostname"));
+
+ s_startserver_dmoptions_action.type = MTYPE_ACTION;
+ s_startserver_dmoptions_action.name = " deathmatch flags";
+ s_startserver_dmoptions_action.flags = QMF_LEFT_JUSTIFY;
+ s_startserver_dmoptions_action.x = 24;
+ s_startserver_dmoptions_action.y = 108;
+ s_startserver_dmoptions_action.statusbar = null;
+ s_startserver_dmoptions_action.callback = new mcallback() {
+ public void execute(Object o) {
+ DMOptionsFunc(o);
+ }
+ };
+
+ s_startserver_start_action.type = MTYPE_ACTION;
+ s_startserver_start_action.name = " begin";
+ s_startserver_start_action.flags = QMF_LEFT_JUSTIFY;
+ s_startserver_start_action.x = 24;
+ s_startserver_start_action.y = 128;
+ s_startserver_start_action.callback = new mcallback() {
+ public void execute(Object o) {
+ StartServerActionFunc(o);
+ }
+ };
+
+ Menu_AddItem(s_startserver_menu, s_startmap_list);
+ Menu_AddItem(s_startserver_menu, s_rules_box);
+ Menu_AddItem(s_startserver_menu, s_timelimit_field);
+ Menu_AddItem(s_startserver_menu, s_fraglimit_field);
+ Menu_AddItem(s_startserver_menu, s_maxclients_field);
+ Menu_AddItem(s_startserver_menu, s_hostname_field);
+ Menu_AddItem(s_startserver_menu, s_startserver_dmoptions_action);
+ Menu_AddItem(s_startserver_menu, s_startserver_start_action);
+
+ Menu_Center(s_startserver_menu);
+
+ // call this now to set proper inital state
+ RulesChangeFunc(null);
+ }
+
+ static void StartServer_MenuDraw() {
+ Menu_Draw(s_startserver_menu);
+ }
+
+ static String StartServer_MenuKey(int key) {
+ if (key == K_ESCAPE) {
+ if (mapnames != null) {
+ int i;
+
+ for (i = 0; i < nummaps; i++)
+ mapnames[i] = null;
+
+ }
+ mapnames = null;
+ nummaps = 0;
+ }
+
+ return Default_MenuKey(s_startserver_menu, key);
+ }
+
+ static xcommand_t Menu_StartServer = new xcommand_t() {
+ public void execute() {
+ Menu_StartServer_f();
+ }
+ };
+ static void Menu_StartServer_f() {
+ StartServer_MenuInit();
+ PushMenu(new xcommand_t() {
+ public void execute() {
+ StartServer_MenuDraw();
+ }
+ }, new keyfunc_t() {
+ public String execute(int key) {
+ return StartServer_MenuKey(key);
+ }
+ });
+ }
+
+ /*
+ =============================================================================
+
+ DMOPTIONS BOOK MENU
+
+ =============================================================================
+ */
+ static String dmoptions_statusbar; //[128];
+
+ static menuframework_s s_dmoptions_menu = new menuframework_s();
+
+ static menulist_s s_friendlyfire_box = new menulist_s();
+ static menulist_s s_falls_box = new menulist_s();
+ static menulist_s s_weapons_stay_box = new menulist_s();
+ static menulist_s s_instant_powerups_box = new menulist_s();
+ static menulist_s s_powerups_box = new menulist_s();
+ static menulist_s s_health_box = new menulist_s();
+ static menulist_s s_spawn_farthest_box = new menulist_s();
+ static menulist_s s_teamplay_box = new menulist_s();
+ static menulist_s s_samelevel_box = new menulist_s();
+ static menulist_s s_force_respawn_box = new menulist_s();
+ static menulist_s s_armor_box = new menulist_s();
+ static menulist_s s_allow_exit_box = new menulist_s();
+ static menulist_s s_infinite_ammo_box = new menulist_s();
+ static menulist_s s_fixed_fov_box = new menulist_s();
+ static menulist_s s_quad_drop_box = new menulist_s();
+
+ // ROGUE
+ static menulist_s s_no_mines_box = new menulist_s();
+ static menulist_s s_no_nukes_box = new menulist_s();
+ static menulist_s s_stack_double_box = new menulist_s();
+ static menulist_s s_no_spheres_box = new menulist_s();
+ // ROGUE
+
+ static void setvalue(int flags) {
+ Cvar.SetValue("dmflags", flags);
+ dmoptions_statusbar = "dmflags = " + flags;
+ }
+
+ static void DMFlagCallback(Object self) {
+ menulist_s f = (menulist_s) self;
+ int flags;
+ int bit = 0;
+
+ flags = (int) Cvar.VariableValue("dmflags");
+
+ if (f == s_friendlyfire_box) {
+ if (f.curvalue != 0)
+ flags &= ~DF_NO_FRIENDLY_FIRE;
+ else
+ flags |= DF_NO_FRIENDLY_FIRE;
+ setvalue(flags);
+ return;
+ }
+ else if (f == s_falls_box) {
+ if (f.curvalue != 0)
+ flags &= ~DF_NO_FALLING;
+ else
+ flags |= DF_NO_FALLING;
+ setvalue(flags);
+ return;
+ }
+ else if (f == s_weapons_stay_box) {
+ bit = DF_WEAPONS_STAY;
+ }
+ else if (f == s_instant_powerups_box) {
+ bit = DF_INSTANT_ITEMS;
+ }
+ else if (f == s_allow_exit_box) {
+ bit = DF_ALLOW_EXIT;
+ }
+ else if (f == s_powerups_box) {
+ if (f.curvalue != 0)
+ flags &= ~DF_NO_ITEMS;
+ else
+ flags |= DF_NO_ITEMS;
+ setvalue(flags);
+ return;
+ }
+ else if (f == s_health_box) {
+ if (f.curvalue != 0)
+ flags &= ~DF_NO_HEALTH;
+ else
+ flags |= DF_NO_HEALTH;
+ setvalue(flags);
+ return;
+ }
+ else if (f == s_spawn_farthest_box) {
+ bit = DF_SPAWN_FARTHEST;
+ }
+ else if (f == s_teamplay_box) {
+ if (f.curvalue == 1) {
+ flags |= DF_SKINTEAMS;
+ flags &= ~DF_MODELTEAMS;
+ }
+ else if (f.curvalue == 2) {
+ flags |= DF_MODELTEAMS;
+ flags &= ~DF_SKINTEAMS;
+ }
+ else {
+ flags &= ~(DF_MODELTEAMS | DF_SKINTEAMS);
+ }
+
+ setvalue(flags);
+ return;
+ }
+ else if (f == s_samelevel_box) {
+ bit = DF_SAME_LEVEL;
+ }
+ else if (f == s_force_respawn_box) {
+ bit = DF_FORCE_RESPAWN;
+ }
+ else if (f == s_armor_box) {
+ if (f.curvalue != 0)
+ flags &= ~DF_NO_ARMOR;
+ else
+ flags |= DF_NO_ARMOR;
+ setvalue(flags);
+ return;
+ }
+ else if (f == s_infinite_ammo_box) {
+ bit = DF_INFINITE_AMMO;
+ }
+ else if (f == s_fixed_fov_box) {
+ bit = DF_FIXED_FOV;
+ }
+ else if (f == s_quad_drop_box) {
+ bit = DF_QUAD_DROP;
+ }
+
+ // =======
+ // ROGUE
+ else if (FS.Developer_searchpath(2) == 2) {
+ if (f == s_no_mines_box) {
+ bit = DF_NO_MINES;
+ }
+ else if (f == s_no_nukes_box) {
+ bit = DF_NO_NUKES;
+ }
+ else if (f == s_stack_double_box) {
+ bit = DF_NO_STACK_DOUBLE;
+ }
+ else if (f == s_no_spheres_box) {
+ bit = DF_NO_SPHERES;
+ }
+ }
+ // ROGUE
+ // =======
+
+ if (f != null) {
+ if (f.curvalue == 0)
+ flags &= ~bit;
+ else
+ flags |= bit;
+ }
+
+ Cvar.SetValue("dmflags", flags);
+
+ dmoptions_statusbar = "dmflags = " + flags;
+
+ }
+
+ //static String yes_no_names[] = { "no", "yes", 0 };
+ static String teamplay_names[] = { "disabled", "by skin", "by model", null };
+
+ static void DMOptions_MenuInit() {
+
+ int dmflags = (int) Cvar.VariableValue("dmflags");
+ int y = 0;
+
+ s_dmoptions_menu.x = (int) (viddef.width * 0.50);
+ s_dmoptions_menu.nitems = 0;
+
+ s_falls_box.type = MTYPE_SPINCONTROL;
+ s_falls_box.x = 0;
+ s_falls_box.y = y;
+ s_falls_box.name = "falling damage";
+ s_falls_box.callback = new mcallback() {
+ public void execute(Object o) {
+ DMFlagCallback(o);
+ }
+ };
+ s_falls_box.itemnames = yes_no_names;
+ s_falls_box.curvalue = (dmflags & DF_NO_FALLING) == 0 ? 1 : 0;
+
+ s_weapons_stay_box.type = MTYPE_SPINCONTROL;
+ s_weapons_stay_box.x = 0;
+ s_weapons_stay_box.y = y += 10;
+ s_weapons_stay_box.name = "weapons stay";
+ s_weapons_stay_box.callback = new mcallback() {
+ public void execute(Object o) {
+ DMFlagCallback(o);
+ }
+ };
+ s_weapons_stay_box.itemnames = yes_no_names;
+ s_weapons_stay_box.curvalue = (dmflags & DF_WEAPONS_STAY) != 0 ? 1 : 0;
+
+ s_instant_powerups_box.type = MTYPE_SPINCONTROL;
+ s_instant_powerups_box.x = 0;
+ s_instant_powerups_box.y = y += 10;
+ s_instant_powerups_box.name = "instant powerups";
+ s_instant_powerups_box.callback = new mcallback() {
+ public void execute(Object o) {
+ DMFlagCallback(o);
+ }
+ };
+ s_instant_powerups_box.itemnames = yes_no_names;
+ s_instant_powerups_box.curvalue = (dmflags & DF_INSTANT_ITEMS) != 0 ? 1 : 0;
+
+ s_powerups_box.type = MTYPE_SPINCONTROL;
+ s_powerups_box.x = 0;
+ s_powerups_box.y = y += 10;
+ s_powerups_box.name = "allow powerups";
+ s_powerups_box.callback = new mcallback() {
+ public void execute(Object o) {
+ DMFlagCallback(o);
+ }
+ };
+ s_powerups_box.itemnames = yes_no_names;
+ s_powerups_box.curvalue = (dmflags & DF_NO_ITEMS) == 0 ? 1 : 0;
+
+ s_health_box.type = MTYPE_SPINCONTROL;
+ s_health_box.x = 0;
+ s_health_box.y = y += 10;
+ s_health_box.callback = new mcallback() {
+ public void execute(Object o) {
+ DMFlagCallback(o);
+ }
+ };
+ s_health_box.name = "allow health";
+ s_health_box.itemnames = yes_no_names;
+ s_health_box.curvalue = (dmflags & DF_NO_HEALTH) == 0 ? 1 : 0;
+
+ s_armor_box.type = MTYPE_SPINCONTROL;
+ s_armor_box.x = 0;
+ s_armor_box.y = y += 10;
+ s_armor_box.name = "allow armor";
+ s_armor_box.callback = new mcallback() {
+ public void execute(Object o) {
+ DMFlagCallback(o);
+ }
+ };
+ s_armor_box.itemnames = yes_no_names;
+ s_armor_box.curvalue = (dmflags & DF_NO_ARMOR) == 0 ? 1 : 0;
+
+ s_spawn_farthest_box.type = MTYPE_SPINCONTROL;
+ s_spawn_farthest_box.x = 0;
+ s_spawn_farthest_box.y = y += 10;
+ s_spawn_farthest_box.name = "spawn farthest";
+ s_spawn_farthest_box.callback = new mcallback() {
+ public void execute(Object o) {
+ DMFlagCallback(o);
+ }
+ };
+ s_spawn_farthest_box.itemnames = yes_no_names;
+ s_spawn_farthest_box.curvalue = (dmflags & DF_SPAWN_FARTHEST) != 0 ? 1 : 0;
+
+ s_samelevel_box.type = MTYPE_SPINCONTROL;
+ s_samelevel_box.x = 0;
+ s_samelevel_box.y = y += 10;
+ s_samelevel_box.name = "same map";
+ s_samelevel_box.callback = new mcallback() {
+ public void execute(Object o) {
+ DMFlagCallback(o);
+ }
+ };
+ s_samelevel_box.itemnames = yes_no_names;
+ s_samelevel_box.curvalue = (dmflags & DF_SAME_LEVEL) != 0 ? 1 : 0;
+
+ s_force_respawn_box.type = MTYPE_SPINCONTROL;
+ s_force_respawn_box.x = 0;
+ s_force_respawn_box.y = y += 10;
+ s_force_respawn_box.name = "force respawn";
+ s_force_respawn_box.callback = new mcallback() {
+ public void execute(Object o) {
+ DMFlagCallback(o);
+ }
+ };
+ s_force_respawn_box.itemnames = yes_no_names;
+ s_force_respawn_box.curvalue = (dmflags & DF_FORCE_RESPAWN) != 0 ? 1 : 0;
+
+ s_teamplay_box.type = MTYPE_SPINCONTROL;
+ s_teamplay_box.x = 0;
+ s_teamplay_box.y = y += 10;
+ s_teamplay_box.name = "teamplay";
+ s_teamplay_box.callback = new mcallback() {
+ public void execute(Object o) {
+ DMFlagCallback(o);
+ }
+ };
+ s_teamplay_box.itemnames = teamplay_names;
+
+ s_allow_exit_box.type = MTYPE_SPINCONTROL;
+ s_allow_exit_box.x = 0;
+ s_allow_exit_box.y = y += 10;
+ s_allow_exit_box.name = "allow exit";
+ s_allow_exit_box.callback = new mcallback() {
+ public void execute(Object o) {
+ DMFlagCallback(o);
+ }
+ };
+ s_allow_exit_box.itemnames = yes_no_names;
+ s_allow_exit_box.curvalue = (dmflags & DF_ALLOW_EXIT) != 0 ? 1 : 0;
+
+ s_infinite_ammo_box.type = MTYPE_SPINCONTROL;
+ s_infinite_ammo_box.x = 0;
+ s_infinite_ammo_box.y = y += 10;
+ s_infinite_ammo_box.name = "infinite ammo";
+ s_infinite_ammo_box.callback = new mcallback() {
+ public void execute(Object o) {
+ DMFlagCallback(o);
+ }
+ };
+ s_infinite_ammo_box.itemnames = yes_no_names;
+ s_infinite_ammo_box.curvalue = (dmflags & DF_INFINITE_AMMO) != 0 ? 1 : 0;
+
+ s_fixed_fov_box.type = MTYPE_SPINCONTROL;
+ s_fixed_fov_box.x = 0;
+ s_fixed_fov_box.y = y += 10;
+ s_fixed_fov_box.name = "fixed FOV";
+ s_fixed_fov_box.callback = new mcallback() {
+ public void execute(Object o) {
+ DMFlagCallback(o);
+ }
+ };
+ s_fixed_fov_box.itemnames = yes_no_names;
+ s_fixed_fov_box.curvalue = (dmflags & DF_FIXED_FOV) != 0 ? 1 : 0;
+
+ s_quad_drop_box.type = MTYPE_SPINCONTROL;
+ s_quad_drop_box.x = 0;
+ s_quad_drop_box.y = y += 10;
+ s_quad_drop_box.name = "quad drop";
+ s_quad_drop_box.callback = new mcallback() {
+ public void execute(Object o) {
+ DMFlagCallback(o);
+ }
+ };
+ s_quad_drop_box.itemnames = yes_no_names;
+ s_quad_drop_box.curvalue = (dmflags & DF_QUAD_DROP) != 0 ? 1 : 0;
+
+ s_friendlyfire_box.type = MTYPE_SPINCONTROL;
+ s_friendlyfire_box.x = 0;
+ s_friendlyfire_box.y = y += 10;
+ s_friendlyfire_box.name = "friendly fire";
+ s_friendlyfire_box.callback = new mcallback() {
+ public void execute(Object o) {
+ DMFlagCallback(o);
+ }
+ };
+ s_friendlyfire_box.itemnames = yes_no_names;
+ s_friendlyfire_box.curvalue = (dmflags & DF_NO_FRIENDLY_FIRE) == 0 ? 1 : 0;
+
+ // ============
+ // ROGUE
+ if (FS.Developer_searchpath(2) == 2) {
+ s_no_mines_box.type = MTYPE_SPINCONTROL;
+ s_no_mines_box.x = 0;
+ s_no_mines_box.y = y += 10;
+ s_no_mines_box.name = "remove mines";
+ s_no_mines_box.callback = new mcallback() {
+ public void execute(Object o) {
+ DMFlagCallback(o);
+ }
+ };
+ s_no_mines_box.itemnames = yes_no_names;
+ s_no_mines_box.curvalue = (dmflags & DF_NO_MINES) != 0 ? 1 : 0;
+
+ s_no_nukes_box.type = MTYPE_SPINCONTROL;
+ s_no_nukes_box.x = 0;
+ s_no_nukes_box.y = y += 10;
+ s_no_nukes_box.name = "remove nukes";
+ s_no_nukes_box.callback = new mcallback() {
+ public void execute(Object o) {
+ DMFlagCallback(o);
+ }
+ };
+ s_no_nukes_box.itemnames = yes_no_names;
+ s_no_nukes_box.curvalue = (dmflags & DF_NO_NUKES) != 0 ? 1 : 0;
+
+ s_stack_double_box.type = MTYPE_SPINCONTROL;
+ s_stack_double_box.x = 0;
+ s_stack_double_box.y = y += 10;
+ s_stack_double_box.name = "2x/4x stacking off";
+ s_stack_double_box.callback = new mcallback() {
+ public void execute(Object o) {
+ DMFlagCallback(o);
+ }
+ };
+ s_stack_double_box.itemnames = yes_no_names;
+ s_stack_double_box.curvalue = (dmflags & DF_NO_STACK_DOUBLE);
+
+ s_no_spheres_box.type = MTYPE_SPINCONTROL;
+ s_no_spheres_box.x = 0;
+ s_no_spheres_box.y = y += 10;
+ s_no_spheres_box.name = "remove spheres";
+ s_no_spheres_box.callback = new mcallback() {
+ public void execute(Object o) {
+ DMFlagCallback(o);
+ }
+ };
+ s_no_spheres_box.itemnames = yes_no_names;
+ s_no_spheres_box.curvalue = (dmflags & DF_NO_SPHERES) != 0 ? 1 : 0;
+
+ }
+ // ROGUE
+ // ============
+
+ Menu_AddItem(s_dmoptions_menu, s_falls_box);
+ Menu_AddItem(s_dmoptions_menu, s_weapons_stay_box);
+ Menu_AddItem(s_dmoptions_menu, s_instant_powerups_box);
+ Menu_AddItem(s_dmoptions_menu, s_powerups_box);
+ Menu_AddItem(s_dmoptions_menu, s_health_box);
+ Menu_AddItem(s_dmoptions_menu, s_armor_box);
+ Menu_AddItem(s_dmoptions_menu, s_spawn_farthest_box);
+ Menu_AddItem(s_dmoptions_menu, s_samelevel_box);
+ Menu_AddItem(s_dmoptions_menu, s_force_respawn_box);
+ Menu_AddItem(s_dmoptions_menu, s_teamplay_box);
+ Menu_AddItem(s_dmoptions_menu, s_allow_exit_box);
+ Menu_AddItem(s_dmoptions_menu, s_infinite_ammo_box);
+ Menu_AddItem(s_dmoptions_menu, s_fixed_fov_box);
+ Menu_AddItem(s_dmoptions_menu, s_quad_drop_box);
+ Menu_AddItem(s_dmoptions_menu, s_friendlyfire_box);
+
+ // =======
+ // ROGUE
+ if (FS.Developer_searchpath(2) == 2) {
+ Menu_AddItem(s_dmoptions_menu, s_no_mines_box);
+ Menu_AddItem(s_dmoptions_menu, s_no_nukes_box);
+ Menu_AddItem(s_dmoptions_menu, s_stack_double_box);
+ Menu_AddItem(s_dmoptions_menu, s_no_spheres_box);
+ }
+ // ROGUE
+ // =======
+
+ Menu_Center(s_dmoptions_menu);
+
+ // set the original dmflags statusbar
+ DMFlagCallback(null);
+ Menu_SetStatusBar(s_dmoptions_menu, dmoptions_statusbar);
+ }
+
+ static void DMOptions_MenuDraw() {
+ Menu_Draw(s_dmoptions_menu);
+ }
+
+ static String DMOptions_MenuKey(int key) {
+ return Default_MenuKey(s_dmoptions_menu, key);
+ }
+
+ static xcommand_t Menu_DMOptions = new xcommand_t() {
+ public void execute() {
+ Menu_DMOptions_f();
+ }
+ };
+ static void Menu_DMOptions_f() {
+ DMOptions_MenuInit();
+ PushMenu(new xcommand_t() {
+ public void execute() {
+ DMOptions_MenuDraw();
+ }
+ }, new keyfunc_t() {
+ public String execute(int key) {
+ return DMOptions_MenuKey(key);
+ }
+ });
+ }
+
+ /*
+ =============================================================================
+
+ DOWNLOADOPTIONS BOOK MENU
+
+ =============================================================================
+ */
+ static menuframework_s s_downloadoptions_menu = new menuframework_s();
+
+ static menuseparator_s s_download_title = new menuseparator_s();
+ static menulist_s s_allow_download_box = new menulist_s();
+ static menulist_s s_allow_download_maps_box = new menulist_s();
+ static menulist_s s_allow_download_models_box = new menulist_s();
+ static menulist_s s_allow_download_players_box = new menulist_s();
+ static menulist_s s_allow_download_sounds_box = new menulist_s();
+
+ static void DownloadCallback(Object self) {
+ menulist_s f = (menulist_s) self;
+
+ if (f == s_allow_download_box) {
+ Cvar.SetValue("allow_download", f.curvalue);
+ }
+
+ else if (f == s_allow_download_maps_box) {
+ Cvar.SetValue("allow_download_maps", f.curvalue);
+ }
+
+ else if (f == s_allow_download_models_box) {
+ Cvar.SetValue("allow_download_models", f.curvalue);
+ }
+
+ else if (f == s_allow_download_players_box) {
+ Cvar.SetValue("allow_download_players", f.curvalue);
+ }
+
+ else if (f == s_allow_download_sounds_box) {
+ Cvar.SetValue("allow_download_sounds", f.curvalue);
+ }
+ }
+
+ static String yes_no_names[] = { "no", "yes", null };
+ static void DownloadOptions_MenuInit() {
+
+ int y = 0;
+
+ s_downloadoptions_menu.x = (int) (viddef.width * 0.50);
+ s_downloadoptions_menu.nitems = 0;
+
+ s_download_title.type = MTYPE_SEPARATOR;
+ s_download_title.name = "Download Options";
+ s_download_title.x = 48;
+ s_download_title.y = y;
+
+ s_allow_download_box.type = MTYPE_SPINCONTROL;
+ s_allow_download_box.x = 0;
+ s_allow_download_box.y = y += 20;
+ s_allow_download_box.name = "allow downloading";
+ s_allow_download_box.callback = new mcallback() {
+ public void execute(Object o) {
+ DownloadCallback(o);
+ }
+ };
+ s_allow_download_box.itemnames = yes_no_names;
+ s_allow_download_box.curvalue = (Cvar.VariableValue("allow_download") != 0) ? 1 : 0;
+
+ s_allow_download_maps_box.type = MTYPE_SPINCONTROL;
+ s_allow_download_maps_box.x = 0;
+ s_allow_download_maps_box.y = y += 20;
+ s_allow_download_maps_box.name = "maps";
+ s_allow_download_maps_box.callback = new mcallback() {
+ public void execute(Object o) {
+ DownloadCallback(o);
+ }
+ };
+ s_allow_download_maps_box.itemnames = yes_no_names;
+ s_allow_download_maps_box.curvalue = (Cvar.VariableValue("allow_download_maps") != 0) ? 1 : 0;
+
+ s_allow_download_players_box.type = MTYPE_SPINCONTROL;
+ s_allow_download_players_box.x = 0;
+ s_allow_download_players_box.y = y += 10;
+ s_allow_download_players_box.name = "player models/skins";
+ s_allow_download_players_box.callback = new mcallback() {
+ public void execute(Object o) {
+ DownloadCallback(o);
+ }
+ };
+ s_allow_download_players_box.itemnames = yes_no_names;
+ s_allow_download_players_box.curvalue = (Cvar.VariableValue("allow_download_players") != 0) ? 1 : 0;
+
+ s_allow_download_models_box.type = MTYPE_SPINCONTROL;
+ s_allow_download_models_box.x = 0;
+ s_allow_download_models_box.y = y += 10;
+ s_allow_download_models_box.name = "models";
+ s_allow_download_models_box.callback = new mcallback() {
+ public void execute(Object o) {
+ DownloadCallback(o);
+ }
+ };
+ s_allow_download_models_box.itemnames = yes_no_names;
+ s_allow_download_models_box.curvalue = (Cvar.VariableValue("allow_download_models") != 0) ? 1 : 0;
+
+ s_allow_download_sounds_box.type = MTYPE_SPINCONTROL;
+ s_allow_download_sounds_box.x = 0;
+ s_allow_download_sounds_box.y = y += 10;
+ s_allow_download_sounds_box.name = "sounds";
+ s_allow_download_sounds_box.callback = new mcallback() {
+ public void execute(Object o) {
+ DownloadCallback(o);
+ }
+ };
+ s_allow_download_sounds_box.itemnames = yes_no_names;
+ s_allow_download_sounds_box.curvalue = (Cvar.VariableValue("allow_download_sounds") != 0) ? 1 : 0;
+
+ Menu_AddItem(s_downloadoptions_menu, s_download_title);
+ Menu_AddItem(s_downloadoptions_menu, s_allow_download_box);
+ Menu_AddItem(s_downloadoptions_menu, s_allow_download_maps_box);
+ Menu_AddItem(s_downloadoptions_menu, s_allow_download_players_box);
+ Menu_AddItem(s_downloadoptions_menu, s_allow_download_models_box);
+ Menu_AddItem(s_downloadoptions_menu, s_allow_download_sounds_box);
+
+ Menu_Center(s_downloadoptions_menu);
+
+ // skip over title
+ if (s_downloadoptions_menu.cursor == 0)
+ s_downloadoptions_menu.cursor = 1;
+ }
+
+ static void DownloadOptions_MenuDraw() {
+ Menu_Draw(s_downloadoptions_menu);
+ }
+
+ static String DownloadOptions_MenuKey(int key) {
+ return Default_MenuKey(s_downloadoptions_menu, key);
+ }
+
+ static xcommand_t Menu_DownloadOptions = new xcommand_t() {
+ public void execute() {
+ Menu_DownloadOptions_f();
+ }
+ };
+ static void Menu_DownloadOptions_f() {
+ DownloadOptions_MenuInit();
+ PushMenu(new xcommand_t() {
+ public void execute() {
+ DownloadOptions_MenuDraw();
+ }
+ }, new keyfunc_t() {
+ public String execute(int key) {
+ return DownloadOptions_MenuKey(key);
+ }
+ });
+ }
+ /*
+ =============================================================================
+
+ ADDRESS BOOK MENU
+
+ =============================================================================
+ */
+
+ static menuframework_s s_addressbook_menu = new menuframework_s();
+ static menufield_s s_addressbook_fields[] = new menufield_s[NUM_ADDRESSBOOK_ENTRIES];
+ static {
+ for (int n = 0; n < NUM_ADDRESSBOOK_ENTRIES; n++)
+ s_addressbook_fields[n] = new menufield_s();
+ }
+
+ static void AddressBook_MenuInit() {
+ int i;
+
+ s_addressbook_menu.x = viddef.width / 2 - 142;
+ s_addressbook_menu.y = viddef.height / 2 - 58;
+ s_addressbook_menu.nitems = 0;
+
+ for (i = 0; i < NUM_ADDRESSBOOK_ENTRIES; i++) {
+ cvar_t adr;
+ //char buffer[20];
+ String buffer;
+
+ //Com_sprintf(buffer, sizeof(buffer), "adr%d", i);
+ buffer = "adr" + i;
+
+ adr = Cvar.Get(buffer, "", CVAR_ARCHIVE);
+
+ s_addressbook_fields[i].type = MTYPE_FIELD;
+ s_addressbook_fields[i].name = null;
+ s_addressbook_fields[i].callback = null;
+ s_addressbook_fields[i].x = 0;
+ s_addressbook_fields[i].y = i * 18 + 0;
+ s_addressbook_fields[i].localdata[0] = i;
+ s_addressbook_fields[i].cursor = 0;
+ s_addressbook_fields[i].length = 60;
+ s_addressbook_fields[i].visible_length = 30;
+
+ s_addressbook_fields[i].buffer = new StringBuffer(adr.string);
+
+ Menu_AddItem(s_addressbook_menu, s_addressbook_fields[i]);
+ }
+ }
+
+ static keyfunc_t AddressBook_MenuKey = new keyfunc_t() {
+ public String execute(int key) {
+ return AddressBook_MenuKey_f(key);
+ }
+ };
+
+ static String AddressBook_MenuKey_f(int key) {
+ if (key == K_ESCAPE) {
+ int index;
+ //char buffer[20];
+ String buffer;
+
+ for (index = 0; index < NUM_ADDRESSBOOK_ENTRIES; index++) {
+ buffer = "adr" + index;
+ //Com_sprintf(buffer, sizeof(buffer), "adr%d", index);
+ Cvar.Set(buffer, s_addressbook_fields[index].buffer.toString());
+ }
+ }
+ return Default_MenuKey(s_addressbook_menu, key);
+ }
+
+ static xcommand_t AddressBook_MenuDraw = new xcommand_t() {
+ public void execute() {
+ AddressBook_MenuDraw_f();
+ }
+ };
+ static void AddressBook_MenuDraw_f() {
+ Banner("m_banner_addressbook");
+ Menu_Draw(s_addressbook_menu);
+ }
+
+ static xcommand_t Menu_AddressBook = new xcommand_t() {
+ public void execute() {
+ Menu_AddressBook_f();
+ }
+ };
+ static void Menu_AddressBook_f() {
+ AddressBook_MenuInit();
+ PushMenu(new xcommand_t() {
+ public void execute() {
+ AddressBook_MenuDraw_f();
+ }
+ }, new keyfunc_t() {
+ public String execute(int key) {
+ return AddressBook_MenuKey_f(key);
+ }
+ });
+ }
+ /*
+ =============================================================================
+
+ PLAYER CONFIG MENU
+
+ =============================================================================
+ */
+ static menuframework_s s_player_config_menu = new menuframework_s();
+ static menufield_s s_player_name_field = new menufield_s();
+ static menulist_s s_player_model_box = new menulist_s();
+ static menulist_s s_player_skin_box = new menulist_s();
+ static menulist_s s_player_handedness_box = new menulist_s();
+ static menulist_s s_player_rate_box = new menulist_s();
+ static menuseparator_s s_player_skin_title = new menuseparator_s();
+ static menuseparator_s s_player_model_title = new menuseparator_s();
+ static menuseparator_s s_player_hand_title = new menuseparator_s();
+ static menuseparator_s s_player_rate_title = new menuseparator_s();
+ static menuaction_s s_player_download_action = new menuaction_s();
+
+ static class playermodelinfo_s {
+ int nskins;
+ String skindisplaynames[];
+ //char displayname[MAX_DISPLAYNAME];
+ String displayname;
+ //char directory[MAX_QPATH];
+ String directory;
+ };
+
+ static playermodelinfo_s s_pmi[] = new playermodelinfo_s[MAX_PLAYERMODELS];
+ static String s_pmnames[] = new String[MAX_PLAYERMODELS];
+ static int s_numplayermodels;
+
+ static int rate_tbl[] = { 2500, 3200, 5000, 10000, 25000, 0 };
+ static String rate_names[] = { "28.8 Modem", "33.6 Modem", "Single ISDN", "Dual ISDN/Cable", "T1/LAN", "User defined", null };
+
+ static void DownloadOptionsFunc(Object self) {
+ Menu_DownloadOptions_f();
+ }
+
+ static void HandednessCallback(Object unused) {
+ Cvar.SetValue("hand", s_player_handedness_box.curvalue);
+ }
+
+ static void RateCallback(Object unused) {
+ if (s_player_rate_box.curvalue != rate_tbl.length - 1) //sizeof(rate_tbl) / sizeof(* rate_tbl) - 1)
+ Cvar.SetValue("rate", rate_tbl[s_player_rate_box.curvalue]);
+ }
+
+ static void ModelCallback(Object unused) {
+ s_player_skin_box.itemnames = s_pmi[s_player_model_box.curvalue].skindisplaynames;
+ s_player_skin_box.curvalue = 0;
+ }
+
+ static boolean IconOfSkinExists(String skin, String pcxfiles[], int npcxfiles) {
+ int i;
+ //char scratch[1024];
+ String scratch;
+
+ //strcpy(scratch, skin);
+ scratch = skin;
+ int pos = scratch.lastIndexOf('.');
+ if (pos != -1)
+ scratch = scratch.substring(0, pos) + "_i.pcx";
+
+ else
+ scratch += "_i.pcx";
+
+ for (i = 0; i < npcxfiles; i++) {
+ if (strcmp(pcxfiles[i], scratch) == 0)
+ return true;
+ }
+
+ return false;
+ }
+
+ static boolean PlayerConfig_ScanDirectories() {
+ //char findname[1024];
+ String findname;
+ //char scratch[1024];
+ String scratch;
+
+ int ndirs = 0, npms = 0;
+ int a, b, c;
+ String dirnames[];
+
+ String path = null;
+
+ int i;
+
+ //extern String * FS_ListFiles(String , int *, unsigned, unsigned);
+
+ s_numplayermodels = 0;
+
+ /*
+ ** get a list of directories
+ */
+ do {
+ path = FS.NextPath(path);
+ findname = path + "/players/*.*";
+
+ if ((dirnames = FS.ListFiles(findname, 0, SFF_SUBDIR)) != null) {
+ ndirs = dirnames.length;
+ break;
+ }
+ }
+ while (path != null);
+
+ if (dirnames == null)
+ return false;
+
+ /*
+ ** go through the subdirectories
+ */
+ npms = ndirs;
+ if (npms > MAX_PLAYERMODELS)
+ npms = MAX_PLAYERMODELS;
+
+ for (i = 0; i < npms; i++) {
+ int k, s;
+ //String a, b, c;
+ String pcxnames[];
+ String skinnames[];
+ int npcxfiles;
+ int nskins = 0;
+
+ if (dirnames[i] == null)
+ continue;
+
+ // verify the existence of tris.md2
+ scratch = dirnames[i];
+ scratch += "/tris.md2";
+ if (Sys.FindFirst(scratch, 0, SFF_SUBDIR | SFF_HIDDEN | SFF_SYSTEM) == null) {
+ //free(dirnames[i]);
+ dirnames[i] = null;
+ Sys.FindClose();
+ continue;
+ }
+ Sys.FindClose();
+
+ // verify the existence of at least one pcx skin
+ scratch = dirnames[i] + "/*.pcx";
+ pcxnames = FS.ListFiles(scratch, 0, 0);
+ npcxfiles = pcxnames.length;
+
+ if (pcxnames == null) {
+
+ dirnames[i] = null;
+ continue;
+ }
+
+ // count valid skins, which consist of a skin with a matching "_i" icon
+ for (k = 0; k < npcxfiles - 1; k++) {
+ if (!pcxnames[k].endsWith("_i.pcx")) {
+ //if (!strstr(pcxnames[k], "_i.pcx")) {
+ if (IconOfSkinExists(pcxnames[k], pcxnames, npcxfiles - 1)) {
+ nskins++;
+ }
+ }
+ }
+ if (nskins == 0)
+ continue;
+
+ skinnames = new String[nskins + 1]; //malloc(sizeof(String) * (nskins + 1));
+ //memset(skinnames, 0, sizeof(String) * (nskins + 1));
+
+ // copy the valid skins
+ for (s = 0, k = 0; k < npcxfiles - 1; k++) {
+
+ if (!strstr(pcxnames[k], "_i.pcx")) {
+ if (IconOfSkinExists(pcxnames[k], pcxnames, npcxfiles - 1)) {
+ a = pcxnames[k].lastIndexOf('/');
+ b = pcxnames[k].lastIndexOf('\\');
+
+ if (a > b)
+ c = a;
+ else
+ c = b;
+
+ scratch = pcxnames[k].substring(c + 1, pcxnames[k].length());
+ int pos = scratch.lastIndexOf('.');
+ if (pos != -1)
+ scratch = scratch.substring(0, pos);
+
+ skinnames[s] = scratch;
+ s++;
+ }
+ }
+ }
+
+ // at this point we have a valid player model
+ if (s_pmi[s_numplayermodels] == null)
+ s_pmi[s_numplayermodels] = new playermodelinfo_s();
+
+ s_pmi[s_numplayermodels].nskins = nskins;
+ s_pmi[s_numplayermodels].skindisplaynames = skinnames;
+
+ // make short name for the model
+ a = dirnames[i].lastIndexOf('/');
+ b = dirnames[i].lastIndexOf('\\');
+
+ if (a > b)
+ c = a;
+ else
+ c = b;
+
+ s_pmi[s_numplayermodels].displayname = dirnames[i].substring(c + 1);
+ s_pmi[s_numplayermodels].directory = dirnames[i].substring(c + 1);
+
+ s_numplayermodels++;
+ }
+
+ return true;
+
+ }
+
+ static int pmicmpfnc(Object _a, Object _b) {
+ playermodelinfo_s a = (playermodelinfo_s) _a;
+ playermodelinfo_s b = (playermodelinfo_s) _b;
+
+ /*
+ ** sort by male, female, then alphabetical
+ */
+ if (strcmp(a.directory, "male") == 0)
+ return -1;
+ else if (strcmp(b.directory, "male") == 0)
+ return 1;
+
+ if (strcmp(a.directory, "female") == 0)
+ return -1;
+ else if (strcmp(b.directory, "female") == 0)
+ return 1;
+
+ return strcmp(a.directory, b.directory);
+ }
+
+ static String handedness[] = { "right", "left", "center", null };
+
+ static boolean PlayerConfig_MenuInit() {
+ /*
+ extern cvar_t * name;
+ extern cvar_t * team;
+ extern cvar_t * skin;
+ */
+ //har currentdirectory[1024];
+ String currentdirectory;
+ //char currentskin[1024];
+ String currentskin;
+
+ int i = 0;
+
+ int currentdirectoryindex = 0;
+ int currentskinindex = 0;
+
+ cvar_t hand = Cvar.Get("hand", "0", CVAR_USERINFO | CVAR_ARCHIVE);
+
+ PlayerConfig_ScanDirectories();
+
+ if (s_numplayermodels == 0)
+ return false;
+
+ if (hand.value < 0 || hand.value > 2)
+ Cvar.SetValue("hand", 0);
+
+ currentdirectory = skin.string;
+
+ if (currentdirectory.lastIndexOf('/') != -1) {
+ currentskin = rightFrom(currentdirectory, '/');
+ currentdirectory = leftFrom(currentdirectory, '/');
+ }
+ else if (currentdirectory.lastIndexOf('\\') != -1) {
+ currentskin = rightFrom(currentdirectory, '\\');
+ currentdirectory = leftFrom(currentdirectory, '\\');
+ }
+ else {
+ currentdirectory = "male";
+ currentskin = "grunt";
+ }
+
+ //qsort(s_pmi, s_numplayermodels, sizeof(s_pmi[0]), pmicmpfnc);
+ Arrays.sort(s_pmi, 0, s_numplayermodels, new Comparator() {
+ public int compare(Object o1, Object o2) {
+ return pmicmpfnc(o1, o2);
+ }
+ });
+
+ //memset(s_pmnames, 0, sizeof(s_pmnames));
+ s_pmnames = new String[MAX_PLAYERMODELS];
+
+ for (i = 0; i < s_numplayermodels; i++) {
+ s_pmnames[i] = s_pmi[i].displayname;
+ if (Q_stricmp(s_pmi[i].directory, currentdirectory) == 0) {
+ int j;
+
+ currentdirectoryindex = i;
+
+ for (j = 0; j < s_pmi[i].nskins; j++) {
+ if (Q_stricmp(s_pmi[i].skindisplaynames[j], currentskin) == 0) {
+ currentskinindex = j;
+ break;
+ }
+ }
+ }
+ }
+
+ s_player_config_menu.x = viddef.width / 2 - 95;
+ s_player_config_menu.y = viddef.height / 2 - 97;
+ s_player_config_menu.nitems = 0;
+
+ s_player_name_field.type = MTYPE_FIELD;
+ s_player_name_field.name = "name";
+ s_player_name_field.callback = null;
+ s_player_name_field.x = 0;
+ s_player_name_field.y = 0;
+ s_player_name_field.length = 20;
+ s_player_name_field.visible_length = 20;
+ s_player_name_field.buffer = new StringBuffer(name.string);
+ s_player_name_field.cursor = strlen(name.string);
+
+ s_player_model_title.type = MTYPE_SEPARATOR;
+ s_player_model_title.name = "model";
+ s_player_model_title.x = -8;
+ s_player_model_title.y = 60;
+
+ s_player_model_box.type = MTYPE_SPINCONTROL;
+ s_player_model_box.x = -56;
+ s_player_model_box.y = 70;
+ s_player_model_box.callback = new mcallback() {
+ public void execute(Object o) {
+ ModelCallback(o);
+ }
+ };
+ s_player_model_box.cursor_offset = -48;
+ s_player_model_box.curvalue = currentdirectoryindex;
+ s_player_model_box.itemnames = s_pmnames;
+
+ s_player_skin_title.type = MTYPE_SEPARATOR;
+ s_player_skin_title.name = "skin";
+ s_player_skin_title.x = -16;
+ s_player_skin_title.y = 84;
+
+ s_player_skin_box.type = MTYPE_SPINCONTROL;
+ s_player_skin_box.x = -56;
+ s_player_skin_box.y = 94;
+ s_player_skin_box.name = null;
+ s_player_skin_box.callback = null;
+ s_player_skin_box.cursor_offset = -48;
+ s_player_skin_box.curvalue = currentskinindex;
+ s_player_skin_box.itemnames = s_pmi[currentdirectoryindex].skindisplaynames;
+
+ s_player_hand_title.type = MTYPE_SEPARATOR;
+ s_player_hand_title.name = "handedness";
+ s_player_hand_title.x = 32;
+ s_player_hand_title.y = 108;
+
+ s_player_handedness_box.type = MTYPE_SPINCONTROL;
+ s_player_handedness_box.x = -56;
+ s_player_handedness_box.y = 118;
+ s_player_handedness_box.name = null;
+ s_player_handedness_box.cursor_offset = -48;
+ s_player_handedness_box.callback = new mcallback() {
+ public void execute(Object o) {
+ HandednessCallback(o);
+ }
+ };
+ s_player_handedness_box.curvalue = (int) Cvar.VariableValue("hand");
+ s_player_handedness_box.itemnames = handedness;
+
+ for (i = 0; i < rate_tbl.length - 1; i++)
+ if (Cvar.VariableValue("rate") == rate_tbl[i])
+ break;
+
+ s_player_rate_title.type = MTYPE_SEPARATOR;
+ s_player_rate_title.name = "connect speed";
+ s_player_rate_title.x = 56;
+ s_player_rate_title.y = 156;
+
+ s_player_rate_box.type = MTYPE_SPINCONTROL;
+ s_player_rate_box.x = -56;
+ s_player_rate_box.y = 166;
+ s_player_rate_box.name = null;
+ s_player_rate_box.cursor_offset = -48;
+ s_player_rate_box.callback = new mcallback() {
+ public void execute(Object o) {
+ RateCallback(o);
+ }
+ };
+ s_player_rate_box.curvalue = i;
+ s_player_rate_box.itemnames = rate_names;
+
+ s_player_download_action.type = MTYPE_ACTION;
+ s_player_download_action.name = "download options";
+ s_player_download_action.flags = QMF_LEFT_JUSTIFY;
+ s_player_download_action.x = -24;
+ s_player_download_action.y = 186;
+ s_player_download_action.statusbar = null;
+ s_player_download_action.callback = new mcallback() {
+ public void execute(Object o) {
+ DownloadOptionsFunc(o);
+ }
+ };
+
+ Menu_AddItem(s_player_config_menu, s_player_name_field);
+ Menu_AddItem(s_player_config_menu, s_player_model_title);
+ Menu_AddItem(s_player_config_menu, s_player_model_box);
+ if (s_player_skin_box.itemnames != null) {
+ Menu_AddItem(s_player_config_menu, s_player_skin_title);
+ Menu_AddItem(s_player_config_menu, s_player_skin_box);
+ }
+ Menu_AddItem(s_player_config_menu, s_player_hand_title);
+ Menu_AddItem(s_player_config_menu, s_player_handedness_box);
+ Menu_AddItem(s_player_config_menu, s_player_rate_title);
+ Menu_AddItem(s_player_config_menu, s_player_rate_box);
+ Menu_AddItem(s_player_config_menu, s_player_download_action);
+
+ return true;
+ }
+
+ static int yaw;
+
+ static void PlayerConfig_MenuDraw() {
+
+ refdef_t refdef = new refdef_t();
+ //char scratch[MAX_QPATH];
+ String scratch;
+
+ //memset(refdef, 0, sizeof(refdef));
+
+ refdef.x = viddef.width / 2;
+ refdef.y = viddef.height / 2 - 72;
+ refdef.width = 144;
+ refdef.height = 168;
+ refdef.fov_x = 40;
+ refdef.fov_y = Math3D.CalcFov(refdef.fov_x, refdef.width, refdef.height);
+ refdef.time = cls.realtime * 0.001f;
+
+ if (s_pmi[s_player_model_box.curvalue].skindisplaynames != null) {
+
+ int maxframe = 29;
+ entity_t entity = new entity_t();
+
+ //memset(entity, 0, sizeof(entity));
+
+ scratch = "players/" + s_pmi[s_player_model_box.curvalue].directory + "/tris.md2";
+
+ entity.model = re.RegisterModel(scratch);
+
+ scratch =
+ "players/"
+ + s_pmi[s_player_model_box.curvalue].directory
+ + "/"
+ + s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue]
+ + ".pcx";
+
+ entity.skin = re.RegisterSkin(scratch);
+ entity.flags = RF_FULLBRIGHT;
+ entity.origin[0] = 80;
+ entity.origin[1] = 0;
+ entity.origin[2] = 0;
+ VectorCopy(entity.origin, entity.oldorigin);
+ entity.frame = 0;
+ entity.oldframe = 0;
+ entity.backlerp = 0.0f;
+ entity.angles[1] = yaw++;
+ if (++yaw > 360)
+ yaw -= 360;
+
+ refdef.areabits = null;
+ refdef.num_entities = 1;
+ refdef.entities = new entity_t[] { entity };
+ refdef.lightstyles = null;
+ refdef.rdflags = RDF_NOWORLDMODEL;
+
+ Menu_Draw(s_player_config_menu);
+
+ DrawTextBox(
+ (int) ((refdef.x) * (320.0F / viddef.width) - 8),
+ (int) ((viddef.height / 2) * (240.0F / viddef.height) - 77),
+ refdef.width / 8,
+ refdef.height / 8);
+ refdef.height += 4;
+
+ re.RenderFrame(refdef);
+
+ scratch =
+ "/players/"
+ + s_pmi[s_player_model_box.curvalue].directory
+ + "/"
+ + s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue]
+ + "_i.pcx";
+
+ re.DrawPic(s_player_config_menu.x - 40, refdef.y, scratch);
+ }
+ }
+
+ static String PlayerConfig_MenuKey(int key) {
+ int i;
+
+ if (key == K_ESCAPE) {
+ //char scratch[1024];
+ String scratch;
+
+ Cvar.Set("name", s_player_name_field.buffer.toString());
+
+ scratch =
+ s_pmi[s_player_model_box.curvalue].directory
+ + "/"
+ + s_pmi[s_player_model_box.curvalue].skindisplaynames[s_player_skin_box.curvalue];
+
+ Cvar.Set("skin", scratch);
+
+ for (i = 0; i < s_numplayermodels; i++) {
+ int j;
+
+ for (j = 0; j < s_pmi[i].nskins; j++) {
+ if (s_pmi[i].skindisplaynames[j] != null)
+ s_pmi[i].skindisplaynames[j] = null;
+ }
+ s_pmi[i].skindisplaynames = null;
+ s_pmi[i].nskins = 0;
+ }
+ }
+ return Default_MenuKey(s_player_config_menu, key);
+ }
+
+ static xcommand_t Menu_PlayerConfig = new xcommand_t() {
+ public void execute() {
+ Menu_PlayerConfig_f();
+ }
+ };
+ static void Menu_PlayerConfig_f() {
+ if (!PlayerConfig_MenuInit()) {
+ Menu_SetStatusBar(s_multiplayer_menu, "No valid player models found");
+ return;
+ }
+ Menu_SetStatusBar(s_multiplayer_menu, null);
+ PushMenu(new xcommand_t() {
+ public void execute() {
+ PlayerConfig_MenuDraw();
+ }
+ }, new keyfunc_t() {
+ public String execute(int key) {
+ return PlayerConfig_MenuKey(key);
+ }
+ });
+ }
+
+ /*
+ =======================================================================
+
+ QUIT MENU
+
+ =======================================================================
+ */
+
+ static String Quit_Key(int key) {
+ switch (key) {
+ case K_ESCAPE :
+ case 'n' :
+ case 'N' :
+ PopMenu();
+ break;
+
+ case 'Y' :
+ case 'y' :
+ cls.key_dest = key_console;
+ CL.Quit_f.execute();
+ break;
+
+ default :
+ break;
+ }
+
+ return null;
+
+ }
+
+ static void Quit_Draw() {
+ int w, h;
+ Dimension d = new Dimension();
+ re.DrawGetPicSize(d, "quit");
+ w = d.width;
+ h = d.height;
+ re.DrawPic((viddef.width - w) / 2, (viddef.height - h) / 2, "quit");
+ }
+
+ static xcommand_t Menu_Quit = new xcommand_t() {
+ public void execute() {
+ Menu_Quit_f();
+ }
+ };
+
+ static void Menu_Quit_f() {
+ PushMenu(new xcommand_t() {
+ public void execute() {
+ Quit_Draw();
+ }
+ }, new keyfunc_t() {
+ public String execute(int key) {
+ return Quit_Key(key);
+ }
+ });
+ }
+
+ // =============================================================================
+ /* Menu Subsystem */
+
+ /**
+ * Init
+ */
+ public static void Init() {
+ Cmd.AddCommand("menu_main", Menu_Main);
+ Cmd.AddCommand("menu_game", Menu_Game);
+ Cmd.AddCommand("menu_loadgame", Menu_LoadGame);
+ Cmd.AddCommand("menu_savegame", Menu_SaveGame);
+ Cmd.AddCommand("menu_joinserver", Menu_JoinServer);
+ Cmd.AddCommand("menu_addressbook", Menu_AddressBook);
+ Cmd.AddCommand("menu_startserver", Menu_StartServer);
+ Cmd.AddCommand("menu_dmoptions", Menu_DMOptions);
+ Cmd.AddCommand("menu_playerconfig", Menu_PlayerConfig);
+ Cmd.AddCommand("menu_downloadoptions", Menu_DownloadOptions);
+ Cmd.AddCommand("menu_credits", Menu_Credits);
+ Cmd.AddCommand("menu_multiplayer", Menu_Multiplayer);
+ Cmd.AddCommand("menu_video", Menu_Video);
+ Cmd.AddCommand("menu_options", Menu_Options);
+ Cmd.AddCommand("menu_keys", Menu_Keys);
+ Cmd.AddCommand("menu_quit", Menu_Quit);
+
+ for (int i = 0; i < m_layers.length; i++) {
+ m_layers[i] = new menulayer_t();
+ }
+ }
+
+ /*
+ =================
+ Draw
+ =================
+ */
+ static void Draw() {
+ if (cls.key_dest != key_menu)
+ return;
+
+ // repaint everything next frame
+ SCR.DirtyScreen();
+
+ // dim everything behind it down
+ if (cl.cinematictime > 0)
+ re.DrawFill(0, 0, viddef.width, viddef.height, 0);
+ else
+ re.DrawFadeScreen();
+
+ m_drawfunc.execute();
+
+ // delay playing the enter sound until after the
+ // menu has been drawn, to avoid delay while
+ // caching images
+ if (m_entersound) {
+ S.StartLocalSound(menu_in_sound);
+ m_entersound = false;
+ }
+ }
+
+ /*
+ =================
+ Keydown
+ =================
+ */
+ static void Keydown(int key) {
+ String s;
+
+ if (m_keyfunc != null)
+ if ((s = m_keyfunc.execute(key)) != null)
+ S.StartLocalSound(s);
+ }
+
+ public static void Action_DoEnter(menuaction_s a) {
+ if (a.callback != null)
+ a.callback.execute(a);
+ }
+
+ public static void Action_Draw(menuaction_s a) {
+ if ((a.flags & QMF_LEFT_JUSTIFY) != 0) {
+ if ((a.flags & QMF_GRAYED) != 0)
+ Menu_DrawStringDark(a.x + a.parent.x + LCOLUMN_OFFSET, a.y + a.parent.y, a.name);
+ else
+ Menu_DrawString(a.x + a.parent.x + LCOLUMN_OFFSET, a.y + a.parent.y, a.name);
+ }
+ else {
+ if ((a.flags & QMF_GRAYED) != 0)
+ Menu_DrawStringR2LDark(a.x + a.parent.x + LCOLUMN_OFFSET, a.y + a.parent.y, a.name);
+ else
+ Menu_DrawStringR2L(a.x + a.parent.x + LCOLUMN_OFFSET, a.y + a.parent.y, a.name);
+ }
+ if (a.ownerdraw != null)
+ a.ownerdraw.execute(a);
+ }
+
+ public static boolean Field_DoEnter(menufield_s f) {
+ if (f.callback != null) {
+ f.callback.execute(f);
+ return true;
+ }
+ return false;
+ }
+
+ public static void Field_Draw(menufield_s f) {
+ int i;
+ String tempbuffer;
+ //[128] = "";
+
+ if (f.name != null)
+ Menu_DrawStringR2LDark(f.x + f.parent.x + LCOLUMN_OFFSET, f.y + f.parent.y, f.name);
+
+ //strncpy(tempbuffer, f.buffer + f.visible_offset, f.visible_length);
+ String s = f.buffer.toString();
+ tempbuffer = s.substring(f.visible_offset, s.length());
+ re.DrawChar(f.x + f.parent.x + 16, f.y + f.parent.y - 4, 18);
+ re.DrawChar(f.x + f.parent.x + 16, f.y + f.parent.y + 4, 24);
+
+ re.DrawChar(f.x + f.parent.x + 24 + f.visible_length * 8, f.y + f.parent.y - 4, 20);
+ re.DrawChar(f.x + f.parent.x + 24 + f.visible_length * 8, f.y + f.parent.y + 4, 26);
+
+ for (i = 0; i < f.visible_length; i++) {
+ re.DrawChar(f.x + f.parent.x + 24 + i * 8, f.y + f.parent.y - 4, 19);
+ re.DrawChar(f.x + f.parent.x + 24 + i * 8, f.y + f.parent.y + 4, 25);
+ }
+
+ Menu_DrawString(f.x + f.parent.x + 24, f.y + f.parent.y, tempbuffer);
+
+ if (Menu_ItemAtCursor(f.parent) == f) {
+ int offset;
+
+ if (f.visible_offset != 0)
+ offset = f.visible_length;
+ else
+ offset = f.cursor;
+
+ if ((((int) (Sys.Milliseconds() / 250)) & 1) != 0) {
+ re.DrawChar(f.x + f.parent.x + (offset + 2) * 8 + 8, f.y + f.parent.y, 11);
+ }
+ else {
+ re.DrawChar(f.x + f.parent.x + (offset + 2) * 8 + 8, f.y + f.parent.y, ' ');
+ }
+ }
+ }
+
+ public static boolean Field_Key(menufield_s f, int k) {
+ char key = (char) k;
+
+ switch (key) {
+ case K_KP_SLASH :
+ key = '/';
+ break;
+ case K_KP_MINUS :
+ key = '-';
+ break;
+ case K_KP_PLUS :
+ key = '+';
+ break;
+ case K_KP_HOME :
+ key = '7';
+ break;
+ case K_KP_UPARROW :
+ key = '8';
+ break;
+ case K_KP_PGUP :
+ key = '9';
+ break;
+ case K_KP_LEFTARROW :
+ key = '4';
+ break;
+ case K_KP_5 :
+ key = '5';
+ break;
+ case K_KP_RIGHTARROW :
+ key = '6';
+ break;
+ case K_KP_END :
+ key = '1';
+ break;
+ case K_KP_DOWNARROW :
+ key = '2';
+ break;
+ case K_KP_PGDN :
+ key = '3';
+ break;
+ case K_KP_INS :
+ key = '0';
+ break;
+ case K_KP_DEL :
+ key = '.';
+ break;
+ }
+
+ if (key > 127) {
+ switch (key) {
+ case K_DEL :
+ default :
+ return false;
+ }
+ }
+
+ /*
+ ** support pasting from the clipboard
+ */
+ if ((Character.toUpperCase(key) == 'V' && keydown[K_CTRL]) || (((key == K_INS) || (key == K_KP_INS)) && keydown[K_SHIFT])) {
+ String cbd;
+
+ if ((cbd = Sys.GetClipboardData()) != null) {
+ //strtok(cbd, "\n\r\b");
+ String lines[] = Lib.linesplit(cbd);
+ if (lines.length > 0 && lines[0].length() != 0) {
+ //strncpy(f.buffer, cbd, f.length - 1);
+ f.buffer = new StringBuffer(lines[0]);
+ f.cursor = f.buffer.length();
+
+ f.visible_offset = f.cursor - f.visible_length;
+
+ if (f.visible_offset < 0)
+ f.visible_offset = 0;
+ }
+ }
+ return true;
+ }
+
+ switch (key) {
+ case K_KP_LEFTARROW :
+ case K_LEFTARROW :
+ case K_BACKSPACE :
+ if (f.cursor > 0) {
+ f.buffer.deleteCharAt(f.cursor - 1);
+ //memmove(f.buffer[f.cursor - 1], f.buffer[f.cursor], strlen(& f.buffer[f.cursor]) + 1);
+ f.cursor--;
+
+ if (f.visible_offset != 0) {
+ f.visible_offset--;
+ }
+ }
+ break;
+
+ case K_KP_DEL :
+ case K_DEL :
+ //memmove(& f.buffer[f.cursor], & f.buffer[f.cursor + 1], strlen(& f.buffer[f.cursor + 1]) + 1);
+ f.buffer.deleteCharAt(f.cursor);
+ break;
+
+ case K_KP_ENTER :
+ case K_ENTER :
+ case K_ESCAPE :
+ case K_TAB :
+ return false;
+
+ case K_SPACE :
+ default :
+ if (!Character.isDigit(key) && (f.flags & QMF_NUMBERSONLY) != 0)
+ return false;
+
+ if (f.cursor < f.length) {
+ f.buffer.append(key);
+ f.cursor++;
+
+ if (f.cursor > f.visible_length) {
+ f.visible_offset++;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public static void Menu_AddItem(menuframework_s menu, menucommon_s item) {
+ if (menu.nitems == 0)
+ menu.nslots = 0;
+
+ if (menu.nitems < MAXMENUITEMS) {
+ menu.items[menu.nitems] = item;
+ ((menucommon_s) menu.items[menu.nitems]).parent = menu;
+ menu.nitems++;
+ }
+
+ menu.nslots = Menu_TallySlots(menu);
+ }
+
+ /*
+ ** Menu_AdjustCursor
+ **
+ ** This function takes the given menu, the direction, and attempts
+ ** to adjust the menu's cursor so that it's at the next available
+ ** slot.
+ */
+ public static void Menu_AdjustCursor(menuframework_s m, int dir) {
+ menucommon_s citem;
+
+ /*
+ ** see if it's in a valid spot
+ */
+ if (m.cursor >= 0 && m.cursor < m.nitems) {
+ if ((citem = Menu_ItemAtCursor(m)) != null) {
+ if (citem.type != MTYPE_SEPARATOR)
+ return;
+ }
+ }
+
+ /*
+ ** it's not in a valid spot, so crawl in the direction indicated until we
+ ** find a valid spot
+ */
+ if (dir == 1) {
+ while (true) {
+ citem = Menu_ItemAtCursor(m);
+ if (citem != null)
+ if (citem.type != MTYPE_SEPARATOR)
+ break;
+ m.cursor += dir;
+ if (m.cursor >= m.nitems)
+ m.cursor = 0;
+ }
+ }
+ else {
+ while (true) {
+ citem = Menu_ItemAtCursor(m);
+ if (citem != null)
+ if (citem.type != MTYPE_SEPARATOR)
+ break;
+ m.cursor += dir;
+ if (m.cursor < 0)
+ m.cursor = m.nitems - 1;
+ }
+ }
+ }
+
+ public static void Menu_Center(menuframework_s menu) {
+ int height;
+
+ height = ((menucommon_s) menu.items[menu.nitems - 1]).y;
+ height += 10;
+
+ menu.y = (viddef.height - height) / 2;
+ }
+
+ public static void Menu_Draw(menuframework_s menu) {
+ int i;
+ menucommon_s item;
+
+ /*
+ ** draw contents
+ */
+ for (i = 0; i < menu.nitems; i++) {
+ switch (((menucommon_s) menu.items[i]).type) {
+ case MTYPE_FIELD :
+ Field_Draw((menufield_s) menu.items[i]);
+ break;
+ case MTYPE_SLIDER :
+ Slider_Draw((menuslider_s) menu.items[i]);
+ break;
+ case MTYPE_LIST :
+ MenuList_Draw((menulist_s) menu.items[i]);
+ break;
+ case MTYPE_SPINCONTROL :
+ SpinControl_Draw((menulist_s) menu.items[i]);
+ break;
+ case MTYPE_ACTION :
+ Action_Draw((menuaction_s) menu.items[i]);
+ break;
+ case MTYPE_SEPARATOR :
+ Separator_Draw((menuseparator_s) menu.items[i]);
+ break;
+ }
+ }
+
+ item = Menu_ItemAtCursor(menu);
+
+ if (item != null && item.cursordraw != null) {
+ item.cursordraw.execute(item);
+ }
+ else if (menu.cursordraw != null) {
+ menu.cursordraw.execute(menu);
+ }
+ else if (item != null && item.type != MTYPE_FIELD) {
+ if ((item.flags & QMF_LEFT_JUSTIFY) != 0) {
+ re.DrawChar(menu.x + item.x - 24 + item.cursor_offset, menu.y + item.y, 12 + ((int) (Sys.Milliseconds() / 250) & 1));
+ }
+ else {
+ re.DrawChar(menu.x + item.cursor_offset, menu.y + item.y, 12 + ((int) (Sys.Milliseconds() / 250) & 1));
+ }
+ }
+
+ if (item != null) {
+ if (item.statusbarfunc != null)
+ item.statusbarfunc.execute(item);
+ else if (item.statusbar != null)
+ Menu_DrawStatusBar(item.statusbar);
+ else
+ Menu_DrawStatusBar(menu.statusbar);
+
+ }
+ else {
+ Menu_DrawStatusBar(menu.statusbar);
+ }
+ }
+
+ public static void Menu_DrawStatusBar(String string) {
+ if (string != null) {
+ int l = strlen(string);
+ int maxrow = viddef.height / 8;
+ int maxcol = viddef.width / 8;
+ int col = maxcol / 2 - l / 2;
+
+ re.DrawFill(0, viddef.height - 8, viddef.width, 8, 4);
+ Menu_DrawString(col * 8, viddef.height - 8, string);
+ }
+ else {
+ re.DrawFill(0, viddef.height - 8, viddef.width, 8, 0);
+ }
+ }
+
+ public static void Menu_DrawString(int x, int y, String string) {
+ int i;
+
+ for (i = 0; i < strlen(string); i++) {
+ re.DrawChar((x + i * 8), y, string.charAt(i));
+ }
+ }
+
+ public static void Menu_DrawStringDark(int x, int y, String string) {
+ int i;
+
+ for (i = 0; i < strlen(string); i++) {
+ re.DrawChar((x + i * 8), y, string.charAt(i) + 128);
+ }
+ }
+
+ public static void Menu_DrawStringR2L(int x, int y, String string) {
+ int i;
+
+ for (i = 0; i < strlen(string); i++) {
+ re.DrawChar((x - i * 8), y, string.charAt(strlen(string) - i - 1));
+ }
+ }
+
+ public static void Menu_DrawStringR2LDark(int x, int y, String string) {
+ int i;
+
+ for (i = 0; i < strlen(string); i++) {
+ re.DrawChar((x - i * 8), y, string.charAt(strlen(string) - i - 1) + 128);
+ }
+ }
+
+ public static menucommon_s Menu_ItemAtCursor(menuframework_s m) {
+ if (m.cursor < 0 || m.cursor >= m.nitems)
+ return null;
+
+ return (menucommon_s) m.items[m.cursor];
+ }
+
+ static boolean Menu_SelectItem(menuframework_s s) {
+ menucommon_s item = Menu_ItemAtCursor(s);
+
+ if (item != null) {
+ switch (item.type) {
+ case MTYPE_FIELD :
+ return Field_DoEnter((menufield_s) item);
+ case MTYPE_ACTION :
+ Action_DoEnter((menuaction_s) item);
+ return true;
+ case MTYPE_LIST :
+ // Menulist_DoEnter( ( menulist_s ) item );
+ return false;
+ case MTYPE_SPINCONTROL :
+ // SpinControl_DoEnter( ( menulist_s ) item );
+ return false;
+ }
+ }
+ return false;
+ }
+
+ public static void Menu_SetStatusBar(menuframework_s m, String string) {
+ m.statusbar = string;
+ }
+
+ public static void Menu_SlideItem(menuframework_s s, int dir) {
+ menucommon_s item = (menucommon_s) Menu_ItemAtCursor(s);
+
+ if (item != null) {
+ switch (item.type) {
+ case MTYPE_SLIDER :
+ Slider_DoSlide((menuslider_s) item, dir);
+ break;
+ case MTYPE_SPINCONTROL :
+ SpinControl_DoSlide((menulist_s) item, dir);
+ break;
+ }
+ }
+ }
+
+ public static int Menu_TallySlots(menuframework_s menu) {
+ int i;
+ int total = 0;
+
+ for (i = 0; i < menu.nitems; i++) {
+ if (((menucommon_s) menu.items[i]).type == MTYPE_LIST) {
+ int nitems = 0;
+ String n[] = ((menulist_s) menu.items[i]).itemnames;
+
+ while (n[nitems] != null)
+ nitems++;
+
+ total += nitems;
+ }
+ else {
+ total++;
+ }
+ }
+
+ return total;
+ }
+
+ public static void Menulist_DoEnter(menulist_s l) {
+ int start;
+
+ start = l.y / 10 + 1;
+
+ l.curvalue = l.parent.cursor - start;
+
+ if (l.callback != null)
+ l.callback.execute(l);
+ }
+
+ public static void MenuList_Draw(menulist_s l) {
+ String n[];
+ int y = 0;
+
+ Menu_DrawStringR2LDark(l.x + l.parent.x + LCOLUMN_OFFSET, l.y + l.parent.y, l.name);
+
+ n = l.itemnames;
+
+ re.DrawFill(l.x - 112 + l.parent.x, l.parent.y + l.y + l.curvalue * 10 + 10, 128, 10, 16);
+ int i = 0;
+
+ while (n[i] != null) {
+ Menu_DrawStringR2LDark(l.x + l.parent.x + LCOLUMN_OFFSET, l.y + l.parent.y + y + 10, n[i]);
+
+ i++;
+ y += 10;
+ }
+ }
+
+ public static void Separator_Draw(menuseparator_s s) {
+ if (s.name != null)
+ Menu_DrawStringR2LDark(s.x + s.parent.x, s.y + s.parent.y, s.name);
+ }
+
+ public static void Slider_DoSlide(menuslider_s s, int dir) {
+ s.curvalue += dir;
+
+ if (s.curvalue > s.maxvalue)
+ s.curvalue = s.maxvalue;
+ else if (s.curvalue < s.minvalue)
+ s.curvalue = s.minvalue;
+
+ if (s.callback != null)
+ s.callback.execute(s);
+ }
+
+ public static final int SLIDER_RANGE = 10;
+
+ public static void Slider_Draw(menuslider_s s) {
+ int i;
+
+ Menu_DrawStringR2LDark(s.x + s.parent.x + LCOLUMN_OFFSET, s.y + s.parent.y, s.name);
+
+ s.range = (s.curvalue - s.minvalue) / (float) (s.maxvalue - s.minvalue);
+
+ if (s.range < 0)
+ s.range = 0;
+ if (s.range > 1)
+ s.range = 1;
+ re.DrawChar(s.x + s.parent.x + RCOLUMN_OFFSET, s.y + s.parent.y, 128);
+ for (i = 0; i < SLIDER_RANGE; i++)
+ re.DrawChar(RCOLUMN_OFFSET + s.x + i * 8 + s.parent.x + 8, s.y + s.parent.y, 129);
+ re.DrawChar(RCOLUMN_OFFSET + s.x + i * 8 + s.parent.x + 8, s.y + s.parent.y, 130);
+ re.DrawChar((int) (8 + RCOLUMN_OFFSET + s.parent.x + s.x + (SLIDER_RANGE - 1) * 8 * s.range), s.y + s.parent.y, 131);
+ }
+
+ public static void SpinControl_DoEnter(menulist_s s) {
+ s.curvalue++;
+ if (s.itemnames[s.curvalue] == null)
+ s.curvalue = 0;
+
+ if (s.callback != null)
+ s.callback.execute(s);
+ }
+
+ public static void SpinControl_DoSlide(menulist_s s, int dir) {
+ s.curvalue += dir;
+
+ if (s.curvalue < 0)
+ s.curvalue = 0;
+ else if (s.itemnames[s.curvalue] == null)
+ s.curvalue--;
+
+ if (s.callback != null)
+ s.callback.execute(s);
+ }
+
+ public static void SpinControl_Draw(menulist_s s) {
+ //char buffer[100];
+ String buffer;
+
+ if (s.name != null) {
+ Menu_DrawStringR2LDark(s.x + s.parent.x + LCOLUMN_OFFSET, s.y + s.parent.y, s.name);
+ }
+
+ if (s.itemnames[s.curvalue].indexOf('\n') == -1) {
+ Menu_DrawString(RCOLUMN_OFFSET + s.x + s.parent.x, s.y + s.parent.y, s.itemnames[s.curvalue]);
+ }
+ else {
+ String line1, line2;
+ line1 = Lib.leftFrom(s.itemnames[s.curvalue], '\n');
+ Menu_DrawString(RCOLUMN_OFFSET + s.x + s.parent.x, s.y + s.parent.y, line1);
+
+ line2 = Lib.rightFrom(s.itemnames[s.curvalue], '\n');
+
+ int pos = line2.indexOf('\n');
+ if (pos != -1)
+ line2 = line2.substring(0, pos);
+
+ Menu_DrawString(RCOLUMN_OFFSET + s.x + s.parent.x, s.y + s.parent.y + 10, line2);
+ }
+ }
+}
diff --git a/src/jake2/client/S.java b/src/jake2/client/S.java
new file mode 100644
index 0000000..302de14
--- /dev/null
+++ b/src/jake2/client/S.java
@@ -0,0 +1,33 @@
+/*
+ * S.java
+ * Copyright (C) 2003
+ *
+ * $Id: S.java,v 1.1 2004-07-07 19:58:51 hzi Exp $
+ */
+/*
+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.
+
+*/
+package jake2.client;
+
+/**
+ * S
+ */
+public class S extends SND_DMA {
+
+}
diff --git a/src/jake2/client/SCR.java b/src/jake2/client/SCR.java
new file mode 100644
index 0000000..9755008
--- /dev/null
+++ b/src/jake2/client/SCR.java
@@ -0,0 +1,1420 @@
+/*
+ * SCR.java
+ * Copyright (C) 2003
+ *
+ * $Id: SCR.java,v 1.1 2004-07-07 19:58:51 hzi Exp $
+ */
+ /*
+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.
+
+*/
+
+
+package jake2.client;
+
+import jake2.Globals;
+import jake2.game.Cmd;
+import jake2.game.cvar_t;
+import jake2.qcommon.*;
+import jake2.sys.Sys;
+import jake2.util.Vargs;
+
+import java.awt.Dimension;
+
+/**
+ * SCR
+ */
+public final class SCR extends Globals {
+
+ // cl_scrn.c -- master for refresh, status bar, console, chat, notify, etc
+
+ static String[][] sb_nums =
+ {
+ {"num_0", "num_1", "num_2", "num_3", "num_4", "num_5",
+ "num_6", "num_7", "num_8", "num_9", "num_minus"},
+ {"anum_0", "anum_1", "anum_2", "anum_3", "anum_4", "anum_5",
+ "anum_6", "anum_7", "anum_8", "anum_9", "anum_minus"}
+ };
+
+ /*
+ full screen console
+ put up loading plaque
+ blanked background with loading plaque
+ blanked background with menu
+ cinematics
+ full screen image for quit and victory
+
+ end of unit intermissions
+ */
+
+ static float scr_con_current; // aproaches scr_conlines at scr_conspeed
+ static float scr_conlines; // 0.0 to 1.0 lines of console to display
+
+ static boolean scr_initialized; // ready to draw
+
+ static int scr_draw_loading;
+
+ // scr_vrect ist in Globals definiert
+ // position of render window on screen
+
+ static cvar_t scr_viewsize;
+ static cvar_t scr_conspeed;
+ static cvar_t scr_centertime;
+ static cvar_t scr_showturtle;
+ static cvar_t scr_showpause;
+ static cvar_t scr_printspeed;
+
+ static cvar_t scr_netgraph;
+ static cvar_t scr_timegraph;
+ static cvar_t scr_debuggraph;
+ static cvar_t scr_graphheight;
+ static cvar_t scr_graphscale;
+ static cvar_t scr_graphshift;
+ static cvar_t scr_drawall;
+
+ static dirty_t scr_dirty = new dirty_t();
+ static dirty_t[] scr_old_dirty = { new dirty_t(), new dirty_t() };
+
+ static String crosshair_pic;
+ static int crosshair_width, crosshair_height;
+
+ static class dirty_t
+ {
+ int x1;
+ int x2;
+ int y1;
+ int y2;
+ }
+
+ /*
+ ===============================================================================
+
+ BAR GRAPHS
+
+ ===============================================================================
+ */
+
+
+// typedef struct
+// {
+// float value;
+// int color;
+// } graphsamp_t;
+ static class graphsamp_t {
+ float value;
+ int color;
+ }
+ static int current;
+ static graphsamp_t[] values = new graphsamp_t[1024];
+
+ static {
+ for (int n=0; n < 1024; n++)
+ values[n]= new graphsamp_t();
+ }
+
+ /*
+ ==============
+ SCR_DebugGraph
+ ==============
+ */
+ public static void DebugGraph(float value, int color) {
+ values[current&1023].value = value;
+ values[current&1023].color = color;
+ current++;
+ }
+
+ /*
+ ==============
+ SCR_DrawDebugGraph
+ ==============
+ */
+ static void DrawDebugGraph() {
+ int a, x, y, w, i, h;
+ float v;
+ int color;
+
+ // draw the graph
+
+ w = scr_vrect.width;
+
+ x = scr_vrect.x;
+ y = scr_vrect.y + scr_vrect.height;
+ re.DrawFill(x, (int) (y - scr_graphheight.value), w, (int)scr_graphheight.value, 8);
+
+ for (a = 0; a < w; a++) {
+ i = (current - 1 - a + 1024) & 1023;
+ v = values[i].value;
+ color = values[i].color;
+ v = v * scr_graphscale.value + scr_graphshift.value;
+
+ if (v < 0)
+ v += scr_graphheight.value * (1 + (int) (-v / scr_graphheight.value));
+ h = (int)v % (int)scr_graphheight.value;
+ re.DrawFill(x + w - 1 - a, y - h, 1, h, color);
+ }
+ }
+
+ /*
+ ===============================================================================
+
+ CENTER PRINTING
+
+ ===============================================================================
+ */
+
+ // char scr_centerstring[1024];
+ static String scr_centerstring;
+ static float scr_centertime_start; // for slow victory printing
+ static float scr_centertime_off;
+ static int scr_center_lines;
+ static int scr_erase_center;
+
+ /*
+ ==============
+ SCR_CenterPrint
+
+ Called for important messages that should stay in the center of the screen
+ for a few moments
+ ==============
+ */
+ static void CenterPrint(String str) {
+ //char *s;
+ int s;
+ StringBuffer line = new StringBuffer(64);
+ int i, j, l;
+
+ //strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);
+ scr_centerstring = str;
+ scr_centertime_off = scr_centertime.value;
+ scr_centertime_start = cl.time;
+
+ // count the number of lines for centering
+ scr_center_lines = 1;
+ s = 0;
+ while (s < str.length()) {
+ if (str.charAt(s) == '\n')
+ scr_center_lines++;
+ s++;
+ }
+
+ // echo it to the console
+ Com.Printf(
+ "\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
+
+ s = 0;
+
+ if (str.length() != 0)
+ {
+ do {
+ // scan the width of the line
+
+ for (l = 0; l < 40 && (l + s) < str.length(); l++)
+ if (str.charAt(s + l) == '\n' || str.charAt(s + l) == 0)
+ break;
+ for (i = 0; i < (40 - l) / 2; i++)
+ line.append(' ');
+
+ for (j = 0; j < l; j++) {
+ line.append(str.charAt(s + j));
+ }
+
+ line.append('\n');
+
+ Com.Printf(line.toString());
+
+ while (s < str.length() && str.charAt(s) != '\n')
+ s++;
+
+ if (s == str.length())
+ break;
+ s++; // skip the \n
+ }
+ while (true);
+ }
+ Com.Printf(
+ "\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
+ Console.ClearNotify();
+ }
+
+ static void DrawCenterString() {
+ String cs = scr_centerstring +"\0";
+ int start;
+ int l;
+ int j;
+ int x, y;
+ int remaining;
+
+ if (cs == null)
+ return;
+ if (cs.length() == 0)
+ return;
+
+ // the finale prints the characters one at a time
+ remaining = 9999;
+
+ scr_erase_center = 0;
+ start = 0;
+
+ if (scr_center_lines <= 4)
+ y = (int) (viddef.height * 0.35);
+ else
+ y = 48;
+
+ do {
+ // scan the width of the line
+ for (l = 0; l < 40; l++)
+
+ if (start + l == cs.length() - 1 || cs.charAt(start + l) == '\n')
+ break;
+ x = (viddef.width - l * 8) / 2;
+ SCR.AddDirtyPoint(x, y);
+ for (j = 0; j < l; j++, x += 8) {
+ re.DrawChar(x, y, cs.charAt(start + j));
+ if (remaining == 0)
+ return;
+ remaining--;
+ }
+ SCR.AddDirtyPoint(x, y + 8);
+
+ y += 8;
+
+ while (start < cs.length() && cs.charAt(start) != '\n')
+ start++;
+
+ if (start == cs.length())
+ break;
+ start++; // skip the \n
+ }
+ while (true);
+ }
+
+ static void CheckDrawCenterString()
+ {
+ scr_centertime_off -= cls.frametime;
+
+ if (scr_centertime_off <= 0)
+ return;
+
+ DrawCenterString();
+ }
+
+// =============================================================================
+
+ /*
+ =================
+ SCR_CalcVrect
+
+ Sets scr_vrect, the coordinates of the rendered window
+ =================
+ */
+ static void CalcVrect()
+ {
+ int size;
+
+ // bound viewsize
+ if (scr_viewsize.value < 40)
+ Cvar.Set ("viewsize","40");
+ if (scr_viewsize.value > 100)
+ Cvar.Set ("viewsize","100");
+
+ size = (int)scr_viewsize.value;
+
+ scr_vrect.width = viddef.width*size/100;
+ scr_vrect.width &= ~7;
+
+ scr_vrect.height = viddef.height*size/100;
+ scr_vrect.height &= ~1;
+
+ scr_vrect.x = (viddef.width - scr_vrect.width)/2;
+ scr_vrect.y = (viddef.height - scr_vrect.height)/2;
+ }
+
+
+ /*
+ =================
+ SCR_SizeUp_f
+
+ Keybinding command
+ =================
+ */
+ static void SizeUp_f()
+ {
+ Cvar.SetValue("viewsize",scr_viewsize.value+10);
+ }
+
+
+ /*
+ =================
+ SCR_SizeDown_f
+
+ Keybinding command
+ =================
+ */
+ static void SizeDown_f()
+ {
+ Cvar.SetValue("viewsize",scr_viewsize.value-10);
+ }
+
+ /*
+ =================
+ SCR_Sky_f
+
+ Set a specific sky and rotation speed
+ =================
+ */
+ static void Sky_f()
+ {
+ float rotate;
+ float[] axis = {0, 0, 0};
+
+ if (Cmd.Argc() < 2)
+ {
+ Com.Printf("Usage: sky <basename> <rotate> <axis x y z>\n");
+ return;
+ }
+ if (Cmd.Argc() > 2)
+ rotate = Float.parseFloat(Cmd.Argv(2));
+ else
+ rotate = 0;
+ if (Cmd.Argc() == 6)
+ {
+ axis[0] = Float.parseFloat(Cmd.Argv(3));
+ axis[1] = Float.parseFloat(Cmd.Argv(4));
+ axis[2] = Float.parseFloat(Cmd.Argv(5));
+ }
+ else
+ {
+ axis[0] = 0;
+ axis[1] = 0;
+ axis[2] = 1;
+ }
+
+ re.SetSky(Cmd.Argv(1), rotate, axis);
+ }
+
+// ============================================================================
+
+ /*
+ ==================
+ SCR_Init
+ ==================
+ */
+ static void Init() {
+ scr_viewsize = Cvar.Get("viewsize", "100", CVAR_ARCHIVE);
+ scr_conspeed = Cvar.Get("scr_conspeed", "3", 0);
+ scr_showturtle = Cvar.Get ("scr_showturtle", "0", 0);
+ scr_showpause = Cvar.Get ("scr_showpause", "1", 0);
+ scr_centertime = Cvar.Get ("scr_centertime", "2.5", 0);
+ scr_printspeed = Cvar.Get ("scr_printspeed", "8", 0);
+ scr_netgraph = Cvar.Get ("netgraph", "1", 0);
+ scr_timegraph = Cvar.Get ("timegraph", "1", 0);
+ scr_debuggraph = Cvar.Get ("debuggraph", "1", 0);
+ scr_graphheight = Cvar.Get ("graphheight", "32", 0);
+ scr_graphscale = Cvar.Get ("graphscale", "1", 0);
+ scr_graphshift = Cvar.Get ("graphshift", "0", 0);
+ scr_drawall = Cvar.Get ("scr_drawall", "1", 0);
+
+ //
+ // register our commands
+ //
+ Cmd.AddCommand ("timerefresh", new xcommand_t() {
+ public void execute() {
+ TimeRefresh_f();
+ }
+ });
+ Cmd.AddCommand ("loading", new xcommand_t() {
+ public void execute() {
+ Loading_f();
+ }
+ });
+ Cmd.AddCommand ("sizeup", new xcommand_t() {
+ public void execute() {
+ SizeUp_f();
+ }
+ });
+ Cmd.AddCommand ("sizedown", new xcommand_t() {
+ public void execute() {
+ SizeDown_f();
+ }
+ });
+ Cmd.AddCommand ("sky", new xcommand_t() {
+ public void execute() {
+ Sky_f();
+ }
+ });
+
+ scr_initialized = true;
+ }
+
+
+ /*
+ ==============
+ SCR_DrawNet
+ ==============
+ */
+ static void DrawNet()
+ {
+ if (cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged
+ < CMD_BACKUP - 1)
+ return;
+
+ re.DrawPic(scr_vrect.x+64, scr_vrect.y, "net");
+ }
+
+ /*
+ ==============
+ SCR_DrawPause
+ ==============
+ */
+ static void DrawPause()
+ {
+ Dimension dim = new Dimension();
+
+ if (scr_showpause.value == 0) // turn off for screenshots
+ return;
+
+ if (cl_paused.value == 0)
+ return;
+
+ re.DrawGetPicSize (dim, "pause");
+ re.DrawPic ((viddef.width - dim.width) / 2, viddef.height / 2 + 8, "pause");
+ }
+
+ /*
+ ==============
+ SCR_DrawLoading
+ ==============
+ */
+ static void DrawLoading()
+ {
+ Dimension dim = new Dimension();
+
+ if (scr_draw_loading == 0)
+ return;
+
+ scr_draw_loading = 0;
+ re.DrawGetPicSize(dim, "loading");
+ re.DrawPic ((viddef.width - dim.width)/2, (viddef.height - dim.height)/2, "loading");
+ }
+
+// =============================================================================
+
+ /*
+ ==================
+ SCR_RunConsole
+
+ Scroll it up or down
+ ==================
+ */
+ static void RunConsole() {
+ // decide on the height of the console
+ if (cls.key_dest == key_console)
+ scr_conlines = 0.5f; // half screen
+ else
+ scr_conlines = 0; // none visible
+
+ if (scr_conlines < scr_con_current)
+ {
+ scr_con_current -= scr_conspeed.value*cls.frametime;
+ if (scr_conlines > scr_con_current)
+ scr_con_current = scr_conlines;
+
+ }
+ else if (scr_conlines > scr_con_current)
+ {
+ scr_con_current += scr_conspeed.value*cls.frametime;
+ if (scr_conlines < scr_con_current)
+ scr_con_current = scr_conlines;
+ }
+ }
+
+ /*
+ ==================
+ SCR_DrawConsole
+ ==================
+ */
+ static void DrawConsole()
+ {
+ Console.CheckResize();
+
+ if (cls.state == ca_disconnected || cls.state == ca_connecting)
+ { // forced full screen console
+ Console.DrawConsole(1.0f);
+ return;
+ }
+
+ if (cls.state != ca_active || !cl.refresh_prepped)
+ { // connected, but can't render
+ Console.DrawConsole(0.5f);
+ re.DrawFill (0, viddef.height/2, viddef.width, viddef.height/2, 0);
+ return;
+ }
+
+ if (scr_con_current != 0)
+ {
+ Console.DrawConsole(scr_con_current);
+ }
+ else
+ {
+ if (cls.key_dest == key_game || cls.key_dest == key_message)
+ Console.DrawNotify(); // only draw notify in game
+ }
+ }
+
+// =============================================================================
+
+ /*
+ ================
+ SCR_BeginLoadingPlaque
+ ================
+ */
+ public static void BeginLoadingPlaque() {
+ S.StopAllSounds ();
+ cl.sound_prepped = false; // don't play ambients
+ CDAudio.Stop();
+ if (cls.disable_screen != 0)
+ return;
+ if (developer.value != 0)
+ return;
+ if (cls.state == ca_disconnected)
+ return; // if at console, don't bring up the plaque
+ if (cls.key_dest == key_console)
+ return;
+ if (cl.cinematictime > 0)
+ scr_draw_loading = 2; // clear to balack first
+ else
+ scr_draw_loading = 1;
+ UpdateScreen();
+ cls.disable_screen = Sys.Milliseconds();
+ cls.disable_servercount = cl.servercount;
+ }
+
+ /*
+ ================
+ SCR_EndLoadingPlaque
+ ================
+ */
+ public static void EndLoadingPlaque() {
+ cls.disable_screen = 0;
+ Console.ClearNotify();
+ }
+
+ /*
+ ================
+ SCR_Loading_f
+ ================
+ */
+ static void Loading_f()
+ {
+ BeginLoadingPlaque();
+ }
+
+ /*
+ ================
+ SCR_TimeRefresh_f
+ ================
+ */
+ static void TimeRefresh_f() {
+ int i;
+ int start, stop;
+ float time;
+
+ if (cls.state != ca_active)
+ return;
+
+ start = Sys.Milliseconds();
+
+ if (Cmd.Argc() == 2) { // run without page flipping
+ re.BeginFrame(0);
+ for (i = 0; i < 128; i++) {
+ cl.refdef.viewangles[1] = i / 128.0f * 360.0f;
+ re.RenderFrame(cl.refdef);
+ }
+ re.EndFrame();
+ } else {
+ for (i = 0; i < 128; i++) {
+ cl.refdef.viewangles[1] = i / 128.0f * 360.0f;
+
+ re.BeginFrame(0);
+ re.RenderFrame(cl.refdef);
+ re.EndFrame();
+ }
+ }
+
+ stop = Sys.Milliseconds();
+ time = (stop - start) / 1000.0f;
+ Com.Printf("%f seconds (%f fps)\n", new Vargs(2).add(time).add(128.0f / time));
+ }
+
+ static void DirtyScreen() {
+ AddDirtyPoint(0, 0);
+ AddDirtyPoint(viddef.width-1, viddef.height-1);
+ }
+
+ /*
+ ==============
+ SCR_TileClear
+
+ Clear any parts of the tiled background that were drawn on last frame
+ ==============
+ */
+ static void TileClear()
+ {
+ int i;
+ int top, bottom, left, right;
+ dirty_t clear = new dirty_t();
+
+ if (scr_drawall.value != 0)
+ DirtyScreen (); // for power vr or broken page flippers...
+
+ if (scr_con_current == 1.0f)
+ return; // full screen console
+ if (scr_viewsize.value == 100)
+ return; // full screen rendering
+ if (cl.cinematictime > 0)
+ return; // full screen cinematic
+
+ // erase rect will be the union of the past three frames
+ // so tripple buffering works properly
+ clear = scr_dirty;
+ for (i=0 ; i<2 ; i++)
+ {
+ if (scr_old_dirty[i].x1 < clear.x1)
+ clear.x1 = scr_old_dirty[i].x1;
+ if (scr_old_dirty[i].x2 > clear.x2)
+ clear.x2 = scr_old_dirty[i].x2;
+ if (scr_old_dirty[i].y1 < clear.y1)
+ clear.y1 = scr_old_dirty[i].y1;
+ if (scr_old_dirty[i].y2 > clear.y2)
+ clear.y2 = scr_old_dirty[i].y2;
+ }
+
+ scr_old_dirty[1] = scr_old_dirty[0];
+ scr_old_dirty[0] = scr_dirty;
+
+ scr_dirty.x1 = 9999;
+ scr_dirty.x2 = -9999;
+ scr_dirty.y1 = 9999;
+ scr_dirty.y2 = -9999;
+
+ // don't bother with anything convered by the console)
+ top = (int)(scr_con_current * viddef.height);
+ if (top >= clear.y1)
+ clear.y1 = top;
+
+ if (clear.y2 <= clear.y1)
+ return; // nothing disturbed
+
+ top = scr_vrect.y;
+ bottom = top + scr_vrect.height-1;
+ left = scr_vrect.x;
+ right = left + scr_vrect.width-1;
+
+ if (clear.y1 < top)
+ { // clear above view screen
+ i = clear.y2 < top-1 ? clear.y2 : top-1;
+ re.DrawTileClear (clear.x1 , clear.y1,
+ clear.x2 - clear.x1 + 1, i - clear.y1+1, "backtile");
+ clear.y1 = top;
+ }
+ if (clear.y2 > bottom)
+ { // clear below view screen
+ i = clear.y1 > bottom+1 ? clear.y1 : bottom+1;
+ re.DrawTileClear (clear.x1, i,
+ clear.x2-clear.x1+1, clear.y2-i+1, "backtile");
+ clear.y2 = bottom;
+ }
+ if (clear.x1 < left)
+ { // clear left of view screen
+ i = clear.x2 < left-1 ? clear.x2 : left-1;
+ re.DrawTileClear (clear.x1, clear.y1,
+ i-clear.x1+1, clear.y2 - clear.y1 + 1, "backtile");
+ clear.x1 = left;
+ }
+ if (clear.x2 > right)
+ { // clear left of view screen
+ i = clear.x1 > right+1 ? clear.x1 : right+1;
+ re.DrawTileClear (i, clear.y1,
+ clear.x2-i+1, clear.y2 - clear.y1 + 1, "backtile");
+ clear.x2 = right;
+ }
+
+ }
+
+
+// ===============================================================
+
+ static final int STAT_MINUS = 10; // num frame for '-' stats digit
+
+ static final int ICON_WIDTH = 24;
+ static final int ICON_HEIGHT = 24;
+ static final int CHAR_WIDTH = 16;
+ static final int ICON_SPACE = 8;
+
+ /*
+ ================
+ SizeHUDString
+
+ Allow embedded \n in the string
+ ================
+ */
+ static void SizeHUDString(String string, Dimension dim) {
+ int lines, width, current;
+
+ lines = 1;
+ width = 0;
+
+ current = 0;
+ for (int i = 0; i < string.length(); i++) {
+ if (string.charAt(i) == '\n') {
+ lines++;
+ current = 0;
+ } else {
+ current++;
+ if (current > width)
+ width = current;
+ }
+
+ }
+
+ dim.width = width * 8;
+ dim.height = lines * 8;
+ }
+
+ static void DrawHUDString(String string, int x, int y, int centerwidth, int xor) {
+ int margin;
+ //char line[1024];
+ StringBuffer line = new StringBuffer(1024);
+ int i;
+
+ margin = x;
+
+ for (int l = 0; l < string.length();) {
+ // scan out one line of text from the string
+ line = new StringBuffer(1024);
+ while (string.charAt(l) != '\n')
+ line.append(string.charAt(l));
+ l++;
+
+ if (centerwidth != 0)
+ x = margin + (centerwidth - line.length() * 8) / 2;
+ else
+ x = margin;
+ for (i = 0; i < line.length(); i++) {
+ re.DrawChar(x, y, line.charAt(i) ^ xor);
+ x += 8;
+ }
+ if (l < string.length()) {
+ l++; // skip the \n
+ x = margin;
+ y += 8;
+ }
+ }
+ }
+
+
+ /*
+ ==============
+ SCR_DrawField
+ ==============
+ */
+ static void DrawField(int x, int y, int color, int width, int value)
+ {
+ char ptr;
+ int ptrp;
+ String num;
+ int l;
+ int frame;
+
+ if (width < 1)
+ return;
+
+ // draw number string
+ if (width > 5)
+ width = 5;
+
+ AddDirtyPoint(x, y);
+ AddDirtyPoint(x + width * CHAR_WIDTH + 2, y + 23);
+
+ num = "" + value;
+ l = num.length();
+ if (l > width)
+ l = width;
+ x += 2 + CHAR_WIDTH*(width - l);
+
+ ptr = num.charAt(0);
+ ptrp = 0;
+ for (int i = 0; i < l; i++)
+ {
+ ptr = num.charAt(i);
+ if (ptr == '-')
+ frame = STAT_MINUS;
+ else
+ frame = ptr - '0';
+
+ re.DrawPic (x,y,sb_nums[color][frame]);
+ x += CHAR_WIDTH;
+ }
+ }
+
+ /*
+ ===============
+ SCR_TouchPics
+
+ Allows rendering code to cache all needed sbar graphics
+ ===============
+ */
+ static void TouchPics() {
+ int i, j;
+
+ for (i=0 ; i<2 ; i++)
+ for (j=0 ; j<11 ; j++)
+ re.RegisterPic(sb_nums[i][j]);
+
+ if (crosshair.value != 0.0f) {
+ if (crosshair.value > 3.0f || crosshair.value < 0.0f)
+ crosshair.value = 3.0f;
+
+ crosshair_pic = "ch" + (int)crosshair.value;
+ Dimension dim = new Dimension();
+ re.DrawGetPicSize(dim, crosshair_pic);
+ crosshair_width = dim.width;
+ crosshair_height = dim.height;
+ if (crosshair_width == 0)
+ crosshair_pic = "";
+ }
+ }
+
+
+ /*
+ ================
+ SCR_ExecuteLayoutString
+
+ ================
+ */
+ static void ExecuteLayoutString(String s)
+ {
+ int x, y;
+ int value;
+ String token;
+ int width;
+ int index;
+ clientinfo_t ci;
+
+ if (cls.state != ca_active || !cl.refresh_prepped)
+ return;
+
+// if (!s[0])
+ if (s == null || s.length() == 0)
+ return;
+
+ x = 0;
+ y = 0;
+ width = 3;
+
+ Com.ParseHelp ph = new Com.ParseHelp(s);
+
+ while (!ph.isEof())
+ {
+ token = Com.Parse(ph);
+ if (token.equals("xl"))
+ {
+ token = Com.Parse(ph);
+ x = atoi(token);
+ continue;
+ }
+ if (token.equals("xr"))
+ {
+ token = Com.Parse(ph);
+ x = viddef.width + atoi(token);
+ continue;
+ }
+ if (token.equals("xv"))
+ {
+ token = Com.Parse(ph);
+ x = viddef.width/2 - 160 + atoi(token);
+ continue;
+ }
+
+ if (token.equals("yt"))
+ {
+ token = Com.Parse(ph);
+ y = atoi(token);
+ continue;
+ }
+ if (token.equals("yb"))
+ {
+ token = Com.Parse(ph);
+ y = viddef.height + atoi(token);
+ continue;
+ }
+ if (token.equals("yv"))
+ {
+ token = Com.Parse(ph);
+ y = viddef.height/2 - 120 + atoi(token);
+ continue;
+ }
+
+ if (token.equals("pic"))
+ { // draw a pic from a stat number
+ token = Com.Parse(ph);
+ value = cl.frame.playerstate.stats[atoi(token)];
+ if (value >= MAX_IMAGES)
+ Com.Error (ERR_DROP, "Pic >= MAX_IMAGES");
+ if (cl.configstrings[CS_IMAGES+value] != null)
+ {
+ AddDirtyPoint (x, y);
+ AddDirtyPoint (x+23, y+23);
+ re.DrawPic (x, y, cl.configstrings[CS_IMAGES+value]);
+ }
+ continue;
+ }
+
+ if (token.equals("client"))
+ { // draw a deathmatch client block
+ int score, ping, time;
+
+ token = Com.Parse(ph);
+ x = viddef.width/2 - 160 + atoi(token);
+ token = Com.Parse(ph);
+ y = viddef.height/2 - 120 + atoi(token);
+ AddDirtyPoint (x, y);
+ AddDirtyPoint (x+159, y+31);
+
+ token = Com.Parse(ph);
+ value = atoi(token);
+ if (value >= MAX_CLIENTS || value < 0)
+ Com.Error (ERR_DROP, "client >= MAX_CLIENTS");
+ ci = cl.clientinfo[value];
+
+ token = Com.Parse(ph);
+ score = atoi(token);
+
+ token = Com.Parse(ph);
+ ping = atoi(token);
+
+ token = Com.Parse(ph);
+ time = atoi(token);
+
+ Console.DrawAltString (x+32, y, ci.name);
+ Console.DrawString (x+32, y+8, "Score: ");
+ Console.DrawAltString (x+32+7*8, y+8, "" + score);
+ Console.DrawString (x+32, y+16, "Ping: " + ping);
+ Console.DrawString (x+32, y+24, "Time: " + time);
+
+ if (ci.icon == null)
+ ci = cl.baseclientinfo;
+ re.DrawPic (x, y, ci.iconname);
+ continue;
+ }
+
+ if (token.equals("ctf"))
+ { // draw a ctf client block
+ int score, ping;
+
+ token = Com.Parse(ph);
+ x = viddef.width/2 - 160 + atoi(token);
+ token = Com.Parse(ph);
+ y = viddef.height/2 - 120 + atoi(token);
+ AddDirtyPoint (x, y);
+ AddDirtyPoint (x+159, y+31);
+
+ token = Com.Parse(ph);
+ value = atoi(token);
+ if (value >= MAX_CLIENTS || value < 0)
+ Com.Error (ERR_DROP, "client >= MAX_CLIENTS");
+ ci = cl.clientinfo[value];
+
+ token = Com.Parse(ph);
+ score = atoi(token);
+
+ token = Com.Parse(ph);
+ ping = atoi(token);
+ if (ping > 999)
+ ping = 999;
+
+ // sprintf(block, "%3d %3d %-12.12s", score, ping, ci->name);
+ String block = Com.sprintf("%3d %3d %-12.12s", new Vargs(3).add(score).add(ping).add(ci.name));
+
+ if (value == cl.playernum)
+ Console.DrawAltString (x, y, block);
+ else
+ Console.DrawString (x, y, block);
+ continue;
+ }
+
+ if (token.equals("picn"))
+ { // draw a pic from a name
+ token = Com.Parse(ph);
+ AddDirtyPoint (x, y);
+ AddDirtyPoint (x+23, y+23);
+ re.DrawPic (x, y, token);
+ continue;
+ }
+
+ if (token.equals("num"))
+ { // draw a number
+ token = Com.Parse(ph);
+ width = atoi(token);
+ token = Com.Parse(ph);
+ value = cl.frame.playerstate.stats[atoi(token)];
+ DrawField (x, y, 0, width, value);
+ continue;
+ }
+
+ if (token.equals("hnum"))
+ { // health number
+ int color;
+
+ width = 3;
+ value = cl.frame.playerstate.stats[STAT_HEALTH];
+ if (value > 25)
+ color = 0; // green
+ else if (value > 0)
+ color = (cl.frame.serverframe>>2) & 1; // flash
+ else
+ color = 1;
+
+ if ((cl.frame.playerstate.stats[STAT_FLASHES] & 1) != 0)
+ re.DrawPic (x, y, "field_3");
+
+ DrawField (x, y, color, width, value);
+ continue;
+ }
+
+ if (token.equals("anum"))
+ { // ammo number
+ int color;
+
+ width = 3;
+ value = cl.frame.playerstate.stats[STAT_AMMO];
+ if (value > 5)
+ color = 0; // green
+ else if (value >= 0)
+ color = (cl.frame.serverframe>>2) & 1; // flash
+ else
+ continue; // negative number = don't show
+
+ if ((cl.frame.playerstate.stats[STAT_FLASHES] & 4) != 0)
+ re.DrawPic (x, y, "field_3");
+
+ DrawField (x, y, color, width, value);
+ continue;
+ }
+
+ if (token.equals("rnum"))
+ { // armor number
+ int color;
+
+ width = 3;
+ value = cl.frame.playerstate.stats[STAT_ARMOR];
+ if (value < 1)
+ continue;
+
+ color = 0; // green
+
+ if ((cl.frame.playerstate.stats[STAT_FLASHES] & 2) != 0)
+ re.DrawPic (x, y, "field_3");
+
+ DrawField (x, y, color, width, value);
+ continue;
+ }
+
+
+ if (token.equals("stat_string"))
+ {
+ token = Com.Parse(ph);
+ index = atoi(token);
+ if (index < 0 || index >= MAX_CONFIGSTRINGS)
+ Com.Error (ERR_DROP, "Bad stat_string index");
+ index = cl.frame.playerstate.stats[index];
+ if (index < 0 || index >= MAX_CONFIGSTRINGS)
+ Com.Error (ERR_DROP, "Bad stat_string index");
+ Console.DrawString (x, y, cl.configstrings[index]);
+ continue;
+ }
+
+ if (token.equals("cstring"))
+ {
+ token = Com.Parse(ph);
+ DrawHUDString (token, x, y, 320, 0);
+ continue;
+ }
+
+ if (token.equals("string"))
+ {
+ token = Com.Parse(ph);
+ Console.DrawString (x, y, token);
+ continue;
+ }
+
+ if (token.equals("cstring2"))
+ {
+ token = Com.Parse(ph);
+ DrawHUDString (token, x, y, 320,0x80);
+ continue;
+ }
+
+ if (token.equals("string2"))
+ {
+ token = Com.Parse(ph);
+ Console.DrawAltString (x, y, token);
+ continue;
+ }
+
+ if (token.equals("if"))
+ { // draw a number
+ token = Com.Parse(ph);
+ value = cl.frame.playerstate.stats[atoi(token)];
+ if (value == 0)
+ { // skip to endif
+// while (s && strcmp(token, "endif") )
+// {
+// token = Com.Parse(ph);
+// }
+
+ while (!ph.isEof() && !(token = Com.Parse(ph)).equals("endif"));
+
+ }
+
+ continue;
+ }
+
+
+ }
+ }
+
+ /*
+ ================
+ SCR_DrawStats
+
+ The status bar is a small layout program that
+ is based on the stats array
+ ================
+ */
+ static void DrawStats() {
+ //TODO:
+ SCR.ExecuteLayoutString(cl.configstrings[CS_STATUSBAR]);
+ }
+
+ /*
+ ================
+ SCR_DrawLayout
+
+ ================
+ */
+ static final int STAT_LAYOUTS = 13;
+
+ static void DrawLayout() {
+ if (cl.frame.playerstate.stats[STAT_LAYOUTS] != 0)
+ return;
+ SCR.ExecuteLayoutString(cl.layout);
+ }
+
+ // =======================================================
+
+ /*
+ ==================
+ SCR_UpdateScreen
+
+ This is called every frame, and can also be called explicitly to flush
+ text to the screen.
+ ==================
+ */
+ static void UpdateScreen2()
+ {
+ int numframes;
+ int i;
+ float[] separation = { 0, 0 };
+
+ // if the screen is disabled (loading plaque is up, or vid mode changing)
+ // do nothing at all
+ if (cls.disable_screen != 0)
+ {
+ if (Sys.Milliseconds() - cls.disable_screen > 120000)
+ {
+ cls.disable_screen = 0;
+ Com.Printf("Loading plaque timed out.\n");
+ }
+ return;
+ }
+
+ if (!scr_initialized || !con.initialized)
+ return; // not initialized yet
+
+ /*
+ ** range check cl_camera_separation so we don't inadvertently fry someone's
+ ** brain
+ */
+ if ( cl_stereo_separation.value > 1.0 )
+ Cvar.SetValue( "cl_stereo_separation", 1.0f );
+ else if ( cl_stereo_separation.value < 0 )
+ Cvar.SetValue( "cl_stereo_separation", 0.0f );
+
+ if ( cl_stereo.value != 0 )
+ {
+ numframes = 2;
+ separation[0] = -cl_stereo_separation.value / 2;
+ separation[1] = cl_stereo_separation.value / 2;
+ }
+ else
+ {
+ separation[0] = 0;
+ separation[1] = 0;
+ numframes = 1;
+ }
+
+ for ( i = 0; i < numframes; i++ )
+ {
+ re.BeginFrame( separation[i] );
+
+ if (scr_draw_loading == 2)
+ { // loading plaque over black screen
+ Dimension dim = new Dimension();
+
+ re.CinematicSetPalette(null);
+ scr_draw_loading = 0; // false
+ re.DrawGetPicSize (dim, "loading");
+ re.DrawPic ((viddef.width-dim.width)/2, (viddef.height-dim.height)/2, "loading");
+ }
+ // if a cinematic is supposed to be running, handle menus
+ // and console specially
+ else if (cl.cinematictime > 0)
+ {
+ if (cls.key_dest == key_menu)
+ {
+ if (cl.cinematicpalette_active)
+ {
+ re.CinematicSetPalette(null);
+ cl.cinematicpalette_active = false;
+ }
+ Menu.Draw();
+ }
+ else if (cls.key_dest == key_console)
+ {
+ if (cl.cinematicpalette_active)
+ {
+ re.CinematicSetPalette(null);
+ cl.cinematicpalette_active = false;
+ }
+ DrawConsole();
+ }
+ else
+ {
+ // TODO impl: cl_cin.c for cinematics
+ //DrawCinematic();
+ }
+ }
+ else
+ {
+ // make sure the game palette is active
+ if (cl.cinematicpalette_active)
+ {
+ re.CinematicSetPalette(null);
+ cl.cinematicpalette_active = false;
+ }
+
+ // do 3D refresh drawing, and then update the screen
+ CalcVrect();
+
+ // clear any dirty part of the background
+ TileClear();
+
+ V.RenderView( separation[i] );
+
+ DrawStats();
+ // TODO impl this
+ if ((cl.frame.playerstate.stats[STAT_LAYOUTS] & 1) != 0)
+ DrawLayout();
+ if ((cl.frame.playerstate.stats[STAT_LAYOUTS] & 2) != 0)
+ CL.DrawInventory();
+
+ DrawNet();
+ CheckDrawCenterString();
+//
+// if (scr_timegraph->value)
+// SCR_DebugGraph (cls.frametime*300, 0);
+//
+// if (scr_debuggraph->value || scr_timegraph->value || scr_netgraph->value)
+// SCR_DrawDebugGraph ();
+//
+ DrawPause();
+
+ DrawConsole();
+
+ Menu.Draw ();
+
+ DrawLoading();
+ }
+ }
+ Globals.re.EndFrame();
+ }
+
+ /*
+ =================
+ SCR_DrawCrosshair
+ =================
+ */
+ static void DrawCrosshair() {
+ if (crosshair.value == 0.0f)
+ return;
+
+ if (crosshair.modified) {
+ crosshair.modified = false;
+ SCR.TouchPics();
+ }
+
+ if (crosshair_pic.length() == 0)
+ return;
+
+ re.DrawPic(scr_vrect.x + ((scr_vrect.width - crosshair_width)>>1),
+ scr_vrect.y + ((scr_vrect.height - crosshair_height)>>1), crosshair_pic);
+ }
+
+ // wird anstelle von der richtigen UpdateScreen benoetigt
+ public static void UpdateScreen() {
+ Globals.re.updateScreen(null);
+ }
+
+ /*
+ =================
+ SCR_AddDirtyPoint
+ =================
+ */
+ static void AddDirtyPoint(int x, int y) {
+ if (x < scr_dirty.x1)
+ scr_dirty.x1 = x;
+ if (x > scr_dirty.x2)
+ scr_dirty.x2 = x;
+ if (y < scr_dirty.y1)
+ scr_dirty.y1 = y;
+ if (y > scr_dirty.y2)
+ scr_dirty.y2 = y;
+ }
+
+
+ public static void PlayCinematic(String str) {
+ // TODO: implement PlayCinematic
+ }
+
+ static void FinishCinematic() {
+ // tell the server to advance to the next map / cinematic
+ MSG.WriteByte(cls.netchan.message, clc_stringcmd);
+ SZ.Print(cls.netchan.message, "nextserver " + cl.servercount + '\n');
+ }
+} \ No newline at end of file
diff --git a/src/jake2/client/SND_DMA.java b/src/jake2/client/SND_DMA.java
new file mode 100644
index 0000000..fba94c1
--- /dev/null
+++ b/src/jake2/client/SND_DMA.java
@@ -0,0 +1,1247 @@
+/*
+ * S_DMA.java
+ * Copyright (C) 2004
+ *
+ * $Id: SND_DMA.java,v 1.1 2004-07-07 19:58:51 hzi Exp $
+ */
+/*
+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 26.01.2004 by RST.
+
+package jake2.client;
+
+import jake2.game.Cmd;
+import jake2.game.cvar_t;
+import jake2.qcommon.*;
+import jake2.util.Vargs;
+
+
+
+/**
+ * SND_DMA
+ * TODO implement sound system
+ */
+public class SND_DMA extends SND_MIX {
+//// snd_dma.c -- main control for any streaming sound output device
+//
+// #include "client.h"
+// #include "snd_loc.h"
+//
+// void S_Play(void);
+// void S_SoundList(void);
+// void S_Update_();
+// void S_StopAllSounds(void);
+//
+//
+//// =======================================================================
+//// Internal sound data & structures
+//// =======================================================================
+//
+//// only begin attenuating sound volumes when outside the FULLVOLUME range
+// #define SOUND_FULLVOLUME 80
+//
+// #define SOUND_LOOPATTENUATE 0.003
+//
+ static int s_registration_sequence;
+//
+// channel_t channels[MAX_CHANNELS];
+//
+// qboolean snd_initialized = false;
+ static boolean sound_started = false;
+//
+
+
+//
+// vec3_t listener_origin;
+// vec3_t listener_forward;
+// vec3_t listener_right;
+// vec3_t listener_up;
+//
+ static boolean s_registering;
+//
+ static int soundtime; // sample PAIRS
+ static int paintedtime; // sample PAIRS
+//
+//// during registration it is possible to have more sounds
+//// than could actually be referenced during gameplay,
+//// because we don't want to free anything until we are
+//// sure we won't need it.
+ static final int MAX_SFX = (MAX_SOUNDS*2);
+ static sfx_t[] known_sfx = new sfx_t[MAX_SFX];
+ static {
+ for (int i = 0; i< known_sfx.length; i++)
+ known_sfx[i] = new sfx_t();
+ }
+ static int num_sfx;
+//
+// #define MAX_PLAYSOUNDS 128
+// playsound_t s_playsounds[MAX_PLAYSOUNDS];
+// playsound_t s_freeplays;
+// playsound_t s_pendingplays;
+//
+// int s_beginofs;
+//
+ static cvar_t s_volume;
+ static cvar_t s_testsound;
+ static cvar_t s_loadas8bit;
+ static cvar_t s_khz;
+ static cvar_t s_show;
+ static cvar_t s_mixahead;
+ static cvar_t s_primary;
+//
+//
+// int s_rawend;
+// portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES];
+//
+//
+// ====================================================================
+// User-setable variables
+// ====================================================================
+
+
+ static void SoundInfo_f()
+ {
+ if (!sound_started)
+ {
+ Com.Printf ("sound system not started\n");
+ return;
+ }
+
+ Com.Printf("%5d stereo\n", new Vargs(1).add(dma.channels - 1));
+ Com.Printf("%5d samples\n", new Vargs(1).add(dma.samples));
+ Com.Printf("%5d samplepos\n", new Vargs(1).add(dma.samplepos));
+ Com.Printf("%5d samplebits\n", new Vargs(1).add(dma.samplebits));
+ Com.Printf("%5d submission_chunk\n", new Vargs(1).add(dma.submission_chunk));
+ Com.Printf("%5d speed\n", new Vargs(1).add(dma.speed));
+ }
+
+ /*
+ ================
+ S_Init
+ ================
+ */
+ public static void Init() {
+ cvar_t cv;
+
+ Com.Printf("\n------- sound initialization -------\n");
+
+ cv = Cvar.Get("s_initsound", "1", 0);
+ if (cv.value == 0.0f)
+ Com.Printf("not initializing.\n");
+ else {
+ s_volume = Cvar.Get("s_volume", "0.7", CVAR_ARCHIVE);
+ s_khz = Cvar.Get("s_khz", "11", CVAR_ARCHIVE);
+ s_loadas8bit = Cvar.Get("s_loadas8bit", "1", CVAR_ARCHIVE);
+ s_mixahead = Cvar.Get("s_mixahead", "0.2", CVAR_ARCHIVE);
+ s_show = Cvar.Get("s_show", "0", 0);
+ s_testsound = Cvar.Get("s_testsound", "0", 0);
+ s_primary = Cvar.Get("s_primary", "0", CVAR_ARCHIVE); // win32 specific
+
+ Cmd.AddCommand("play", new xcommand_t() {
+ public void execute() {
+ S.Play();
+ }
+ });
+ Cmd.AddCommand("stopsound", new xcommand_t() {
+ public void execute() {
+ S.StopAllSounds();
+ }
+ });
+ Cmd.AddCommand("soundlist", new xcommand_t() {
+ public void execute() {
+ S.SoundList();
+ }
+ });
+ Cmd.AddCommand("soundinfo", new xcommand_t() {
+ public void execute() {
+ S.SoundInfo_f();
+ }
+ });
+
+ if (!SNDDMA_Init())
+ return;
+
+ S.InitScaletable();
+
+ sound_started = true;
+ num_sfx = 0;
+
+ soundtime = 0;
+ paintedtime = 0;
+
+ Com.Printf("sound sampling rate: " + dma.speed + "\n");
+
+ S.StopAllSounds();
+ }
+S.SoundInfo_f();
+ Com.Printf("------------------------------------\n");
+ }
+
+
+// =======================================================================
+// Shutdown sound engine
+// =======================================================================
+
+ static void Shutdown()
+ {
+ int i;
+ sfx_t[] sfx;
+
+ if (!sound_started)
+ return;
+
+ SNDDMA_Shutdown();
+
+ sound_started = false;
+
+ Cmd.RemoveCommand("play");
+ Cmd.RemoveCommand("stopsound");
+ Cmd.RemoveCommand("soundlist");
+ Cmd.RemoveCommand("soundinfo");
+
+ // free all sounds
+ for (i=0, sfx=known_sfx ; i < num_sfx ; i++)
+ {
+ if (sfx[i].name == null)
+ continue;
+
+ //memset (sfx, 0, sizeof(*sfx));
+ sfx[i].clear();
+ }
+
+ num_sfx = 0;
+ }
+
+// =======================================================================
+// Load a sound
+// =======================================================================
+
+ /*
+ ==================
+ S_FindName
+
+ ==================
+ */
+ static sfx_t FindName(String name, boolean create) {
+ int i;
+ sfx_t sfx = null;
+
+ if (name == null)
+ Com.Error(ERR_FATAL, "S_FindName: NULL\n");
+ if (name.length() == 0)
+ Com.Error(ERR_FATAL, "S_FindName: empty name\n");
+
+ if (strlen(name) >= MAX_QPATH)
+ Com.Error(ERR_FATAL, "Sound name too long: " + name);
+
+ // see if already loaded
+ for (i = 0; i < num_sfx; i++)
+ if (name.equals(known_sfx[i].name)) {
+ return known_sfx[i];
+ }
+
+ if (!create)
+ return null;
+
+ // find a free sfx
+ for (i = 0; i < num_sfx; i++)
+ if (known_sfx[i].name == null)
+ // registration_sequence < s_registration_sequence)
+ break;
+
+ if (i == num_sfx) {
+ if (num_sfx == MAX_SFX)
+ Com.Error(ERR_FATAL, "S_FindName: out of sfx_t");
+ num_sfx++;
+ }
+
+ sfx = known_sfx[i];
+ //memset (sfx, 0, sizeof(*sfx));
+ sfx.clear();
+ sfx.name = name;
+ sfx.registration_sequence = s_registration_sequence;
+
+ return sfx;
+ }
+//
+//
+// /*
+// ==================
+// S_AliasName
+//
+// ==================
+// */
+// sfx_t *S_AliasName (char *aliasname, char *truename)
+// {
+// sfx_t *sfx;
+// char *s;
+// int i;
+//
+// s = Z_Malloc (MAX_QPATH);
+// strcpy (s, truename);
+//
+// // find a free sfx
+// for (i=0 ; i < num_sfx ; i++)
+// if (!known_sfx[i].name[0])
+// break;
+//
+// if (i == num_sfx)
+// {
+// if (num_sfx == MAX_SFX)
+// Com_Error (ERR_FATAL, "S_FindName: out of sfx_t");
+// num_sfx++;
+// }
+//
+// sfx = &known_sfx[i];
+// memset (sfx, 0, sizeof(*sfx));
+// strcpy (sfx->name, aliasname);
+// sfx->registration_sequence = s_registration_sequence;
+// sfx->truename = s;
+//
+// return sfx;
+// }
+//
+//
+ /*
+ =====================
+ S_BeginRegistration
+
+ =====================
+ */
+ static void BeginRegistration() {
+ s_registration_sequence++;
+ s_registering = true;
+ }
+
+ /*
+ ==================
+ S_RegisterSound
+
+ ==================
+ */
+ static sfx_t RegisterSound(String name) {
+ sfx_t sfx = null;
+
+// if (!sound_started)
+// return null;
+//
+// sfx = S.FindName(name, true);
+// sfx.registration_sequence = s_registration_sequence;
+//
+// if (!s_registering)
+// S.LoadSound(sfx);
+
+ return sfx;
+ }
+
+
+ /*
+ =====================
+ S_EndRegistration
+
+ =====================
+ */
+ static void EndRegistration ()
+ {
+// int i;
+// sfx_t *sfx;
+// int size;
+//
+// // free any sounds not from this registration sequence
+// for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++)
+// {
+// if (!sfx->name[0])
+// continue;
+// if (sfx->registration_sequence != s_registration_sequence)
+// { // don't need this sound
+// if (sfx->cache) // it is possible to have a leftover
+// Z_Free (sfx->cache); // from a server that didn't finish loading
+// memset (sfx, 0, sizeof(*sfx));
+// }
+// else
+// { // make sure it is paged in
+// if (sfx->cache)
+// {
+// size = sfx->cache->length*sfx->cache->width;
+// Com_PageInMemory ((byte *)sfx->cache, size);
+// }
+// }
+//
+// }
+//
+// // load everything in
+// for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++)
+// {
+// if (!sfx->name[0])
+// continue;
+// S_LoadSound (sfx);
+// }
+//
+// s_registering = false;
+ }
+//
+//
+//// =============================================================================
+//
+// /*
+// =================
+// S_PickChannel
+// =================
+// */
+// channel_t *S_PickChannel(int entnum, int entchannel)
+// {
+// int ch_idx;
+// int first_to_die;
+// int life_left;
+// channel_t *ch;
+//
+// if (entchannel<0)
+// Com_Error (ERR_DROP, "S_PickChannel: entchannel<0");
+//
+//// Check for replacement sound, or find the best one to replace
+// first_to_die = -1;
+// life_left = 0x7fffffff;
+// for (ch_idx=0 ; ch_idx < MAX_CHANNELS ; ch_idx++)
+// {
+// if (entchannel != 0 // channel 0 never overrides
+// && channels[ch_idx].entnum == entnum
+// && channels[ch_idx].entchannel == entchannel)
+// { // always override sound from same entity
+// first_to_die = ch_idx;
+// break;
+// }
+//
+// // don't let monster sounds override player sounds
+// if (channels[ch_idx].entnum == cl.playernum+1 && entnum != cl.playernum+1 && channels[ch_idx].sfx)
+// continue;
+//
+// if (channels[ch_idx].end - paintedtime < life_left)
+// {
+// life_left = channels[ch_idx].end - paintedtime;
+// first_to_die = ch_idx;
+// }
+// }
+//
+// if (first_to_die == -1)
+// return NULL;
+//
+// ch = &channels[first_to_die];
+// memset (ch, 0, sizeof(*ch));
+//
+// return ch;
+// }
+//
+// /*
+// =================
+// S_SpatializeOrigin
+//
+// Used for spatializing channels and autosounds
+// =================
+// */
+// void S_SpatializeOrigin (vec3_t origin, float master_vol, float dist_mult, int *left_vol, int *right_vol)
+// {
+// vec_t dot;
+// vec_t dist;
+// vec_t lscale, rscale, scale;
+// vec3_t source_vec;
+//
+// if (cls.state != ca_active)
+// {
+// *left_vol = *right_vol = 255;
+// return;
+// }
+//
+//// calculate stereo seperation and distance attenuation
+// VectorSubtract(origin, listener_origin, source_vec);
+//
+// dist = VectorNormalize(source_vec);
+// dist -= SOUND_FULLVOLUME;
+// if (dist < 0)
+// dist = 0; // close enough to be at full volume
+// dist *= dist_mult; // different attenuation levels
+//
+// dot = DotProduct(listener_right, source_vec);
+//
+// if (dma.channels == 1 || !dist_mult)
+// { // no attenuation = no spatialization
+// rscale = 1.0;
+// lscale = 1.0;
+// }
+// else
+// {
+// rscale = 0.5 * (1.0 + dot);
+// lscale = 0.5*(1.0 - dot);
+// }
+//
+// // add in distance effect
+// scale = (1.0 - dist) * rscale;
+// *right_vol = (int) (master_vol * scale);
+// if (*right_vol < 0)
+// *right_vol = 0;
+//
+// scale = (1.0 - dist) * lscale;
+// *left_vol = (int) (master_vol * scale);
+// if (*left_vol < 0)
+// *left_vol = 0;
+// }
+//
+// /*
+// =================
+// S_Spatialize
+// =================
+// */
+// void S_Spatialize(channel_t *ch)
+// {
+// vec3_t origin;
+//
+// // anything coming from the view entity will always be full volume
+// if (ch->entnum == cl.playernum+1)
+// {
+// ch->leftvol = ch->master_vol;
+// ch->rightvol = ch->master_vol;
+// return;
+// }
+//
+// if (ch->fixed_origin)
+// {
+// VectorCopy (ch->origin, origin);
+// }
+// else
+// CL_GetEntitySoundOrigin (ch->entnum, origin);
+//
+// S_SpatializeOrigin (origin, ch->master_vol, ch->dist_mult, &ch->leftvol, &ch->rightvol);
+// }
+//
+//
+// /*
+// =================
+// S_AllocPlaysound
+// =================
+// */
+// playsound_t *S_AllocPlaysound (void)
+// {
+// playsound_t *ps;
+//
+// ps = s_freeplays.next;
+// if (ps == &s_freeplays)
+// return NULL; // no free playsounds
+//
+// // unlink from freelist
+// ps->prev->next = ps->next;
+// ps->next->prev = ps->prev;
+//
+// return ps;
+// }
+//
+//
+// /*
+// =================
+// S_FreePlaysound
+// =================
+// */
+// void S_FreePlaysound (playsound_t *ps)
+// {
+// // unlink from channel
+// ps->prev->next = ps->next;
+// ps->next->prev = ps->prev;
+//
+// // add to free list
+// ps->next = s_freeplays.next;
+// s_freeplays.next->prev = ps;
+// ps->prev = &s_freeplays;
+// s_freeplays.next = ps;
+// }
+//
+//
+//
+// /*
+// ===============
+// S_IssuePlaysound
+//
+// Take the next playsound and begin it on the channel
+// This is never called directly by S_Play*, but only
+// by the update loop.
+// ===============
+// */
+// void S_IssuePlaysound (playsound_t *ps)
+// {
+// channel_t *ch;
+// sfxcache_t *sc;
+//
+// if (s_show->value)
+// Com_Printf ("Issue %i\n", ps->begin);
+// // pick a channel to play on
+// ch = S_PickChannel(ps->entnum, ps->entchannel);
+// if (!ch)
+// {
+// S_FreePlaysound (ps);
+// return;
+// }
+//
+// // spatialize
+// if (ps->attenuation == ATTN_STATIC)
+// ch->dist_mult = ps->attenuation * 0.001;
+// else
+// ch->dist_mult = ps->attenuation * 0.0005;
+// ch->master_vol = ps->volume;
+// ch->entnum = ps->entnum;
+// ch->entchannel = ps->entchannel;
+// ch->sfx = ps->sfx;
+// VectorCopy (ps->origin, ch->origin);
+// ch->fixed_origin = ps->fixed_origin;
+//
+// S_Spatialize(ch);
+//
+// ch->pos = 0;
+// sc = S_LoadSound (ch->sfx);
+// ch->end = paintedtime + sc->length;
+//
+// // free the playsound
+// S_FreePlaysound (ps);
+// }
+//
+// struct sfx_s *S_RegisterSexedSound (entity_state_t *ent, char *base)
+// {
+// int n;
+// char *p;
+// struct sfx_s *sfx;
+// FILE *f;
+// char model[MAX_QPATH];
+// char sexedFilename[MAX_QPATH];
+// char maleFilename[MAX_QPATH];
+//
+// // determine what model the client is using
+// model[0] = 0;
+// n = CS_PLAYERSKINS + ent->number - 1;
+// if (cl.configstrings[n][0])
+// {
+// p = strchr(cl.configstrings[n], '\\');
+// if (p)
+// {
+// p += 1;
+// strcpy(model, p);
+// p = strchr(model, '/');
+// if (p)
+// *p = 0;
+// }
+// }
+// // if we can't figure it out, they're male
+// if (!model[0])
+// strcpy(model, "male");
+//
+// // see if we already know of the model specific sound
+// Com_sprintf (sexedFilename, sizeof(sexedFilename), "#players/%s/%s", model, base+1);
+// sfx = S_FindName (sexedFilename, false);
+//
+// if (!sfx)
+// {
+// // no, so see if it exists
+// FS_FOpenFile (&sexedFilename[1], &f);
+// if (f)
+// {
+// // yes, close the file and register it
+// FS_FCloseFile (f);
+// sfx = S_RegisterSound (sexedFilename);
+// }
+// else
+// {
+// // no, revert to the male sound in the pak0.pak
+// Com_sprintf (maleFilename, sizeof(maleFilename), "player/%s/%s", "male", base+1);
+// sfx = S_AliasName (sexedFilename, maleFilename);
+// }
+// }
+//
+// return sfx;
+// }
+//
+//
+//// =======================================================================
+//// Start a sound effect
+//// =======================================================================
+//
+ /*
+ ====================
+ S_StartSound
+
+ Validates the parms and ques the sound up
+ if pos is NULL, the sound will be dynamically sourced from the entity
+ Entchannel 0 will never override a playing sound
+ ====================
+ */
+ static void StartSound(float[] origin, int entnum, int entchannel, sfx_t sfx, float fvol, float attenuation, float timeofs)
+ {
+// sfxcache_t *sc;
+// int vol;
+// playsound_t *ps, *sort;
+// int start;
+//
+// if (!sound_started)
+// return;
+//
+// if (!sfx)
+// return;
+//
+// if (sfx->name[0] == '*')
+// sfx = S_RegisterSexedSound(&cl_entities[entnum].current, sfx->name);
+//
+// // make sure the sound is loaded
+// sc = S_LoadSound (sfx);
+// if (!sc)
+// return; // couldn't load the sound's data
+//
+// vol = fvol*255;
+//
+// // make the playsound_t
+// ps = S_AllocPlaysound ();
+// if (!ps)
+// return;
+//
+// if (origin)
+// {
+// VectorCopy (origin, ps->origin);
+// ps->fixed_origin = true;
+// }
+// else
+// ps->fixed_origin = false;
+//
+// ps->entnum = entnum;
+// ps->entchannel = entchannel;
+// ps->attenuation = attenuation;
+// ps->volume = vol;
+// ps->sfx = sfx;
+//
+// // drift s_beginofs
+// start = cl.frame.servertime * 0.001 * dma.speed + s_beginofs;
+// if (start < paintedtime)
+// {
+// start = paintedtime;
+// s_beginofs = start - (cl.frame.servertime * 0.001 * dma.speed);
+// }
+// else if (start > paintedtime + 0.3 * dma.speed)
+// {
+// start = paintedtime + 0.1 * dma.speed;
+// s_beginofs = start - (cl.frame.servertime * 0.001 * dma.speed);
+// }
+// else
+// {
+// s_beginofs-=10;
+// }
+//
+// if (!timeofs)
+// ps->begin = paintedtime;
+// else
+// ps->begin = start + timeofs * dma.speed;
+//
+// // sort into the pending sound list
+// for (sort = s_pendingplays.next ;
+// sort != &s_pendingplays && sort->begin < ps->begin ;
+// sort = sort->next)
+// ;
+//
+// ps->next = sort;
+// ps->prev = sort->prev;
+//
+// ps->next->prev = ps;
+// ps->prev->next = ps;
+ }
+
+//
+// /*
+// ==================
+// S_StartLocalSound
+// ==================
+// */
+ static void StartLocalSound(String sound) {
+// sfx_t *sfx;
+//
+// if (!sound_started)
+// return;
+//
+// sfx = S_RegisterSound (sound);
+// if (!sfx)
+// {
+// Com_Printf ("S_StartLocalSound: can't cache %s\n", sound);
+// return;
+// }
+// S_StartSound (NULL, cl.playernum+1, 0, sfx, 1, 1, 0);
+ }
+//
+//
+// /*
+// ==================
+// S_ClearBuffer
+// ==================
+// */
+// void S_ClearBuffer (void)
+// {
+// int clear;
+//
+// if (!sound_started)
+// return;
+//
+// s_rawend = 0;
+//
+// if (dma.samplebits == 8)
+// clear = 0x80;
+// else
+// clear = 0;
+//
+// SNDDMA_BeginPainting ();
+// if (dma.buffer)
+// memset(dma.buffer, clear, dma.samples * dma.samplebits/8);
+// SNDDMA_Submit ();
+// }
+//
+ /*
+ ==================
+ S_StopAllSounds
+ ==================
+ */
+ static void StopAllSounds()
+ {
+// int i;
+//
+// if (!sound_started)
+// return;
+//
+// // clear all the playsounds
+// memset(s_playsounds, 0, sizeof(s_playsounds));
+// s_freeplays.next = s_freeplays.prev = &s_freeplays;
+// s_pendingplays.next = s_pendingplays.prev = &s_pendingplays;
+//
+// for (i=0 ; i<MAX_PLAYSOUNDS ; i++)
+// {
+// s_playsounds[i].prev = &s_freeplays;
+// s_playsounds[i].next = s_freeplays.next;
+// s_playsounds[i].prev->next = &s_playsounds[i];
+// s_playsounds[i].next->prev = &s_playsounds[i];
+// }
+//
+// // clear all the channels
+// memset(channels, 0, sizeof(channels));
+//
+// S_ClearBuffer ();
+ }
+//
+// /*
+// ==================
+// S_AddLoopSounds
+//
+// Entities with a ->sound field will generated looped sounds
+// that are automatically started, stopped, and merged together
+// as the entities are sent to the client
+// ==================
+// */
+// void S_AddLoopSounds (void)
+// {
+// int i, j;
+// int sounds[MAX_EDICTS];
+// int left, right, left_total, right_total;
+// channel_t *ch;
+// sfx_t *sfx;
+// sfxcache_t *sc;
+// int num;
+// entity_state_t *ent;
+//
+// if (cl_paused->value)
+// return;
+//
+// if (cls.state != ca_active)
+// return;
+//
+// if (!cl.sound_prepped)
+// return;
+//
+// for (i=0 ; i<cl.frame.num_entities ; i++)
+// {
+// num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
+// ent = &cl_parse_entities[num];
+// sounds[i] = ent->sound;
+// }
+//
+// for (i=0 ; i<cl.frame.num_entities ; i++)
+// {
+// if (!sounds[i])
+// continue;
+//
+// sfx = cl.sound_precache[sounds[i]];
+// if (!sfx)
+// continue; // bad sound effect
+// sc = sfx->cache;
+// if (!sc)
+// continue;
+//
+// num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1);
+// ent = &cl_parse_entities[num];
+//
+// // find the total contribution of all sounds of this type
+// S_SpatializeOrigin (ent->origin, 255.0, SOUND_LOOPATTENUATE,
+// &left_total, &right_total);
+// for (j=i+1 ; j<cl.frame.num_entities ; j++)
+// {
+// if (sounds[j] != sounds[i])
+// continue;
+// sounds[j] = 0; // don't check this again later
+//
+// num = (cl.frame.parse_entities + j)&(MAX_PARSE_ENTITIES-1);
+// ent = &cl_parse_entities[num];
+//
+// S_SpatializeOrigin (ent->origin, 255.0, SOUND_LOOPATTENUATE,
+// &left, &right);
+// left_total += left;
+// right_total += right;
+// }
+//
+// if (left_total == 0 && right_total == 0)
+// continue; // not audible
+//
+// // allocate a channel
+// ch = S_PickChannel(0, 0);
+// if (!ch)
+// return;
+//
+// if (left_total > 255)
+// left_total = 255;
+// if (right_total > 255)
+// right_total = 255;
+// ch->leftvol = left_total;
+// ch->rightvol = right_total;
+// ch->autosound = true; // remove next frame
+// ch->sfx = sfx;
+// ch->pos = paintedtime % sc->length;
+// ch->end = paintedtime + sc->length - ch->pos;
+// }
+// }
+//
+//// =============================================================================
+//
+// /*
+// ============
+// S_RawSamples
+//
+// Cinematic streaming and voice over network
+// ============
+// */
+// void S_RawSamples (int samples, int rate, int width, int channels, byte *data)
+// {
+// int i;
+// int src, dst;
+// float scale;
+//
+// if (!sound_started)
+// return;
+//
+// if (s_rawend < paintedtime)
+// s_rawend = paintedtime;
+// scale = (float)rate / dma.speed;
+//
+//// Com_Printf ("%i < %i < %i\n", soundtime, paintedtime, s_rawend);
+// if (channels == 2 && width == 2)
+// {
+// if (scale == 1.0)
+// { // optimized case
+// for (i=0 ; i<samples ; i++)
+// {
+// dst = s_rawend&(MAX_RAW_SAMPLES-1);
+// s_rawend++;
+// s_rawsamples[dst].left =
+// LittleShort(((short *)data)[i*2]) << 8;
+// s_rawsamples[dst].right =
+// LittleShort(((short *)data)[i*2+1]) << 8;
+// }
+// }
+// else
+// {
+// for (i=0 ; ; i++)
+// {
+// src = i*scale;
+// if (src >= samples)
+// break;
+// dst = s_rawend&(MAX_RAW_SAMPLES-1);
+// s_rawend++;
+// s_rawsamples[dst].left =
+// LittleShort(((short *)data)[src*2]) << 8;
+// s_rawsamples[dst].right =
+// LittleShort(((short *)data)[src*2+1]) << 8;
+// }
+// }
+// }
+// else if (channels == 1 && width == 2)
+// {
+// for (i=0 ; ; i++)
+// {
+// src = i*scale;
+// if (src >= samples)
+// break;
+// dst = s_rawend&(MAX_RAW_SAMPLES-1);
+// s_rawend++;
+// s_rawsamples[dst].left =
+// LittleShort(((short *)data)[src]) << 8;
+// s_rawsamples[dst].right =
+// LittleShort(((short *)data)[src]) << 8;
+// }
+// }
+// else if (channels == 2 && width == 1)
+// {
+// for (i=0 ; ; i++)
+// {
+// src = i*scale;
+// if (src >= samples)
+// break;
+// dst = s_rawend&(MAX_RAW_SAMPLES-1);
+// s_rawend++;
+// s_rawsamples[dst].left =
+// ((char *)data)[src*2] << 16;
+// s_rawsamples[dst].right =
+// ((char *)data)[src*2+1] << 16;
+// }
+// }
+// else if (channels == 1 && width == 1)
+// {
+// for (i=0 ; ; i++)
+// {
+// src = i*scale;
+// if (src >= samples)
+// break;
+// dst = s_rawend&(MAX_RAW_SAMPLES-1);
+// s_rawend++;
+// s_rawsamples[dst].left =
+// (((byte *)data)[src]-128) << 16;
+// s_rawsamples[dst].right = (((byte *)data)[src]-128) << 16;
+// }
+// }
+// }
+//
+//// =============================================================================
+//
+// /*
+// ============
+// S_Update
+//
+// Called once each time through the main loop
+// ============
+// */
+ static void Update(float[] origin, float[] forward, float[] right, float[] up) {
+// int i;
+// int total;
+// channel_t *ch;
+// channel_t *combine;
+//
+// if (!sound_started)
+// return;
+//
+// // if the laoding plaque is up, clear everything
+// // out to make sure we aren't looping a dirty
+// // dma buffer while loading
+// if (cls.disable_screen)
+// {
+// S_ClearBuffer ();
+// return;
+// }
+//
+// // rebuild scale tables if volume is modified
+// if (s_volume->modified)
+// S_InitScaletable ();
+//
+// VectorCopy(origin, listener_origin);
+// VectorCopy(forward, listener_forward);
+// VectorCopy(right, listener_right);
+// VectorCopy(up, listener_up);
+//
+// combine = NULL;
+//
+// // update spatialization for dynamic sounds
+// ch = channels;
+// for (i=0 ; i<MAX_CHANNELS; i++, ch++)
+// {
+// if (!ch->sfx)
+// continue;
+// if (ch->autosound)
+// { // autosounds are regenerated fresh each frame
+// memset (ch, 0, sizeof(*ch));
+// continue;
+// }
+// S_Spatialize(ch); // respatialize channel
+// if (!ch->leftvol && !ch->rightvol)
+// {
+// memset (ch, 0, sizeof(*ch));
+// continue;
+// }
+// }
+//
+// // add loopsounds
+// S_AddLoopSounds ();
+//
+// //
+// // debugging output
+// //
+// if (s_show->value)
+// {
+// total = 0;
+// ch = channels;
+// for (i=0 ; i<MAX_CHANNELS; i++, ch++)
+// if (ch->sfx && (ch->leftvol || ch->rightvol) )
+// {
+// Com_Printf ("%3i %3i %s\n", ch->leftvol, ch->rightvol, ch->sfx->name);
+// total++;
+// }
+//
+// Com_Printf ("----(%i)---- painted: %i\n", total, paintedtime);
+// }
+//
+//// mix some sound
+// S_Update_();
+ }
+
+//
+// void GetSoundtime(void)
+// {
+// int samplepos;
+// static int buffers;
+// static int oldsamplepos;
+// int fullsamples;
+//
+// fullsamples = dma.samples / dma.channels;
+//
+//// it is possible to miscount buffers if it has wrapped twice between
+//// calls to S_Update. Oh well.
+// samplepos = SNDDMA_GetDMAPos();
+//
+// if (samplepos < oldsamplepos)
+// {
+// buffers++; // buffer wrapped
+//
+// if (paintedtime > 0x40000000)
+// { // time to chop things off to avoid 32 bit limits
+// buffers = 0;
+// paintedtime = fullsamples;
+// S_StopAllSounds ();
+// }
+// }
+// oldsamplepos = samplepos;
+//
+// soundtime = buffers*fullsamples + samplepos/dma.channels;
+// }
+//
+//
+// void S_Update_(void)
+// {
+// unsigned endtime;
+// int samps;
+//
+// if (!sound_started)
+// return;
+//
+// SNDDMA_BeginPainting ();
+//
+// if (!dma.buffer)
+// return;
+//
+//// Updates DMA time
+// GetSoundtime();
+//
+//// check to make sure that we haven't overshot
+// if (paintedtime < soundtime)
+// {
+// Com_DPrintf ("S_Update_ : overflow\n");
+// paintedtime = soundtime;
+// }
+//
+//// mix ahead of current position
+// endtime = soundtime + s_mixahead->value * dma.speed;
+//// endtime = (soundtime + 4096) & ~4095;
+//
+// // mix to an even submission block size
+// endtime = (endtime + dma.submission_chunk-1)
+// & ~(dma.submission_chunk-1);
+// samps = dma.samples >> (dma.channels-1);
+// if (endtime - soundtime > samps)
+// endtime = soundtime + samps;
+//
+// S_PaintChannels (endtime);
+//
+// SNDDMA_Submit ();
+// }
+//
+ /*
+ ===============================================================================
+
+ console functions
+
+ ===============================================================================
+ */
+
+ static void Play()
+ {
+// int i;
+// char name[256];
+// sfx_t *sfx;
+//
+// i = 1;
+// while (i<Cmd_Argc())
+// {
+// if (!strrchr(Cmd_Argv(i), '.'))
+// {
+// strcpy(name, Cmd_Argv(i));
+// strcat(name, ".wav");
+// }
+// else
+// strcpy(name, Cmd_Argv(i));
+// sfx = S_RegisterSound(name);
+// S_StartSound(NULL, cl.playernum+1, 0, sfx, 1.0, 1.0, 0);
+// i++;
+// }
+ }
+//
+ static void SoundList() {
+// int i;
+// sfx_t *sfx;
+// sfxcache_t *sc;
+// int size, total;
+//
+// total = 0;
+// for (sfx=known_sfx, i=0 ; i<num_sfx ; i++, sfx++)
+// {
+// if (!sfx->registration_sequence)
+// continue;
+// sc = sfx->cache;
+// if (sc)
+// {
+// size = sc->length*sc->width*(sc->stereo+1);
+// total += size;
+// if (sc->loopstart >= 0)
+// Com_Printf ("L");
+// else
+// Com_Printf (" ");
+// Com_Printf("(%2db) %6i : %s\n",sc->width*8, size, sfx->name);
+// }
+// else
+// {
+// if (sfx->name[0] == '*')
+// Com_Printf(" placeholder : %s\n", sfx->name);
+// else
+// Com_Printf(" not loaded : %s\n", sfx->name);
+// }
+// }
+// Com_Printf ("Total resident: %i\n", total);
+ }
+
+}
diff --git a/src/jake2/client/SND_JAVA.java b/src/jake2/client/SND_JAVA.java
new file mode 100644
index 0000000..3853e09
--- /dev/null
+++ b/src/jake2/client/SND_JAVA.java
@@ -0,0 +1,168 @@
+/*
+ * SND_JAVA.java
+ * Copyright (C) 2004
+ *
+ * $Id: SND_JAVA.java,v 1.1 2004-07-07 19:58:51 hzi Exp $
+ */
+/*
+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.
+
+*/
+package jake2.client;
+
+import jake2.Globals;
+import jake2.game.cvar_t;
+import jake2.qcommon.Cvar;
+import jake2.qcommon.FS;
+
+import java.io.*;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+import javax.sound.sampled.*;
+
+/**
+ * SND_JAVA
+ */
+public class SND_JAVA extends Globals {
+
+ static boolean snd_inited= false;
+
+ static cvar_t sndbits;
+ static cvar_t sndspeed;
+ static cvar_t sndchannels;
+
+// static int tryrates[] = { 11025, 22051, 44100, 8000 };
+ static class dma_t {
+ int channels;
+ int samples; // mono samples in buffer
+ int submission_chunk; // don't mix less than this #
+ int samplepos; // in mono samples
+ int samplebits;
+ int speed;
+ byte[] buffer;
+ }
+ static SND_DMA.dma_t dma = new dma_t();
+
+ static SourceDataLine line;
+ static AudioFormat format;
+
+
+ static boolean SNDDMA_Init() {
+
+ if (snd_inited)
+ return true;
+
+ if (sndbits == null) {
+ sndbits = Cvar.Get("sndbits", "16", CVAR_ARCHIVE);
+ sndspeed = Cvar.Get("sndspeed", "0", CVAR_ARCHIVE);
+ sndchannels = Cvar.Get("sndchannels", "2", CVAR_ARCHIVE);
+ }
+
+ byte[] sound = FS.LoadFile("sound/misc/menu1.wav");
+ AudioInputStream stream;
+ try {
+ stream = AudioSystem.getAudioInputStream(new ByteArrayInputStream(sound));
+ } catch (UnsupportedAudioFileException e) {
+ return false;
+ } catch (IOException e) {
+ return false;
+ }
+ format = stream.getFormat();
+
+ DataLine.Info dinfo = new DataLine.Info(SourceDataLine.class, format);
+ //format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, format.getSampleRate(), format.getSampleSizeInBits(), 2, 2*format.getFrameSize(), format.getFrameRate(), format.isBigEndian());
+
+ try {
+ line = (SourceDataLine)AudioSystem.getLine(dinfo);
+ } catch (LineUnavailableException e4) {
+ return false;
+ }
+ dma.buffer = new byte[65536];
+// try {
+// stream.read(dma.buffer);
+// } catch (IOException e3) {
+// // TODO Auto-generated catch block
+// e3.printStackTrace();
+// }
+
+ dma.channels = format.getChannels();
+ dma.samplebits = format.getSampleSizeInBits();
+ dma.samples = dma.buffer.length / format.getFrameSize();
+ dma.speed = (int)format.getSampleRate();
+ dma.samplepos = 0;
+ dma.submission_chunk = 1;
+
+ try {
+ line.open(format, 4096);
+ } catch (LineUnavailableException e5) {
+ return false;
+ }
+
+ line.start();
+ runLine();
+
+ snd_inited = true;
+ return true;
+
+ }
+
+ static int SNDDMA_GetDMAPos() {
+ dma.samplepos = line.getFramePosition() % dma.samples;
+ return dma.samplepos;
+ }
+
+ static void SNDDMA_Shutdown() {
+ line.stop();
+ line.flush();
+ line.close();
+ line=null;
+ snd_inited = false;
+ }
+
+ /*
+ ==============
+ SNDDMA_Submit
+
+ Send sound to device if buffer isn't really the dma buffer
+ ===============
+ */
+ public static void SNDDMA_Submit() {
+ runLine();
+ }
+
+ void SNDDMA_BeginPainting() {}
+
+ private static int pos = 0;
+ static void runLine() {
+
+ int p = line.getFramePosition() * format.getFrameSize() % dma.buffer.length;
+ System.out.println("run " + p + " " + pos);
+ if (p == 0) {
+ writeLine();
+ }
+ else if (pos - p < 2048 ) writeLine();
+ }
+
+ static void writeLine() {
+ line.write(dma.buffer, pos, 4096);
+ pos+=4096;
+ if (pos>=dma.buffer.length) pos = 0;
+ }
+
+}
diff --git a/src/jake2/client/SND_MEM.java b/src/jake2/client/SND_MEM.java
new file mode 100644
index 0000000..a5f7671
--- /dev/null
+++ b/src/jake2/client/SND_MEM.java
@@ -0,0 +1,374 @@
+/*
+ * SND_MEM.java
+ * Copyright (C) 2004
+ *
+ * $Id: SND_MEM.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+ */
+/*
+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.
+
+*/
+package jake2.client;
+
+/**
+ * SND_MEM
+ */
+public class SND_MEM extends SND_JAVA {
+
+//// snd_mem.c: sound caching
+//
+// #include "client.h"
+// #include "snd_loc.h"
+//
+// int cache_full_cycle;
+//
+// byte *S_Alloc (int size);
+//
+// /*
+// ================
+// ResampleSfx
+// ================
+// */
+// void ResampleSfx (sfx_t *sfx, int inrate, int inwidth, byte *data)
+// {
+// int outcount;
+// int srcsample;
+// float stepscale;
+// int i;
+// int sample, samplefrac, fracstep;
+// sfxcache_t *sc;
+//
+// sc = sfx->cache;
+// if (!sc)
+// return;
+//
+// stepscale = (float)inrate / dma.speed; // this is usually 0.5, 1, or 2
+//
+// outcount = sc->length / stepscale;
+// sc->length = outcount;
+// if (sc->loopstart != -1)
+// sc->loopstart = sc->loopstart / stepscale;
+//
+// sc->speed = dma.speed;
+// if (s_loadas8bit->value)
+// sc->width = 1;
+// else
+// sc->width = inwidth;
+// sc->stereo = 0;
+//
+//// resample / decimate to the current source rate
+//
+// if (stepscale == 1 && inwidth == 1 && sc->width == 1)
+// {
+//// fast special case
+// for (i=0 ; i<outcount ; i++)
+// ((signed char *)sc->data)[i]
+// = (int)( (unsigned char)(data[i]) - 128);
+// }
+// else
+// {
+//// general case
+// samplefrac = 0;
+// fracstep = stepscale*256;
+// for (i=0 ; i<outcount ; i++)
+// {
+// srcsample = samplefrac >> 8;
+// samplefrac += fracstep;
+// if (inwidth == 2)
+// sample = LittleShort ( ((short *)data)[srcsample] );
+// else
+// sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
+// if (sc->width == 2)
+// ((short *)sc->data)[i] = sample;
+// else
+// ((signed char *)sc->data)[i] = sample >> 8;
+// }
+// }
+// }
+//
+//// =============================================================================
+//
+ /*
+ ==============
+ S_LoadSound
+ ==============
+ */
+ static sfxcache_t LoadSound (sfx_t s)
+ {
+// char namebuffer[MAX_QPATH];
+// byte *data;
+// wavinfo_t info;
+// int len;
+// float stepscale;
+ sfxcache_t sc = null;
+// int size;
+// char *name;
+//
+// if (s->name[0] == '*')
+// return NULL;
+//
+//// see if still in memory
+// sc = s->cache;
+// if (sc)
+// return sc;
+//
+//// Com_Printf ("S_LoadSound: %x\n", (int)stackbuf);
+//// load it in
+// if (s->truename)
+// name = s->truename;
+// else
+// name = s->name;
+//
+// if (name[0] == '#')
+// strcpy(namebuffer, &name[1]);
+// else
+// Com_sprintf (namebuffer, sizeof(namebuffer), "sound/%s", name);
+//
+//// Com_Printf ("loading %s\n",namebuffer);
+//
+// size = FS_LoadFile (namebuffer, (void **)&data);
+//
+// if (!data)
+// {
+// Com_DPrintf ("Couldn't load %s\n", namebuffer);
+// return NULL;
+// }
+//
+// info = GetWavinfo (s->name, data, size);
+// if (info.channels != 1)
+// {
+// Com_Printf ("%s is a stereo sample\n",s->name);
+// FS_FreeFile (data);
+// return NULL;
+// }
+//
+// stepscale = (float)info.rate / dma.speed;
+// len = info.samples / stepscale;
+//
+// len = len * info.width * info.channels;
+//
+// sc = s->cache = Z_Malloc (len + sizeof(sfxcache_t));
+// if (!sc)
+// {
+// FS_FreeFile (data);
+// return NULL;
+// }
+//
+// sc->length = info.samples;
+// sc->loopstart = info.loopstart;
+// sc->speed = info.rate;
+// sc->width = info.width;
+// sc->stereo = info.channels;
+//
+// ResampleSfx (s, sc->speed, sc->width, data + info.dataofs);
+//
+// FS_FreeFile (data);
+//
+ return sc;
+ }
+//
+//
+//
+// /*
+// ===============================================================================
+//
+// WAV loading
+//
+// ===============================================================================
+// */
+//
+//
+// byte *data_p;
+// byte *iff_end;
+// byte *last_chunk;
+// byte *iff_data;
+// int iff_chunk_len;
+//
+//
+// short GetLittleShort(void)
+// {
+// short val = 0;
+// val = *data_p;
+// val = val + (*(data_p+1)<<8);
+// data_p += 2;
+// return val;
+// }
+//
+// int GetLittleLong(void)
+// {
+// int val = 0;
+// val = *data_p;
+// val = val + (*(data_p+1)<<8);
+// val = val + (*(data_p+2)<<16);
+// val = val + (*(data_p+3)<<24);
+// data_p += 4;
+// return val;
+// }
+//
+// void FindNextChunk(char *name)
+// {
+// while (1)
+// {
+// data_p=last_chunk;
+//
+// if (data_p >= iff_end)
+// { // didn't find the chunk
+// data_p = NULL;
+// return;
+// }
+//
+// data_p += 4;
+// iff_chunk_len = GetLittleLong();
+// if (iff_chunk_len < 0)
+// {
+// data_p = NULL;
+// return;
+// }
+//// if (iff_chunk_len > 1024*1024)
+//// Sys_Error ("FindNextChunk: %i length is past the 1 meg sanity limit", iff_chunk_len);
+// data_p -= 8;
+// last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 );
+// if (!strncmp(data_p, name, 4))
+// return;
+// }
+// }
+//
+// void FindChunk(char *name)
+// {
+// last_chunk = iff_data;
+// FindNextChunk (name);
+// }
+//
+//
+// void DumpChunks(void)
+// {
+// char str[5];
+//
+// str[4] = 0;
+// data_p=iff_data;
+// do
+// {
+// memcpy (str, data_p, 4);
+// data_p += 4;
+// iff_chunk_len = GetLittleLong();
+// Com_Printf ("0x%x : %s (%d)\n", (int)(data_p - 4), str, iff_chunk_len);
+// data_p += (iff_chunk_len + 1) & ~1;
+// } while (data_p < iff_end);
+// }
+//
+// /*
+// ============
+// GetWavinfo
+// ============
+// */
+// wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength)
+// {
+// wavinfo_t info;
+// int i;
+// int format;
+// int samples;
+//
+// memset (&info, 0, sizeof(info));
+//
+// if (!wav)
+// return info;
+//
+// iff_data = wav;
+// iff_end = wav + wavlength;
+//
+//// find "RIFF" chunk
+// FindChunk("RIFF");
+// if (!(data_p && !strncmp(data_p+8, "WAVE", 4)))
+// {
+// Com_Printf("Missing RIFF/WAVE chunks\n");
+// return info;
+// }
+//
+//// get "fmt " chunk
+// iff_data = data_p + 12;
+//// DumpChunks ();
+//
+// FindChunk("fmt ");
+// if (!data_p)
+// {
+// Com_Printf("Missing fmt chunk\n");
+// return info;
+// }
+// data_p += 8;
+// format = GetLittleShort();
+// if (format != 1)
+// {
+// Com_Printf("Microsoft PCM format only\n");
+// return info;
+// }
+//
+// info.channels = GetLittleShort();
+// info.rate = GetLittleLong();
+// data_p += 4+2;
+// info.width = GetLittleShort() / 8;
+//
+//// get cue chunk
+// FindChunk("cue ");
+// if (data_p)
+// {
+// data_p += 32;
+// info.loopstart = GetLittleLong();
+//// Com_Printf("loopstart=%d\n", sfx->loopstart);
+//
+// // if the next chunk is a LIST chunk, look for a cue length marker
+// FindNextChunk ("LIST");
+// if (data_p)
+// {
+// if (!strncmp (data_p + 28, "mark", 4))
+// { // this is not a proper parse, but it works with cooledit...
+// data_p += 24;
+// i = GetLittleLong (); // samples in loop
+// info.samples = info.loopstart + i;
+//// Com_Printf("looped length: %i\n", i);
+// }
+// }
+// }
+// else
+// info.loopstart = -1;
+//
+//// find data chunk
+// FindChunk("data");
+// if (!data_p)
+// {
+// Com_Printf("Missing data chunk\n");
+// return info;
+// }
+//
+// data_p += 4;
+// samples = GetLittleLong () / info.width;
+//
+// if (info.samples)
+// {
+// if (samples < info.samples)
+// Com_Error (ERR_DROP, "Sound %s has a bad loop length", name);
+// }
+// else
+// info.samples = samples;
+//
+// info.dataofs = data_p - wav;
+//
+// return info;
+// }
+//
+
+}
diff --git a/src/jake2/client/SND_MIX.java b/src/jake2/client/SND_MIX.java
new file mode 100644
index 0000000..9ba7747
--- /dev/null
+++ b/src/jake2/client/SND_MIX.java
@@ -0,0 +1,513 @@
+/*
+ * SND_MIX.java
+ * Copyright (C) 2004
+ *
+ * $Id: SND_MIX.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+ */
+/*
+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.
+
+*/
+package jake2.client;
+
+/**
+ * SND_MIX
+ */
+public class SND_MIX extends SND_MEM {
+
+//// snd_mix.c -- portable code to mix sounds for snd_dma.c
+//
+// #include "client.h"
+// #include "snd_loc.h"
+//
+// #define PAINTBUFFER_SIZE 2048
+// portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE];
+// int snd_scaletable[32][256];
+// int *snd_p, snd_linear_count, snd_vol;
+// short *snd_out;
+//
+// void S_WriteLinearBlastStereo16 (void);
+//
+// #if !(defined __linux__ && defined __i386__)
+// #if !id386
+//
+// void S_WriteLinearBlastStereo16 (void)
+// {
+// int i;
+// int val;
+//
+// for (i=0 ; i<snd_linear_count ; i+=2)
+// {
+// val = snd_p[i]>>8;
+// if (val > 0x7fff)
+// snd_out[i] = 0x7fff;
+// else if (val < (short)0x8000)
+// snd_out[i] = (short)0x8000;
+// else
+// snd_out[i] = val;
+//
+// val = snd_p[i+1]>>8;
+// if (val > 0x7fff)
+// snd_out[i+1] = 0x7fff;
+// else if (val < (short)0x8000)
+// snd_out[i+1] = (short)0x8000;
+// else
+// snd_out[i+1] = val;
+// }
+// }
+// #else
+// __declspec( naked ) void S_WriteLinearBlastStereo16 (void)
+// {
+// __asm {
+//
+// push edi
+// push ebx
+// mov ecx,ds:dword ptr[snd_linear_count]
+// mov ebx,ds:dword ptr[snd_p]
+// mov edi,ds:dword ptr[snd_out]
+// LWLBLoopTop:
+// mov eax,ds:dword ptr[-8+ebx+ecx*4]
+// sar eax,8
+// cmp eax,07FFFh
+// jg LClampHigh
+// cmp eax,0FFFF8000h
+// jnl LClampDone
+// mov eax,0FFFF8000h
+// jmp LClampDone
+// LClampHigh:
+// mov eax,07FFFh
+// LClampDone:
+// mov edx,ds:dword ptr[-4+ebx+ecx*4]
+// sar edx,8
+// cmp edx,07FFFh
+// jg LClampHigh2
+// cmp edx,0FFFF8000h
+// jnl LClampDone2
+// mov edx,0FFFF8000h
+// jmp LClampDone2
+// LClampHigh2:
+// mov edx,07FFFh
+// LClampDone2:
+// shl edx,16
+// and eax,0FFFFh
+// or edx,eax
+// mov ds:dword ptr[-4+edi+ecx*2],edx
+// sub ecx,2
+// jnz LWLBLoopTop
+// pop ebx
+// pop edi
+// ret
+// }
+// }
+//
+// #endif
+// #endif
+//
+// void S_TransferStereo16 (unsigned long *pbuf, int endtime)
+// {
+// int lpos;
+// int lpaintedtime;
+//
+// snd_p = (int *) paintbuffer;
+// lpaintedtime = paintedtime;
+//
+// while (lpaintedtime < endtime)
+// {
+// // handle recirculating buffer issues
+// lpos = lpaintedtime & ((dma.samples>>1)-1);
+//
+// snd_out = (short *) pbuf + (lpos<<1);
+//
+// snd_linear_count = (dma.samples>>1) - lpos;
+// if (lpaintedtime + snd_linear_count > endtime)
+// snd_linear_count = endtime - lpaintedtime;
+//
+// snd_linear_count <<= 1;
+//
+// // write a linear blast of samples
+// S_WriteLinearBlastStereo16 ();
+//
+// snd_p += snd_linear_count;
+// lpaintedtime += (snd_linear_count>>1);
+// }
+// }
+//
+// /*
+// ===================
+// S_TransferPaintBuffer
+//
+// ===================
+// */
+// void S_TransferPaintBuffer(int endtime)
+// {
+// int out_idx;
+// int count;
+// int out_mask;
+// int *p;
+// int step;
+// int val;
+// unsigned long *pbuf;
+//
+// pbuf = (unsigned long *)dma.buffer;
+//
+// if (s_testsound->value)
+// {
+// int i;
+// int count;
+//
+// // write a fixed sine wave
+// count = (endtime - paintedtime);
+// for (i=0 ; i<count ; i++)
+// paintbuffer[i].left = paintbuffer[i].right = sin((paintedtime+i)*0.1)*20000*256;
+// }
+//
+//
+// if (dma.samplebits == 16 && dma.channels == 2)
+// { // optimized case
+// S_TransferStereo16 (pbuf, endtime);
+// }
+// else
+// { // general case
+// p = (int *) paintbuffer;
+// count = (endtime - paintedtime) * dma.channels;
+// out_mask = dma.samples - 1;
+// out_idx = paintedtime * dma.channels & out_mask;
+// step = 3 - dma.channels;
+//
+// if (dma.samplebits == 16)
+// {
+// short *out = (short *) pbuf;
+// while (count--)
+// {
+// val = *p >> 8;
+// p+= step;
+// if (val > 0x7fff)
+// val = 0x7fff;
+// else if (val < (short)0x8000)
+// val = (short)0x8000;
+// out[out_idx] = val;
+// out_idx = (out_idx + 1) & out_mask;
+// }
+// }
+// else if (dma.samplebits == 8)
+// {
+// unsigned char *out = (unsigned char *) pbuf;
+// while (count--)
+// {
+// val = *p >> 8;
+// p+= step;
+// if (val > 0x7fff)
+// val = 0x7fff;
+// else if (val < (short)0x8000)
+// val = (short)0x8000;
+// out[out_idx] = (val>>8) + 128;
+// out_idx = (out_idx + 1) & out_mask;
+// }
+// }
+// }
+// }
+//
+//
+// /*
+// ===============================================================================
+//
+// CHANNEL MIXING
+//
+// ===============================================================================
+// */
+//
+// void S_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int endtime, int offset);
+// void S_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int endtime, int offset);
+//
+// void S_PaintChannels(int endtime)
+// {
+// int i;
+// int end;
+// channel_t *ch;
+// sfxcache_t *sc;
+// int ltime, count;
+// playsound_t *ps;
+//
+// snd_vol = s_volume->value*256;
+//
+//// Com_Printf ("%i to %i\n", paintedtime, endtime);
+// while (paintedtime < endtime)
+// {
+// // if paintbuffer is smaller than DMA buffer
+// end = endtime;
+// if (endtime - paintedtime > PAINTBUFFER_SIZE)
+// end = paintedtime + PAINTBUFFER_SIZE;
+//
+// // start any playsounds
+// while (1)
+// {
+// ps = s_pendingplays.next;
+// if (ps == &s_pendingplays)
+// break; // no more pending sounds
+// if (ps->begin <= paintedtime)
+// {
+// S_IssuePlaysound (ps);
+// continue;
+// }
+//
+// if (ps->begin < end)
+// end = ps->begin; // stop here
+// break;
+// }
+//
+// // clear the paint buffer
+// if (s_rawend < paintedtime)
+// {
+//// Com_Printf ("clear\n");
+// memset(paintbuffer, 0, (end - paintedtime) * sizeof(portable_samplepair_t));
+// }
+// else
+// { // copy from the streaming sound source
+// int s;
+// int stop;
+//
+// stop = (end < s_rawend) ? end : s_rawend;
+//
+// for (i=paintedtime ; i<stop ; i++)
+// {
+// s = i&(MAX_RAW_SAMPLES-1);
+// paintbuffer[i-paintedtime] = s_rawsamples[s];
+// }
+//// if (i != end)
+//// Com_Printf ("partial stream\n");
+//// else
+//// Com_Printf ("full stream\n");
+// for ( ; i<end ; i++)
+// {
+// paintbuffer[i-paintedtime].left =
+// paintbuffer[i-paintedtime].right = 0;
+// }
+// }
+//
+//
+// // paint in the channels.
+// ch = channels;
+// for (i=0; i<MAX_CHANNELS ; i++, ch++)
+// {
+// ltime = paintedtime;
+//
+// while (ltime < end)
+// {
+// if (!ch->sfx || (!ch->leftvol && !ch->rightvol) )
+// break;
+//
+// // max painting is to the end of the buffer
+// count = end - ltime;
+//
+// // might be stopped by running out of data
+// if (ch->end - ltime < count)
+// count = ch->end - ltime;
+//
+// sc = S_LoadSound (ch->sfx);
+// if (!sc)
+// break;
+//
+// if (count > 0 && ch->sfx)
+// {
+// if (sc->width == 1)// FIXME; 8 bit asm is wrong now
+// S_PaintChannelFrom8(ch, sc, count, ltime - paintedtime);
+// else
+// S_PaintChannelFrom16(ch, sc, count, ltime - paintedtime);
+//
+// ltime += count;
+// }
+//
+// // if at end of loop, restart
+// if (ltime >= ch->end)
+// {
+// if (ch->autosound)
+// { // autolooping sounds always go back to start
+// ch->pos = 0;
+// ch->end = ltime + sc->length;
+// }
+// else if (sc->loopstart >= 0)
+// {
+// ch->pos = sc->loopstart;
+// ch->end = ltime + sc->length - ch->pos;
+// }
+// else
+// { // channel just stopped
+// ch->sfx = NULL;
+// }
+// }
+// }
+//
+// }
+//
+// // transfer out according to DMA format
+// S_TransferPaintBuffer(end);
+// paintedtime = end;
+// }
+// }
+//
+ static void InitScaletable()
+ {
+// int i, j;
+// int scale;
+//
+// s_volume->modified = false;
+// for (i=0 ; i<32 ; i++)
+// {
+// scale = i * 8 * 256 * s_volume->value;
+// for (j=0 ; j<256 ; j++)
+// snd_scaletable[i][j] = ((signed char)j) * scale;
+// }
+ }
+//
+//
+// #if !(defined __linux__ && defined __i386__)
+// #if !id386
+//
+// void S_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count, int offset)
+// {
+// int data;
+// int *lscale, *rscale;
+// unsigned char *sfx;
+// int i;
+// portable_samplepair_t *samp;
+//
+// if (ch->leftvol > 255)
+// ch->leftvol = 255;
+// if (ch->rightvol > 255)
+// ch->rightvol = 255;
+//
+// //ZOID-- >>11 has been changed to >>3, >>11 didn't make much sense
+// //as it would always be zero.
+// lscale = snd_scaletable[ ch->leftvol >> 3];
+// rscale = snd_scaletable[ ch->rightvol >> 3];
+// sfx = (signed char *)sc->data + ch->pos;
+//
+// samp = &paintbuffer[offset];
+//
+// for (i=0 ; i<count ; i++, samp++)
+// {
+// data = sfx[i];
+// samp->left += lscale[data];
+// samp->right += rscale[data];
+// }
+//
+// ch->pos += count;
+// }
+//
+// #else
+//
+// __declspec( naked ) void S_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count, int offset)
+// {
+// __asm {
+// push esi
+// push edi
+// push ebx
+// push ebp
+// mov ebx,ds:dword ptr[4+16+esp]
+// mov esi,ds:dword ptr[8+16+esp]
+// mov eax,ds:dword ptr[4+ebx]
+// mov edx,ds:dword ptr[8+ebx]
+// cmp eax,255
+// jna LLeftSet
+// mov eax,255
+// LLeftSet:
+// cmp edx,255
+// jna LRightSet
+// mov edx,255
+// LRightSet:
+// and eax,0F8h
+// add esi,20
+// and edx,0F8h
+// mov edi,ds:dword ptr[16+ebx]
+// mov ecx,ds:dword ptr[12+16+esp]
+// add esi,edi
+// shl eax,7
+// add edi,ecx
+// shl edx,7
+// mov ds:dword ptr[16+ebx],edi
+// add eax,offset snd_scaletable
+// add edx,offset snd_scaletable
+// sub ebx,ebx
+// mov bl,ds:byte ptr[-1+esi+ecx*1]
+// test ecx,1
+// jz LMix8Loop
+// mov edi,ds:dword ptr[eax+ebx*4]
+// mov ebp,ds:dword ptr[edx+ebx*4]
+// add edi,ds:dword ptr[paintbuffer+0-8+ecx*8]
+// add ebp,ds:dword ptr[paintbuffer+4-8+ecx*8]
+// mov ds:dword ptr[paintbuffer+0-8+ecx*8],edi
+// mov ds:dword ptr[paintbuffer+4-8+ecx*8],ebp
+// mov bl,ds:byte ptr[-2+esi+ecx*1]
+// dec ecx
+// jz LDone
+// LMix8Loop:
+// mov edi,ds:dword ptr[eax+ebx*4]
+// mov ebp,ds:dword ptr[edx+ebx*4]
+// add edi,ds:dword ptr[paintbuffer+0-8+ecx*8]
+// add ebp,ds:dword ptr[paintbuffer+4-8+ecx*8]
+// mov bl,ds:byte ptr[-2+esi+ecx*1]
+// mov ds:dword ptr[paintbuffer+0-8+ecx*8],edi
+// mov ds:dword ptr[paintbuffer+4-8+ecx*8],ebp
+// mov edi,ds:dword ptr[eax+ebx*4]
+// mov ebp,ds:dword ptr[edx+ebx*4]
+// mov bl,ds:byte ptr[-3+esi+ecx*1]
+// add edi,ds:dword ptr[paintbuffer+0-8*2+ecx*8]
+// add ebp,ds:dword ptr[paintbuffer+4-8*2+ecx*8]
+// mov ds:dword ptr[paintbuffer+0-8*2+ecx*8],edi
+// mov ds:dword ptr[paintbuffer+4-8*2+ecx*8],ebp
+// sub ecx,2
+// jnz LMix8Loop
+// LDone:
+// pop ebp
+// pop ebx
+// pop edi
+// pop esi
+// ret
+// }
+// }
+//
+// #endif
+// #endif
+//
+// void S_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count, int offset)
+// {
+// int data;
+// int left, right;
+// int leftvol, rightvol;
+// signed short *sfx;
+// int i;
+// portable_samplepair_t *samp;
+//
+// leftvol = ch->leftvol*snd_vol;
+// rightvol = ch->rightvol*snd_vol;
+// sfx = (signed short *)sc->data + ch->pos;
+//
+// samp = &paintbuffer[offset];
+// for (i=0 ; i<count ; i++, samp++)
+// {
+// data = sfx[i];
+// left = (data * leftvol)>>8;
+// right = (data * rightvol)>>8;
+// samp->left += left;
+// samp->right += right;
+// }
+//
+// ch->pos += count;
+// }
+
+}
diff --git a/src/jake2/client/V.java b/src/jake2/client/V.java
new file mode 100644
index 0000000..3b9d139
--- /dev/null
+++ b/src/jake2/client/V.java
@@ -0,0 +1,417 @@
+/*
+ * V.java
+ * Copyright (C) 2003
+ *
+ * $Id: V.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+ */
+/*
+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.
+
+*/
+package jake2.client;
+
+import jake2.Globals;
+import jake2.game.Cmd;
+import jake2.game.cvar_t;
+import jake2.qcommon.*;
+import jake2.sys.Sys;
+import jake2.util.Math3D;
+import jake2.util.Vargs;
+
+import java.io.IOException;
+
+/**
+ * V
+ */
+public final class V extends Globals {
+
+ static cvar_t cl_testblend;
+ static cvar_t cl_testparticles;
+ static cvar_t cl_testentities;
+ static cvar_t cl_testlights;
+ static cvar_t cl_stats;
+
+ static int r_numdlights;
+ static dlight_t[] r_dlights = new dlight_t[MAX_DLIGHTS];
+
+ static int r_numentities;
+ static entity_t[] r_entities = new entity_t[MAX_ENTITIES];
+
+ static int r_numparticles;
+ static particle_t[] r_particles = new particle_t[MAX_PARTICLES];
+
+ static lightstyle_t[] r_lightstyles = new lightstyle_t[MAX_LIGHTSTYLES];
+ static {
+ for (int i = 0; i < r_dlights.length; i++)
+ r_dlights[i] = new dlight_t();
+ for (int i = 0; i < r_entities.length; i++)
+ r_entities[i] = new entity_t();
+ for (int i = 0; i < r_particles.length; i++)
+ r_particles[i] = new particle_t();
+ for (int i = 0; i < r_lightstyles.length; i++)
+ r_lightstyles[i] = new lightstyle_t();
+ }
+
+ /*
+ ====================
+ V_ClearScene
+
+ Specifies the model that will be used as the world
+ ====================
+ */
+ static void ClearScene() {
+ r_numdlights = 0;
+ r_numentities = 0;
+ r_numparticles = 0;
+ }
+
+ /*
+ =====================
+ V_AddEntity
+
+ =====================
+ */
+ static void AddEntity(entity_t ent) {
+ if (r_numentities >= MAX_ENTITIES)
+ return;
+ r_entities[r_numentities++].set(ent);
+ }
+
+ /*
+ =====================
+ V_AddParticle
+
+ =====================
+ */
+ static void AddParticle(float[] org, int color, float alpha) {
+ particle_t p;
+
+ if (r_numparticles >= MAX_PARTICLES)
+ return;
+
+ p = r_particles[r_numparticles++];
+
+ VectorCopy(org, p.origin);
+ p.color = color;
+ p.alpha = alpha;
+ }
+
+ /*
+ =====================
+ V_AddLight
+
+ =====================
+ */
+ static void AddLight(float[] org, float intensity, float r, float g, float b) {
+ dlight_t dl;
+
+ if (r_numdlights >= MAX_DLIGHTS)
+ return;
+ dl = r_dlights[r_numdlights++];
+ VectorCopy(org, dl.origin);
+ dl.intensity = intensity;
+ dl.color[0] = r;
+ dl.color[1] = g;
+ dl.color[2] = b;
+ }
+
+
+ /*
+ =====================
+ V_AddLightStyle
+
+ =====================
+ */
+ static void AddLightStyle(int style, float r, float g, float b) {
+ lightstyle_t ls;
+
+ if (style < 0 || style > MAX_LIGHTSTYLES)
+ Com.Error(ERR_DROP, "Bad light style " + style);
+ ls = r_lightstyles[style];
+
+ ls.white = r + g + b;
+ ls.rgb[0] = r;
+ ls.rgb[1] = g;
+ ls.rgb[2] = b;
+ }
+
+ /*
+ ================
+ V_TestParticles
+
+ If cl_testparticles is set, create 4096 particles in the view
+ ================
+ */
+ static void TestParticles() {
+ particle_t p;
+ int i, j;
+ float d, r, u;
+
+ r_numparticles = MAX_PARTICLES;
+ for (i = 0; i < r_numparticles; i++) {
+ d = i * 0.25f;
+ r = 4 * ((i & 7) - 3.5f);
+ u = 4 * (((i >> 3) & 7) - 3.5f);
+ p = r_particles[i];
+
+ for (j = 0; j < 3; j++)
+ p.origin[j] =
+ cl.refdef.vieworg[j]
+ + cl.v_forward[j] * d
+ + cl.v_right[j] * r
+ + cl.v_up[j] * u;
+
+ p.color = 8;
+ p.alpha = cl_testparticles.value;
+ }
+ }
+
+ /*
+ ================
+ V_TestEntities
+
+ If cl_testentities is set, create 32 player models
+ ================
+ */
+ static void TestEntities() {
+ int i, j;
+ float f, r;
+ entity_t ent;
+
+ r_numentities = 32;
+ //memset (r_entities, 0, sizeof(r_entities));
+ for (i = 0; i < r_entities.length; i++)
+ r_entities[i] = new entity_t();
+
+ for (i=0 ; i<r_numentities ; i++)
+ {
+ ent = r_entities[i];
+
+ r = 64 * ( (i%4) - 1.5f );
+ f = 64 * (i/4) + 128;
+
+ for (j=0 ; j<3 ; j++)
+ ent.origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*f +
+ cl.v_right[j]*r;
+
+ ent.model = cl.baseclientinfo.model;
+ ent.skin = cl.baseclientinfo.skin;
+ }
+ }
+
+ /*
+ ================
+ V_TestLights
+
+ If cl_testlights is set, create 32 lights models
+ ================
+ */
+ static void TestLights() {
+ int i, j;
+ float f, r;
+ dlight_t dl;
+
+ r_numdlights = 32;
+ //memset (r_dlights, 0, sizeof(r_dlights));
+ for (i = 0; i < r_dlights.length; i++)
+ r_dlights[i] = new dlight_t();
+
+ for (i=0 ; i<r_numdlights ; i++)
+ {
+ dl = r_dlights[i];
+
+ r = 64 * ( (i%4) - 1.5f );
+ f = 64 * (i/4) + 128;
+
+ for (j=0 ; j<3 ; j++)
+ dl.origin[j] = cl.refdef.vieworg[j] + cl.v_forward[j]*f +
+ cl.v_right[j]*r;
+ dl.color[0] = ((i%6)+1) & 1;
+ dl.color[1] = (((i%6)+1) & 2)>>1;
+ dl.color[2] = (((i%6)+1) & 4)>>2;
+ dl.intensity = 200;
+ }
+ }
+
+ static xcommand_t Gun_Next_f = new xcommand_t() {
+ public void execute() {
+ gun_frame++;
+ Com.Printf("frame " + gun_frame + "\n");
+ }
+ };
+
+ static xcommand_t Gun_Prev_f = new xcommand_t() {
+ public void execute() {
+ gun_frame--;
+ if (gun_frame < 0)
+ gun_frame = 0;
+ Com.Printf("frame " + gun_frame + "\n");
+ }
+ };
+
+ static xcommand_t Gun_Model_f = new xcommand_t() {
+ public void execute() {
+ if (Cmd.Argc() != 2) {
+ gun_model = null;
+ return;
+ }
+ String name = "models/" + Cmd.Argv(1) + "/tris.md2";
+ gun_model = re.RegisterModel(name);
+ }
+ };
+
+ /*
+ ==================
+ V_RenderView
+
+ ==================
+ */
+ static void RenderView(float stereo_separation) {
+// extern int entitycmpfnc( const entity_t *, const entity_t * );
+//
+ if (cls.state != ca_active) return;
+
+ if (!cl.refresh_prepped) return; // still loading
+
+ if (cl_timedemo.value != 0.0f) {
+ if (cl.timedemo_start == 0)
+ cl.timedemo_start = Sys.Milliseconds();
+ cl.timedemo_frames++;
+ }
+
+ // an invalid frame will just use the exact previous refdef
+ // we can't use the old frame if the video mode has changed, though...
+ if ( cl.frame.valid && (cl.force_refdef || cl_paused.value == 0.0f) ) {
+ cl.force_refdef = false;
+
+ V.ClearScene();
+
+ // build a refresh entity list and calc cl.sim*
+ // this also calls CL_CalcViewValues which loads
+ // v_forward, etc.
+ CL.AddEntities();
+
+ if (cl_testparticles.value != 0.0f)
+ TestParticles();
+ if (cl_testentities.value != 0.0f)
+ TestEntities();
+ if (cl_testlights.value != 0.0f)
+ TestLights();
+ if (cl_testblend.value != 0.0f) {
+ cl.refdef.blend[0] = 1.0f;
+ cl.refdef.blend[1] = 0.5f;
+ cl.refdef.blend[2] = 0.25f;
+ cl.refdef.blend[3] = 0.5f;
+ }
+
+ // offset vieworg appropriately if we're doing stereo separation
+ if ( stereo_separation != 0 ) {
+ float[] tmp = new float[3];
+
+ Math3D.VectorScale( cl.v_right, stereo_separation, tmp );
+ Math3D.VectorAdd( cl.refdef.vieworg, tmp, cl.refdef.vieworg );
+ }
+
+ // never let it sit exactly on a node line, because a water plane can
+ // dissapear when viewed with the eye exactly on it.
+ // the server protocol only specifies to 1/8 pixel, so add 1/16 in each axis
+ cl.refdef.vieworg[0] += 1.0/16;
+ cl.refdef.vieworg[1] += 1.0/16;
+ cl.refdef.vieworg[2] += 1.0/16;
+
+ cl.refdef.x = scr_vrect.x;
+ cl.refdef.y = scr_vrect.y;
+ cl.refdef.width = scr_vrect.width;
+ cl.refdef.height = scr_vrect.height;
+ cl.refdef.fov_y = Math3D.CalcFov(cl.refdef.fov_x, cl.refdef.width, cl.refdef.height);
+ cl.refdef.time = cl.time*0.001f;
+
+ cl.refdef.areabits = cl.frame.areabits;
+
+ if (cl_add_entities.value == 0.0f)
+ r_numentities = 0;
+ if (cl_add_particles.value == 0.0f)
+ r_numparticles = 0;
+ if (cl_add_lights.value == 0.0f)
+ r_numdlights = 0;
+ if (cl_add_blend.value == 0) {
+ Math3D.VectorClear(cl.refdef.blend);
+ }
+
+ cl.refdef.num_entities = r_numentities;
+ cl.refdef.entities = r_entities;
+ cl.refdef.num_particles = r_numparticles;
+ cl.refdef.particles = r_particles;
+ cl.refdef.num_dlights = r_numdlights;
+ cl.refdef.dlights = r_dlights;
+ cl.refdef.lightstyles = r_lightstyles;
+
+ cl.refdef.rdflags = cl.frame.playerstate.rdflags;
+
+ // sort entities for better cache locality
+ // !!! useless in Java !!!
+ //Arrays.sort(cl.refdef.entities, entitycmpfnc);
+ }
+
+ re.RenderFrame(cl.refdef);
+ if (cl_stats.value != 0.0f)
+ Com.Printf("ent:%i lt:%i part:%i\n", new Vargs(3).add(r_numentities).add(
+ r_numdlights).add(r_numparticles));
+ if ( log_stats.value != 0.0f && ( log_stats_file != null ) )
+ try {
+ log_stats_file.write(r_numentities + "," + r_numdlights + "," + r_numparticles);
+ } catch (IOException e) {}
+
+ SCR.AddDirtyPoint(scr_vrect.x, scr_vrect.y);
+ SCR.AddDirtyPoint(scr_vrect.x+scr_vrect.width-1, scr_vrect.y+scr_vrect.height-1);
+
+ SCR.DrawCrosshair();
+ }
+
+ /*
+ =============
+ V_Viewpos_f
+ =============
+ */
+ static xcommand_t Viewpos_f = new xcommand_t() {
+ public void execute() {
+ Com.Printf("(%i %i %i) : %i\n",
+ new Vargs(4).add((int)cl.refdef.vieworg[0]).add(
+ (int)cl.refdef.vieworg[1]).add(
+ (int)cl.refdef.vieworg[2]).add(
+ (int)cl.refdef.viewangles[YAW]));
+ }
+ };
+
+ public static void Init() {
+ Cmd.AddCommand("gun_next", Gun_Next_f);
+ Cmd.AddCommand("gun_prev", Gun_Prev_f);
+ Cmd.AddCommand("gun_model", Gun_Model_f);
+
+ Cmd.AddCommand("viewpos", Viewpos_f);
+
+ crosshair = Cvar.Get("crosshair", "0", CVAR_ARCHIVE);
+
+ cl_testblend = Cvar.Get("cl_testblend", "0", 0);
+ cl_testparticles = Cvar.Get("cl_testparticles", "0", 0);
+ cl_testentities = Cvar.Get("cl_testentities", "0", 0);
+ cl_testlights = Cvar.Get("cl_testlights", "0", 0);
+
+ cl_stats = Cvar.Get("cl_stats", "0", 0);
+ }
+}
diff --git a/src/jake2/client/VID.java b/src/jake2/client/VID.java
new file mode 100644
index 0000000..dad6fc0
--- /dev/null
+++ b/src/jake2/client/VID.java
@@ -0,0 +1,915 @@
+/*
+ * VID.java
+ * Copyright (C) 2003
+ *
+ * $Id: VID.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+ */
+/*
+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.
+
+*/
+package jake2.client;
+
+import jake2.Defines;
+import jake2.Globals;
+import jake2.game.Cmd;
+import jake2.game.cvar_t;
+import jake2.qcommon.*;
+import jake2.render.Renderer;
+import jake2.sys.*;
+import jake2.sys.KBD;
+import jake2.sys.RW;
+import jake2.util.Vargs;
+
+import java.awt.Dimension;
+
+/**
+ * VID is a video driver.
+ *
+ * source: client/vid.h linux/vid_so.c
+ *
+ * @author cwei
+ */
+public class VID extends Globals {
+ // Main windowed and fullscreen graphics interface module. This module
+ // is used for both the software and OpenGL rendering versions of the
+ // Quake refresh engine.
+
+ // Global variables used internally by this module
+ // Globals.viddef
+ // global video state; used by other modules
+
+ // Structure containing functions exported from refresh DLL
+ // Globals.re;
+
+ // Console variables that we need to access from this module
+ static cvar_t vid_gamma;
+ static cvar_t vid_ref; // Name of Refresh DLL loaded
+ static cvar_t vid_xpos; // X coordinate of window position
+ static cvar_t vid_ypos; // Y coordinate of window position
+ static cvar_t vid_fullscreen;
+
+ // Global variables used internally by this module
+ // void *reflib_library; // Handle to refresh DLL
+ static boolean reflib_active = false;
+ // const char so_file[] = "/etc/quake2.conf";
+
+ /*
+ ==========================================================================
+
+ DLL GLUE
+
+ ==========================================================================
+ */
+
+ public static void Printf(int print_level, String fmt, Vargs vargs) {
+ // static qboolean inupdate;
+ if (print_level == Defines.PRINT_ALL)
+ Com.Printf(fmt, vargs);
+ else
+ Com.DPrintf(fmt, vargs);
+ }
+
+ public static void Error(int err_level, String fmt, Vargs vargs)
+ {
+ //static qboolean inupdate;
+ Com.Error(err_level, fmt, vargs);
+ }
+
+ // ==========================================================================
+
+ /*
+ ============
+ VID_Restart_f
+
+ Console command to re-start the video mode and refresh DLL. We do this
+ simply by setting the modified flag for the vid_ref variable, which will
+ cause the entire video mode and refresh DLL to be reset on the next frame.
+ ============
+ */
+ static void Restart_f()
+ {
+ vid_ref.modified = true;
+ }
+
+ /*
+ ** VID_GetModeInfo
+ */
+ static final vidmode_t vid_modes[] =
+ {
+ new vidmode_t("Mode 0: 320x240", 320, 240, 0),
+ new vidmode_t("Mode 1: 400x300", 400, 300, 1),
+ new vidmode_t("Mode 2: 512x384", 512, 384, 2),
+ new vidmode_t("Mode 3: 640x480", 640, 480, 3),
+ new vidmode_t("Mode 4: 800x600", 800, 600, 4),
+ new vidmode_t("Mode 5: 960x720", 960, 720, 5),
+ new vidmode_t("Mode 6: 1024x768", 1024, 768, 6),
+ new vidmode_t("Mode 7: 1152x864", 1152, 864, 7),
+ new vidmode_t("Mode 8: 1280x1024", 1280, 1024, 8),
+ new vidmode_t("Mode 9: 1600x1200", 1600, 1200, 9),
+ new vidmode_t("Mode 10: 2048x1536", 2048, 1536, 10)};
+
+ static final int NUM_MODES = vid_modes.length;
+
+ public static boolean GetModeInfo(Dimension dim, int mode) {
+ if (mode < 0 || mode >= NUM_MODES)
+ return false;
+
+ dim.width = vid_modes[mode].width;
+ dim.height = vid_modes[mode].height;
+ return true;
+ }
+
+ /*
+ ** VID_NewWindow
+ */
+ public static void NewWindow(int width, int height) {
+ Globals.viddef.width = width;
+ Globals.viddef.height = height;
+ }
+
+ static void FreeReflib()
+ {
+ if (Globals.re != null) {
+ KBD.Close();
+ RW.IN_Shutdown();
+ }
+
+ Globals.re = null;
+ reflib_active = false;
+ }
+
+ /*
+ ==============
+ VID_LoadRefresh
+ ==============
+ */
+ static boolean LoadRefresh( String name )
+ {
+
+ if ( reflib_active )
+ {
+ KBD.Close();
+ RW.IN_Shutdown();
+
+ Globals.re.Shutdown();
+ FreeReflib();
+ }
+
+ Com.Printf( "------- Loading " + name + " -------\n");
+
+ boolean found = false;
+
+ String[] driverNames = Renderer.getDriverNames();
+ for (int i = 0; i < driverNames.length; i++) {
+ if (driverNames[i].equals(name)) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ Com.Printf( "LoadLibrary(\"" + name +"\") failed\n");
+ return false;
+ }
+
+ Com.Printf( "LoadLibrary(\"" + name +"\")\n" );
+ refimport_t ri = new refimport_t() {
+ public void Sys_Error(int err_level, String str) {
+ VID.Error(err_level, str, null);
+ }
+
+ public void Sys_Error(int err_level, String str, Vargs vargs) {
+ VID.Error(err_level, str, vargs);
+ }
+
+ public void Cmd_AddCommand(String name, xcommand_t cmd) {
+ Cmd.AddCommand(name, cmd);
+ }
+
+ public void Cmd_RemoveCommand(String name) {
+ Cmd.RemoveCommand(name);
+ }
+
+ public int Cmd_Argc() {
+ return Cmd.Argc();
+ }
+
+ public String Cmd_Argv(int i) {
+ return Cmd.Argv(i);
+ }
+
+ public void Cmd_ExecuteText(int exec_when, String text) {
+ Cbuf.ExecuteText(exec_when, text);
+ }
+
+ public void Con_Printf(int print_level, String str) {
+ VID.Printf(print_level, str, null);
+ }
+
+ public void Con_Printf(int print_level, String str, Vargs vargs) {
+ VID.Printf(print_level, str, vargs);
+ }
+
+ public byte[] FS_LoadFile(String name) {
+ return FS.LoadFile(name);
+ }
+
+ public int FS_FileLength(String name) {
+ return FS.FileLength(name);
+ }
+
+ public void FS_FreeFile(byte[] buf) {
+ FS.FreeFile(buf);
+ }
+
+ public String FS_Gamedir() {
+ return FS.Gamedir();
+ }
+
+ public cvar_t Cvar_Get(String name, String value, int flags) {
+ return Cvar.Get(name, value, flags);
+ }
+
+ public cvar_t Cvar_Set(String name, String value) {
+ return Cvar.Set(name, value);
+ }
+
+ public void Cvar_SetValue(String name, float value) {
+ Cvar.SetValue(name, value);
+ }
+
+ public boolean Vid_GetModeInfo(Dimension dim, int mode) {
+ return VID.GetModeInfo(dim, mode);
+ }
+
+ public void Vid_MenuInit() {
+ VID.MenuInit();
+ }
+
+ public void Vid_NewWindow(int width, int height) {
+ VID.NewWindow(width, height);
+ }
+
+ public void updateScreenCallback() {
+ SCR.UpdateScreen2();
+ }
+ };
+
+ Globals.re = Renderer.getDriver( name, ri );
+
+ if (Globals.re == null)
+ {
+ Com.Error(Defines.ERR_FATAL, name + " can't load but registered");
+ }
+
+ if (Globals.re.apiVersion() != Defines.API_VERSION)
+ {
+ FreeReflib();
+ Com.Error(Defines.ERR_FATAL, name + " has incompatible api_version");
+ }
+
+ /* Init IN (Mouse) */
+// in_state.IN_CenterView_fp = IN_CenterView;
+// in_state.Key_Event_fp = Do_Key_Event;
+// in_state.viewangles = cl.viewangles;
+// in_state.in_strafe_state = &in_strafe.state;
+
+ IN.Real_IN_Init();
+
+ if ( !Globals.re.Init((int)vid_xpos.value, (int)vid_ypos.value) )
+ {
+ Globals.re.Shutdown();
+ FreeReflib();
+ return false;
+ }
+
+ /* Init KBD */
+ KBD.Init();
+
+ Com.Printf( "------------------------------------\n");
+ reflib_active = true;
+ return true;
+ }
+
+ /*
+ ============
+ VID_CheckChanges
+
+ This function gets called once just before drawing each frame, and it's sole purpose in life
+ is to check to see if any of the video mode parameters have changed, and if they have to
+ update the rendering DLL and/or video mode to match.
+ ============
+ */
+ public static void CheckChanges()
+ {
+ cvar_t gl_mode;
+
+ if ( vid_ref.modified )
+ {
+ S.StopAllSounds();
+ }
+
+ while (vid_ref.modified)
+ {
+ /*
+ ** refresh has changed
+ */
+ vid_ref.modified = false;
+ vid_fullscreen.modified = true;
+ Globals.cl.refresh_prepped = false;
+ Globals.cls.disable_screen = 1.0f; // true;
+
+ if ( !LoadRefresh( vid_ref.string ) )
+ {
+ if ( vid_ref.string.equals("jogl") ) {
+ Com.Printf("Refresh failed\n");
+ gl_mode = Cvar.Get( "gl_mode", "0", 0 );
+ if (gl_mode.value != 0.0f) {
+ Com.Printf("Trying mode 0\n");
+ Cvar.SetValue("gl_mode", 0);
+ if ( !LoadRefresh( vid_ref.string ) )
+ Com.Error(Defines.ERR_FATAL, "Couldn't fall back to jogl refresh!");
+ } else
+ Com.Error(Defines.ERR_FATAL, "Couldn't fall back to jogl refresh!");
+ }
+
+ Cvar.Set( "vid_ref", "jogl" );
+
+ /*
+ * drop the console if we fail to load a refresh
+ */
+ if ( Globals.cls.key_dest != Globals.key_console )
+ {
+ try {
+ Console.ToggleConsole_f.execute();
+ } catch (Exception e) {
+ }
+ }
+ }
+ Globals.cls.disable_screen = 0.0f; //false;
+ }
+ }
+
+ /*
+ ============
+ VID_Init
+ ============
+ */
+ public static void Init()
+ {
+ /* Create the video variables so we know how to start the graphics drivers */
+ vid_ref = Cvar.Get("vid_ref", "jogl", CVAR_ARCHIVE);
+ vid_xpos = Cvar.Get("vid_xpos", "3", CVAR_ARCHIVE);
+ vid_ypos = Cvar.Get("vid_ypos", "22", CVAR_ARCHIVE);
+ vid_fullscreen = Cvar.Get("vid_fullscreen", "0", CVAR_ARCHIVE);
+ vid_gamma = Cvar.Get( "vid_gamma", "1", CVAR_ARCHIVE );
+
+ /* Add some console commands that we want to handle */
+ Cmd.AddCommand ("vid_restart", new xcommand_t() {
+ public void execute() {
+ Restart_f();
+ }
+ });
+
+ /* Disable the 3Dfx splash screen */
+ // putenv("FX_GLIDE_NO_SPLASH=0");
+
+ /* Start the graphics mode and load refresh DLL */
+ CheckChanges();
+ }
+
+ /*
+ ============
+ VID_Shutdown
+ ============
+ */
+ public static void Shutdown()
+ {
+ if ( reflib_active )
+ {
+ KBD.Close();
+ RW.IN_Shutdown();
+
+ Globals.re.Shutdown();
+ FreeReflib();
+ }
+ }
+
+ // ==========================================================================
+ //
+ // vid_menu.c
+ //
+ // ==========================================================================
+
+// #define REF_SOFT 0
+// #define REF_SOFTX11 1
+// #define REF_MESA3D 2
+// #define REF_3DFXGL 3
+// #define REF_OPENGLX 4
+ static final int REF_OPENGL_JOGL = 0;
+// #define REF_MESA3DGLX 5
+
+// extern cvar_t *vid_ref;
+// extern cvar_t *vid_fullscreen;
+// extern cvar_t *vid_gamma;
+// extern cvar_t *scr_viewsize;
+
+ static cvar_t gl_mode;
+ static cvar_t gl_driver;
+ static cvar_t gl_picmip;
+ static cvar_t gl_ext_palettedtexture;
+
+ static cvar_t sw_mode;
+ static cvar_t sw_stipplealpha;
+
+ static cvar_t _windowed_mouse;
+
+ /*
+ ====================================================================
+
+ MENU INTERACTION
+
+ ====================================================================
+ */
+ static final int SOFTWARE_MENU = 0;
+ static final int OPENGL_MENU = 1;
+
+ static Menu.menuframework_s s_software_menu = new Menu.menuframework_s();
+ static Menu.menuframework_s s_opengl_menu = new Menu.menuframework_s();
+ static Menu.menuframework_s s_current_menu; // referenz
+ static int s_current_menu_index = 1; // default is the openGL menu
+
+ static Menu.menulist_s[] s_mode_list = new Menu.menulist_s[2];
+ static {
+ s_mode_list[0] = new Menu.menulist_s();
+ s_mode_list[1] = new Menu.menulist_s();
+ }
+ static Menu.menulist_s[] s_ref_list = new Menu.menulist_s[2];
+ static {
+ s_ref_list[0] = new Menu.menulist_s();
+ s_ref_list[1] = new Menu.menulist_s();
+ }
+ static Menu.menuslider_s s_tq_slider = new Menu.menuslider_s();
+ static Menu.menuslider_s[] s_screensize_slider = new Menu.menuslider_s[2];
+ static {
+ s_screensize_slider[0] = new Menu.menuslider_s();
+ s_screensize_slider[1] = new Menu.menuslider_s();
+ }
+ static Menu.menuslider_s[] s_brightness_slider = new Menu.menuslider_s[2];
+ static {
+ s_brightness_slider[0] = new Menu.menuslider_s();
+ s_brightness_slider[1] = new Menu.menuslider_s();
+ }
+ static Menu.menulist_s[] s_fs_box = new Menu.menulist_s[2];
+ static {
+ s_fs_box[0] = new Menu.menulist_s();
+ s_fs_box[1] = new Menu.menulist_s();
+ }
+ static Menu.menulist_s s_stipple_box = new Menu.menulist_s();
+ static Menu.menulist_s s_paletted_texture_box = new Menu.menulist_s();
+ static Menu.menulist_s s_windowed_mouse = new Menu.menulist_s();
+ static Menu.menuaction_s[] s_apply_action = new Menu.menuaction_s[2];
+ static {
+ s_apply_action[0] = new Menu.menuaction_s();
+ s_apply_action[1] = new Menu.menuaction_s();
+ }
+ static Menu.menuaction_s[] s_defaults_action= new Menu.menuaction_s[2];
+ static {
+ s_defaults_action[0] = new Menu.menuaction_s();
+ s_defaults_action[1] = new Menu.menuaction_s();
+ }
+
+ static void DriverCallback( Object unused )
+ {
+ s_ref_list[1 - s_current_menu_index].curvalue = s_ref_list[s_current_menu_index].curvalue;
+
+ if ( s_ref_list[s_current_menu_index].curvalue < 2 )
+ {
+ // we only use opengl today
+ s_current_menu = s_opengl_menu; // s_software_menu;
+ s_current_menu_index = 1; // 0;
+ }
+ else
+ {
+ s_current_menu = s_opengl_menu;
+ s_current_menu_index = 1;
+ }
+ }
+
+ static void ScreenSizeCallback( Object s )
+ {
+ Menu.menuslider_s slider = (Menu.menuslider_s) s;
+
+ Cvar.SetValue( "viewsize", slider.curvalue * 10 );
+ }
+
+ static void BrightnessCallback( Object s )
+ {
+ Menu.menuslider_s slider = (Menu.menuslider_s) s;
+
+ if ( s_current_menu_index == 0)
+ s_brightness_slider[1].curvalue = s_brightness_slider[0].curvalue;
+ else
+ s_brightness_slider[0].curvalue = s_brightness_slider[1].curvalue;
+
+ // if ( stricmp( vid_ref.string, "soft" ) == 0 ||
+ // stricmp( vid_ref.string, "softx" ) == 0 )
+ if ( vid_ref.string.equalsIgnoreCase("soft") ||
+ vid_ref.string.equalsIgnoreCase("softx") )
+ {
+ float gamma = ( 0.8f - ( slider.curvalue/10.0f - 0.5f ) ) + 0.5f;
+
+ Cvar.SetValue( "vid_gamma", gamma );
+ }
+ }
+
+ static void ResetDefaults( Object unused )
+ {
+ MenuInit();
+ }
+
+ static void ApplyChanges( Object unused )
+ {
+ /*
+ ** make values consistent
+ */
+ s_fs_box[1 - s_current_menu_index].curvalue = s_fs_box[s_current_menu_index].curvalue;
+ s_brightness_slider[1 - s_current_menu_index].curvalue = s_brightness_slider[s_current_menu_index].curvalue;
+ s_ref_list[1 - s_current_menu_index].curvalue = s_ref_list[s_current_menu_index].curvalue;
+
+ /*
+ ** invert sense so greater = brighter, and scale to a range of 0.5 to 1.3
+ */
+ float gamma = ( 0.8f - ( s_brightness_slider[s_current_menu_index].curvalue/10.0f - 0.5f ) ) + 0.5f;
+
+ Cvar.SetValue( "vid_gamma", gamma );
+ Cvar.SetValue( "sw_stipplealpha", s_stipple_box.curvalue );
+ Cvar.SetValue( "gl_picmip", 3 - s_tq_slider.curvalue );
+ Cvar.SetValue( "vid_fullscreen", s_fs_box[s_current_menu_index].curvalue );
+ Cvar.SetValue( "gl_ext_palettedtexture", s_paletted_texture_box.curvalue );
+ Cvar.SetValue( "sw_mode", s_mode_list[SOFTWARE_MENU].curvalue );
+ Cvar.SetValue( "gl_mode", s_mode_list[OPENGL_MENU].curvalue );
+ Cvar.SetValue( "_windowed_mouse", s_windowed_mouse.curvalue);
+
+ switch ( s_ref_list[s_current_menu_index].curvalue )
+ {
+// case REF_SOFT:
+// Cvar_Set( "vid_ref", "soft" );
+// break;
+// case REF_SOFTX11:
+// Cvar_Set( "vid_ref", "softx" );
+// break;
+//
+// case REF_MESA3D :
+// Cvar_Set( "vid_ref", "gl" );
+// Cvar_Set( "gl_driver", "libMesaGL.so.2" );
+// if (gl_driver->modified)
+// vid_ref->modified = true;
+// break;
+//
+// case REF_OPENGLX :
+// Cvar_Set( "vid_ref", "glx" );
+// Cvar_Set( "gl_driver", "libGL.so" );
+// if (gl_driver->modified)
+// vid_ref->modified = true;
+// break;
+//
+// case REF_MESA3DGLX :
+// Cvar_Set( "vid_ref", "glx" );
+// Cvar_Set( "gl_driver", "libMesaGL.so.2" );
+// if (gl_driver->modified)
+// vid_ref->modified = true;
+// break;
+//
+// case REF_3DFXGL :
+// Cvar_Set( "vid_ref", "gl" );
+// Cvar_Set( "gl_driver", "lib3dfxgl.so" );
+// if (gl_driver->modified)
+// vid_ref->modified = true;
+// break;
+ case REF_OPENGL_JOGL :
+ Cvar.Set( "vid_ref", "jogl" );
+ Cvar.Set( "gl_driver", "jogl" );
+ if (gl_driver.modified)
+ vid_ref.modified = true;
+ break;
+ }
+
+ Menu.ForceMenuOff();
+ }
+
+ static final String[] resolutions =
+ {
+ "[320 240 ]",
+ "[400 300 ]",
+ "[512 384 ]",
+ "[640 480 ]",
+ "[800 600 ]",
+ "[960 720 ]",
+ "[1024 768 ]",
+ "[1152 864 ]",
+ "[1280 1024]",
+ "[1600 1200]",
+ "[2048 1536]",
+ null
+ };
+ static final String[] refs =
+ {
+ // "[software ]",
+ // "[software X11 ]",
+ // "[Mesa 3-D 3DFX ]",
+ // "[3DFXGL Miniport]",
+ // "[OpenGL glX ]",
+ // "[Mesa 3-D glX ]",
+ "[OpenGL jogl ]",
+ null
+ };
+ static final String[] yesno_names =
+ {
+ "no",
+ "yes",
+ null
+ };
+
+ /*
+ ** VID_MenuInit
+ */
+ public static void MenuInit()
+ {
+ int i;
+
+ if ( gl_driver == null )
+ gl_driver = Cvar.Get( "gl_driver", "jogl", 0 );
+ if ( gl_picmip == null )
+ gl_picmip = Cvar.Get( "gl_picmip", "0", 0 );
+ if ( gl_mode == null)
+ gl_mode = Cvar.Get( "gl_mode", "3", 0 );
+ if ( sw_mode == null )
+ sw_mode = Cvar.Get( "sw_mode", "0", 0 );
+ if ( gl_ext_palettedtexture == null )
+ gl_ext_palettedtexture = Cvar.Get( "gl_ext_palettedtexture", "1", CVAR_ARCHIVE );
+
+ if ( sw_stipplealpha == null )
+ sw_stipplealpha = Cvar.Get( "sw_stipplealpha", "0", CVAR_ARCHIVE );
+
+ if ( _windowed_mouse == null)
+ _windowed_mouse = Cvar.Get( "_windowed_mouse", "0", CVAR_ARCHIVE );
+
+ s_mode_list[SOFTWARE_MENU].curvalue = (int)sw_mode.value;
+ s_mode_list[OPENGL_MENU].curvalue = (int)gl_mode.value;
+
+ if ( SCR.scr_viewsize == null )
+ SCR.scr_viewsize = Cvar.Get ("viewsize", "100", CVAR_ARCHIVE);
+
+ s_screensize_slider[SOFTWARE_MENU].curvalue = (int)(SCR.scr_viewsize.value/10);
+ s_screensize_slider[OPENGL_MENU].curvalue = (int)(SCR.scr_viewsize.value/10);
+
+// if ( strcmp( vid_ref->string, "soft" ) == 0)
+// {
+// s_current_menu_index = SOFTWARE_MENU;
+// s_ref_list[0].curvalue = s_ref_list[1].curvalue = REF_SOFT;
+// }
+ if ( vid_ref.string.equalsIgnoreCase("jogl"))
+ {
+ s_current_menu_index = OPENGL_MENU;
+ s_ref_list[0].curvalue = s_ref_list[1].curvalue = REF_OPENGL_JOGL;
+ }
+// else if (strcmp( vid_ref->string, "softx" ) == 0 )
+// {
+// s_current_menu_index = SOFTWARE_MENU;
+// s_ref_list[0].curvalue = s_ref_list[1].curvalue = REF_SOFTX11;
+// }
+// else if ( strcmp( vid_ref->string, "gl" ) == 0 )
+// {
+// s_current_menu_index = OPENGL_MENU;
+// if ( strcmp( gl_driver->string, "lib3dfxgl.so" ) == 0 )
+// s_ref_list[s_current_menu_index].curvalue = REF_3DFXGL;
+// else
+// s_ref_list[s_current_menu_index].curvalue = REF_MESA3D;
+// }
+// else if ( strcmp( vid_ref->string, "glx" ) == 0 )
+// {
+// s_current_menu_index = OPENGL_MENU;
+// if ( strcmp( gl_driver->string, "libMesaGL.so.2" ) == 0 )
+// s_ref_list[s_current_menu_index].curvalue = REF_MESA3DGLX;
+// else
+// s_ref_list[s_current_menu_index].curvalue = REF_OPENGLX;
+// }
+//
+ s_software_menu.x = (int)(viddef.width * 0.50f);
+ s_software_menu.nitems = 0;
+ s_opengl_menu.x = (int)(viddef.width * 0.50f);
+ s_opengl_menu.nitems = 0;
+
+ for ( i = 0; i < 2; i++ )
+ {
+ s_ref_list[i].type = MTYPE_SPINCONTROL;
+ s_ref_list[i].name = "driver";
+ s_ref_list[i].x = 0;
+ s_ref_list[i].y = 0;
+ s_ref_list[i].callback = new Menu.mcallback() {
+ public void execute(Object self) {
+ DriverCallback(self);
+ }
+ };
+ s_ref_list[i].itemnames = refs;
+
+ s_mode_list[i].type = MTYPE_SPINCONTROL;
+ s_mode_list[i].name = "video mode";
+ s_mode_list[i].x = 0;
+ s_mode_list[i].y = 10;
+ s_mode_list[i].itemnames = resolutions;
+
+ s_screensize_slider[i].type = MTYPE_SLIDER;
+ s_screensize_slider[i].x = 0;
+ s_screensize_slider[i].y = 20;
+ s_screensize_slider[i].name = "screen size";
+ s_screensize_slider[i].minvalue = 3;
+ s_screensize_slider[i].maxvalue = 12;
+ s_screensize_slider[i].callback = new Menu.mcallback() {
+ public void execute(Object self) {
+ ScreenSizeCallback(self);
+ }
+ };
+ s_brightness_slider[i].type = MTYPE_SLIDER;
+ s_brightness_slider[i].x = 0;
+ s_brightness_slider[i].y = 30;
+ s_brightness_slider[i].name = "brightness";
+ s_brightness_slider[i].callback = new Menu.mcallback() {
+ public void execute(Object self) {
+ BrightnessCallback(self);
+ }
+ };
+ s_brightness_slider[i].minvalue = 5;
+ s_brightness_slider[i].maxvalue = 13;
+ s_brightness_slider[i].curvalue = ( 1.3f - vid_gamma.value + 0.5f ) * 10;
+
+ s_fs_box[i].type = MTYPE_SPINCONTROL;
+ s_fs_box[i].x = 0;
+ s_fs_box[i].y = 40;
+ s_fs_box[i].name = "fullscreen";
+ s_fs_box[i].itemnames = yesno_names;
+ s_fs_box[i].curvalue = (int)vid_fullscreen.value;
+
+ s_defaults_action[i].type = MTYPE_ACTION;
+ s_defaults_action[i].name = "reset to default";
+ s_defaults_action[i].x = 0;
+ s_defaults_action[i].y = 90;
+ s_defaults_action[i].callback = new Menu.mcallback() {
+ public void execute(Object self) {
+ ResetDefaults(self);
+ }
+ };
+
+ s_apply_action[i].type = MTYPE_ACTION;
+ s_apply_action[i].name = "apply";
+ s_apply_action[i].x = 0;
+ s_apply_action[i].y = 100;
+ s_apply_action[i].callback = new Menu.mcallback() {
+ public void execute(Object self) {
+ ApplyChanges(self);
+ }
+ };
+ }
+
+ s_stipple_box.type = MTYPE_SPINCONTROL;
+ s_stipple_box.x = 0;
+ s_stipple_box.y = 60;
+ s_stipple_box.name = "stipple alpha";
+ s_stipple_box.curvalue = (int)sw_stipplealpha.value;
+ s_stipple_box.itemnames = yesno_names;
+
+ s_windowed_mouse.type = MTYPE_SPINCONTROL;
+ s_windowed_mouse.x = 0;
+ s_windowed_mouse.y = 72;
+ s_windowed_mouse.name = "windowed mouse";
+ s_windowed_mouse.curvalue = (int)_windowed_mouse.value;
+ s_windowed_mouse.itemnames = yesno_names;
+
+ s_tq_slider.type = MTYPE_SLIDER;
+ s_tq_slider.x = 0;
+ s_tq_slider.y = 60;
+ s_tq_slider.name = "texture quality";
+ s_tq_slider.minvalue = 0;
+ s_tq_slider.maxvalue = 3;
+ s_tq_slider.curvalue = 3 - gl_picmip.value;
+
+ s_paletted_texture_box.type = MTYPE_SPINCONTROL;
+ s_paletted_texture_box.x = 0;
+ s_paletted_texture_box.y = 70;
+ s_paletted_texture_box.name = "8-bit textures";
+ s_paletted_texture_box.itemnames = yesno_names;
+ s_paletted_texture_box.curvalue = (int)gl_ext_palettedtexture.value;
+
+ Menu.Menu_AddItem( s_software_menu, s_ref_list[SOFTWARE_MENU] );
+ Menu.Menu_AddItem( s_software_menu, s_mode_list[SOFTWARE_MENU] );
+ Menu.Menu_AddItem( s_software_menu, s_screensize_slider[SOFTWARE_MENU] );
+ Menu.Menu_AddItem( s_software_menu, s_brightness_slider[SOFTWARE_MENU] );
+ Menu.Menu_AddItem( s_software_menu, s_fs_box[SOFTWARE_MENU] );
+ Menu.Menu_AddItem( s_software_menu, s_stipple_box );
+ Menu.Menu_AddItem( s_software_menu, s_windowed_mouse );
+
+ Menu.Menu_AddItem( s_opengl_menu, s_ref_list[OPENGL_MENU] );
+ Menu.Menu_AddItem( s_opengl_menu, s_mode_list[OPENGL_MENU] );
+ Menu.Menu_AddItem( s_opengl_menu, s_screensize_slider[OPENGL_MENU] );
+ Menu.Menu_AddItem( s_opengl_menu, s_brightness_slider[OPENGL_MENU] );
+ Menu.Menu_AddItem( s_opengl_menu, s_fs_box[OPENGL_MENU] );
+ Menu.Menu_AddItem( s_opengl_menu, s_tq_slider );
+ Menu.Menu_AddItem( s_opengl_menu, s_paletted_texture_box );
+
+ Menu.Menu_AddItem( s_software_menu, s_defaults_action[SOFTWARE_MENU] );
+ Menu.Menu_AddItem( s_software_menu, s_apply_action[SOFTWARE_MENU] );
+ Menu.Menu_AddItem( s_opengl_menu, s_defaults_action[OPENGL_MENU] );
+ Menu.Menu_AddItem( s_opengl_menu, s_apply_action[OPENGL_MENU] );
+
+ Menu.Menu_Center( s_software_menu );
+ Menu.Menu_Center( s_opengl_menu );
+ s_opengl_menu.x -= 8;
+ s_software_menu.x -= 8;
+ }
+
+ /*
+ ================
+ VID_MenuDraw
+ ================
+ */
+ static void MenuDraw()
+ {
+
+ if ( s_current_menu_index == 0 )
+ s_current_menu = s_software_menu;
+ else
+ s_current_menu = s_opengl_menu;
+
+ /*
+ ** draw the banner
+ */
+ Dimension dim = new Dimension();
+ re.DrawGetPicSize( dim, "m_banner_video" );
+ re.DrawPic( viddef.width / 2 - dim.width / 2, viddef.height /2 - 110, "m_banner_video" );
+
+ /*
+ ** move cursor to a reasonable starting position
+ */
+ Menu.Menu_AdjustCursor( s_current_menu, 1 );
+
+ /*
+ ** draw the menu
+ */
+ Menu.Menu_Draw( s_current_menu );
+ }
+
+ /*
+ ================
+ VID_MenuKey
+ ================
+ */
+ static String MenuKey( int key )
+ {
+ Menu.menuframework_s m = s_current_menu;
+ final String sound = "misc/menu1.wav";
+
+ switch ( key )
+ {
+ case K_ESCAPE:
+ Menu.PopMenu();
+ return null;
+ case K_UPARROW:
+ m.cursor--;
+ Menu.Menu_AdjustCursor( m, -1 );
+ break;
+ case K_DOWNARROW:
+ m.cursor++;
+ Menu.Menu_AdjustCursor( m, 1 );
+ break;
+ case K_LEFTARROW:
+ Menu.Menu_SlideItem( m, -1 );
+ break;
+ case K_RIGHTARROW:
+ Menu.Menu_SlideItem( m, 1 );
+ break;
+ case K_ENTER:
+ Menu.Menu_SelectItem( m );
+ break;
+ }
+
+ return sound;
+ }
+
+}
diff --git a/src/jake2/client/centity_t.java b/src/jake2/client/centity_t.java
new file mode 100644
index 0000000..0c26bed
--- /dev/null
+++ b/src/jake2/client/centity_t.java
@@ -0,0 +1,39 @@
+/*
+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 27.11.2003 by RST.
+// $Id: centity_t.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+
+package jake2.client;
+
+import jake2.game.entity_state_t;
+
+public class centity_t {
+ entity_state_t baseline= new entity_state_t(null); // delta from this if not from a previous frame
+ entity_state_t current= new entity_state_t(null);
+ entity_state_t prev= new entity_state_t(null); // will always be valid, but might just be a copy of current
+
+ int serverframe; // if not current, this ent isn't in the frame
+
+ int trailcount; // for diminishing grenade trails
+ float[] lerp_origin = { 0, 0, 0 }; // for trails (variable hz)
+
+ int fly_stoptime;
+}
diff --git a/src/jake2/client/cl_sustain_t.java b/src/jake2/client/cl_sustain_t.java
new file mode 100644
index 0000000..6ba3767
--- /dev/null
+++ b/src/jake2/client/cl_sustain_t.java
@@ -0,0 +1,55 @@
+/*
+ * cl_sustain_t.java
+ * Copyright (C) 2004
+ *
+ * $Id: cl_sustain_t.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+ */
+/*
+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.
+
+*/
+package jake2.client;
+
+/**
+ * cl_sustain_t
+ */
+public class cl_sustain_t {
+ static abstract class ThinkAdapter {
+ abstract void think(cl_sustain_t self);
+ }
+
+ int id;
+ int type;
+ int endtime;
+ int nextthink;
+ int thinkinterval;
+ float[] org = new float[3];
+ float[] dir = new float[3];
+ int color;
+ int count;
+ int magnitude;
+
+ ThinkAdapter think;
+
+ void clear() {
+ org[0] = org[1] = org[2] =
+ dir[0] = dir[1] = dir[2] =
+ id = type = endtime = nextthink = thinkinterval = color = count = magnitude = 0;
+ think = null;
+ }
+}
diff --git a/src/jake2/client/client_state_t.java b/src/jake2/client/client_state_t.java
new file mode 100644
index 0000000..3577932
--- /dev/null
+++ b/src/jake2/client/client_state_t.java
@@ -0,0 +1,137 @@
+/*
+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 27.11.2003 by RST.
+//$Id: client_state_t.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+
+package jake2.client;
+
+import jake2.Defines;
+import jake2.game.cmodel_t;
+import jake2.game.usercmd_t;
+import jake2.render.image_t;
+import jake2.render.model_t;
+
+import java.io.RandomAccessFile;
+
+public class client_state_t {
+
+ public client_state_t() {
+ for (int n = 0; n < Defines.CMD_BACKUP; n++)
+ cmds[n] = new usercmd_t();
+ for (int i = 0; i < frames.length; i++) {
+ frames[i] = new frame_t();
+ }
+
+ for (int n = 0; n < Defines.MAX_CONFIGSTRINGS; n++)
+ configstrings[n] = new String();
+
+ for (int n=0; n < Defines.MAX_CLIENTS; n++)
+ clientinfo[n] = new clientinfo_t();
+ }
+ //
+ // the client_state_t structure is wiped completely at every
+ // server map change
+ //
+ int timeoutcount;
+
+ int timedemo_frames;
+ int timedemo_start;
+
+ public boolean refresh_prepped; // false if on new level or new ref dll
+ boolean sound_prepped; // ambient sounds can start
+ boolean force_refdef; // vid has changed, so we can't use a paused refdef
+
+ int parse_entities; // index (not anded off) into cl_parse_entities[]
+
+ usercmd_t cmd = new usercmd_t();
+ usercmd_t cmds[] = new usercmd_t[Defines.CMD_BACKUP]; // each mesage will send several old cmds
+
+ int cmd_time[] = new int[Defines.CMD_BACKUP]; // time sent, for calculating pings
+ short predicted_origins[][] = new short[Defines.CMD_BACKUP][3]; // for debug comparing against server
+
+ float predicted_step; // for stair up smoothing
+ int predicted_step_time;
+
+ float[] predicted_origin ={0,0,0}; // generated by CL_PredictMovement
+ float[] predicted_angles={0,0,0};
+ float[] prediction_error={0,0,0};
+
+ public frame_t frame = new frame_t(); // received from server
+ int surpressCount; // number of messages rate supressed
+ frame_t frames[] = new frame_t[Defines.UPDATE_BACKUP];
+
+ // the client maintains its own idea of view angles, which are
+ // sent to the server each frame. It is cleared to 0 upon entering each level.
+ // the server sends a delta each frame which is added to the locally
+ // tracked view angles to account for standing on rotating objects,
+ // and teleport direction changes
+ public float[] viewangles = { 0, 0, 0 };
+
+ int time; // this is the time value that the client
+ // is rendering at. always <= cls.realtime
+ float lerpfrac; // between oldframe and frame
+
+ refdef_t refdef = new refdef_t();
+
+ float[] v_forward = { 0, 0, 0 };
+ float[] v_right = { 0, 0, 0 };
+ float[] v_up = { 0, 0, 0 }; // set when refdef.angles is set
+
+ //
+ // transient data from server
+ //
+
+ String layout = ""; // general 2D overlay
+ int inventory[] = new int[Defines.MAX_ITEMS];
+
+ //
+ // non-gameserver infornamtion
+ // FIXME: move this cinematic stuff into the cin_t structure
+ RandomAccessFile cinematic_file;
+
+ int cinematictime; // cls.realtime for first cinematic frame
+ int cinematicframe;
+ byte cinematicpalette[] = new byte[768];
+ boolean cinematicpalette_active;
+
+ //
+ // server state information
+ //
+ boolean attractloop; // running the attract loop, any key will menu
+ int servercount; // server identification for prespawns
+ String gamedir ="";
+ int playernum;
+
+ String configstrings[] = new String[Defines.MAX_CONFIGSTRINGS];
+
+ //
+ // locally derived information from server state
+ //
+ model_t model_draw[] = new model_t[Defines.MAX_MODELS];
+ cmodel_t model_clip[] = new cmodel_t[Defines.MAX_MODELS];
+
+ sfx_t sound_precache[] = new sfx_t[Defines.MAX_SOUNDS];
+ image_t image_precache[] = new image_t[Defines.MAX_IMAGES];
+
+ clientinfo_t clientinfo[] = new clientinfo_t[Defines.MAX_CLIENTS];
+ clientinfo_t baseclientinfo = new clientinfo_t();
+
+}
diff --git a/src/jake2/client/client_static_t.java b/src/jake2/client/client_static_t.java
new file mode 100644
index 0000000..c89a81d
--- /dev/null
+++ b/src/jake2/client/client_static_t.java
@@ -0,0 +1,72 @@
+/*
+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 27.11.2003 by RST.
+// $Id: client_static_t.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+
+
+package jake2.client;
+
+import jake2.qcommon.netchan_t;
+import java.io.*;
+
+public class client_static_t {
+
+ // was enum connstate_t
+ public int state;
+
+ // was enum keydest_t
+ public int key_dest;
+
+ public int framecount;
+ public int realtime; // always increasing, no clamping, etc
+ public float frametime; // seconds since last frame
+
+ // screen rendering information
+ public float disable_screen; // showing loading plaque between levels
+ // or changing rendering dlls
+ // if time gets > 30 seconds ahead, break it
+ public int disable_servercount; // when we receive a frame and cl.servercount
+ // > cls.disable_servercount, clear disable_screen
+
+ // connection information
+ public String servername = ""; // name of server from original connect
+ public float connect_time; // for connection retransmits
+
+ int quakePort; // a 16 bit value that allows quake servers
+ // to work around address translating routers
+ public netchan_t netchan = new netchan_t();
+ public int serverProtocol; // in case we are doing some kind of version hack
+
+ public int challenge; // from the server to use for connecting
+
+ public RandomAccessFile download; // file transfer from server
+ public String downloadtempname="";
+ public String downloadname="";
+ public int downloadnumber;
+ // was enum dltype_t
+ public int downloadtype;
+ public int downloadpercent;
+
+ // demo recording info must be here, so it isn't cleared on level change
+ public boolean demorecording;
+ public boolean demowaiting; // don't record until a non-delta message is received
+ public RandomAccessFile demofile;
+}
diff --git a/src/jake2/client/clientinfo_t.java b/src/jake2/client/clientinfo_t.java
new file mode 100644
index 0000000..4276b08
--- /dev/null
+++ b/src/jake2/client/clientinfo_t.java
@@ -0,0 +1,53 @@
+/*
+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.11.2003 by RST.
+//$Id: clientinfo_t.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+
+package jake2.client;
+
+import jake2.*;
+import jake2.render.*;
+
+public class clientinfo_t {
+ String name ="";
+ String cinfo ="";
+ image_t skin; // ptr
+ image_t icon; // ptr
+ String iconname ="";
+ model_t model; // ptr
+ model_t weaponmodel[] = new model_t[Defines.MAX_CLIENTWEAPONMODELS]; // arary of references
+
+// public void reset()
+// {
+// set(new clientinfo_t());
+// }
+
+ public void set (clientinfo_t from)
+ {
+ name = from.name;
+ cinfo = from.cinfo;
+ skin = from.skin;
+ icon = from.icon;
+ iconname = from.iconname;
+ model = from.model;
+ System.arraycopy(from.weaponmodel,0, weaponmodel, 0 , Defines.MAX_CLIENTWEAPONMODELS);
+ }
+}
diff --git a/src/jake2/client/console_t.java b/src/jake2/client/console_t.java
new file mode 100644
index 0000000..eff5d2f
--- /dev/null
+++ b/src/jake2/client/console_t.java
@@ -0,0 +1,51 @@
+/*
+ * console_t.java
+ * Copyright (C) 2003
+ *
+ * $Id: console_t.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+ */
+/*
+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.
+
+*/
+package jake2.client;
+
+import jake2.Defines;
+
+/**
+ * console_t
+ */
+public final class console_t {
+ boolean initialized;
+ byte[] text = new byte[Defines.CON_TEXTSIZE];
+ int current; // line where next message will be printed
+ int x; // offset in current line for next print
+ int display; // bottom of console displays this line
+
+ int ormask; // high bit mask for colored characters
+
+ int linewidth; // characters across screen
+ int totallines; // total lines in console scrollback
+
+ float cursorspeed;
+
+ int vislines;
+
+ float[] times = new float[Defines.NUM_CON_TIMES]; // cls.realtime time the line was generated
+ // for transparent notify lines
+}
diff --git a/src/jake2/client/cparticle_t.java b/src/jake2/client/cparticle_t.java
new file mode 100644
index 0000000..a208077
--- /dev/null
+++ b/src/jake2/client/cparticle_t.java
@@ -0,0 +1,46 @@
+/*
+ * cparticle_t.java
+ * Copyright (C) 2003
+ *
+ * $Id: cparticle_t.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+ */
+/*
+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.
+
+*/
+package jake2.client;
+
+/**
+ * cparticle_t
+ *
+ * @author cwei
+ */
+public class cparticle_t {
+
+ public cparticle_t next;
+ public float time;
+
+ public float[] org = {0, 0, 0}; // vec3_t
+ public float[] vel = {0, 0, 0}; // vec3_t
+ public float[] accel = {0, 0, 0}; // vec3_t
+
+ public float color;
+ //public float colorvel;
+ public float alpha;
+ public float alphavel;
+}
diff --git a/src/jake2/client/dlight_t.java b/src/jake2/client/dlight_t.java
new file mode 100644
index 0000000..cefb1cb
--- /dev/null
+++ b/src/jake2/client/dlight_t.java
@@ -0,0 +1,31 @@
+/*
+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 20.11.2003 by RST.
+// $Id: dlight_t.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+
+package jake2.client;
+
+public class dlight_t
+{
+ public float origin[] = { 0, 0, 0 };
+ public float color[] = { 0, 0, 0 };
+ public float intensity;
+}
diff --git a/src/jake2/client/entity_t.java b/src/jake2/client/entity_t.java
new file mode 100644
index 0000000..3547e86
--- /dev/null
+++ b/src/jake2/client/entity_t.java
@@ -0,0 +1,76 @@
+/*
+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 20.11.2003 by RST.
+// $Id: entity_t.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+
+package jake2.client;
+
+import jake2.render.*;
+import jake2.util.Math3D;
+
+// ok!
+public class entity_t implements Cloneable{
+ //ptr
+ public model_t model; // opaque type outside refresh
+ public float angles[] = { 0, 0, 0 };
+
+ /*
+ ** most recent data
+ */
+ public float origin[] = { 0, 0, 0 }; // also used as RF_BEAM's "from"
+ public int frame; // also used as RF_BEAM's diameter
+
+ /*
+ ** previous data for lerping
+ */
+ public float oldorigin[] = { 0, 0, 0 }; // also used as RF_BEAM's "to"
+ public int oldframe;
+
+ /*
+ ** misc
+ */
+ public float backlerp; // 0.0 = current, 1.0 = old
+ public int skinnum; // also used as RF_BEAM's palette index
+
+ public int lightstyle; // for flashing entities
+ public float alpha; // ignore if RF_TRANSLUCENT isn't set
+
+ // reference
+ public image_t skin; // NULL for inline skin
+ public int flags;
+
+
+ public void set(entity_t src) {
+ this.model = src.model;
+ Math3D.VectorCopy(src.angles, this.angles);
+ Math3D.VectorCopy(src.origin, this.origin);
+ this.frame = src.frame;
+ Math3D.VectorCopy(src.oldorigin, this.oldorigin);
+ this.oldframe = src.oldframe;
+ this.backlerp = src.backlerp;
+ this.skinnum = src.skinnum;
+ this.lightstyle = src.lightstyle;
+ this.alpha = src.alpha;
+ this.skin = src.skin;
+ this.flags = src.flags;
+ }
+
+}
diff --git a/src/jake2/client/frame_t.java b/src/jake2/client/frame_t.java
new file mode 100644
index 0000000..d493363
--- /dev/null
+++ b/src/jake2/client/frame_t.java
@@ -0,0 +1,61 @@
+/*
+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 27.11.2003 by RST.
+// $Id: frame_t.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+
+package jake2.client;
+
+import jake2.game.player_state_t;
+
+import java.util.Arrays;
+
+public class frame_t implements Cloneable {
+
+ public static final int MAX_MAP_AREAS = 256;
+
+ boolean valid; // cleared if delta parsing was invalid
+ int serverframe;
+ int servertime; // server time the message is valid for (in msec)
+ int deltaframe;
+ byte areabits[] = new byte [MAX_MAP_AREAS/8]; // portalarea visibility bits
+ public player_state_t playerstate = new player_state_t(); // mem
+ int num_entities;
+ int parse_entities; // non-masked index into cl_parse_entities array
+
+ public void set(frame_t from) {
+ valid = from.valid;
+ serverframe = from.serverframe;
+ deltaframe = from.deltaframe;
+ num_entities = from.num_entities;
+ parse_entities = from.parse_entities;
+ System.arraycopy(from.areabits, 0, areabits, 0, areabits.length);
+ playerstate.set(from.playerstate);
+ }
+
+ public void reset()
+ {
+ valid = false;
+ serverframe = servertime = deltaframe = 0;
+ Arrays.fill(areabits, (byte)0);
+ playerstate.clear();
+ num_entities = parse_entities = 0;
+ }
+}
diff --git a/src/jake2/client/kbutton_t.java b/src/jake2/client/kbutton_t.java
new file mode 100644
index 0000000..d192bc2
--- /dev/null
+++ b/src/jake2/client/kbutton_t.java
@@ -0,0 +1,36 @@
+/*
+ * kbutton_t.java
+ * Copyright (C) 2004
+ *
+ * $Id: kbutton_t.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+ */
+/*
+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.
+
+*/
+package jake2.client;
+
+/**
+ * kbutton_t
+ */
+public class kbutton_t {
+ int[] down = new int[2]; // key nums holding it down
+ long downtime; // msec timestamp
+ long msec; // msec down this frame
+ public int state;
+}
diff --git a/src/jake2/client/lightstyle_t.java b/src/jake2/client/lightstyle_t.java
new file mode 100644
index 0000000..328e3c1
--- /dev/null
+++ b/src/jake2/client/lightstyle_t.java
@@ -0,0 +1,30 @@
+/*
+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 20.11.2003 by RST.
+// $Id: lightstyle_t.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+
+package jake2.client;
+
+public class lightstyle_t
+{
+ public float rgb[] = { 0, 0, 0 }; // 0.0 - 2.0
+ public float white; // highest of rgb
+}
diff --git a/src/jake2/client/particle_t.java b/src/jake2/client/particle_t.java
new file mode 100644
index 0000000..2127b5d
--- /dev/null
+++ b/src/jake2/client/particle_t.java
@@ -0,0 +1,30 @@
+/*
+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 20.11.2003 by RST.
+// $Id: particle_t.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+
+package jake2.client;
+
+public class particle_t {
+ public float origin[] = { 0, 0, 0 };
+ public int color;
+ public float alpha;
+}
diff --git a/src/jake2/client/refdef_t.java b/src/jake2/client/refdef_t.java
new file mode 100644
index 0000000..a01ab06
--- /dev/null
+++ b/src/jake2/client/refdef_t.java
@@ -0,0 +1,47 @@
+/*
+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 20.11.2003 by RST.
+// $Id: refdef_t.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+
+package jake2.client;
+
+public class refdef_t {
+ public int x, y, width, height;// in virtual screen coordinates
+ public float fov_x, fov_y;
+ public float vieworg[] ={0,0,0};
+ public float viewangles[]={0,0,0};
+ public float blend[]={0,0,0,0}; // rgba 0-1 full screen blend
+ public float time; // time is uesed to auto animate
+ public int rdflags; // RDF_UNDERWATER, etc
+
+ public byte areabits[]; // if not NULL, only areas with set bits will be drawn
+
+ public lightstyle_t lightstyles[]; // [MAX_LIGHTSTYLES]
+
+ public int num_entities;
+ public entity_t entities[];
+
+ public int num_dlights;
+ public dlight_t dlights[];
+
+ public int num_particles;
+ public particle_t particles[];
+}
diff --git a/src/jake2/client/refexport_t.java b/src/jake2/client/refexport_t.java
new file mode 100644
index 0000000..d1872c9
--- /dev/null
+++ b/src/jake2/client/refexport_t.java
@@ -0,0 +1,107 @@
+/*
+ * refexport_t.java
+ * Copyright (C) 2003
+ *
+ * $Id: refexport_t.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+ */
+ /*
+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.
+
+*/
+
+package jake2.client;
+
+import jake2.qcommon.xcommand_t;
+import jake2.render.image_t;
+import jake2.render.model_t;
+
+import java.awt.Dimension;
+
+/**
+ * refexport_t
+ *
+ * @author cwei
+ */
+public interface refexport_t {
+ // ============================================================================
+ // public interface for Renderer implementations
+ //
+ // ref.h, refexport_t
+ // ============================================================================
+ //
+ // these are the functions exported by the refresh module
+ //
+ // called when the library is loaded
+ boolean Init(int vid_xpos, int vid_ypos);
+
+ // called before the library is unloaded
+ void Shutdown();
+
+ // All data that will be used in a level should be
+ // registered before rendering any frames to prevent disk hits,
+ // but they can still be registered at a later time
+ // if necessary.
+ //
+ // EndRegistration will free any remaining data that wasn't registered.
+ // Any model_s or skin_s pointers from before the BeginRegistration
+ // are no longer valid after EndRegistration.
+ //
+ // Skins and images need to be differentiated, because skins
+ // are flood filled to eliminate mip map edge errors, and pics have
+ // an implicit "pics/" prepended to the name. (a pic name that starts with a
+ // slash will not use the "pics/" prefix or the ".pcx" postfix)
+ void BeginRegistration(String map);
+ model_t RegisterModel(String name);
+ image_t RegisterSkin(String name);
+ image_t RegisterPic(String name);
+ void SetSky(String name, float rotate, /* vec3_t */
+ float[] axis);
+ void EndRegistration();
+
+ void RenderFrame(refdef_t fd);
+
+ void DrawGetPicSize(Dimension dim /* int *w, *h */, String name);
+ // will return 0 0 if not found
+ void DrawPic(int x, int y, String name);
+ void DrawStretchPic(int x, int y, int w, int h, String name);
+ void DrawChar(int x, int y, int num); // num is 8 bit ASCII
+ void DrawTileClear(int x, int y, int w, int h, String name);
+ void DrawFill(int x, int y, int w, int h, int c);
+ void DrawFadeScreen();
+
+ // Draw images for cinematic rendering (which can have a different palette). Note that calls
+ void DrawStretchRaw(int x, int y, int w, int h, int cols, int rows, byte[] data);
+
+ /*
+ ** video mode and refresh state management entry points
+ */
+ /* 256 r,g,b values; null = game palette, size = 768 bytes */
+ void CinematicSetPalette(final byte[] palette);
+ void BeginFrame(float camera_separation);
+ void EndFrame();
+
+ void AppActivate(boolean activate);
+
+ /**
+ *
+ *
+ */
+ void updateScreen(xcommand_t callback);
+
+ int apiVersion();
+}
diff --git a/src/jake2/client/refimport_t.java b/src/jake2/client/refimport_t.java
new file mode 100644
index 0000000..f465482
--- /dev/null
+++ b/src/jake2/client/refimport_t.java
@@ -0,0 +1,76 @@
+/*
+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 20.11.2003 by RST.
+// $Id: refimport_t.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+
+
+package jake2.client;
+
+import java.awt.Dimension;
+
+import jake2.game.*;
+import jake2.qcommon.xcommand_t;
+import jake2.util.Vargs;
+
+public interface refimport_t {
+ // ref.h
+ // these are the functions imported by the refresh module
+ //
+ void Sys_Error(int err_level, String str);
+ void Sys_Error(int err_level, String str, Vargs vargs);
+
+ void Cmd_AddCommand(String name, xcommand_t cmd);
+ void Cmd_RemoveCommand(String name);
+ int Cmd_Argc();
+ String Cmd_Argv(int i);
+ void Cmd_ExecuteText(int exec_when, String text);
+
+ void Con_Printf(int print_level, String str, Vargs vargs);
+
+ void Con_Printf(int print_level, String str);
+
+ // files will be memory mapped read only
+ // the returned buffer may be part of a larger pak file,
+ // or a discrete file from anywhere in the quake search path
+ // a -1 return means the file does not exist
+ // NULL can be passed for buf to just determine existance
+ byte[] FS_LoadFile(String name);
+ int FS_FileLength(String name);
+
+ void FS_FreeFile(byte[] buf);
+ // gamedir will be the current directory that generated
+ // files should be stored to, ie: "f:\quake\id1"
+ String FS_Gamedir();
+
+ cvar_t Cvar_Get(String name, String value, int flags);
+ cvar_t Cvar_Set(String name, String value);
+ void Cvar_SetValue(String name, float value);
+
+ boolean Vid_GetModeInfo(Dimension dim /* int *w, *h */, int mode);
+ void Vid_MenuInit();
+ void Vid_NewWindow(int width, int height);
+
+ /**
+ * This is the callback for Renderer.
+ */
+ void updateScreenCallback();
+
+} \ No newline at end of file
diff --git a/src/jake2/client/sfx_t.java b/src/jake2/client/sfx_t.java
new file mode 100644
index 0000000..97431ab
--- /dev/null
+++ b/src/jake2/client/sfx_t.java
@@ -0,0 +1,41 @@
+/*
+ * sfx_t.java
+ * Copyright (C) 2003
+ *
+ * $Id: sfx_t.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+ */
+/*
+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.11.2003 by RST.
+
+package jake2.client;
+
+public class sfx_t {
+ String name =""; //mem
+ int registration_sequence;
+ sfxcache_t cache; //ptr
+ String truename; //ptr
+ public void clear() {
+ name = truename = null;
+ cache = null;
+ registration_sequence = 0;
+ }
+}
diff --git a/src/jake2/client/sfxcache_t.java b/src/jake2/client/sfxcache_t.java
new file mode 100644
index 0000000..69fbcde
--- /dev/null
+++ b/src/jake2/client/sfxcache_t.java
@@ -0,0 +1,34 @@
+/*
+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.11.2003 by RST.
+// $Id: sfxcache_t.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+
+package jake2.client;
+
+public class sfxcache_t {
+ int length;
+ int loopstart;
+ int speed; // not needed, because converted on load?
+ int width;
+ int stereo;
+ byte data[] = new byte[1]; // variable sized
+
+}
diff --git a/src/jake2/client/viddef_t.java b/src/jake2/client/viddef_t.java
new file mode 100644
index 0000000..56c92aa
--- /dev/null
+++ b/src/jake2/client/viddef_t.java
@@ -0,0 +1,28 @@
+/*
+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 20.11.2003 by RST.
+// $Id: viddef_t.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+
+package jake2.client;
+
+public class viddef_t {
+ public int width, height;
+}
diff --git a/src/jake2/client/vidmode_t.java b/src/jake2/client/vidmode_t.java
new file mode 100644
index 0000000..69cf055
--- /dev/null
+++ b/src/jake2/client/vidmode_t.java
@@ -0,0 +1,44 @@
+/*
+ * vidmode_t.java
+ * Copyright (C) 2003
+ *
+ * $Id: vidmode_t.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+ */
+ /*
+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.
+
+*/
+package jake2.client;
+
+/**
+ * vidmode_t
+ *
+ * @author cwei
+ */
+public class vidmode_t {
+ String description;
+ int width, height;
+ int mode;
+
+ vidmode_t (String description, int width, int height, int mode) {
+ this.description = description;
+ this.width = width;
+ this.height = height;
+ this.mode = mode;
+ }
+}
diff --git a/src/jake2/client/vrect_t.java b/src/jake2/client/vrect_t.java
new file mode 100644
index 0000000..03d15d6
--- /dev/null
+++ b/src/jake2/client/vrect_t.java
@@ -0,0 +1,39 @@
+/*
+ * vrect_t.java
+ * Copyright (C) 2003
+ *
+ * $Id: vrect_t.java,v 1.1 2004-07-07 19:58:52 hzi Exp $
+ */
+/*
+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.
+
+*/
+package jake2.client;
+
+/**
+ * vrect_t
+ *
+ * @author cwei
+ */
+public class vrect_t {
+ public int x;
+ public int y;
+ public int width;
+ public int height;
+ vrect_t pnext;
+}