aboutsummaryrefslogtreecommitdiffstats
path: root/src/jake2/qcommon
diff options
context:
space:
mode:
authorRene Stoeckel <[email protected]>2004-09-22 19:22:16 +0000
committerRene Stoeckel <[email protected]>2004-09-22 19:22:16 +0000
commitc4fcffe436fbfb5b0f3b7be2e5ee103ec74932f7 (patch)
tree7c9439ab1d9f5a4fd61bd57c755069007b23e0b6 /src/jake2/qcommon
parentbcb4ac6eefb425d5b0a90009da506361d5739e75 (diff)
major refactoring in game, server and client package
Diffstat (limited to 'src/jake2/qcommon')
-rw-r--r--src/jake2/qcommon/CM.java3779
-rw-r--r--src/jake2/qcommon/Cbuf.java452
-rw-r--r--src/jake2/qcommon/Cvar.java854
-rw-r--r--src/jake2/qcommon/MSG.java1105
-rw-r--r--src/jake2/qcommon/Netchan.java707
-rw-r--r--src/jake2/qcommon/PMove.java2421
-rw-r--r--src/jake2/qcommon/Q2DataDialog.java854
-rw-r--r--src/jake2/qcommon/netchan_t.java122
8 files changed, 5084 insertions, 5210 deletions
diff --git a/src/jake2/qcommon/CM.java b/src/jake2/qcommon/CM.java
index 5978f88..52495db 100644
--- a/src/jake2/qcommon/CM.java
+++ b/src/jake2/qcommon/CM.java
@@ -1,29 +1,29 @@
/*
-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.
-
-*/
+ * 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 02.01.2004 by RST.
-// $Id: CM.java,v 1.5 2004-07-28 12:01:27 hzi Exp $
-
+// $Id: CM.java,v 1.6 2004-09-22 19:22:09 salomo Exp $
package jake2.qcommon;
import jake2.Defines;
+import jake2.Globals;
import jake2.game.*;
import jake2.util.*;
@@ -31,1889 +31,1866 @@ import java.io.RandomAccessFile;
import java.nio.*;
import java.util.Arrays;
-public class CM extends Game {
-
- public static class cnode_t {
- cplane_t plane; // ptr
- int children[] = { 0, 0 }; // negative numbers are leafs
- }
-
- public static class cbrushside_t {
- cplane_t plane; // ptr
- mapsurface_t surface; // ptr
- }
-
- public static class cleaf_t {
- int contents;
- int cluster;
- int area;
-
- // was unsigned short, but is ok (rst)
- short firstleafbrush;
- // was unsigned short, but is ok (rst)
- short numleafbrushes;
- }
-
- public static class cbrush_t {
- int contents;
- int numsides;
- int firstbrushside;
- int checkcount; // to avoid repeated testings
- }
-
- public static class carea_t {
- int numareaportals;
- int firstareaportal;
- int floodnum; // if two areas have equal floodnums, they are connected
- int floodvalid;
- }
+public class CM {
+
+ public static class cnode_t {
+ cplane_t plane; // ptr
+
+ int children[] = { 0, 0 }; // negative numbers are leafs
+ }
+
+ public static class cbrushside_t {
+ cplane_t plane; // ptr
+
+ mapsurface_t surface; // ptr
+ }
+
+ public static class cleaf_t {
+ int contents;
+
+ int cluster;
+
+ int area;
+
+ // was unsigned short, but is ok (rst)
+ short firstleafbrush;
+
+ // was unsigned short, but is ok (rst)
+ short numleafbrushes;
+ }
+
+ public static class cbrush_t {
+ int contents;
+
+ int numsides;
+
+ int firstbrushside;
+
+ int checkcount; // to avoid repeated testings
+ }
+
+ public static class carea_t {
+ int numareaportals;
+
+ int firstareaportal;
+
+ int floodnum; // if two areas have equal floodnums, they are connected
+
+ int floodvalid;
+ }
+
+ static int checkcount;
+
+ static String map_name = "";
+
+ static int numbrushsides;
+
+ static cbrushside_t map_brushsides[] = new cbrushside_t[Defines.MAX_MAP_BRUSHSIDES];
+ static {
+ for (int n = 0; n < Defines.MAX_MAP_BRUSHSIDES; n++)
+ map_brushsides[n] = new cbrushside_t();
+ }
+
+ public static int numtexinfo;
+
+ public static mapsurface_t map_surfaces[] = new mapsurface_t[Defines.MAX_MAP_TEXINFO];
+ static {
+ for (int n = 0; n < Defines.MAX_MAP_TEXINFO; n++)
+ map_surfaces[n] = new mapsurface_t();
+ }
+
+ static int numplanes;
+
+ // extra for box hull ( +6)
+ static cplane_t map_planes[] = new cplane_t[Defines.MAX_MAP_PLANES + 6];
+
+ static {
+ for (int n = 0; n < Defines.MAX_MAP_PLANES + 6; n++)
+ map_planes[n] = new cplane_t();
+ }
+
+ static int numnodes;
+
+ // extra for box hull ( +6)
+ static cnode_t map_nodes[] = new cnode_t[Defines.MAX_MAP_NODES + 6];
+
+ static {
+ for (int n = 0; n < Defines.MAX_MAP_NODES + 6; n++)
+ map_nodes[n] = new cnode_t();
+ }
+
+ static int numleafs = 1; // allow leaf funcs to be called without a map
+
+ static cleaf_t map_leafs[] = new cleaf_t[Defines.MAX_MAP_LEAFS];
+ static {
+ for (int n = 0; n < Defines.MAX_MAP_LEAFS; n++)
+ map_leafs[n] = new cleaf_t();
+ }
+
+ static int emptyleaf, solidleaf;
+
+ static int numleafbrushes;
+
+ //static unsigned short map_leafbrushes[Defines.MAX_MAP_LEAFBRUSHES];
+ public static int map_leafbrushes[] = new int[Defines.MAX_MAP_LEAFBRUSHES];
+
+ public static int numcmodels;
+
+ public static cmodel_t map_cmodels[] = new cmodel_t[Defines.MAX_MAP_MODELS];
+ static {
+ for (int n = 0; n < Defines.MAX_MAP_MODELS; n++)
+ map_cmodels[n] = new cmodel_t();
+
+ }
+
+ public static int numbrushes;
+
+ public static cbrush_t map_brushes[] = new cbrush_t[Defines.MAX_MAP_BRUSHES];
+ static {
+ for (int n = 0; n < Defines.MAX_MAP_BRUSHES; n++)
+ map_brushes[n] = new cbrush_t();
+
+ }
+
+ public static int numvisibility;
+
+ public static byte map_visibility[] = new byte[Defines.MAX_MAP_VISIBILITY];
+
+ // main visibility data. rst
+ // was: static dvis_t *map_vis = (dvis_t *)map_visibility;
+ public static qfiles.dvis_t map_vis = new qfiles.dvis_t(ByteBuffer
+ .wrap(map_visibility));
+
+ public static int numentitychars;
+
+ public static String map_entitystring;
+
+ public static int numareas = 1;
+
+ public static carea_t map_areas[] = new carea_t[Defines.MAX_MAP_AREAS];
+ static {
+ for (int n = 0; n < Defines.MAX_MAP_AREAS; n++)
+ map_areas[n] = new carea_t();
+
+ }
+
+ public static int numareaportals;
+
+ public static qfiles.dareaportal_t map_areaportals[] = new qfiles.dareaportal_t[Defines.MAX_MAP_AREAPORTALS];
+
+ static {
+ for (int n = 0; n < Defines.MAX_MAP_AREAPORTALS; n++)
+ map_areaportals[n] = new qfiles.dareaportal_t();
+
+ }
+
+ public static int numclusters = 1;
+
+ public static mapsurface_t nullsurface = new mapsurface_t();
+
+ public static int floodvalid;
+
+ public static boolean portalopen[] = new boolean[Defines.MAX_MAP_AREAPORTALS];
+
+ public static cvar_t map_noareas;
+
+ /*
+ * ===============================================================================
+ *
+ * MAP LOADING
+ *
+ * ===============================================================================
+ */
+
+ public static byte cmod_base[];
+
+ // is that right (rst) ?
+ public static int checksum;
+
+ public static int last_checksum;
+
+ /*
+ * ================== CM_LoadMap
+ *
+ * Loads in the map and all submodels ==================
+ */
+ public static cmodel_t CM_LoadMap(String name, boolean clientload,
+ int checksum[]) {
+ Com.DPrintf("CM_LoadMap...\n");
+ byte buf[];
+ int i;
+ qfiles.dheader_t header;
+ int length;
+
+ map_noareas = Cvar.Get("map_noareas", "0", 0);
+
+ if (map_name.equals(name)
+ && (clientload || 0 == Cvar.VariableValue("flushmap"))) {
+
+ checksum[0] = last_checksum;
+
+ if (!clientload) {
+ Arrays.fill(portalopen, false);
+ FloodAreaConnections();
+ }
+ return map_cmodels[0]; // still have the right version
+ }
+
+ // free old stuff
+ numnodes = 0;
+ numleafs = 0;
+ numcmodels = 0;
+ numvisibility = 0;
+ numentitychars = 0;
+ map_entitystring = "";
+ map_name = "";
+
+ if (name == null || name.length() == 0) {
+ numleafs = 1;
+ numclusters = 1;
+ numareas = 1;
+ checksum[0] = 0;
+ return map_cmodels[0];
+ // cinematic servers won't have anything at all
+ }
+
+ //
+ // load the file
+ //
+ buf = FS.LoadFile(name);
+
+ if (buf == null)
+ Com.Error(Defines.ERR_DROP, "Couldn't load " + name);
+
+ length = buf.length;
+
+ ByteBuffer bbuf = ByteBuffer.wrap(buf);
+
+ last_checksum = MD4.Com_BlockChecksum(buf, length);
+ checksum[0] = last_checksum;
+
+ header = new qfiles.dheader_t(bbuf.slice());
+
+ if (header.version != Defines.BSPVERSION)
+ Com.Error(Defines.ERR_DROP, "CMod_LoadBrushModel: " + name
+ + " has wrong version number (" + header.version
+ + " should be " + Defines.BSPVERSION + ")");
+
+ cmod_base = buf;
+
+ // load into heap
+ CMod_LoadSurfaces(header.lumps[Defines.LUMP_TEXINFO]); // ok.
+ CMod_LoadLeafs(header.lumps[Defines.LUMP_LEAFS]);
+ CMod_LoadLeafBrushes(header.lumps[Defines.LUMP_LEAFBRUSHES]);
+ CMod_LoadPlanes(header.lumps[Defines.LUMP_PLANES]);
+ CMod_LoadBrushes(header.lumps[Defines.LUMP_BRUSHES]);
+ CMod_LoadBrushSides(header.lumps[Defines.LUMP_BRUSHSIDES]);
+ CMod_LoadSubmodels(header.lumps[Defines.LUMP_MODELS]);
+
+ CMod_LoadNodes(header.lumps[Defines.LUMP_NODES]);
+ CMod_LoadAreas(header.lumps[Defines.LUMP_AREAS]);
+ CMod_LoadAreaPortals(header.lumps[Defines.LUMP_AREAPORTALS]);
+ CMod_LoadVisibility(header.lumps[Defines.LUMP_VISIBILITY]);
+ CMod_LoadEntityString(header.lumps[Defines.LUMP_ENTITIES]);
+
+ FS.FreeFile(buf);
+
+ CM_InitBoxHull();
+
+ Arrays.fill(portalopen, false);
+
+ FloodAreaConnections();
+
+ map_name = name;
+
+ // debug (rst)
+ /*
+ * Com.p("Testing pointleafes:"); for (int n = 0; n < 20; n++) { float
+ * pos[] = new float[] {(float) (Math.random() * 1000), (float)
+ * (Math.random() * 1000), 0 }; int x = CM_PointLeafnum(pos);
+ * Com.p(Lib.vtofsbeaty(pos) + " ---> leaf=" + x + " area = "
+ * +map_leafs[x].area); }
+ */
+ return map_cmodels[0];
+ }
+
+ /*
+ * ================= CMod_LoadSubmodels =================
+ */
+ public static void CMod_LoadSubmodels(lump_t l) {
+ Com.DPrintf("CMod_LoadSubmodels...\n");
+ qfiles.dmodel_t in;
+ cmodel_t out;
+ int i, j, count;
+
+ if ((l.filelen % qfiles.dmodel_t.SIZE) != 0)
+ Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size");
+
+ count = l.filelen / qfiles.dmodel_t.SIZE;
+
+ if (count < 1)
+ Com.Error(Defines.ERR_DROP, "Map with no models");
+ if (count > Defines.MAX_MAP_MODELS)
+ Com.Error(Defines.ERR_DROP, "Map has too many models");
+
+ Com.DPrintf(" numcmodels=" + count + "\n");
+ numcmodels = count;
+
+ if (debugloadmap) {
+ Com.DPrintf("submodles(headnode, <origin>, <mins>, <maxs>)\n");
+ }
+ for (i = 0; i < count; i++) {
+ in = new qfiles.dmodel_t(ByteBuffer.wrap(cmod_base, i
+ * qfiles.dmodel_t.SIZE + l.fileofs, qfiles.dmodel_t.SIZE));
+ out = map_cmodels[i];
+
+ for (j = 0; j < 3; j++) { // spread the mins / maxs by a pixel
+ out.mins[j] = in.mins[j] - 1;
+ out.maxs[j] = in.maxs[j] + 1;
+ out.origin[j] = in.origin[j];
+ }
+ out.headnode = in.headnode;
+ if (debugloadmap) {
+ Com
+ .DPrintf(
+ "|%6i|%8.2f|%8.2f|%8.2f| %8.2f|%8.2f|%8.2f| %8.2f|%8.2f|%8.2f|\n",
+ new Vargs().add(out.headnode)
+ .add(out.origin[0]).add(out.origin[1])
+ .add(out.origin[2]).add(out.mins[0])
+ .add(out.mins[1]).add(out.mins[2]).add(
+ out.maxs[0]).add(out.maxs[1])
+ .add(out.maxs[2]));
+ }
+ }
+ }
+
+ static boolean debugloadmap = false;
+
+ /*
+ * ================= CMod_LoadSurfaces =================
+ */
+ public static void CMod_LoadSurfaces(lump_t l) {
+ Com.DPrintf("CMod_LoadSurfaces...\n");
+ texinfo_t in;
+ mapsurface_t out;
+ int i, count;
+
+ if ((l.filelen % texinfo_t.SIZE) != 0)
+ Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size");
+
+ count = l.filelen / texinfo_t.SIZE;
+ if (count < 1)
+ Com.Error(Defines.ERR_DROP, "Map with no surfaces");
+ if (count > Defines.MAX_MAP_TEXINFO)
+ Com.Error(Defines.ERR_DROP, "Map has too many surfaces");
+
+ numtexinfo = count;
+ Com.DPrintf("numtexinfo=" + count + "\n");
+ if (debugloadmap)
+ Com.DPrintf("surfaces:\n");
+
+ for (i = 0; i < count; i++) {
+ out = map_surfaces[i] = new mapsurface_t();
+ in = new texinfo_t(cmod_base, l.fileofs + i * texinfo_t.SIZE,
+ texinfo_t.SIZE);
+
+ out.c.name = in.texture;
+ out.rname = in.texture;
+ out.c.flags = in.flags;
+ out.c.value = in.value;
+
+ if (debugloadmap) {
+ Com.DPrintf("|%20s|%20s|%6i|%6i|\n", new Vargs()
+ .add(out.c.name).add(out.rname).add(out.c.value).add(
+ out.c.flags));
+ }
+
+ }
+ }
+
+ /*
+ * ================= CMod_LoadNodes
+ *
+ * =================
+ */
+ public static void CMod_LoadNodes(lump_t l) {
+ Com.DPrintf("CMod_LoadNodes...\n");
+ qfiles.dnode_t in;
+ int child;
+ cnode_t out;
+ int i, j, count;
+
+ if ((l.filelen % qfiles.dnode_t.SIZE) != 0)
+ Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size:"
+ + l.fileofs + "," + qfiles.dnode_t.SIZE);
+ count = l.filelen / qfiles.dnode_t.SIZE;
+
+ if (count < 1)
+ Com.Error(Defines.ERR_DROP, "Map has no nodes");
+ if (count > Defines.MAX_MAP_NODES)
+ Com.Error(Defines.ERR_DROP, "Map has too many nodes");
+
+ numnodes = count;
+ Com.DPrintf(" numnodes=" + count + "\n");
+
+ if (debugloadmap) {
+ Com.DPrintf("nodes(planenum, child[0], child[1])\n");
+ }
+
+ for (i = 0; i < count; i++) {
+ in = new qfiles.dnode_t(ByteBuffer.wrap(cmod_base,
+ qfiles.dnode_t.SIZE * i + l.fileofs, qfiles.dnode_t.SIZE));
+ out = map_nodes[i];
+
+ out.plane = map_planes[in.planenum];
+ for (j = 0; j < 2; j++) {
+ child = in.children[j];
+ out.children[j] = child;
+ }
+ if (debugloadmap) {
+ Com.DPrintf("|%6i| %6i| %6i|\n", new Vargs().add(in.planenum)
+ .add(out.children[0]).add(out.children[1]));
+ }
+ }
+ }
+
+ /*
+ * ================= CMod_LoadBrushes
+ *
+ * =================
+ */
+ public static void CMod_LoadBrushes(lump_t l) {
+ Com.DPrintf("CMod_LoadBrushes...\n");
+ qfiles.dbrush_t in;
+ cbrush_t out;
+ int i, count;
+
+ if ((l.filelen % qfiles.dbrush_t.SIZE) != 0)
+ Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size");
+
+ count = l.filelen / qfiles.dbrush_t.SIZE;
+
+ if (count > Defines.MAX_MAP_BRUSHES)
+ Com.Error(Defines.ERR_DROP, "Map has too many brushes");
+
+ numbrushes = count;
+ Com.DPrintf(" numbrushes=" + count + "\n");
+ if (debugloadmap) {
+ Com.DPrintf("brushes:(firstbrushside, numsides, contents)\n");
+ }
+ for (i = 0; i < count; i++) {
+ in = new qfiles.dbrush_t(ByteBuffer.wrap(cmod_base, i
+ * qfiles.dbrush_t.SIZE + l.fileofs, qfiles.dbrush_t.SIZE));
+ out = map_brushes[i];
+ out.firstbrushside = in.firstside;
+ out.numsides = in.numsides;
+ out.contents = in.contents;
+
+ if (debugloadmap) {
+ Com
+ .DPrintf("| %6i| %6i| %8X|\n", new Vargs().add(
+ out.firstbrushside).add(out.numsides).add(
+ out.contents));
+ }
+ }
+ }
+
+ /*
+ * ================= CMod_LoadLeafs =================
+ */
+ public static void CMod_LoadLeafs(lump_t l) {
+ Com.DPrintf("CMod_LoadLeafs...\n");
+ int i;
+ cleaf_t out;
+ qfiles.dleaf_t in;
+ int count;
+
+ if ((l.filelen % qfiles.dleaf_t.SIZE) != 0)
+ Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size");
+
+ count = l.filelen / qfiles.dleaf_t.SIZE;
+
+ if (count < 1)
+ Com.Error(Defines.ERR_DROP, "Map with no leafs");
+
+ // need to save space for box planes
+ if (count > Defines.MAX_MAP_PLANES)
+ Com.Error(Defines.ERR_DROP, "Map has too many planes");
+
+ Com.DPrintf(" numleafes=" + count + "\n");
+
+ numleafs = count;
+ numclusters = 0;
+ if (debugloadmap)
+ Com
+ .DPrintf("cleaf-list:(contents, cluster, area, firstleafbrush, numleafbrushes)\n");
+ for (i = 0; i < count; i++) {
+ in = new qfiles.dleaf_t(cmod_base, i * qfiles.dleaf_t.SIZE
+ + l.fileofs, qfiles.dleaf_t.SIZE);
+
+ out = map_leafs[i];
+
+ out.contents = in.contents;
+ out.cluster = in.cluster;
+ out.area = in.area;
+ out.firstleafbrush = (short) in.firstleafbrush;
+ out.numleafbrushes = (short) in.numleafbrushes;
+
+ if (out.cluster >= numclusters)
+ numclusters = out.cluster + 1;
+
+ if (debugloadmap) {
+ Com.DPrintf("|%8x|%6i|%6i|%6i|\n", new Vargs()
+ .add(out.contents).add(out.cluster).add(out.area).add(
+ out.firstleafbrush).add(out.numleafbrushes));
+ }
+
+ }
+
+ Com.DPrintf(" numclusters=" + numclusters + "\n");
+
+ if (map_leafs[0].contents != Defines.CONTENTS_SOLID)
+ Com.Error(Defines.ERR_DROP, "Map leaf 0 is not CONTENTS_SOLID");
+
+ solidleaf = 0;
+ emptyleaf = -1;
+
+ for (i = 1; i < numleafs; i++) {
+ if (map_leafs[i].contents == 0) {
+ emptyleaf = i;
+ break;
+ }
+ }
+
+ if (emptyleaf == -1)
+ Com.Error(Defines.ERR_DROP, "Map does not have an empty leaf");
+ }
+
+ /*
+ * ================= CMod_LoadPlanes =================
+ */
+ public static void CMod_LoadPlanes(lump_t l) {
+ Com.DPrintf("CMod_LoadPlanes...\n");
+ int i, j;
+ cplane_t out;
+ qfiles.dplane_t in;
+ int count;
+ int bits;
+
+ if ((l.filelen % qfiles.dplane_t.SIZE) != 0)
+ Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size");
+
+ count = l.filelen / qfiles.dplane_t.SIZE;
+
+ if (count < 1)
+ Com.Error(Defines.ERR_DROP, "Map with no planes");
+
+ // need to save space for box planes
+ if (count > Defines.MAX_MAP_PLANES)
+ Com.Error(Defines.ERR_DROP, "Map has too many planes");
+
+ Com.DPrintf(" numplanes=" + count + "\n");
+
+ numplanes = count;
+ if (debugloadmap) {
+ Com
+ .DPrintf("cplanes(normal[0],normal[1],normal[2], dist, type, signbits)\n");
+ }
+
+ for (i = 0; i < count; i++) {
+ in = new qfiles.dplane_t(ByteBuffer.wrap(cmod_base, i
+ * qfiles.dplane_t.SIZE + l.fileofs, qfiles.dplane_t.SIZE));
+
+ out = map_planes[i];
+
+ bits = 0;
+ for (j = 0; j < 3; j++) {
+ out.normal[j] = in.normal[j];
+
+ if (out.normal[j] < 0)
+ bits |= 1 << j;
+ }
+
+ out.dist = in.dist;
+ out.type = (byte) in.type;
+ out.signbits = (byte) bits;
+
+ if (debugloadmap) {
+ Com.DPrintf("|%6.2f|%6.2f|%6.2f| %10.2f|%3i| %1i|\n",
+ new Vargs().add(out.normal[0]).add(out.normal[1]).add(
+ out.normal[2]).add(out.dist).add(out.type).add(
+ out.signbits));
+ }
+ }
+ }
+
+ /*
+ * ================= CMod_LoadLeafBrushes =================
+ */
+ public static void CMod_LoadLeafBrushes(lump_t l) {
+ Com.DPrintf("CMod_LoadLeafBrushes...\n");
+ int i;
+ int out[];
+ short in[];
+ int count;
+
+ if ((l.filelen % 2) != 0)
+ Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size");
+
+ count = l.filelen / 2;
+
+ Com.DPrintf(" numbrushes=" + count + "\n");
+
+ if (count < 1)
+ Com.Error(Defines.ERR_DROP, "Map with no planes");
+
+ // need to save space for box planes
+ if (count > Defines.MAX_MAP_LEAFBRUSHES)
+ Com.Error(Defines.ERR_DROP, "Map has too many leafbrushes");
+
+ out = map_leafbrushes;
+ numleafbrushes = count;
+
+ ByteBuffer bb = ByteBuffer.wrap(cmod_base, l.fileofs, count * 2).order(
+ ByteOrder.LITTLE_ENDIAN);
+
+ if (debugloadmap) {
+ Com.DPrintf("map_brushes:\n");
+ }
+
+ for (i = 0; i < count; i++) {
+ out[i] = bb.getShort();
+ if (debugloadmap) {
+ Com.DPrintf("|%6i|%6i|\n", new Vargs().add(i).add(out[i]));
+ }
+ }
+ }
+
+ /*
+ * ================= CMod_LoadBrushSides =================
+ */
+ public static void CMod_LoadBrushSides(lump_t l) {
+ Com.DPrintf("CMod_LoadBrushSides...\n");
+ int i, j;
+ cbrushside_t out;
+ qfiles.dbrushside_t in;
+ int count;
+ int num;
+
+ if ((l.filelen % qfiles.dbrushside_t.SIZE) != 0)
+ Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size");
+ count = l.filelen / qfiles.dbrushside_t.SIZE;
+
+ // need to save space for box planes
+ if (count > Defines.MAX_MAP_BRUSHSIDES)
+ Com.Error(Defines.ERR_DROP, "Map has too many planes");
+
+ numbrushsides = count;
+
+ Com.DPrintf(" numbrushsides=" + count + "\n");
+
+ if (debugloadmap) {
+ Com.DPrintf("brushside(planenum, surfacenum):\n");
+ }
+ for (i = 0; i < count; i++) {
+
+ in = new qfiles.dbrushside_t(ByteBuffer.wrap(cmod_base, i
+ * qfiles.dbrushside_t.SIZE + l.fileofs,
+ qfiles.dbrushside_t.SIZE));
+
+ out = map_brushsides[i];
+
+ num = in.planenum;
+
+ out.plane = map_planes[num]; // pointer
+
+ j = in.texinfo;
+
+ if (j >= numtexinfo)
+ Com.Error(Defines.ERR_DROP, "Bad brushside texinfo");
+
+ // rst: some mysterious happens here, even in the original code ???,
+ // texinfo is -1!!!
+ // hoz: checked against c version: ok.
+ if (j == -1)
+ out.surface = new mapsurface_t(); // just for safety
+ else
+ out.surface = map_surfaces[j];
+
+ if (debugloadmap) {
+ Com.DPrintf("| %6i| %6i|\n", new Vargs().add(num).add(j));
+ }
+ }
+ }
+
+ /*
+ * ================= CMod_LoadAreas =================
+ */
+ public static void CMod_LoadAreas(lump_t l) {
+ Com.DPrintf("CMod_LoadAreas...\n");
+ int i;
+ carea_t out;
+ qfiles.darea_t in;
+ int count;
+
+ if ((l.filelen % qfiles.darea_t.SIZE) != 0)
+ Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size");
+
+ count = l.filelen / qfiles.darea_t.SIZE;
+
+ if (count > Defines.MAX_MAP_AREAS)
+ Com.Error(Defines.ERR_DROP, "Map has too many areas");
+
+ Com.DPrintf(" numareas=" + count + "\n");
+ numareas = count;
+
+ if (debugloadmap) {
+ Com.DPrintf("areas(numportals, firstportal)\n");
+ }
+
+ for (i = 0; i < count; i++) {
+
+ in = new qfiles.darea_t(ByteBuffer.wrap(cmod_base, i
+ * qfiles.darea_t.SIZE + l.fileofs, qfiles.darea_t.SIZE));
+ out = map_areas[i];
+
+ out.numareaportals = in.numareaportals;
+ out.firstareaportal = in.firstareaportal;
+ out.floodvalid = 0;
+ out.floodnum = 0;
+ if (debugloadmap) {
+ Com.DPrintf("| %6i| %6i|\n", new Vargs()
+ .add(out.numareaportals).add(out.firstareaportal));
+ }
+ }
+ }
+
+ /*
+ * ================= CMod_LoadAreaPortals =================
+ */
+ public static void CMod_LoadAreaPortals(lump_t l) {
+ Com.DPrintf("CMod_LoadAreaPortals...\n");
+ int i;
+ qfiles.dareaportal_t out;
+ qfiles.dareaportal_t in;
+ int count;
+
+ if ((l.filelen % qfiles.dareaportal_t.SIZE) != 0)
+ Com.Error(Defines.ERR_DROP, "MOD_LoadBmodel: funny lump size");
+ count = l.filelen / qfiles.dareaportal_t.SIZE;
- static int checkcount;
-
- static String map_name = "";
-
- static int numbrushsides;
- static cbrushside_t map_brushsides[] = new cbrushside_t[MAX_MAP_BRUSHSIDES];
- static {
- for (int n = 0; n < MAX_MAP_BRUSHSIDES; n++)
- map_brushsides[n] = new cbrushside_t();
- }
-
- public static int numtexinfo;
- public static mapsurface_t map_surfaces[] = new mapsurface_t[MAX_MAP_TEXINFO];
- static {
- for (int n = 0; n < MAX_MAP_TEXINFO; n++)
- map_surfaces[n] = new mapsurface_t();
- }
-
- static int numplanes;
- // extra for box hull ( +6)
- static cplane_t map_planes[] = new cplane_t[MAX_MAP_PLANES + 6];
-
- static {
- for (int n = 0; n < MAX_MAP_PLANES + 6; n++)
- map_planes[n] = new cplane_t();
- }
-
- static int numnodes;
- // extra for box hull ( +6)
- static cnode_t map_nodes[] = new cnode_t[MAX_MAP_NODES + 6];
-
- static {
- for (int n = 0; n < MAX_MAP_NODES + 6; n++)
- map_nodes[n] = new cnode_t();
- }
-
- static int numleafs = 1; // allow leaf funcs to be called without a map
- static cleaf_t map_leafs[] = new cleaf_t[MAX_MAP_LEAFS];
- static {
- for (int n = 0; n < MAX_MAP_LEAFS; n++)
- map_leafs[n] = new cleaf_t();
- }
-
- static int emptyleaf, solidleaf;
-
- static int numleafbrushes;
- //static unsigned short map_leafbrushes[MAX_MAP_LEAFBRUSHES];
- public static int map_leafbrushes[] = new int[MAX_MAP_LEAFBRUSHES];
- public static int numcmodels;
- public static cmodel_t map_cmodels[] = new cmodel_t[MAX_MAP_MODELS];
- static {
- for (int n = 0; n < MAX_MAP_MODELS; n++)
- map_cmodels[n] = new cmodel_t();
-
- }
-
- public static int numbrushes;
- public static cbrush_t map_brushes[] = new cbrush_t[MAX_MAP_BRUSHES];
- static {
- for (int n = 0; n < MAX_MAP_BRUSHES; n++)
- map_brushes[n] = new cbrush_t();
-
- }
-
- public static int numvisibility;
- public static byte map_visibility[] = new byte[MAX_MAP_VISIBILITY];
-
- // main visibility data. rst
- // was: static dvis_t *map_vis = (dvis_t *)map_visibility;
- public static qfiles.dvis_t map_vis = new qfiles.dvis_t(ByteBuffer.wrap(map_visibility));
-
- public static int numentitychars;
- public static String map_entitystring;
-
- public static int numareas = 1;
- public static carea_t map_areas[] = new carea_t[MAX_MAP_AREAS];
- static {
- for (int n = 0; n < MAX_MAP_AREAS; n++)
- map_areas[n] = new carea_t();
-
- }
- public static int numareaportals;
- public static qfiles.dareaportal_t map_areaportals[] = new qfiles.dareaportal_t[MAX_MAP_AREAPORTALS];
-
- static {
- for (int n = 0; n < MAX_MAP_AREAPORTALS; n++)
- map_areaportals[n] = new qfiles.dareaportal_t();
-
- }
-
- public static int numclusters = 1;
-
- public static mapsurface_t nullsurface = new mapsurface_t();
-
- public static int floodvalid;
-
- public static boolean portalopen[] = new boolean[MAX_MAP_AREAPORTALS];
-
- public static cvar_t map_noareas;
-
- /*
- ===============================================================================
-
- MAP LOADING
-
- ===============================================================================
- */
-
- public static byte cmod_base[];
-
- // is that right (rst) ?
- public static int checksum;
- public static int last_checksum;
-
- /*
- ==================
- CM_LoadMap
-
- Loads in the map and all submodels
- ==================
- */
- public static cmodel_t CM_LoadMap(String name, boolean clientload, int checksum[]) {
- Com.DPrintf("CM_LoadMap...\n");
- byte buf[];
- int i;
- qfiles.dheader_t header;
- int length;
-
- map_noareas = Cvar.Get("map_noareas", "0", 0);
-
- if (map_name.equals(name) && (clientload || 0 == Cvar.VariableValue("flushmap"))) {
-
- checksum[0] = last_checksum;
-
- if (!clientload) {
- Arrays.fill(portalopen, false);
- FloodAreaConnections();
- }
- return map_cmodels[0]; // still have the right version
- }
-
- // free old stuff
- numnodes = 0;
- numleafs = 0;
- numcmodels = 0;
- numvisibility = 0;
- numentitychars = 0;
- map_entitystring = "";
- map_name = "";
-
- if (name == null || name.length() == 0) {
- numleafs = 1;
- numclusters = 1;
- numareas = 1;
- checksum[0] = 0;
- return map_cmodels[0];
- // cinematic servers won't have anything at all
- }
-
- //
- // load the file
- //
- buf = FS.LoadFile(name);
-
- if (buf == null)
- Com.Error(ERR_DROP, "Couldn't load " + name);
-
- length = buf.length;
-
- ByteBuffer bbuf = ByteBuffer.wrap(buf);
-
- last_checksum = MD4.Com_BlockChecksum(buf, length);
- checksum[0] = last_checksum;
-
- header = new qfiles.dheader_t(bbuf.slice());
-
- if (header.version != BSPVERSION)
- Com.Error(
- ERR_DROP,
- "CMod_LoadBrushModel: " + name + " has wrong version number (" + header.version + " should be " + BSPVERSION + ")");
-
- cmod_base = buf;
-
- // load into heap
- CMod_LoadSurfaces(header.lumps[LUMP_TEXINFO]); // ok.
- CMod_LoadLeafs(header.lumps[LUMP_LEAFS]);
- CMod_LoadLeafBrushes(header.lumps[LUMP_LEAFBRUSHES]);
- CMod_LoadPlanes(header.lumps[LUMP_PLANES]);
- CMod_LoadBrushes(header.lumps[LUMP_BRUSHES]);
- CMod_LoadBrushSides(header.lumps[LUMP_BRUSHSIDES]);
- CMod_LoadSubmodels(header.lumps[LUMP_MODELS]);
-
- CMod_LoadNodes(header.lumps[LUMP_NODES]);
- CMod_LoadAreas(header.lumps[LUMP_AREAS]);
- CMod_LoadAreaPortals(header.lumps[LUMP_AREAPORTALS]);
- CMod_LoadVisibility(header.lumps[LUMP_VISIBILITY]);
- CMod_LoadEntityString(header.lumps[LUMP_ENTITIES]);
-
- FS.FreeFile(buf);
-
- CM_InitBoxHull();
-
- Arrays.fill(portalopen, false);
-
- FloodAreaConnections();
-
- map_name = name;
-
- // debug (rst)
- /*
- Com.p("Testing pointleafes:");
- for (int n = 0; n < 20; n++) {
- float pos[] = new float[] {(float) (Math.random() * 1000), (float) (Math.random() * 1000), 0 };
- int x = CM_PointLeafnum(pos);
- Com.p(Lib.vtofsbeaty(pos) + " ---> leaf=" + x + " area = " +map_leafs[x].area);
- }
- */
- return map_cmodels[0];
- }
-
- /*
- =================
- CMod_LoadSubmodels
- =================
- */
- public static void CMod_LoadSubmodels(lump_t l) {
- Com.DPrintf("CMod_LoadSubmodels...\n");
- qfiles.dmodel_t in;
- cmodel_t out;
- int i, j, count;
-
- if ((l.filelen % qfiles.dmodel_t.SIZE) != 0)
- Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size");
-
- count = l.filelen / qfiles.dmodel_t.SIZE;
-
- if (count < 1)
- Com.Error(ERR_DROP, "Map with no models");
- if (count > MAX_MAP_MODELS)
- Com.Error(ERR_DROP, "Map has too many models");
-
- Com.DPrintf(" numcmodels=" + count + "\n");
- numcmodels = count;
-
- if (debugloadmap) {
- Com.DPrintf("submodles(headnode, <origin>, <mins>, <maxs>)\n");
- }
- for (i = 0; i < count; i++) {
- in = new qfiles.dmodel_t(ByteBuffer.wrap(cmod_base, i * qfiles.dmodel_t.SIZE + l.fileofs, qfiles.dmodel_t.SIZE));
- out = map_cmodels[i];
-
- for (j = 0; j < 3; j++) { // spread the mins / maxs by a pixel
- out.mins[j] = in.mins[j] - 1;
- out.maxs[j] = in.maxs[j] + 1;
- out.origin[j] = in.origin[j];
- }
- out.headnode = in.headnode;
- if (debugloadmap) {
- Com.DPrintf(
- "|%6i|%8.2f|%8.2f|%8.2f| %8.2f|%8.2f|%8.2f| %8.2f|%8.2f|%8.2f|\n",
- new Vargs()
- .add(out.headnode)
- .add(out.origin[0])
- .add(out.origin[1])
- .add(out.origin[2])
- .add(out.mins[0])
- .add(out.mins[1])
- .add(out.mins[2])
- .add(out.maxs[0])
- .add(out.maxs[1])
- .add(out.maxs[2]));
- }
- }
- }
- static boolean debugloadmap = false;
-
- /*
- =================
- CMod_LoadSurfaces
- =================
- */
- public static void CMod_LoadSurfaces(lump_t l) {
- Com.DPrintf("CMod_LoadSurfaces...\n");
- texinfo_t in;
- mapsurface_t out;
- int i, count;
-
- if ((l.filelen % texinfo_t.SIZE) != 0)
- Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size");
-
- count = l.filelen / texinfo_t.SIZE;
- if (count < 1)
- Com.Error(ERR_DROP, "Map with no surfaces");
- if (count > MAX_MAP_TEXINFO)
- Com.Error(ERR_DROP, "Map has too many surfaces");
-
- numtexinfo = count;
- Com.DPrintf("numtexinfo=" + count + "\n");
- if (debugloadmap)
- Com.DPrintf("surfaces:\n");
-
- for (i = 0; i < count; i++) {
- out = map_surfaces[i] = new mapsurface_t();
- in = new texinfo_t(cmod_base, l.fileofs + i * texinfo_t.SIZE, texinfo_t.SIZE);
-
- out.c.name = in.texture;
- out.rname = in.texture;
- out.c.flags = in.flags;
- out.c.value = in.value;
-
- if (debugloadmap) {
- Com.DPrintf("|%20s|%20s|%6i|%6i|\n", new Vargs().add(out.c.name).add(out.rname).add(out.c.value).add(out.c.flags));
- }
-
- }
- }
-
- /*
- =================
- CMod_LoadNodes
-
- =================
- */
- public static void CMod_LoadNodes(lump_t l) {
- Com.DPrintf("CMod_LoadNodes...\n");
- qfiles.dnode_t in;
- int child;
- cnode_t out;
- int i, j, count;
-
- if ((l.filelen % qfiles.dnode_t.SIZE) != 0)
- Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size:" + l.fileofs + "," + qfiles.dnode_t.SIZE);
- count = l.filelen / qfiles.dnode_t.SIZE;
-
- if (count < 1)
- Com.Error(ERR_DROP, "Map has no nodes");
- if (count > MAX_MAP_NODES)
- Com.Error(ERR_DROP, "Map has too many nodes");
-
- numnodes = count;
- Com.DPrintf(" numnodes=" + count + "\n");
-
- if (debugloadmap) {
- Com.DPrintf("nodes(planenum, child[0], child[1])\n");
- }
-
- for (i = 0; i < count; i++) {
- in = new qfiles.dnode_t(ByteBuffer.wrap(cmod_base, qfiles.dnode_t.SIZE * i + l.fileofs, qfiles.dnode_t.SIZE));
- out = map_nodes[i];
-
- out.plane = map_planes[in.planenum];
- for (j = 0; j < 2; j++) {
- child = in.children[j];
- out.children[j] = child;
- }
- if (debugloadmap) {
- Com.DPrintf("|%6i| %6i| %6i|\n", new Vargs().add(in.planenum).add(out.children[0]).add(out.children[1]));
- }
- }
- }
-
- /*
- =================
- CMod_LoadBrushes
-
- =================
- */
- public static void CMod_LoadBrushes(lump_t l) {
- Com.DPrintf("CMod_LoadBrushes...\n");
- qfiles.dbrush_t in;
- cbrush_t out;
- int i, count;
-
- if ((l.filelen % qfiles.dbrush_t.SIZE) != 0)
- Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size");
-
- count = l.filelen / qfiles.dbrush_t.SIZE;
-
- if (count > MAX_MAP_BRUSHES)
- Com.Error(ERR_DROP, "Map has too many brushes");
-
- numbrushes = count;
- Com.DPrintf(" numbrushes=" + count + "\n");
- if (debugloadmap) {
- Com.DPrintf("brushes:(firstbrushside, numsides, contents)\n");
- }
- for (i = 0; i < count; i++) {
- in = new qfiles.dbrush_t(ByteBuffer.wrap(cmod_base, i * qfiles.dbrush_t.SIZE + l.fileofs, qfiles.dbrush_t.SIZE));
- out = map_brushes[i];
- out.firstbrushside = in.firstside;
- out.numsides = in.numsides;
- out.contents = in.contents;
-
- if (debugloadmap) {
- Com.DPrintf("| %6i| %6i| %8X|\n", new Vargs().add(out.firstbrushside).add(out.numsides).add(out.contents));
- }
- }
- }
-
- /*
- =================
- CMod_LoadLeafs
- =================
- */
- public static void CMod_LoadLeafs(lump_t l) {
- Com.DPrintf("CMod_LoadLeafs...\n");
- int i;
- cleaf_t out;
- qfiles.dleaf_t in;
- int count;
-
- if ((l.filelen % qfiles.dleaf_t.SIZE) != 0)
- Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size");
-
- count = l.filelen / qfiles.dleaf_t.SIZE;
-
- if (count < 1)
- Com.Error(ERR_DROP, "Map with no leafs");
-
- // need to save space for box planes
- if (count > MAX_MAP_PLANES)
- Com.Error(ERR_DROP, "Map has too many planes");
-
- Com.DPrintf(" numleafes=" + count + "\n");
-
- numleafs = count;
- numclusters = 0;
- if (debugloadmap)
- Com.DPrintf("cleaf-list:(contents, cluster, area, firstleafbrush, numleafbrushes)\n");
- for (i = 0; i < count; i++) {
- in = new qfiles.dleaf_t(cmod_base, i * qfiles.dleaf_t.SIZE + l.fileofs, qfiles.dleaf_t.SIZE);
-
- out = map_leafs[i];
-
- out.contents = in.contents;
- out.cluster = in.cluster;
- out.area = in.area;
- out.firstleafbrush = (short) in.firstleafbrush;
- out.numleafbrushes = (short) in.numleafbrushes;
-
- if (out.cluster >= numclusters)
- numclusters = out.cluster + 1;
-
- if (debugloadmap) {
- Com.DPrintf(
- "|%8x|%6i|%6i|%6i|\n",
- new Vargs().add(out.contents).add(out.cluster).add(out.area).add(out.firstleafbrush).add(out.numleafbrushes));
- }
-
- }
-
- Com.DPrintf(" numclusters=" + numclusters + "\n");
-
- if (map_leafs[0].contents != CONTENTS_SOLID)
- Com.Error(ERR_DROP, "Map leaf 0 is not CONTENTS_SOLID");
-
- solidleaf = 0;
- emptyleaf = -1;
-
- for (i = 1; i < numleafs; i++) {
- if (map_leafs[i].contents == 0) {
- emptyleaf = i;
- break;
- }
- }
-
- if (emptyleaf == -1)
- Com.Error(ERR_DROP, "Map does not have an empty leaf");
- }
-
- /*
- =================
- CMod_LoadPlanes
- =================
- */
- public static void CMod_LoadPlanes(lump_t l) {
- Com.DPrintf("CMod_LoadPlanes...\n");
- int i, j;
- cplane_t out;
- qfiles.dplane_t in;
- int count;
- int bits;
-
- if ((l.filelen % qfiles.dplane_t.SIZE) != 0)
- Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size");
-
- count = l.filelen / qfiles.dplane_t.SIZE;
-
- if (count < 1)
- Com.Error(ERR_DROP, "Map with no planes");
-
- // need to save space for box planes
- if (count > MAX_MAP_PLANES)
- Com.Error(ERR_DROP, "Map has too many planes");
-
- Com.DPrintf(" numplanes=" + count + "\n");
-
- numplanes = count;
- if (debugloadmap) {
- Com.DPrintf("cplanes(normal[0],normal[1],normal[2], dist, type, signbits)\n");
- }
-
- for (i = 0; i < count; i++) {
- in = new qfiles.dplane_t(ByteBuffer.wrap(cmod_base, i * qfiles.dplane_t.SIZE + l.fileofs, qfiles.dplane_t.SIZE));
-
- out = map_planes[i];
-
- bits = 0;
- for (j = 0; j < 3; j++) {
- out.normal[j] = in.normal[j];
+ if (count > Defines.MAX_MAP_AREAS)
+ Com.Error(Defines.ERR_DROP, "Map has too many areas");
- if (out.normal[j] < 0)
- bits |= 1 << j;
- }
-
- out.dist = in.dist;
- out.type = (byte) in.type;
- out.signbits = (byte) bits;
-
- if (debugloadmap) {
- Com.DPrintf(
- "|%6.2f|%6.2f|%6.2f| %10.2f|%3i| %1i|\n",
- new Vargs().add(out.normal[0]).add(out.normal[1]).add(out.normal[2]).add(out.dist).add(out.type).add(
- out.signbits));
- }
- }
- }
-
- /*
- =================
- CMod_LoadLeafBrushes
- =================
- */
- public static void CMod_LoadLeafBrushes(lump_t l) {
- Com.DPrintf("CMod_LoadLeafBrushes...\n");
- int i;
- int out[];
- short in[];
- int count;
-
- if ((l.filelen % 2) != 0)
- Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size");
-
- count = l.filelen / 2;
-
- Com.DPrintf(" numbrushes=" + count + "\n");
-
- if (count < 1)
- Com.Error(ERR_DROP, "Map with no planes");
-
- // need to save space for box planes
- if (count > MAX_MAP_LEAFBRUSHES)
- Com.Error(ERR_DROP, "Map has too many leafbrushes");
-
- out = map_leafbrushes;
- numleafbrushes = count;
-
- ByteBuffer bb = ByteBuffer.wrap(cmod_base, l.fileofs, count * 2).order(ByteOrder.LITTLE_ENDIAN);
-
- if (debugloadmap) {
- Com.DPrintf("map_brushes:\n");
- }
-
- for (i = 0; i < count; i++) {
- out[i] = bb.getShort();
- if (debugloadmap) {
- Com.DPrintf("|%6i|%6i|\n", new Vargs().add(i).add(out[i]));
- }
- }
- }
-
- /*
- =================
- CMod_LoadBrushSides
- =================
- */
- public static void CMod_LoadBrushSides(lump_t l) {
- Com.DPrintf("CMod_LoadBrushSides...\n");
- int i, j;
- cbrushside_t out;
- qfiles.dbrushside_t in;
- int count;
- int num;
-
- if ((l.filelen % qfiles.dbrushside_t.SIZE) != 0)
- Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size");
- count = l.filelen / qfiles.dbrushside_t.SIZE;
-
- // need to save space for box planes
- if (count > MAX_MAP_BRUSHSIDES)
- Com.Error(ERR_DROP, "Map has too many planes");
-
- numbrushsides = count;
-
- Com.DPrintf(" numbrushsides=" + count + "\n");
-
- if (debugloadmap) {
- Com.DPrintf("brushside(planenum, surfacenum):\n");
- }
- for (i = 0; i < count; i++) {
-
- in =
- new qfiles.dbrushside_t(
- ByteBuffer.wrap(cmod_base, i * qfiles.dbrushside_t.SIZE + l.fileofs, qfiles.dbrushside_t.SIZE));
-
- out = map_brushsides[i];
-
- num = in.planenum;
-
- out.plane = map_planes[num]; // pointer
-
- j = in.texinfo;
-
- if (j >= numtexinfo)
- Com.Error(ERR_DROP, "Bad brushside texinfo");
-
- // rst: some mysterious happens here, even in the original code ???, texinfo is -1!!!
- // hoz: checked against c version: ok.
- if (j == -1)
- out.surface = new mapsurface_t(); // just for safety
- else
- out.surface = map_surfaces[j];
-
- if (debugloadmap) {
- Com.DPrintf("| %6i| %6i|\n", new Vargs().add(num).add(j));
- }
- }
- }
-
- /*
- =================
- CMod_LoadAreas
- =================
- */
- public static void CMod_LoadAreas(lump_t l) {
- Com.DPrintf("CMod_LoadAreas...\n");
- int i;
- carea_t out;
- qfiles.darea_t in;
- int count;
-
- if ((l.filelen % qfiles.darea_t.SIZE) != 0)
- Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size");
-
- count = l.filelen / qfiles.darea_t.SIZE;
-
- if (count > MAX_MAP_AREAS)
- Com.Error(ERR_DROP, "Map has too many areas");
-
- Com.DPrintf(" numareas=" + count + "\n");
- numareas = count;
-
- if (debugloadmap) {
- Com.DPrintf("areas(numportals, firstportal)\n");
- }
-
- for (i = 0; i < count; i++) {
-
- in = new qfiles.darea_t(ByteBuffer.wrap(cmod_base, i * qfiles.darea_t.SIZE + l.fileofs, qfiles.darea_t.SIZE));
- out = map_areas[i];
-
- out.numareaportals = in.numareaportals;
- out.firstareaportal = in.firstareaportal;
- out.floodvalid = 0;
- out.floodnum = 0;
- if (debugloadmap) {
- Com.DPrintf("| %6i| %6i|\n", new Vargs().add(out.numareaportals).add(out.firstareaportal));
- }
- }
- }
-
- /*
- =================
- CMod_LoadAreaPortals
- =================
- */
- public static void CMod_LoadAreaPortals(lump_t l) {
- Com.DPrintf("CMod_LoadAreaPortals...\n");
- int i;
- qfiles.dareaportal_t out;
- qfiles.dareaportal_t in;
- int count;
+ numareaportals = count;
+ Com.DPrintf(" numareaportals=" + count + "\n");
+ if (debugloadmap) {
+ Com.DPrintf("areaportals(portalnum, otherarea)\n");
+ }
+ for (i = 0; i < count; i++) {
+ in = new qfiles.dareaportal_t(ByteBuffer.wrap(cmod_base, i
+ * qfiles.dareaportal_t.SIZE + l.fileofs,
+ qfiles.dareaportal_t.SIZE));
+
+ out = map_areaportals[i];
- if ((l.filelen % qfiles.dareaportal_t.SIZE) != 0)
- Com.Error(ERR_DROP, "MOD_LoadBmodel: funny lump size");
- count = l.filelen / qfiles.dareaportal_t.SIZE;
+ out.portalnum = in.portalnum;
+ out.otherarea = in.otherarea;
- if (count > MAX_MAP_AREAS)
- Com.Error(ERR_DROP, "Map has too many areas");
+ if (debugloadmap) {
+ Com.DPrintf("|%6i|%6i|\n", new Vargs().add(out.portalnum).add(
+ out.otherarea));
+ }
+ }
+ }
- numareaportals = count;
- Com.DPrintf(" numareaportals=" + count + "\n");
- if (debugloadmap) {
- Com.DPrintf("areaportals(portalnum, otherarea)\n");
- }
- for (i = 0; i < count; i++) {
- in =
- new qfiles.dareaportal_t(
- ByteBuffer.wrap(cmod_base, i * qfiles.dareaportal_t.SIZE + l.fileofs, qfiles.dareaportal_t.SIZE));
-
- out = map_areaportals[i];
-
- out.portalnum = in.portalnum;
- out.otherarea = in.otherarea;
-
- if (debugloadmap) {
- Com.DPrintf("|%6i|%6i|\n", new Vargs().add(out.portalnum).add(out.otherarea));
- }
- }
- }
-
-
- /*
- =================
- CMod_LoadVisibility
- =================
- */
- public static void CMod_LoadVisibility(lump_t l) {
- Com.DPrintf("CMod_LoadVisibility...\n");
- int i;
-
- numvisibility = l.filelen;
-
- Com.DPrintf(" numvisibility=" + numvisibility + "\n");
-
- if (l.filelen > MAX_MAP_VISIBILITY)
- Com.Error(ERR_DROP, "Map has too large visibility lump");
-
- System.arraycopy(cmod_base, l.fileofs, map_visibility, 0, l.filelen);
-
- ByteBuffer bb = ByteBuffer.wrap(map_visibility, 0, l.filelen);
- bb.order(ByteOrder.LITTLE_ENDIAN);
-
- map_vis = new qfiles.dvis_t(bb);
-
- }
-
- /*
- =================
- CMod_LoadEntityString
- =================
- */
- public static void CMod_LoadEntityString(lump_t l) {
- Com.DPrintf("CMod_LoadEntityString...\n");
-
- numentitychars = l.filelen;
-
- if (l.filelen > MAX_MAP_ENTSTRING)
- Com.Error(ERR_DROP, "Map has too large entity lump");
-
- int x = 0;
- for (; x < l.filelen && cmod_base[x + l.fileofs] != 0; x++);
-
- map_entitystring = new String(cmod_base, l.fileofs, x).trim();
- }
-
- /*
- ==================
- CM_InlineModel
- ==================
- */
-
- // works fine
- public static cmodel_t InlineModel(String name) {
- int num;
-
- if (name == null || name.charAt(0) != '*')
- Com.Error(ERR_DROP, "CM_InlineModel: bad name");
-
- num = atoi(name.substring(1));
-
- if (num < 1 || num >= numcmodels)
- Com.Error(ERR_DROP, "CM_InlineModel: bad number");
-
- return map_cmodels[num];
- }
-
- public static int CM_NumClusters() {
- return numclusters;
- }
-
- public static int CM_NumInlineModels() {
- return numcmodels;
- }
-
- public static String CM_EntityString() {
- return map_entitystring;
- }
-
- public static int CM_LeafContents(int leafnum) {
- if (leafnum < 0 || leafnum >= numleafs)
- Com.Error(ERR_DROP, "CM_LeafContents: bad number");
- return map_leafs[leafnum].contents;
- }
-
- public static int CM_LeafCluster(int leafnum) {
- if (leafnum < 0 || leafnum >= numleafs)
- Com.Error(ERR_DROP, "CM_LeafCluster: bad number");
- return map_leafs[leafnum].cluster;
- }
-
- public static int CM_LeafArea(int leafnum) {
- if (leafnum < 0 || leafnum >= numleafs)
- Com.Error(ERR_DROP, "CM_LeafArea: bad number");
- return map_leafs[leafnum].area;
- }
-
- //=======================================================================
-
- static cplane_t box_planes[];
- static int box_headnode;
- static cbrush_t box_brush;
- static cleaf_t box_leaf;
-
- /*
- ===================
- CM_InitBoxHull
-
- Set up the planes and nodes so that the six floats of a bounding box
- can just be stored out and get a proper clipping hull structure.
- ===================
- */
- public static void CM_InitBoxHull() {
- int i;
- int side;
- cnode_t c;
- cplane_t p;
- cbrushside_t s;
-
- box_headnode = numnodes; // noch platz f?r 6 brushes
-
- box_planes =
- new cplane_t[] {
- map_planes[numplanes],
- map_planes[numplanes + 1],
- map_planes[numplanes + 2],
- map_planes[numplanes + 3],
- map_planes[numplanes + 4],
- map_planes[numplanes + 5],
- map_planes[numplanes + 6],
- map_planes[numplanes + 7],
- map_planes[numplanes + 8],
- map_planes[numplanes + 9],
- map_planes[numplanes + 10],
- map_planes[numplanes + 11],
- map_planes[numplanes + 12] };
-
- if (numnodes + 6 > MAX_MAP_NODES
- || numbrushes + 1 > MAX_MAP_BRUSHES
- || numleafbrushes + 1 > MAX_MAP_LEAFBRUSHES
- || numbrushsides + 6 > MAX_MAP_BRUSHSIDES
- || numplanes + 12 > MAX_MAP_PLANES)
- Com.Error(ERR_DROP, "Not enough room for box tree");
-
- box_brush = map_brushes[numbrushes];
- box_brush.numsides = 6;
- box_brush.firstbrushside = numbrushsides;
- box_brush.contents = CONTENTS_MONSTER;
-
- box_leaf = map_leafs[numleafs];
- box_leaf.contents = CONTENTS_MONSTER;
- box_leaf.firstleafbrush = (short) numleafbrushes;
- box_leaf.numleafbrushes = 1;
-
- map_leafbrushes[numleafbrushes] = numbrushes;
-
- for (i = 0; i < 6; i++) {
- side = i & 1;
-
- // brush sides
- s = map_brushsides[numbrushsides + i];
- s.plane = map_planes[(numplanes + i * 2 + side)];
- s.surface = nullsurface;
-
- // nodes
- c = map_nodes[box_headnode + i];
- c.plane = map_planes[(numplanes + i * 2)];
- c.children[side] = -1 - emptyleaf;
- if (i != 5)
- c.children[side ^ 1] = box_headnode + i + 1;
- else
- c.children[side ^ 1] = -1 - numleafs;
-
- // planes
- p = box_planes[i * 2];
- p.type = (byte) (i >> 1);
- p.signbits = 0;
- VectorClear(p.normal);
- p.normal[i >> 1] = 1;
-
- p = box_planes[i * 2 + 1];
- p.type = (byte) (3 + (i >> 1));
- p.signbits = 0;
- VectorClear(p.normal);
- p.normal[i >> 1] = -1;
- }
- }
-
- /*
- ===================
- CM_HeadnodeForBox
-
- To keep everything totally uniform, bounding boxes are turned into small
- BSP trees instead of being compared directly.
- ===================
- */
- public static int HeadnodeForBox(float[] mins, float[] maxs) {
- box_planes[0].dist = maxs[0];
- box_planes[1].dist = -maxs[0];
- box_planes[2].dist = mins[0];
- box_planes[3].dist = -mins[0];
- box_planes[4].dist = maxs[1];
- box_planes[5].dist = -maxs[1];
- box_planes[6].dist = mins[1];
- box_planes[7].dist = -mins[1];
- box_planes[8].dist = maxs[2];
- box_planes[9].dist = -maxs[2];
- box_planes[10].dist = mins[2];
- box_planes[11].dist = -mins[2];
-
- return box_headnode;
- }
-
- /*
- ==================
- CM_PointLeafnum_r
- ==================
- */
- public static int CM_PointLeafnum_r(float[] p, int num) {
- float d;
- cnode_t node;
- cplane_t plane;
-
- while (num >= 0) {
- node = map_nodes[num];
- plane = node.plane;
-
- if (plane.type < 3)
- d = p[plane.type] - plane.dist;
- else
- d = DotProduct(plane.normal, p) - plane.dist;
- if (d < 0)
- num = node.children[1];
- else
- num = node.children[0];
- }
-
- c_pointcontents++; // optimize counter
-
- return -1 - num;
- }
-
- public static int CM_PointLeafnum(float[] p) {
- if (numplanes == 0)
- return 0; // sound may call this without map loaded
- return CM_PointLeafnum_r(p, 0);
- }
-
- /*
- =============
- CM_BoxLeafnums
-
- Fills in a list of all the leafs touched
- =============
- */
- static int leaf_count, leaf_maxcount;
- static int leaf_list[];
- static float leaf_mins[], leaf_maxs[];
- static int leaf_topnode;
-
- public static void CM_BoxLeafnums_r(int nodenum) {
- cplane_t plane;
- cnode_t node;
- int s;
-
- while (true) {
- if (nodenum < 0) {
- if (leaf_count >= leaf_maxcount) {
- //TODO: here is still an error.
- //Com.DPrintf("CM_BoxLeafnums_r: overflow\n");
- return;
- }
- leaf_list[leaf_count++] = -1 - nodenum;
- return;
- }
-
- node = map_nodes[nodenum];
- plane = node.plane;
-
- s = Math3D.BoxOnPlaneSide(leaf_mins, leaf_maxs, plane);
-
- if (s == 1)
- nodenum = node.children[0];
- else if (s == 2)
- nodenum = node.children[1];
- else {
- // go down both
- if (leaf_topnode == -1)
- leaf_topnode = nodenum;
- CM_BoxLeafnums_r(node.children[0]);
- nodenum = node.children[1];
- }
- }
- }
-
- public static int CM_BoxLeafnums_headnode(float[] mins, float[] maxs, int list[], int listsize, int headnode, int topnode[]) {
- leaf_list = list;
- leaf_count = 0;
- leaf_maxcount = listsize;
- leaf_mins = mins;
- leaf_maxs = maxs;
-
- leaf_topnode = -1;
-
- CM_BoxLeafnums_r(headnode);
-
- if (topnode != null)
- topnode[0] = leaf_topnode;
-
- return leaf_count;
- }
-
- public static int CM_BoxLeafnums(float[] mins, float[] maxs, int list[], int listsize, int topnode[]) {
- return CM_BoxLeafnums_headnode(mins, maxs, list, listsize, map_cmodels[0].headnode, topnode);
- }
-
- /*
- public static class intwrap1 {
- public intwrap(int i) {
- this.i = i;
- }
- public int i;
- }
- */
- /*
- ==================
- CM_PointContents
- ==================
- */
- public static int PointContents(float[] p, int headnode) {
- int l;
-
- if (numnodes == 0) // map not loaded
- return 0;
-
- l = CM_PointLeafnum_r(p, headnode);
-
- return map_leafs[l].contents;
- }
-
- /*
- ==================
- CM_TransformedPointContents
-
- Handles offseting and rotation of the end points for moving and
- rotating entities
- ==================
- */
- public static int TransformedPointContents(float[] p, int headnode, float[] origin, float[] angles) {
- float[] p_l = { 0, 0, 0 };
- float[] temp = { 0, 0, 0 };
- float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 }, up = { 0, 0, 0 };
- int l;
-
- // subtract origin offset
- VectorSubtract(p, origin, p_l);
-
- // rotate start and end into the models frame of reference
- if (headnode != box_headnode && (angles[0] != 0 || angles[1] != 0 || angles[2] != 0)) {
- AngleVectors(angles, forward, right, up);
-
- VectorCopy(p_l, temp);
- p_l[0] = DotProduct(temp, forward);
- p_l[1] = -DotProduct(temp, right);
- p_l[2] = DotProduct(temp, up);
- }
-
- l = CM_PointLeafnum_r(p_l, headnode);
-
- return map_leafs[l].contents;
- }
-
- /*
- ===============================================================================
-
- BOX TRACING
-
- ===============================================================================
- */
-
- // 1/32 epsilon to keep floating point happy
- private static final float DIST_EPSILON = 0.03125f;
-
- private static float[] trace_start = { 0, 0, 0 }, trace_end = { 0, 0, 0 };
- private static float[] trace_mins = { 0, 0, 0 }, trace_maxs = { 0, 0, 0 };
- private static float[] trace_extents = { 0, 0, 0 };
-
- private static trace_t trace_trace = new trace_t();
- private static int trace_contents;
- private static boolean trace_ispoint; // optimized case
-
- /*
- ================
- CM_ClipBoxToBrush
- ================
- */
- public static void CM_ClipBoxToBrush(float[] mins, float[] maxs, float[] p1, float[] p2, trace_t trace, cbrush_t brush) {
- int i, j;
- cplane_t plane, clipplane;
- float dist;
- float enterfrac, leavefrac;
- float[] ofs = { 0, 0, 0 };
- float d1, d2;
- boolean getout, startout;
- float f;
- cbrushside_t side, leadside;
-
- enterfrac = -1;
- leavefrac = 1;
- clipplane = null;
-
- if (brush.numsides == 0)
- return;
-
- c_brush_traces++;
-
- getout = false;
- startout = false;
- leadside = null;
-
- for (i = 0; i < brush.numsides; i++) {
- side = map_brushsides[brush.firstbrushside + i];
- plane = side.plane;
-
- // FIXME: special case for axial
-
- if (!trace_ispoint) { // general box case
-
- // push the plane out apropriately for mins/maxs
-
- // FIXME: use signbits into 8 way lookup for each mins/maxs
- for (j = 0; j < 3; j++) {
- if (plane.normal[j] < 0)
- ofs[j] = maxs[j];
- else
- ofs[j] = mins[j];
- }
- dist = DotProduct(ofs, plane.normal);
- dist = plane.dist - dist;
- }
- else { // special point case
- dist = plane.dist;
- }
-
- d1 = DotProduct(p1, plane.normal) - dist;
- d2 = DotProduct(p2, plane.normal) - dist;
-
- if (d2 > 0)
- getout = true; // endpoint is not in solid
- if (d1 > 0)
- startout = true;
-
- // if completely in front of face, no intersection
- if (d1 > 0 && d2 >= d1)
- return;
-
- if (d1 <= 0 && d2 <= 0)
- continue;
-
- // crosses face
- if (d1 > d2) { // enter
- f = (d1 - DIST_EPSILON) / (d1 - d2);
- if (f > enterfrac) {
- enterfrac = f;
- clipplane = plane;
- leadside = side;
- }
- }
- else { // leave
- f = (d1 + DIST_EPSILON) / (d1 - d2);
- if (f < leavefrac)
- leavefrac = f;
- }
- }
-
- if (!startout) { // original point was inside brush
- trace.startsolid = true;
- if (!getout)
- trace.allsolid = true;
- return;
- }
- if (enterfrac < leavefrac) {
- if (enterfrac > -1 && enterfrac < trace.fraction) {
- if (enterfrac < 0)
- enterfrac = 0;
- trace.fraction = enterfrac;
- // copy
- trace.plane.set(clipplane);
- trace.surface = leadside.surface.c;
- trace.contents = brush.contents;
- }
- }
- }
-
- /*
- ================
- CM_TestBoxInBrush
- ================
- */
- public static void CM_TestBoxInBrush(float[] mins, float[] maxs, float[] p1, trace_t trace, cbrush_t brush) {
- int i, j;
- cplane_t plane;
- float dist;
- float[] ofs = { 0, 0, 0 };
- float d1;
- cbrushside_t side;
-
- if (brush.numsides == 0)
- return;
-
- for (i = 0; i < brush.numsides; i++) {
- side = map_brushsides[brush.firstbrushside + i];
- plane = side.plane;
-
- // FIXME: special case for axial
- // general box case
- // push the plane out apropriately for mins/maxs
- // FIXME: use signbits into 8 way lookup for each mins/maxs
-
- for (j = 0; j < 3; j++) {
- if (plane.normal[j] < 0)
- ofs[j] = maxs[j];
- else
- ofs[j] = mins[j];
- }
- dist = DotProduct(ofs, plane.normal);
- dist = plane.dist - dist;
-
- d1 = DotProduct(p1, plane.normal) - dist;
-
- // if completely in front of face, no intersection
- if (d1 > 0)
- return;
-
- }
-
- // inside this brush
- trace.startsolid = trace.allsolid = true;
- trace.fraction = 0;
- trace.contents = brush.contents;
- }
-
- /*
- ================
- CM_TraceToLeaf
- ================
- */
- public static void CM_TraceToLeaf(int leafnum) {
- int k;
- int brushnum;
- cleaf_t leaf;
- cbrush_t b;
-
- leaf = map_leafs[leafnum];
- if (0 == (leaf.contents & trace_contents))
- return;
-
- // trace line against all brushes in the leaf
- for (k = 0; k < leaf.numleafbrushes; k++) {
-
- brushnum = map_leafbrushes[leaf.firstleafbrush + k];
- b = map_brushes[brushnum];
- if (b.checkcount == checkcount)
- continue; // already checked this brush in another leaf
- b.checkcount = checkcount;
-
- if (0 == (b.contents & trace_contents))
- continue;
- CM_ClipBoxToBrush(trace_mins, trace_maxs, trace_start, trace_end, trace_trace, b);
- if (0 == trace_trace.fraction)
- return;
- }
-
- }
-
- /*
- ================
- CM_TestInLeaf
- ================
- */
- public static void CM_TestInLeaf(int leafnum) {
- int k;
- int brushnum;
- cleaf_t leaf;
- cbrush_t b;
-
- leaf = map_leafs[leafnum];
- if (0 == (leaf.contents & trace_contents))
- return;
- // trace line against all brushes in the leaf
- for (k = 0; k < leaf.numleafbrushes; k++) {
- brushnum = map_leafbrushes[leaf.firstleafbrush + k];
- b = map_brushes[brushnum];
- if (b.checkcount == checkcount)
- continue; // already checked this brush in another leaf
- b.checkcount = checkcount;
-
- if (0 == (b.contents & trace_contents))
- continue;
- CM_TestBoxInBrush(trace_mins, trace_maxs, trace_start, trace_trace, b);
- if (0 == trace_trace.fraction)
- return;
- }
-
- }
-
- /*
- ==================
- CM_RecursiveHullCheck
- ==================
- */
- public static void CM_RecursiveHullCheck(int num, float p1f, float p2f, float[] p1, float[] p2) {
- cnode_t node;
- cplane_t plane;
- float t1, t2, offset;
- float frac, frac2;
- float idist;
- int i;
- float[] mid = { 0, 0, 0 };
- int side;
- float midf;
-
- if (trace_trace.fraction <= p1f)
- return; // already hit something nearer
-
- // if < 0, we are in a leaf node
- if (num < 0) {
- CM_TraceToLeaf(-1 - num);
- return;
- }
-
- //
- // find the point distances to the seperating plane
- // and the offset for the size of the box
- //
- node = map_nodes[num];
- plane = node.plane;
-
- if (plane.type < 3) {
- t1 = p1[plane.type] - plane.dist;
- t2 = p2[plane.type] - plane.dist;
- offset = trace_extents[plane.type];
- }
- else {
- t1 = DotProduct(plane.normal, p1) - plane.dist;
- t2 = DotProduct(plane.normal, p2) - plane.dist;
- if (trace_ispoint)
- offset = 0;
- else
- offset =
- Math.abs(trace_extents[0] * plane.normal[0])
- + Math.abs(trace_extents[1] * plane.normal[1])
- + Math.abs(trace_extents[2] * plane.normal[2]);
- }
-
- // see which sides we need to consider
- if (t1 >= offset && t2 >= offset) {
- CM_RecursiveHullCheck(node.children[0], p1f, p2f, p1, p2);
- return;
- }
- if (t1 < -offset && t2 < -offset) {
- CM_RecursiveHullCheck(node.children[1], p1f, p2f, p1, p2);
- return;
- }
-
- // put the crosspoint DIST_EPSILON pixels on the near side
- if (t1 < t2) {
- idist = 1.0f / (t1 - t2);
- side = 1;
- frac2 = (t1 + offset + DIST_EPSILON) * idist;
- frac = (t1 - offset + DIST_EPSILON) * idist;
- }
- else if (t1 > t2) {
- idist = 1.0f / (t1 - t2);
- side = 0;
- frac2 = (t1 - offset - DIST_EPSILON) * idist;
- frac = (t1 + offset + DIST_EPSILON) * idist;
- }
- else {
- side = 0;
- frac = 1;
- frac2 = 0;
- }
-
- // move up to the node
- if (frac < 0)
- frac = 0;
- if (frac > 1)
- frac = 1;
-
- midf = p1f + (p2f - p1f) * frac;
- for (i = 0; i < 3; i++)
- mid[i] = p1[i] + frac * (p2[i] - p1[i]);
-
- CM_RecursiveHullCheck(node.children[side], p1f, midf, p1, mid);
-
- // go past the node
- if (frac2 < 0)
- frac2 = 0;
- if (frac2 > 1)
- frac2 = 1;
-
- midf = p1f + (p2f - p1f) * frac2;
- for (i = 0; i < 3; i++)
- mid[i] = p1[i] + frac2 * (p2[i] - p1[i]);
-
- CM_RecursiveHullCheck(node.children[side ^ 1], midf, p2f, mid, p2);
- }
-
- //======================================================================
-
- /*
- ==================
- CM_BoxTrace
- ==================
- */
- public static trace_t BoxTrace(float[] start, float[] end, float[] mins, float[] maxs, int headnode, int brushmask) {
-
- // for multi-check avoidance
- checkcount++;
-
- // for statistics, may be zeroed
- c_traces++;
-
- // fill in a default trace
- //was: memset(& trace_trace, 0, sizeof(trace_trace));
- trace_trace = new trace_t();
-
- trace_trace.fraction = 1;
- trace_trace.surface = nullsurface.c;
-
- if (numnodes == 0) // map not loaded
- {
- Com.DPrintf("dummy trace zurueck, da map not loaded!\n");
- return trace_trace;
- }
-
- trace_contents = brushmask;
- VectorCopy(start, trace_start);
- VectorCopy(end, trace_end);
- VectorCopy(mins, trace_mins);
- VectorCopy(maxs, trace_maxs);
-
- //
- // check for position test special case
- //
- if (start[0] == end[0] && start[1] == end[1] && start[2] == end[2]) {
-
- int leafs[] = new int[1024];
- int i, numleafs;
- float[] c1 = { 0, 0, 0 }, c2 = { 0, 0, 0 };
- int topnode = 0;
-
- VectorAdd(start, mins, c1);
- VectorAdd(start, maxs, c2);
-
- for (i = 0; i < 3; i++) {
- c1[i] -= 1;
- c2[i] += 1;
- }
-
- int tn[] = {topnode};
-
- numleafs = CM_BoxLeafnums_headnode(c1, c2, leafs, 1024, headnode, tn);
- topnode = tn[0];
- for (i = 0; i < numleafs; i++) {
- CM_TestInLeaf(leafs[i]);
- if (trace_trace.allsolid)
- break;
- }
- VectorCopy(start, trace_trace.endpos);
- return trace_trace;
- }
-
- //
- // check for point special case
- //
- if (mins[0] == 0 && mins[1] == 0 && mins[2] == 0 && maxs[0] == 0 && maxs[1] == 0 && maxs[2] == 0) {
- trace_ispoint = true;
- VectorClear(trace_extents);
- }
- else {
- trace_ispoint = false;
- trace_extents[0] = -mins[0] > maxs[0] ? -mins[0] : maxs[0];
- trace_extents[1] = -mins[1] > maxs[1] ? -mins[1] : maxs[1];
- trace_extents[2] = -mins[2] > maxs[2] ? -mins[2] : maxs[2];
- }
-
- //
- // general sweeping through world
- //
- CM_RecursiveHullCheck(headnode, 0, 1, start, end);
-
- if (trace_trace.fraction == 1) {
- VectorCopy(end, trace_trace.endpos);
- }
- else {
- for (int i = 0; i < 3; i++)
- trace_trace.endpos[i] = start[i] + trace_trace.fraction * (end[i] - start[i]);
- }
- return trace_trace;
- }
-
- /*
- ==================
- CM_TransformedBoxTrace
-
- Handles offseting and rotation of the end points for moving and
- rotating entities
- ==================
- */
- public static trace_t TransformedBoxTrace(
- float[] start,
- float[] end,
- float[] mins,
- float[] maxs,
- int headnode,
- int brushmask,
- float[] origin,
- float[] angles) {
- trace_t trace;
- float[] start_l = { 0, 0, 0 }, end_l = { 0, 0, 0 };
- float[] a = { 0, 0, 0 };
- float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 }, up = { 0, 0, 0 };
- float[] temp = { 0, 0, 0 };
- boolean rotated;
-
- // subtract origin offset
- VectorSubtract(start, origin, start_l);
- VectorSubtract(end, origin, end_l);
-
- // rotate start and end into the models frame of reference
- if (headnode != box_headnode && (angles[0] != 0 || angles[1] != 0 || angles[2] != 0))
- rotated = true;
- else
- rotated = false;
-
- if (rotated) {
- AngleVectors(angles, forward, right, up);
-
- VectorCopy(start_l, temp);
- start_l[0] = DotProduct(temp, forward);
- start_l[1] = -DotProduct(temp, right);
- start_l[2] = DotProduct(temp, up);
-
- VectorCopy(end_l, temp);
- end_l[0] = DotProduct(temp, forward);
- end_l[1] = -DotProduct(temp, right);
- end_l[2] = DotProduct(temp, up);
- }
-
- // sweep the box through the model
- trace = BoxTrace(start_l, end_l, mins, maxs, headnode, brushmask);
-
- if (rotated && trace.fraction != 1.0) {
- // FIXME: figure out how to do this with existing angles
- VectorNegate(angles, a);
- AngleVectors(a, forward, right, up);
-
- VectorCopy(trace.plane.normal, temp);
- trace.plane.normal[0] = DotProduct(temp, forward);
- trace.plane.normal[1] = -DotProduct(temp, right);
- trace.plane.normal[2] = DotProduct(temp, up);
- }
-
- trace.endpos[0] = start[0] + trace.fraction * (end[0] - start[0]);
- trace.endpos[1] = start[1] + trace.fraction * (end[1] - start[1]);
- trace.endpos[2] = start[2] + trace.fraction * (end[2] - start[2]);
-
- return trace;
- }
-
- /*
- ===============================================================================
- PVS / PHS
- ===============================================================================
- */
-
- /*
- ===================
- CM_DecompressVis
- ===================
- */
- public static void CM_DecompressVis(byte in[], int offset, byte out[]) {
- int c;
-
- int row;
-
- row = (numclusters + 7) >> 3;
- int outp = 0;
- int inp = offset;
-
- if (in == null || numvisibility == 0) { // no vis info, so make all visible
- while (row != 0) {
- out[outp++] = (byte) 0xFF;
- row--;
- }
- return;
- }
-
- do {
- if (in[inp] != 0) {
- out[outp++] = in[inp++];
- continue;
- }
-
- c = in[inp + 1] & 0xFF;
- inp += 2;
- if (outp + c > row) {
- c = row - (outp);
- Com.DPrintf("warning: Vis decompression overrun\n");
- }
- while (c != 0) {
- out[outp++] = 0;
- c--;
- }
- }
- while (outp < row);
- }
-
- public static byte pvsrow[] = new byte[MAX_MAP_LEAFS / 8];
- public static byte phsrow[] = new byte[MAX_MAP_LEAFS / 8];
-
- public static byte[] CM_ClusterPVS(int cluster) {
- if (cluster == -1)
- Arrays.fill(pvsrow, 0, (numclusters + 7) >> 3, (byte)0);
- else
- CM_DecompressVis(map_visibility, map_vis.bitofs[cluster][DVIS_PVS], pvsrow);
- return pvsrow;
- }
-
- public static byte[] CM_ClusterPHS(int cluster) {
- if (cluster == -1)
- Arrays.fill(phsrow, 0, (numclusters + 7) >> 3, (byte)0);
- else
- CM_DecompressVis(map_visibility, map_vis.bitofs[cluster][Defines.DVIS_PHS], phsrow);
- return phsrow;
- }
-
- /*
- ===============================================================================
- AREAPORTALS
- ===============================================================================
- */
-
- public static void FloodArea_r(carea_t area, int floodnum) {
- //Com.Printf("FloodArea_r(" + floodnum + ")...\n");
- int i;
- qfiles.dareaportal_t p;
-
- if (area.floodvalid == floodvalid) {
- if (area.floodnum == floodnum)
- return;
- Com.Error(ERR_DROP, "FloodArea_r: reflooded");
- }
-
- area.floodnum = floodnum;
- area.floodvalid = floodvalid;
-
- for (i = 0; i < area.numareaportals; i++) {
- p = map_areaportals[area.firstareaportal + i];
- if (portalopen[p.portalnum])
- FloodArea_r(map_areas[p.otherarea], floodnum);
- }
- }
-
- /*
- ====================
- FloodAreaConnections
- ====================
- */
- public static void FloodAreaConnections() {
- Com.DPrintf("FloodAreaConnections...\n");
-
- int i;
- carea_t area;
- int floodnum;
-
- // all current floods are now invalid
- floodvalid++;
- floodnum = 0;
-
- // area 0 is not used
- for (i = 1; i < numareas; i++) {
-
- area = map_areas[i];
-
- if (area.floodvalid == floodvalid)
- continue; // already flooded into
- floodnum++;
- FloodArea_r(area, floodnum);
- }
- }
-
- /*
- =================
- CM_SetAreaPortalState
- =================
- */
- public static void CM_SetAreaPortalState(int portalnum, boolean open) {
- if (portalnum > numareaportals)
- Com.Error(ERR_DROP, "areaportal > numareaportals");
-
- portalopen[portalnum] = open;
- FloodAreaConnections();
- }
-
- /*
- =================
- CM_AreasConnected
- =================
- */
-
- public static boolean CM_AreasConnected(int area1, int area2) {
- if (map_noareas.value != 0)
- return true;
-
- if (area1 > numareas || area2 > numareas)
- Com.Error(ERR_DROP, "area > numareas");
-
- if (map_areas[area1].floodnum == map_areas[area2].floodnum)
- return true;
-
- return false;
- }
-
- /*
- =================
- CM_WriteAreaBits
-
- Writes a length byte followed by a bit vector of all the areas
- that area in the same flood as the area parameter
-
- This is used by the client refreshes to cull visibility
- =================
- */
- public static int CM_WriteAreaBits(byte buffer[], int area) {
- int i;
- int floodnum;
- int bytes;
-
- bytes = (numareas + 7) >> 3;
-
- if (map_noareas.value != 0) { // for debugging, send everything
- Arrays.fill(buffer, 0, bytes, (byte)255);
- }
- else {
- Arrays.fill(buffer, 0, bytes, (byte)0);
- floodnum = map_areas[area].floodnum;
- for (i = 0; i < numareas; i++) {
- if (map_areas[i].floodnum == floodnum || area == 0)
- buffer[i >> 3] |= 1 << (i & 7);
- }
- }
-
- return bytes;
- }
-
- /*
- ===================
- CM_WritePortalState
-
- Writes the portal state to a savegame file
- ===================
- */
-
- public static void CM_WritePortalState(RandomAccessFile os) {
-
- //was: fwrite(portalopen, sizeof(portalopen), 1, f);
- try {
-
- for (int n = 0; n < portalopen.length; n++)
- if (portalopen[n])
- os.writeInt(1);
- else
- os.writeInt(0);
- }
- catch (Exception e) {
- Com.Printf("ERROR:" + e);
- e.printStackTrace();
- }
- }
-
- /*
- ===================
- CM_ReadPortalState
-
- Reads the portal state from a savegame file
- and recalculates the area connections
- ===================
- */
- public static void CM_ReadPortalState(RandomAccessFile f) {
-
- //was: FS_Read(portalopen, sizeof(portalopen), f);
- int len = portalopen.length * 4;
-
- byte buf[] = new byte[len];
-
-
- FS.Read(buf, len, f);
-
- ByteBuffer bb = ByteBuffer.wrap(buf);
- IntBuffer ib = bb.asIntBuffer();
-
- for (int n = 0; n < portalopen.length; n++)
- portalopen[n] = ib.get() != 0;
-
- FloodAreaConnections();
- }
-
- /*
- =============
- CM_HeadnodeVisible
-
- Returns true if any leaf under headnode has a cluster that
- is potentially visible
- =============
- */
- public static boolean CM_HeadnodeVisible(int nodenum, byte visbits[]) {
- int leafnum;
- int cluster;
- cnode_t node;
-
- if (nodenum < 0) {
- leafnum = -1 - nodenum;
- cluster = map_leafs[leafnum].cluster;
- if (cluster == -1)
- return false;
- if (0 != (visbits[cluster >>> 3] & (1 << (cluster & 7))))
- return true;
- return false;
- }
-
- node = map_nodes[nodenum];
- if (CM_HeadnodeVisible(node.children[0], visbits))
- return true;
- return CM_HeadnodeVisible(node.children[1], visbits);
- }
-}
+ /*
+ * ================= CMod_LoadVisibility =================
+ */
+ public static void CMod_LoadVisibility(lump_t l) {
+ Com.DPrintf("CMod_LoadVisibility...\n");
+ int i;
+
+ numvisibility = l.filelen;
+
+ Com.DPrintf(" numvisibility=" + numvisibility + "\n");
+
+ if (l.filelen > Defines.MAX_MAP_VISIBILITY)
+ Com.Error(Defines.ERR_DROP, "Map has too large visibility lump");
+
+ System.arraycopy(cmod_base, l.fileofs, map_visibility, 0, l.filelen);
+
+ ByteBuffer bb = ByteBuffer.wrap(map_visibility, 0, l.filelen);
+ bb.order(ByteOrder.LITTLE_ENDIAN);
+
+ map_vis = new qfiles.dvis_t(bb);
+
+ }
+
+ /*
+ * ================= CMod_LoadEntityString =================
+ */
+ public static void CMod_LoadEntityString(lump_t l) {
+ Com.DPrintf("CMod_LoadEntityString...\n");
+
+ numentitychars = l.filelen;
+
+ if (l.filelen > Defines.MAX_MAP_ENTSTRING)
+ Com.Error(Defines.ERR_DROP, "Map has too large entity lump");
+
+ int x = 0;
+ for (; x < l.filelen && cmod_base[x + l.fileofs] != 0; x++)
+ ;
+
+ map_entitystring = new String(cmod_base, l.fileofs, x).trim();
+ }
+
+ /*
+ * ================== CM_InlineModel ==================
+ */
+
+ // works fine
+ public static cmodel_t InlineModel(String name) {
+ int num;
+
+ if (name == null || name.charAt(0) != '*')
+ Com.Error(Defines.ERR_DROP, "CM_InlineModel: bad name");
+
+ num = Lib.atoi(name.substring(1));
+
+ if (num < 1 || num >= numcmodels)
+ Com.Error(Defines.ERR_DROP, "CM_InlineModel: bad number");
+
+ return map_cmodels[num];
+ }
+
+ public static int CM_NumClusters() {
+ return numclusters;
+ }
+
+ public static int CM_NumInlineModels() {
+ return numcmodels;
+ }
+
+ public static String CM_EntityString() {
+ return map_entitystring;
+ }
+
+ public static int CM_LeafContents(int leafnum) {
+ if (leafnum < 0 || leafnum >= numleafs)
+ Com.Error(Defines.ERR_DROP, "CM_LeafContents: bad number");
+ return map_leafs[leafnum].contents;
+ }
+
+ public static int CM_LeafCluster(int leafnum) {
+ if (leafnum < 0 || leafnum >= numleafs)
+ Com.Error(Defines.ERR_DROP, "CM_LeafCluster: bad number");
+ return map_leafs[leafnum].cluster;
+ }
+
+ public static int CM_LeafArea(int leafnum) {
+ if (leafnum < 0 || leafnum >= numleafs)
+ Com.Error(Defines.ERR_DROP, "CM_LeafArea: bad number");
+ return map_leafs[leafnum].area;
+ }
+
+ //=======================================================================
+
+ static cplane_t box_planes[];
+
+ static int box_headnode;
+
+ static cbrush_t box_brush;
+
+ static cleaf_t box_leaf;
+
+ /*
+ * =================== CM_InitBoxHull
+ *
+ * Set up the planes and nodes so that the six floats of a bounding box can
+ * just be stored out and get a proper clipping hull structure.
+ * ===================
+ */
+ public static void CM_InitBoxHull() {
+ int i;
+ int side;
+ cnode_t c;
+ cplane_t p;
+ cbrushside_t s;
+
+ box_headnode = numnodes; // noch platz f?r 6 brushes
+
+ box_planes = new cplane_t[] { map_planes[numplanes],
+ map_planes[numplanes + 1], map_planes[numplanes + 2],
+ map_planes[numplanes + 3], map_planes[numplanes + 4],
+ map_planes[numplanes + 5], map_planes[numplanes + 6],
+ map_planes[numplanes + 7], map_planes[numplanes + 8],
+ map_planes[numplanes + 9], map_planes[numplanes + 10],
+ map_planes[numplanes + 11], map_planes[numplanes + 12] };
+
+ if (numnodes + 6 > Defines.MAX_MAP_NODES
+ || numbrushes + 1 > Defines.MAX_MAP_BRUSHES
+ || numleafbrushes + 1 > Defines.MAX_MAP_LEAFBRUSHES
+ || numbrushsides + 6 > Defines.MAX_MAP_BRUSHSIDES
+ || numplanes + 12 > Defines.MAX_MAP_PLANES)
+ Com.Error(Defines.ERR_DROP, "Not enough room for box tree");
+
+ box_brush = map_brushes[numbrushes];
+ box_brush.numsides = 6;
+ box_brush.firstbrushside = numbrushsides;
+ box_brush.contents = Defines.CONTENTS_MONSTER;
+
+ box_leaf = map_leafs[numleafs];
+ box_leaf.contents = Defines.CONTENTS_MONSTER;
+ box_leaf.firstleafbrush = (short) numleafbrushes;
+ box_leaf.numleafbrushes = 1;
+
+ map_leafbrushes[numleafbrushes] = numbrushes;
+
+ for (i = 0; i < 6; i++) {
+ side = i & 1;
+
+ // brush sides
+ s = map_brushsides[numbrushsides + i];
+ s.plane = map_planes[(numplanes + i * 2 + side)];
+ s.surface = nullsurface;
+
+ // nodes
+ c = map_nodes[box_headnode + i];
+ c.plane = map_planes[(numplanes + i * 2)];
+ c.children[side] = -1 - emptyleaf;
+ if (i != 5)
+ c.children[side ^ 1] = box_headnode + i + 1;
+ else
+ c.children[side ^ 1] = -1 - numleafs;
+
+ // planes
+ p = box_planes[i * 2];
+ p.type = (byte) (i >> 1);
+ p.signbits = 0;
+ Math3D.VectorClear(p.normal);
+ p.normal[i >> 1] = 1;
+
+ p = box_planes[i * 2 + 1];
+ p.type = (byte) (3 + (i >> 1));
+ p.signbits = 0;
+ Math3D.VectorClear(p.normal);
+ p.normal[i >> 1] = -1;
+ }
+ }
+
+ /*
+ * =================== CM_HeadnodeForBox
+ *
+ * To keep everything totally uniform, bounding boxes are turned into small
+ * BSP trees instead of being compared directly. ===================
+ */
+ public static int HeadnodeForBox(float[] mins, float[] maxs) {
+ box_planes[0].dist = maxs[0];
+ box_planes[1].dist = -maxs[0];
+ box_planes[2].dist = mins[0];
+ box_planes[3].dist = -mins[0];
+ box_planes[4].dist = maxs[1];
+ box_planes[5].dist = -maxs[1];
+ box_planes[6].dist = mins[1];
+ box_planes[7].dist = -mins[1];
+ box_planes[8].dist = maxs[2];
+ box_planes[9].dist = -maxs[2];
+ box_planes[10].dist = mins[2];
+ box_planes[11].dist = -mins[2];
+
+ return box_headnode;
+ }
+
+ /*
+ * ================== CM_PointLeafnum_r ==================
+ */
+ public static int CM_PointLeafnum_r(float[] p, int num) {
+ float d;
+ cnode_t node;
+ cplane_t plane;
+
+ while (num >= 0) {
+ node = map_nodes[num];
+ plane = node.plane;
+
+ if (plane.type < 3)
+ d = p[plane.type] - plane.dist;
+ else
+ d = Math3D.DotProduct(plane.normal, p) - plane.dist;
+ if (d < 0)
+ num = node.children[1];
+ else
+ num = node.children[0];
+ }
+
+ Globals.c_pointcontents++; // optimize counter
+
+ return -1 - num;
+ }
+
+ public static int CM_PointLeafnum(float[] p) {
+ if (numplanes == 0)
+ return 0; // sound may call this without map loaded
+ return CM_PointLeafnum_r(p, 0);
+ }
+
+ /*
+ * ============= CM_BoxLeafnums
+ *
+ * Fills in a list of all the leafs touched =============
+ */
+ static int leaf_count, leaf_maxcount;
+
+ static int leaf_list[];
+
+ static float leaf_mins[], leaf_maxs[];
+
+ static int leaf_topnode;
+
+ public static void CM_BoxLeafnums_r(int nodenum) {
+ cplane_t plane;
+ cnode_t node;
+ int s;
+
+ while (true) {
+ if (nodenum < 0) {
+ if (leaf_count >= leaf_maxcount) {
+ //TODO: here is still an error.
+ //Com.DPrintf("CM_BoxLeafnums_r: overflow\n");
+ return;
+ }
+ leaf_list[leaf_count++] = -1 - nodenum;
+ return;
+ }
+
+ node = map_nodes[nodenum];
+ plane = node.plane;
+
+ s = Math3D.BoxOnPlaneSide(leaf_mins, leaf_maxs, plane);
+
+ if (s == 1)
+ nodenum = node.children[0];
+ else if (s == 2)
+ nodenum = node.children[1];
+ else {
+ // go down both
+ if (leaf_topnode == -1)
+ leaf_topnode = nodenum;
+ CM_BoxLeafnums_r(node.children[0]);
+ nodenum = node.children[1];
+ }
+ }
+ }
+
+ public static int CM_BoxLeafnums_headnode(float[] mins, float[] maxs,
+ int list[], int listsize, int headnode, int topnode[]) {
+ leaf_list = list;
+ leaf_count = 0;
+ leaf_maxcount = listsize;
+ leaf_mins = mins;
+ leaf_maxs = maxs;
+
+ leaf_topnode = -1;
+
+ CM_BoxLeafnums_r(headnode);
+
+ if (topnode != null)
+ topnode[0] = leaf_topnode;
+
+ return leaf_count;
+ }
+
+ public static int CM_BoxLeafnums(float[] mins, float[] maxs, int list[],
+ int listsize, int topnode[]) {
+ return CM_BoxLeafnums_headnode(mins, maxs, list, listsize,
+ map_cmodels[0].headnode, topnode);
+ }
+
+ /*
+ * public static class intwrap1 { public intwrap(int i) { this.i = i; }
+ * public int i; }
+ */
+ /*
+ * ================== CM_PointContents ==================
+ */
+ public static int PointContents(float[] p, int headnode) {
+ int l;
+
+ if (numnodes == 0) // map not loaded
+ return 0;
+
+ l = CM_PointLeafnum_r(p, headnode);
+
+ return map_leafs[l].contents;
+ }
+
+ /*
+ * ================== CM_TransformedPointContents
+ *
+ * Handles offseting and rotation of the end points for moving and rotating
+ * entities ==================
+ */
+ public static int TransformedPointContents(float[] p, int headnode,
+ float[] origin, float[] angles) {
+ float[] p_l = { 0, 0, 0 };
+ float[] temp = { 0, 0, 0 };
+ float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 }, up = { 0, 0, 0 };
+ int l;
+
+ // subtract origin offset
+ Math3D.VectorSubtract(p, origin, p_l);
+
+ // rotate start and end into the models frame of reference
+ if (headnode != box_headnode
+ && (angles[0] != 0 || angles[1] != 0 || angles[2] != 0)) {
+ Math3D.AngleVectors(angles, forward, right, up);
+
+ Math3D.VectorCopy(p_l, temp);
+ p_l[0] = Math3D.DotProduct(temp, forward);
+ p_l[1] = -Math3D.DotProduct(temp, right);
+ p_l[2] = Math3D.DotProduct(temp, up);
+ }
+
+ l = CM_PointLeafnum_r(p_l, headnode);
+
+ return map_leafs[l].contents;
+ }
+
+ /*
+ * ===============================================================================
+ *
+ * BOX TRACING
+ *
+ * ===============================================================================
+ */
+
+ // 1/32 epsilon to keep floating point happy
+ private static final float DIST_EPSILON = 0.03125f;
+
+ private static float[] trace_start = { 0, 0, 0 }, trace_end = { 0, 0, 0 };
+
+ private static float[] trace_mins = { 0, 0, 0 }, trace_maxs = { 0, 0, 0 };
+
+ private static float[] trace_extents = { 0, 0, 0 };
+
+ private static trace_t trace_trace = new trace_t();
+
+ private static int trace_contents;
+
+ private static boolean trace_ispoint; // optimized case
+
+ /*
+ * ================ CM_ClipBoxToBrush ================
+ */
+ public static void CM_ClipBoxToBrush(float[] mins, float[] maxs,
+ float[] p1, float[] p2, trace_t trace, cbrush_t brush) {
+ int i, j;
+ cplane_t plane, clipplane;
+ float dist;
+ float enterfrac, leavefrac;
+ float[] ofs = { 0, 0, 0 };
+ float d1, d2;
+ boolean getout, startout;
+ float f;
+ cbrushside_t side, leadside;
+
+ enterfrac = -1;
+ leavefrac = 1;
+ clipplane = null;
+
+ if (brush.numsides == 0)
+ return;
+
+ Globals.c_brush_traces++;
+
+ getout = false;
+ startout = false;
+ leadside = null;
+
+ for (i = 0; i < brush.numsides; i++) {
+ side = map_brushsides[brush.firstbrushside + i];
+ plane = side.plane;
+
+ // FIXME: special case for axial
+
+ if (!trace_ispoint) { // general box case
+
+ // push the plane out apropriately for mins/maxs
+
+ // FIXME: use signbits into 8 way lookup for each mins/maxs
+ for (j = 0; j < 3; j++) {
+ if (plane.normal[j] < 0)
+ ofs[j] = maxs[j];
+ else
+ ofs[j] = mins[j];
+ }
+ dist = Math3D.DotProduct(ofs, plane.normal);
+ dist = plane.dist - dist;
+ } else { // special point case
+ dist = plane.dist;
+ }
+
+ d1 = Math3D.DotProduct(p1, plane.normal) - dist;
+ d2 = Math3D.DotProduct(p2, plane.normal) - dist;
+
+ if (d2 > 0)
+ getout = true; // endpoint is not in solid
+ if (d1 > 0)
+ startout = true;
+
+ // if completely in front of face, no intersection
+ if (d1 > 0 && d2 >= d1)
+ return;
+
+ if (d1 <= 0 && d2 <= 0)
+ continue;
+
+ // crosses face
+ if (d1 > d2) { // enter
+ f = (d1 - DIST_EPSILON) / (d1 - d2);
+ if (f > enterfrac) {
+ enterfrac = f;
+ clipplane = plane;
+ leadside = side;
+ }
+ } else { // leave
+ f = (d1 + DIST_EPSILON) / (d1 - d2);
+ if (f < leavefrac)
+ leavefrac = f;
+ }
+ }
+
+ if (!startout) { // original point was inside brush
+ trace.startsolid = true;
+ if (!getout)
+ trace.allsolid = true;
+ return;
+ }
+ if (enterfrac < leavefrac) {
+ if (enterfrac > -1 && enterfrac < trace.fraction) {
+ if (enterfrac < 0)
+ enterfrac = 0;
+ trace.fraction = enterfrac;
+ // copy
+ trace.plane.set(clipplane);
+ trace.surface = leadside.surface.c;
+ trace.contents = brush.contents;
+ }
+ }
+ }
+
+ /*
+ * ================ CM_TestBoxInBrush ================
+ */
+ public static void CM_TestBoxInBrush(float[] mins, float[] maxs,
+ float[] p1, trace_t trace, cbrush_t brush) {
+ int i, j;
+ cplane_t plane;
+ float dist;
+ float[] ofs = { 0, 0, 0 };
+ float d1;
+ cbrushside_t side;
+
+ if (brush.numsides == 0)
+ return;
+
+ for (i = 0; i < brush.numsides; i++) {
+ side = map_brushsides[brush.firstbrushside + i];
+ plane = side.plane;
+
+ // FIXME: special case for axial
+ // general box case
+ // push the plane out apropriately for mins/maxs
+ // FIXME: use signbits into 8 way lookup for each mins/maxs
+
+ for (j = 0; j < 3; j++) {
+ if (plane.normal[j] < 0)
+ ofs[j] = maxs[j];
+ else
+ ofs[j] = mins[j];
+ }
+ dist = Math3D.DotProduct(ofs, plane.normal);
+ dist = plane.dist - dist;
+
+ d1 = Math3D.DotProduct(p1, plane.normal) - dist;
+
+ // if completely in front of face, no intersection
+ if (d1 > 0)
+ return;
+
+ }
+
+ // inside this brush
+ trace.startsolid = trace.allsolid = true;
+ trace.fraction = 0;
+ trace.contents = brush.contents;
+ }
+
+ /*
+ * ================ CM_TraceToLeaf ================
+ */
+ public static void CM_TraceToLeaf(int leafnum) {
+ int k;
+ int brushnum;
+ cleaf_t leaf;
+ cbrush_t b;
+
+ leaf = map_leafs[leafnum];
+ if (0 == (leaf.contents & trace_contents))
+ return;
+
+ // trace line against all brushes in the leaf
+ for (k = 0; k < leaf.numleafbrushes; k++) {
+
+ brushnum = map_leafbrushes[leaf.firstleafbrush + k];
+ b = map_brushes[brushnum];
+ if (b.checkcount == checkcount)
+ continue; // already checked this brush in another leaf
+ b.checkcount = checkcount;
+
+ if (0 == (b.contents & trace_contents))
+ continue;
+ CM_ClipBoxToBrush(trace_mins, trace_maxs, trace_start, trace_end,
+ trace_trace, b);
+ if (0 == trace_trace.fraction)
+ return;
+ }
+
+ }
+
+ /*
+ * ================ CM_TestInLeaf ================
+ */
+ public static void CM_TestInLeaf(int leafnum) {
+ int k;
+ int brushnum;
+ cleaf_t leaf;
+ cbrush_t b;
+
+ leaf = map_leafs[leafnum];
+ if (0 == (leaf.contents & trace_contents))
+ return;
+ // trace line against all brushes in the leaf
+ for (k = 0; k < leaf.numleafbrushes; k++) {
+ brushnum = map_leafbrushes[leaf.firstleafbrush + k];
+ b = map_brushes[brushnum];
+ if (b.checkcount == checkcount)
+ continue; // already checked this brush in another leaf
+ b.checkcount = checkcount;
+
+ if (0 == (b.contents & trace_contents))
+ continue;
+ CM_TestBoxInBrush(trace_mins, trace_maxs, trace_start, trace_trace,
+ b);
+ if (0 == trace_trace.fraction)
+ return;
+ }
+
+ }
+
+ /*
+ * ================== CM_RecursiveHullCheck ==================
+ */
+ public static void CM_RecursiveHullCheck(int num, float p1f, float p2f,
+ float[] p1, float[] p2) {
+ cnode_t node;
+ cplane_t plane;
+ float t1, t2, offset;
+ float frac, frac2;
+ float idist;
+ int i;
+ float[] mid = { 0, 0, 0 };
+ int side;
+ float midf;
+
+ if (trace_trace.fraction <= p1f)
+ return; // already hit something nearer
+
+ // if < 0, we are in a leaf node
+ if (num < 0) {
+ CM_TraceToLeaf(-1 - num);
+ return;
+ }
+
+ //
+ // find the point distances to the seperating plane
+ // and the offset for the size of the box
+ //
+ node = map_nodes[num];
+ plane = node.plane;
+
+ if (plane.type < 3) {
+ t1 = p1[plane.type] - plane.dist;
+ t2 = p2[plane.type] - plane.dist;
+ offset = trace_extents[plane.type];
+ } else {
+ t1 = Math3D.DotProduct(plane.normal, p1) - plane.dist;
+ t2 = Math3D.DotProduct(plane.normal, p2) - plane.dist;
+ if (trace_ispoint)
+ offset = 0;
+ else
+ offset = Math.abs(trace_extents[0] * plane.normal[0])
+ + Math.abs(trace_extents[1] * plane.normal[1])
+ + Math.abs(trace_extents[2] * plane.normal[2]);
+ }
+
+ // see which sides we need to consider
+ if (t1 >= offset && t2 >= offset) {
+ CM_RecursiveHullCheck(node.children[0], p1f, p2f, p1, p2);
+ return;
+ }
+ if (t1 < -offset && t2 < -offset) {
+ CM_RecursiveHullCheck(node.children[1], p1f, p2f, p1, p2);
+ return;
+ }
+
+ // put the crosspoint DIST_EPSILON pixels on the near side
+ if (t1 < t2) {
+ idist = 1.0f / (t1 - t2);
+ side = 1;
+ frac2 = (t1 + offset + DIST_EPSILON) * idist;
+ frac = (t1 - offset + DIST_EPSILON) * idist;
+ } else if (t1 > t2) {
+ idist = 1.0f / (t1 - t2);
+ side = 0;
+ frac2 = (t1 - offset - DIST_EPSILON) * idist;
+ frac = (t1 + offset + DIST_EPSILON) * idist;
+ } else {
+ side = 0;
+ frac = 1;
+ frac2 = 0;
+ }
+
+ // move up to the node
+ if (frac < 0)
+ frac = 0;
+ if (frac > 1)
+ frac = 1;
+
+ midf = p1f + (p2f - p1f) * frac;
+ for (i = 0; i < 3; i++)
+ mid[i] = p1[i] + frac * (p2[i] - p1[i]);
+
+ CM_RecursiveHullCheck(node.children[side], p1f, midf, p1, mid);
+
+ // go past the node
+ if (frac2 < 0)
+ frac2 = 0;
+ if (frac2 > 1)
+ frac2 = 1;
+
+ midf = p1f + (p2f - p1f) * frac2;
+ for (i = 0; i < 3; i++)
+ mid[i] = p1[i] + frac2 * (p2[i] - p1[i]);
+
+ CM_RecursiveHullCheck(node.children[side ^ 1], midf, p2f, mid, p2);
+ }
+
+ //======================================================================
+
+ /*
+ * ================== CM_BoxTrace ==================
+ */
+ public static trace_t BoxTrace(float[] start, float[] end, float[] mins,
+ float[] maxs, int headnode, int brushmask) {
+
+ // for multi-check avoidance
+ checkcount++;
+
+ // for statistics, may be zeroed
+ Globals.c_traces++;
+
+ // fill in a default trace
+ //was: memset(& trace_trace, 0, sizeof(trace_trace));
+ trace_trace = new trace_t();
+
+ trace_trace.fraction = 1;
+ trace_trace.surface = nullsurface.c;
+
+ if (numnodes == 0) // map not loaded
+ {
+ Com.DPrintf("dummy trace zurueck, da map not loaded!\n");
+ return trace_trace;
+ }
+
+ trace_contents = brushmask;
+ Math3D.VectorCopy(start, trace_start);
+ Math3D.VectorCopy(end, trace_end);
+ Math3D.VectorCopy(mins, trace_mins);
+ Math3D.VectorCopy(maxs, trace_maxs);
+
+ //
+ // check for position test special case
+ //
+ if (start[0] == end[0] && start[1] == end[1] && start[2] == end[2]) {
+
+ int leafs[] = new int[1024];
+ int i, numleafs;
+ float[] c1 = { 0, 0, 0 }, c2 = { 0, 0, 0 };
+ int topnode = 0;
+
+ Math3D.VectorAdd(start, mins, c1);
+ Math3D.VectorAdd(start, maxs, c2);
+
+ for (i = 0; i < 3; i++) {
+ c1[i] -= 1;
+ c2[i] += 1;
+ }
+
+ int tn[] = { topnode };
+
+ numleafs = CM_BoxLeafnums_headnode(c1, c2, leafs, 1024, headnode,
+ tn);
+ topnode = tn[0];
+ for (i = 0; i < numleafs; i++) {
+ CM_TestInLeaf(leafs[i]);
+ if (trace_trace.allsolid)
+ break;
+ }
+ Math3D.VectorCopy(start, trace_trace.endpos);
+ return trace_trace;
+ }
+
+ //
+ // check for point special case
+ //
+ if (mins[0] == 0 && mins[1] == 0 && mins[2] == 0 && maxs[0] == 0
+ && maxs[1] == 0 && maxs[2] == 0) {
+ trace_ispoint = true;
+ Math3D.VectorClear(trace_extents);
+ } else {
+ trace_ispoint = false;
+ trace_extents[0] = -mins[0] > maxs[0] ? -mins[0] : maxs[0];
+ trace_extents[1] = -mins[1] > maxs[1] ? -mins[1] : maxs[1];
+ trace_extents[2] = -mins[2] > maxs[2] ? -mins[2] : maxs[2];
+ }
+
+ //
+ // general sweeping through world
+ //
+ CM_RecursiveHullCheck(headnode, 0, 1, start, end);
+
+ if (trace_trace.fraction == 1) {
+ Math3D.VectorCopy(end, trace_trace.endpos);
+ } else {
+ for (int i = 0; i < 3; i++)
+ trace_trace.endpos[i] = start[i] + trace_trace.fraction
+ * (end[i] - start[i]);
+ }
+ return trace_trace;
+ }
+
+ /*
+ * ================== CM_TransformedBoxTrace
+ *
+ * Handles offseting and rotation of the end points for moving and rotating
+ * entities ==================
+ */
+ public static trace_t TransformedBoxTrace(float[] start, float[] end,
+ float[] mins, float[] maxs, int headnode, int brushmask,
+ float[] origin, float[] angles) {
+ trace_t trace;
+ float[] start_l = { 0, 0, 0 }, end_l = { 0, 0, 0 };
+ float[] a = { 0, 0, 0 };
+ float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 }, up = { 0, 0, 0 };
+ float[] temp = { 0, 0, 0 };
+ boolean rotated;
+
+ // subtract origin offset
+ Math3D.VectorSubtract(start, origin, start_l);
+ Math3D.VectorSubtract(end, origin, end_l);
+
+ // rotate start and end into the models frame of reference
+ if (headnode != box_headnode
+ && (angles[0] != 0 || angles[1] != 0 || angles[2] != 0))
+ rotated = true;
+ else
+ rotated = false;
+
+ if (rotated) {
+ Math3D.AngleVectors(angles, forward, right, up);
+
+ Math3D.VectorCopy(start_l, temp);
+ start_l[0] = Math3D.DotProduct(temp, forward);
+ start_l[1] = -Math3D.DotProduct(temp, right);
+ start_l[2] = Math3D.DotProduct(temp, up);
+
+ Math3D.VectorCopy(end_l, temp);
+ end_l[0] = Math3D.DotProduct(temp, forward);
+ end_l[1] = -Math3D.DotProduct(temp, right);
+ end_l[2] = Math3D.DotProduct(temp, up);
+ }
+
+ // sweep the box through the model
+ trace = BoxTrace(start_l, end_l, mins, maxs, headnode, brushmask);
+
+ if (rotated && trace.fraction != 1.0) {
+ // FIXME: figure out how to do this with existing angles
+ Math3D.VectorNegate(angles, a);
+ Math3D.AngleVectors(a, forward, right, up);
+
+ Math3D.VectorCopy(trace.plane.normal, temp);
+ trace.plane.normal[0] = Math3D.DotProduct(temp, forward);
+ trace.plane.normal[1] = -Math3D.DotProduct(temp, right);
+ trace.plane.normal[2] = Math3D.DotProduct(temp, up);
+ }
+
+ trace.endpos[0] = start[0] + trace.fraction * (end[0] - start[0]);
+ trace.endpos[1] = start[1] + trace.fraction * (end[1] - start[1]);
+ trace.endpos[2] = start[2] + trace.fraction * (end[2] - start[2]);
+
+ return trace;
+ }
+
+ /*
+ * ===============================================================================
+ * PVS / PHS
+ * ===============================================================================
+ */
+
+ /*
+ * =================== CM_DecompressVis ===================
+ */
+ public static void CM_DecompressVis(byte in[], int offset, byte out[]) {
+ int c;
+
+ int row;
+
+ row = (numclusters + 7) >> 3;
+ int outp = 0;
+ int inp = offset;
+
+ if (in == null || numvisibility == 0) { // no vis info, so make all
+ // visible
+ while (row != 0) {
+ out[outp++] = (byte) 0xFF;
+ row--;
+ }
+ return;
+ }
+
+ do {
+ if (in[inp] != 0) {
+ out[outp++] = in[inp++];
+ continue;
+ }
+
+ c = in[inp + 1] & 0xFF;
+ inp += 2;
+ if (outp + c > row) {
+ c = row - (outp);
+ Com.DPrintf("warning: Vis decompression overrun\n");
+ }
+ while (c != 0) {
+ out[outp++] = 0;
+ c--;
+ }
+ } while (outp < row);
+ }
+
+ public static byte pvsrow[] = new byte[Defines.MAX_MAP_LEAFS / 8];
+
+ public static byte phsrow[] = new byte[Defines.MAX_MAP_LEAFS / 8];
+
+ public static byte[] CM_ClusterPVS(int cluster) {
+ if (cluster == -1)
+ Arrays.fill(pvsrow, 0, (numclusters + 7) >> 3, (byte) 0);
+ else
+ CM_DecompressVis(map_visibility,
+ map_vis.bitofs[cluster][Defines.DVIS_PVS], pvsrow);
+ return pvsrow;
+ }
+
+ public static byte[] CM_ClusterPHS(int cluster) {
+ if (cluster == -1)
+ Arrays.fill(phsrow, 0, (numclusters + 7) >> 3, (byte) 0);
+ else
+ CM_DecompressVis(map_visibility,
+ map_vis.bitofs[cluster][Defines.DVIS_PHS], phsrow);
+ return phsrow;
+ }
+
+ /*
+ * ===============================================================================
+ * AREAPORTALS
+ * ===============================================================================
+ */
+
+ public static void FloodArea_r(carea_t area, int floodnum) {
+ //Com.Printf("FloodArea_r(" + floodnum + ")...\n");
+ int i;
+ qfiles.dareaportal_t p;
+
+ if (area.floodvalid == floodvalid) {
+ if (area.floodnum == floodnum)
+ return;
+ Com.Error(Defines.ERR_DROP, "FloodArea_r: reflooded");
+ }
+
+ area.floodnum = floodnum;
+ area.floodvalid = floodvalid;
+
+ for (i = 0; i < area.numareaportals; i++) {
+ p = map_areaportals[area.firstareaportal + i];
+ if (portalopen[p.portalnum])
+ FloodArea_r(map_areas[p.otherarea], floodnum);
+ }
+ }
+
+ /*
+ * ==================== FloodAreaConnections ====================
+ */
+ public static void FloodAreaConnections() {
+ Com.DPrintf("FloodAreaConnections...\n");
+
+ int i;
+ carea_t area;
+ int floodnum;
+
+ // all current floods are now invalid
+ floodvalid++;
+ floodnum = 0;
+
+ // area 0 is not used
+ for (i = 1; i < numareas; i++) {
+
+ area = map_areas[i];
+
+ if (area.floodvalid == floodvalid)
+ continue; // already flooded into
+ floodnum++;
+ FloodArea_r(area, floodnum);
+ }
+ }
+
+ /*
+ * ================= CM_SetAreaPortalState =================
+ */
+ public static void CM_SetAreaPortalState(int portalnum, boolean open) {
+ if (portalnum > numareaportals)
+ Com.Error(Defines.ERR_DROP, "areaportal > numareaportals");
+
+ portalopen[portalnum] = open;
+ FloodAreaConnections();
+ }
+
+ /*
+ * ================= CM_AreasConnected =================
+ */
+
+ public static boolean CM_AreasConnected(int area1, int area2) {
+ if (map_noareas.value != 0)
+ return true;
+
+ if (area1 > numareas || area2 > numareas)
+ Com.Error(Defines.ERR_DROP, "area > numareas");
+
+ if (map_areas[area1].floodnum == map_areas[area2].floodnum)
+ return true;
+
+ return false;
+ }
+
+ /*
+ * ================= CM_WriteAreaBits
+ *
+ * Writes a length byte followed by a bit vector of all the areas that area
+ * in the same flood as the area parameter
+ *
+ * This is used by the client refreshes to cull visibility =================
+ */
+ public static int CM_WriteAreaBits(byte buffer[], int area) {
+ int i;
+ int floodnum;
+ int bytes;
+
+ bytes = (numareas + 7) >> 3;
+
+ if (map_noareas.value != 0) { // for debugging, send everything
+ Arrays.fill(buffer, 0, bytes, (byte) 255);
+ } else {
+ Arrays.fill(buffer, 0, bytes, (byte) 0);
+ floodnum = map_areas[area].floodnum;
+ for (i = 0; i < numareas; i++) {
+ if (map_areas[i].floodnum == floodnum || area == 0)
+ buffer[i >> 3] |= 1 << (i & 7);
+ }
+ }
+
+ return bytes;
+ }
+
+ /*
+ * =================== CM_WritePortalState
+ *
+ * Writes the portal state to a savegame file ===================
+ */
+
+ public static void CM_WritePortalState(RandomAccessFile os) {
+
+ //was: fwrite(portalopen, sizeof(portalopen), 1, f);
+ try {
+
+ for (int n = 0; n < portalopen.length; n++)
+ if (portalopen[n])
+ os.writeInt(1);
+ else
+ os.writeInt(0);
+ } catch (Exception e) {
+ Com.Printf("ERROR:" + e);
+ e.printStackTrace();
+ }
+ }
+
+ /*
+ * =================== CM_ReadPortalState
+ *
+ * Reads the portal state from a savegame file and recalculates the area
+ * connections ===================
+ */
+ public static void CM_ReadPortalState(RandomAccessFile f) {
+
+ //was: FS_Read(portalopen, sizeof(portalopen), f);
+ int len = portalopen.length * 4;
+
+ byte buf[] = new byte[len];
+
+ FS.Read(buf, len, f);
+
+ ByteBuffer bb = ByteBuffer.wrap(buf);
+ IntBuffer ib = bb.asIntBuffer();
+
+ for (int n = 0; n < portalopen.length; n++)
+ portalopen[n] = ib.get() != 0;
+
+ FloodAreaConnections();
+ }
+
+ /*
+ * ============= CM_HeadnodeVisible
+ *
+ * Returns true if any leaf under headnode has a cluster that is potentially
+ * visible =============
+ */
+ public static boolean CM_HeadnodeVisible(int nodenum, byte visbits[]) {
+ int leafnum;
+ int cluster;
+ cnode_t node;
+
+ if (nodenum < 0) {
+ leafnum = -1 - nodenum;
+ cluster = map_leafs[leafnum].cluster;
+ if (cluster == -1)
+ return false;
+ if (0 != (visbits[cluster >>> 3] & (1 << (cluster & 7))))
+ return true;
+ return false;
+ }
+
+ node = map_nodes[nodenum];
+ if (CM_HeadnodeVisible(node.children[0], visbits))
+ return true;
+ return CM_HeadnodeVisible(node.children[1], visbits);
+ }
+} \ No newline at end of file
diff --git a/src/jake2/qcommon/Cbuf.java b/src/jake2/qcommon/Cbuf.java
index f78577b..baa7090 100644
--- a/src/jake2/qcommon/Cbuf.java
+++ b/src/jake2/qcommon/Cbuf.java
@@ -2,245 +2,249 @@
* Cbuf.java
* Copyright (C) 2003
*
- * $Id: Cbuf.java,v 1.4 2004-09-18 13:07:46 hzi Exp $
+ * $Id: Cbuf.java,v 1.5 2004-09-22 19:22:09 salomo Exp $
*/
/*
-Copyright (C) 1997-2001 Id Software, Inc.
+ 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 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.
+ 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.
+ 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.
+ 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.qcommon;
import jake2.Defines;
import jake2.Globals;
import jake2.game.Cmd;
+import jake2.util.Lib;
/**
* Cbuf
*/
public final class Cbuf {
- /**
- *
- */
- public static void Init() {
- SZ.Init(Globals.cmd_text, Globals.cmd_text_buf, Globals.cmd_text_buf.length);
- }
-
- public static void InsertText(String text) {
-
- byte[] temp = null;
- int templen = 0;
-
- // copy off any commands still remaining in the exec buffer
- templen = Globals.cmd_text.cursize;
- if (templen != 0) {
- temp = new byte[templen];
- System.arraycopy(Globals.cmd_text.data, 0, temp, 0, templen);
- SZ.Clear(Globals.cmd_text);
- }
-
- // add the entire text of the file
- Cbuf.AddText(text);
-
- // add the copied off data
- if (templen != 0) {
- SZ.Write(Globals.cmd_text, temp, templen);
- temp = null;
- }
- }
-
- /**
- * @param clear
- */
- static void AddEarlyCommands(boolean clear) {
-
- for (int i = 0; i < Com.Argc(); i++) {
- String s = Com.Argv(i);
- if (!s.equals("+set"))
- continue;
- Cbuf.AddText("set " + Com.Argv(i + 1) + " " + Com.Argv(i + 2) + "\n");
- if (clear) {
- Com.ClearArgv(i);
- Com.ClearArgv(i + 1);
- Com.ClearArgv(i + 2);
- }
- i += 2;
- }
- }
-
- /**
- * @return
- */
- static boolean AddLateCommands() {
- int i;
- int j;
- boolean ret = false;
-
- // build the combined string to parse from
- int s = 0;
- int argc = Com.Argc();
- for (i = 1; i < argc; i++) {
- s += Com.Argv(i).length();
- }
- if (s == 0)
- return false;
-
- String text = "";
- for (i = 1; i < argc; i++) {
- text += Com.Argv(i);
- if (i != argc - 1)
- text += " ";
- }
-
- // pull out the commands
- String build = "";
- for (i = 0; i < text.length(); i++) {
- if (text.charAt(i) == '+') {
- i++;
-
- for (j = i;(text.charAt(j) != '+') && (text.charAt(j) != '-') && j < text.length(); j++);
-
- build += text.substring(i, j - 1);
- build += "\n";
-
- i = j - 1;
- }
- }
-
- ret = (build.length() != 0);
- if (ret)
- Cbuf.AddText(build);
-
- text = null;
- build = null;
-
- return ret;
- }
-
- /**
- * @param text
- */
- public static void AddText(String text) {
- int l = text.length();
-
- if (Globals.cmd_text.cursize + l >= Globals.cmd_text.maxsize) {
- Com.Printf("Cbuf_AddText: overflow\n");
- return;
- }
- SZ.Write(Globals.cmd_text, text.getBytes(), l);
- }
-
- /**
- *
- */
- public static void Execute() {
-
- byte[] text = null;
- byte[] line = new byte[1024];
-
- Globals.alias_count = 0; // don't allow infinite alias loops
-
- while (Globals.cmd_text.cursize != 0) {
- // find a \n or ; line break
- text = Globals.cmd_text.data;
-
- int quotes = 0;
- int i;
-
- for (i = 0; i < Globals.cmd_text.cursize; i++) {
- if (text[i] == '"')
- quotes++;
- if (!(quotes % 2 != 0) && text[i] == ';')
- break; // don't break if inside a quoted string
- if (text[i] == '\n')
- break;
- }
-
- System.arraycopy(text, 0, line, 0, i);
- line[i] = 0;
-
- // delete the text from the command buffer and move remaining commands down
- // this is necessary because commands (exec, alias) can insert data at the
- // beginning of the text buffer
-
- if (i == Globals.cmd_text.cursize)
- Globals.cmd_text.cursize = 0;
- else {
- i++;
- Globals.cmd_text.cursize -= i;
- byte[] tmp = new byte[Globals.cmd_text.cursize];
-
- System.arraycopy(text, i, tmp, 0, Globals.cmd_text.cursize);
- System.arraycopy(tmp, 0, text, 0, Globals.cmd_text.cursize);
- text[Globals.cmd_text.cursize] = '\0';
-
- }
-
- // execute the command line
- int len = jake2.util.Lib.strlen(line);
-
- String cmd = new String(line, 0, len);
- Cmd.ExecuteString(cmd);
-
- if (Globals.cmd_wait) {
- // skip out while text still remains in buffer, leaving it
- // for next frame
- Globals.cmd_wait = false;
- break;
- }
- }
- }
-
- public static void ExecuteText(int exec_when, String text) {
- switch(exec_when) {
- case Defines.EXEC_NOW:
- Cmd.ExecuteString(text);
- break;
- case Defines.EXEC_INSERT:
- Cbuf.InsertText(text);
- break;
- case Defines.EXEC_APPEND:
- Cbuf.AddText(text);
- break;
- default:
- Com.Error(Defines.ERR_FATAL, "Cbuf_ExecuteText: bad exec_when");
- }
- }
-
- /*
- ============
- Cbuf_CopyToDefer
- ============
- */
- public static void CopyToDefer() {
- System.arraycopy(Globals.cmd_text_buf, 0, Globals.defer_text_buf, 0, Globals.cmd_text.cursize);
- Globals.defer_text_buf[Globals.cmd_text.cursize] = 0;
- Globals.cmd_text.cursize = 0;
- }
-
- /*
- ============
- Cbuf_InsertFromDefer
- ============
- */
- public static void InsertFromDefer() {
- InsertText(new String(Globals.defer_text_buf).trim());
- Globals.defer_text_buf[0] = 0;
- }
-
-}
+ /**
+ *
+ */
+ public static void Init() {
+ SZ.Init(Globals.cmd_text, Globals.cmd_text_buf,
+ Globals.cmd_text_buf.length);
+ }
+
+ public static void InsertText(String text) {
+
+ byte[] temp = null;
+ int templen = 0;
+
+ // copy off any commands still remaining in the exec buffer
+ templen = Globals.cmd_text.cursize;
+ if (templen != 0) {
+ temp = new byte[templen];
+ System.arraycopy(Globals.cmd_text.data, 0, temp, 0, templen);
+ SZ.Clear(Globals.cmd_text);
+ }
+
+ // add the entire text of the file
+ Cbuf.AddText(text);
+
+ // add the copied off data
+ if (templen != 0) {
+ SZ.Write(Globals.cmd_text, temp, templen);
+ temp = null;
+ }
+ }
+
+ /**
+ * @param clear
+ */
+ static void AddEarlyCommands(boolean clear) {
+
+ for (int i = 0; i < Com.Argc(); i++) {
+ String s = Com.Argv(i);
+ if (!s.equals("+set"))
+ continue;
+ Cbuf.AddText("set " + Com.Argv(i + 1) + " " + Com.Argv(i + 2)
+ + "\n");
+ if (clear) {
+ Com.ClearArgv(i);
+ Com.ClearArgv(i + 1);
+ Com.ClearArgv(i + 2);
+ }
+ i += 2;
+ }
+ }
+
+ /**
+ * @return
+ */
+ static boolean AddLateCommands() {
+ int i;
+ int j;
+ boolean ret = false;
+
+ // build the combined string to parse from
+ int s = 0;
+ int argc = Com.Argc();
+ for (i = 1; i < argc; i++) {
+ s += Com.Argv(i).length();
+ }
+ if (s == 0)
+ return false;
+
+ String text = "";
+ for (i = 1; i < argc; i++) {
+ text += Com.Argv(i);
+ if (i != argc - 1)
+ text += " ";
+ }
+
+ // pull out the commands
+ String build = "";
+ for (i = 0; i < text.length(); i++) {
+ if (text.charAt(i) == '+') {
+ i++;
+
+ for (j = i; (text.charAt(j) != '+') && (text.charAt(j) != '-')
+ && j < text.length(); j++)
+ ;
+
+ build += text.substring(i, j - 1);
+ build += "\n";
+
+ i = j - 1;
+ }
+ }
+
+ ret = (build.length() != 0);
+ if (ret)
+ Cbuf.AddText(build);
+
+ text = null;
+ build = null;
+
+ return ret;
+ }
+
+ /**
+ * @param text
+ */
+ public static void AddText(String text) {
+ int l = text.length();
+
+ if (Globals.cmd_text.cursize + l >= Globals.cmd_text.maxsize) {
+ Com.Printf("Cbuf_AddText: overflow\n");
+ return;
+ }
+ SZ.Write(Globals.cmd_text, text.getBytes(), l);
+ }
+
+ /**
+ *
+ */
+ public static void Execute() {
+
+ byte[] text = null;
+ byte[] line = new byte[1024];
+
+ Globals.alias_count = 0; // don't allow infinite alias loops
+
+ while (Globals.cmd_text.cursize != 0) {
+ // find a \n or ; line break
+ text = Globals.cmd_text.data;
+
+ int quotes = 0;
+ int i;
+
+ for (i = 0; i < Globals.cmd_text.cursize; i++) {
+ if (text[i] == '"')
+ quotes++;
+ if (!(quotes % 2 != 0) && text[i] == ';')
+ break; // don't break if inside a quoted string
+ if (text[i] == '\n')
+ break;
+ }
+
+ System.arraycopy(text, 0, line, 0, i);
+ line[i] = 0;
+
+ // delete the text from the command buffer and move remaining
+ // commands down
+ // this is necessary because commands (exec, alias) can insert data
+ // at the
+ // beginning of the text buffer
+
+ if (i == Globals.cmd_text.cursize)
+ Globals.cmd_text.cursize = 0;
+ else {
+ i++;
+ Globals.cmd_text.cursize -= i;
+ byte[] tmp = new byte[Globals.cmd_text.cursize];
+
+ System.arraycopy(text, i, tmp, 0, Globals.cmd_text.cursize);
+ System.arraycopy(tmp, 0, text, 0, Globals.cmd_text.cursize);
+ text[Globals.cmd_text.cursize] = '\0';
+
+ }
+
+ // execute the command line
+ int len = Lib.strlen(line);
+
+ String cmd = new String(line, 0, len);
+ Cmd.ExecuteString(cmd);
+
+ if (Globals.cmd_wait) {
+ // skip out while text still remains in buffer, leaving it
+ // for next frame
+ Globals.cmd_wait = false;
+ break;
+ }
+ }
+ }
+
+ public static void ExecuteText(int exec_when, String text) {
+ switch (exec_when) {
+ case Defines.EXEC_NOW:
+ Cmd.ExecuteString(text);
+ break;
+ case Defines.EXEC_INSERT:
+ Cbuf.InsertText(text);
+ break;
+ case Defines.EXEC_APPEND:
+ Cbuf.AddText(text);
+ break;
+ default:
+ Com.Error(Defines.ERR_FATAL, "Cbuf_ExecuteText: bad exec_when");
+ }
+ }
+
+ /*
+ * ============ Cbuf_CopyToDefer ============
+ */
+ public static void CopyToDefer() {
+ System.arraycopy(Globals.cmd_text_buf, 0, Globals.defer_text_buf, 0,
+ Globals.cmd_text.cursize);
+ Globals.defer_text_buf[Globals.cmd_text.cursize] = 0;
+ Globals.cmd_text.cursize = 0;
+ }
+
+ /*
+ * ============ Cbuf_InsertFromDefer ============
+ */
+ public static void InsertFromDefer() {
+ InsertText(new String(Globals.defer_text_buf).trim());
+ Globals.defer_text_buf[0] = 0;
+ }
+
+} \ No newline at end of file
diff --git a/src/jake2/qcommon/Cvar.java b/src/jake2/qcommon/Cvar.java
index a43464b..7255afd 100644
--- a/src/jake2/qcommon/Cvar.java
+++ b/src/jake2/qcommon/Cvar.java
@@ -2,459 +2,437 @@
* Cvar.java
* Copyright (C) 2003
*
- * $Id: Cvar.java,v 1.4 2004-08-19 20:56:41 hzi Exp $
+ * $Id: Cvar.java,v 1.5 2004-09-22 19:22:09 salomo Exp $
*/
/*
-Copyright (C) 1997-2001 Id Software, Inc.
+ 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 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.
+ 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.
+ 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.
+ 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.qcommon;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.util.Vector;
-
import jake2.Defines;
import jake2.Globals;
-import jake2.game.*;
+import jake2.game.Cmd;
+import jake2.game.Info;
+import jake2.game.cvar_t;
import jake2.util.Lib;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.Vector;
+
/**
- * Cvar implements console variables. The original code is
- * located in cvar.c
+ * Cvar implements console variables. The original code is located in cvar.c
*/
public class Cvar extends Globals {
- /**
- * @param var_name
- * @param var_value
- * @param flags
- * @return
- */
- public static cvar_t Get(String var_name, String var_value, int flags) {
- cvar_t var;
-
- if ((flags & (CVAR_USERINFO | CVAR_SERVERINFO)) != 0) {
- if (!Info.Info_Validate(var_name)) {
- Com.Printf("invalid info cvar name\n");
- return null;
- }
- }
-
- var = Cvar.FindVar(var_name);
- if (var != null) {
- var.flags |= flags;
- return var;
- }
-
- if (var_value == null)
- return null;
-
- if ((flags & (CVAR_USERINFO | CVAR_SERVERINFO)) != 0) {
- if (!InfoValidate(var_value)) {
- Com.Printf("invalid info cvar value\n");
- return null;
- }
- }
- var = new cvar_t();
- var.name = new String(var_name);
- var.string = new String(var_value);
- var.modified = true;
- // handles atof(var.string)
- try {
- var.value = Float.parseFloat(var.string);
- }
- catch (NumberFormatException e) {
- var.value = 0.0f;
- }
- // link the variable in
- var.next = Globals.cvar_vars;
- Globals.cvar_vars = var;
-
- var.flags = flags;
-
- return var;
- }
-
- static void Init() {
- Cmd.AddCommand("set", Set_f);
- Cmd.AddCommand("cvarlist", List_f);
- }
-
- public static String VariableString(String var_name) {
- cvar_t var;
- var = FindVar(var_name);
- return (var == null) ? "" : var.string;
- }
-
- static cvar_t FindVar(String var_name) {
- cvar_t var;
-
- for (var = Globals.cvar_vars; var != null; var = var.next) {
- if (var_name.equals(var.name))
- return var;
- }
-
- return null;
- }
-
- /*
- ============
- Cvar_FullSet
- ============
- */
- public static cvar_t FullSet(String var_name, String value, int flags) {
- cvar_t var;
-
- var = Cvar.FindVar(var_name);
- if (null == var) { // create it
- return Cvar.Get(var_name, value, flags);
- }
-
- var.modified = true;
-
- if ((var.flags & CVAR_USERINFO) != 0)
- Globals.userinfo_modified = true; // transmit at next oportunity
-
- var.string = value;
- try {
- var.value = Float.parseFloat(var.string);
- } catch (Exception e) {
- var.value = 0.0f;
- }
-
- var.flags = flags;
-
- return var;
- }
-
- /*
- ============
- Cvar_Set
- ============
- */
- public static cvar_t Set(String var_name, String value) {
- return Set2(var_name, value, false);
- }
-
- /*
- ============
- Cvar_Set2
- ============
- */
- static cvar_t Set2(String var_name, String value, boolean force) {
-
- cvar_t var = Cvar.FindVar(var_name);
- if (var == null) { // create it
- return Cvar.Get(var_name, value, 0);
- }
-
- if ((var.flags & (CVAR_USERINFO | CVAR_SERVERINFO)) != 0) {
- if (!InfoValidate(value)) {
- Com.Printf("invalid info cvar value\n");
- return var;
- }
- }
-
- if (!force) {
- if ((var.flags & CVAR_NOSET) != 0) {
- Com.Printf(var_name + " is write protected.\n");
- return var;
- }
-
- if ((var.flags & CVAR_LATCH) != 0) {
- if (var.latched_string != null) {
- if (value.equals(var.latched_string))
- return var;
- //Z_Free (var.latched_string);
- var.latched_string = null;
- }
- else {
- if (value.equals(var.string))
- return var;
- }
-
- if (Globals.server_state != 0) {
- Com.Printf(var_name + " will be changed for next game.\n");
- var.latched_string = value;
- }
- else {
- var.string = value;
- try {
- var.value = Float.parseFloat(var.string);
- } catch (Exception e) {
- var.value = 0.0f;
- }
- if (var.name.equals("game")) {
- FS.SetGamedir(var.string);
- FS.ExecAutoexec();
- }
- }
- return var;
- }
- }
- else {
- if (var.latched_string != null) {
- //Z_Free(var.latched_string);
- var.latched_string = null;
- }
- }
-
- if (value.equals(var.string))
- return var; // not changed
-
- var.modified = true;
-
- if ((var.flags & CVAR_USERINFO) != 0)
- Globals.userinfo_modified = true; // transmit at next oportunity
-
- var.string = value;
- try {
- var.value = Float.parseFloat(var.string);
- } catch (Exception e) {
- var.value = 0.0f;
- }
-
- return var;
- }
-
- static xcommand_t Set_f = new xcommand_t() {
- public void execute() {
- int c;
- int flags;
-
- c = Cmd.Argc();
- if (c != 3 && c != 4) {
- Com.Printf("usage: set <variable> <value> [u / s]\n");
- return;
- }
-
- if (c == 4) {
- if (Cmd.Argv(3).equals("u"))
- flags = CVAR_USERINFO;
- else if (Cmd.Argv(3).equals("s"))
- flags = CVAR_SERVERINFO;
- else {
- Com.Printf("flags can only be 'u' or 's'\n");
- return;
- }
- Cvar.FullSet(Cmd.Argv(1), Cmd.Argv(2), flags);
- }
- else
- Cvar.Set(Cmd.Argv(1), Cmd.Argv(2));
-
- }
-
- };
-
- static xcommand_t List_f = new xcommand_t() {
- public void execute() {
- cvar_t var;
- int i;
-
- i = 0;
- for (var = Globals.cvar_vars; var != null; var = var.next, i++) {
- if ((var.flags & CVAR_ARCHIVE) != 0)
- Com.Printf("*");
- else
- Com.Printf(" ");
- if ((var.flags & CVAR_USERINFO) != 0)
- Com.Printf("U");
- else
- Com.Printf(" ");
- if ((var.flags & CVAR_SERVERINFO) != 0)
- Com.Printf("S");
- else
- Com.Printf(" ");
- if ((var.flags & CVAR_NOSET) != 0)
- Com.Printf("-");
- else if ((var.flags & CVAR_LATCH) != 0)
- Com.Printf("L");
- else
- Com.Printf(" ");
- Com.Printf(" " + var.name + " \"" + var.string + "\"\n");
- }
- Com.Printf(i + " cvars\n");
- }
- };
-
- /*
- ============
- Cvar_ForceSet
- ============
- */
- public static cvar_t ForceSet(String var_name, String value) {
- return Cvar.Set2(var_name, value, true);
- }
- /*
- ============
- Cvar_SetValue
- ============
- */
- public static void SetValue(String var_name, float value) {
- Cvar.Set(var_name, "" + value);
- }
-
- /*
- ============
- Cvar_VariableValue
- ============
- */
- public static float VariableValue(String var_name) {
- cvar_t var = Cvar.FindVar(var_name);
- if (var == null)
- return 0;
- float val = 0.0f;
- try {
- val = Float.parseFloat(var.string);
- } catch (Exception e) {}
- return val;
- }
-
- /*
- ============
- Cvar_Command
-
- Handles variable inspection and changing from the console
- ============
- */
- public static boolean Command() {
- cvar_t v;
-
- // check variables
- v = Cvar.FindVar(Cmd.Argv(0));
- if (v == null)
- return false;
-
- // perform a variable print or set
- if (Cmd.Argc() == 1) {
- Com.Printf("\"" + v.name + "\" is \"" + v.string + "\"\n");
- return true;
- }
-
- Cvar.Set(v.name, Cmd.Argv(1));
- return true;
- }
-
- public static String BitInfo(int bit) {
- String info;
- cvar_t var;
-
- info = "";
-
- for (var = Globals.cvar_vars; var != null; var = var.next) {
- if ((var.flags & bit) != 0)
- info = Info.Info_SetValueForKey1(info, var.name, var.string);
- }
- return info;
- }
-
- // returns an info string containing all the CVAR_SERVERINFO cvars
- public static String Serverinfo() {
- return BitInfo(Defines.CVAR_SERVERINFO);
- }
-
- public static void GetLatchedVars() {
- cvar_t var;
-
- for (var = Globals.cvar_vars; var != null; var = var.next) {
- if (var.latched_string == null || var.latched_string == "")
- continue;
- var.string = var.latched_string;
- var.latched_string = null;
- try {
- var.value = Float.parseFloat(var.string);
- }
- catch (NumberFormatException e) {
- var.value = 0.0f;
- }
- if (var.name.equals("game")) {
- FS.SetGamedir(var.string);
- FS.ExecAutoexec();
- }
- }
- }
-
- /**
- * returns an info string containing all the CVAR_USERINFO cvars.
- */
- public static String Userinfo() {
- return BitInfo(CVAR_USERINFO);
- }
-
- public static void WriteVariables(String path) {
- cvar_t var;
- RandomAccessFile f;
- String buffer;
-
- f = Lib.fopen(path, "rw");
- if (f == null)
- return;
-
- try {
- f.seek(f.length());
- } catch (IOException e1) {
- fclose(f);
- return;
- }
- for (var = cvar_vars; var != null; var = var.next) {
- if ((var.flags & CVAR_ARCHIVE) != 0) {
- buffer = "set " + var.name + " \"" + var.string + "\"\n";
- try {
- f.writeBytes(buffer);
- }
- catch (IOException e) {
- }
- }
- }
- fclose(f);
- }
-
- /*
- ============
- Cvar_CompleteVariable
- ============
- */
- public static Vector CompleteVariable(String partial) {
-
- Vector vars = new Vector();
-
- // check match
- for (cvar_t cvar = Globals.cvar_vars; cvar != null; cvar = cvar.next)
- if (cvar.name.startsWith(partial))
- vars.add(cvar.name);
-
- return vars;
- }
-
- /*
- ============
- Cvar_InfoValidate
- ============
- */
- static boolean InfoValidate(String s) {
- if (s.indexOf("\\") != -1)
- return false;
- if (s.indexOf("\"") != -1)
- return false;
- if (s.indexOf(";") != -1)
- return false;
- return true;
- }
-}
+ /**
+ * @param var_name
+ * @param var_value
+ * @param flags
+ * @return
+ */
+ public static cvar_t Get(String var_name, String var_value, int flags) {
+ cvar_t var;
+
+ if ((flags & (CVAR_USERINFO | CVAR_SERVERINFO)) != 0) {
+ if (!Info.Info_Validate(var_name)) {
+ Com.Printf("invalid info cvar name\n");
+ return null;
+ }
+ }
+
+ var = Cvar.FindVar(var_name);
+ if (var != null) {
+ var.flags |= flags;
+ return var;
+ }
+
+ if (var_value == null)
+ return null;
+
+ if ((flags & (CVAR_USERINFO | CVAR_SERVERINFO)) != 0) {
+ if (!InfoValidate(var_value)) {
+ Com.Printf("invalid info cvar value\n");
+ return null;
+ }
+ }
+ var = new cvar_t();
+ var.name = new String(var_name);
+ var.string = new String(var_value);
+ var.modified = true;
+ // handles atof(var.string)
+ try {
+ var.value = Float.parseFloat(var.string);
+ } catch (NumberFormatException e) {
+ var.value = 0.0f;
+ }
+ // link the variable in
+ var.next = Globals.cvar_vars;
+ Globals.cvar_vars = var;
+
+ var.flags = flags;
+
+ return var;
+ }
+
+ static void Init() {
+ Cmd.AddCommand("set", Set_f);
+ Cmd.AddCommand("cvarlist", List_f);
+ }
+
+ public static String VariableString(String var_name) {
+ cvar_t var;
+ var = FindVar(var_name);
+ return (var == null) ? "" : var.string;
+ }
+
+ static cvar_t FindVar(String var_name) {
+ cvar_t var;
+
+ for (var = Globals.cvar_vars; var != null; var = var.next) {
+ if (var_name.equals(var.name))
+ return var;
+ }
+
+ return null;
+ }
+
+ /*
+ * ============ Cvar_FullSet ============
+ */
+ public static cvar_t FullSet(String var_name, String value, int flags) {
+ cvar_t var;
+
+ var = Cvar.FindVar(var_name);
+ if (null == var) { // create it
+ return Cvar.Get(var_name, value, flags);
+ }
+
+ var.modified = true;
+
+ if ((var.flags & CVAR_USERINFO) != 0)
+ Globals.userinfo_modified = true; // transmit at next oportunity
+
+ var.string = value;
+ try {
+ var.value = Float.parseFloat(var.string);
+ } catch (Exception e) {
+ var.value = 0.0f;
+ }
+
+ var.flags = flags;
+
+ return var;
+ }
+
+ /*
+ * ============ Cvar_Set ============
+ */
+ public static cvar_t Set(String var_name, String value) {
+ return Set2(var_name, value, false);
+ }
+
+ /*
+ * ============ Cvar_Set2 ============
+ */
+ static cvar_t Set2(String var_name, String value, boolean force) {
+
+ cvar_t var = Cvar.FindVar(var_name);
+ if (var == null) { // create it
+ return Cvar.Get(var_name, value, 0);
+ }
+
+ if ((var.flags & (CVAR_USERINFO | CVAR_SERVERINFO)) != 0) {
+ if (!InfoValidate(value)) {
+ Com.Printf("invalid info cvar value\n");
+ return var;
+ }
+ }
+
+ if (!force) {
+ if ((var.flags & CVAR_NOSET) != 0) {
+ Com.Printf(var_name + " is write protected.\n");
+ return var;
+ }
+
+ if ((var.flags & CVAR_LATCH) != 0) {
+ if (var.latched_string != null) {
+ if (value.equals(var.latched_string))
+ return var;
+ //Z_Free (var.latched_string);
+ var.latched_string = null;
+ } else {
+ if (value.equals(var.string))
+ return var;
+ }
+
+ if (Globals.server_state != 0) {
+ Com.Printf(var_name + " will be changed for next game.\n");
+ var.latched_string = value;
+ } else {
+ var.string = value;
+ try {
+ var.value = Float.parseFloat(var.string);
+ } catch (Exception e) {
+ var.value = 0.0f;
+ }
+ if (var.name.equals("game")) {
+ FS.SetGamedir(var.string);
+ FS.ExecAutoexec();
+ }
+ }
+ return var;
+ }
+ } else {
+ if (var.latched_string != null) {
+ //Z_Free(var.latched_string);
+ var.latched_string = null;
+ }
+ }
+
+ if (value.equals(var.string))
+ return var; // not changed
+
+ var.modified = true;
+
+ if ((var.flags & CVAR_USERINFO) != 0)
+ Globals.userinfo_modified = true; // transmit at next oportunity
+
+ var.string = value;
+ try {
+ var.value = Float.parseFloat(var.string);
+ } catch (Exception e) {
+ var.value = 0.0f;
+ }
+
+ return var;
+ }
+
+ static xcommand_t Set_f = new xcommand_t() {
+ public void execute() {
+ int c;
+ int flags;
+
+ c = Cmd.Argc();
+ if (c != 3 && c != 4) {
+ Com.Printf("usage: set <variable> <value> [u / s]\n");
+ return;
+ }
+
+ if (c == 4) {
+ if (Cmd.Argv(3).equals("u"))
+ flags = CVAR_USERINFO;
+ else if (Cmd.Argv(3).equals("s"))
+ flags = CVAR_SERVERINFO;
+ else {
+ Com.Printf("flags can only be 'u' or 's'\n");
+ return;
+ }
+ Cvar.FullSet(Cmd.Argv(1), Cmd.Argv(2), flags);
+ } else
+ Cvar.Set(Cmd.Argv(1), Cmd.Argv(2));
+
+ }
+
+ };
+
+ static xcommand_t List_f = new xcommand_t() {
+ public void execute() {
+ cvar_t var;
+ int i;
+
+ i = 0;
+ for (var = Globals.cvar_vars; var != null; var = var.next, i++) {
+ if ((var.flags & CVAR_ARCHIVE) != 0)
+ Com.Printf("*");
+ else
+ Com.Printf(" ");
+ if ((var.flags & CVAR_USERINFO) != 0)
+ Com.Printf("U");
+ else
+ Com.Printf(" ");
+ if ((var.flags & CVAR_SERVERINFO) != 0)
+ Com.Printf("S");
+ else
+ Com.Printf(" ");
+ if ((var.flags & CVAR_NOSET) != 0)
+ Com.Printf("-");
+ else if ((var.flags & CVAR_LATCH) != 0)
+ Com.Printf("L");
+ else
+ Com.Printf(" ");
+ Com.Printf(" " + var.name + " \"" + var.string + "\"\n");
+ }
+ Com.Printf(i + " cvars\n");
+ }
+ };
+
+ /*
+ * ============ Cvar_ForceSet ============
+ */
+ public static cvar_t ForceSet(String var_name, String value) {
+ return Cvar.Set2(var_name, value, true);
+ }
+
+ /*
+ * ============ Cvar_SetValue ============
+ */
+ public static void SetValue(String var_name, float value) {
+ Cvar.Set(var_name, "" + value);
+ }
+
+ /*
+ * ============ Cvar_VariableValue ============
+ */
+ public static float VariableValue(String var_name) {
+ cvar_t var = Cvar.FindVar(var_name);
+ if (var == null)
+ return 0;
+ float val = 0.0f;
+ try {
+ val = Float.parseFloat(var.string);
+ } catch (Exception e) {
+ }
+ return val;
+ }
+
+ /*
+ * ============ Cvar_Command
+ *
+ * Handles variable inspection and changing from the console ============
+ */
+ public static boolean Command() {
+ cvar_t v;
+
+ // check variables
+ v = Cvar.FindVar(Cmd.Argv(0));
+ if (v == null)
+ return false;
+
+ // perform a variable print or set
+ if (Cmd.Argc() == 1) {
+ Com.Printf("\"" + v.name + "\" is \"" + v.string + "\"\n");
+ return true;
+ }
+
+ Cvar.Set(v.name, Cmd.Argv(1));
+ return true;
+ }
+
+ public static String BitInfo(int bit) {
+ String info;
+ cvar_t var;
+
+ info = "";
+
+ for (var = Globals.cvar_vars; var != null; var = var.next) {
+ if ((var.flags & bit) != 0)
+ info = Info.Info_SetValueForKey1(info, var.name, var.string);
+ }
+ return info;
+ }
+
+ // returns an info string containing all the CVAR_SERVERINFO cvars
+ public static String Serverinfo() {
+ return BitInfo(Defines.CVAR_SERVERINFO);
+ }
+
+ public static void GetLatchedVars() {
+ cvar_t var;
+
+ for (var = Globals.cvar_vars; var != null; var = var.next) {
+ if (var.latched_string == null || var.latched_string == "")
+ continue;
+ var.string = var.latched_string;
+ var.latched_string = null;
+ try {
+ var.value = Float.parseFloat(var.string);
+ } catch (NumberFormatException e) {
+ var.value = 0.0f;
+ }
+ if (var.name.equals("game")) {
+ FS.SetGamedir(var.string);
+ FS.ExecAutoexec();
+ }
+ }
+ }
+
+ /**
+ * returns an info string containing all the CVAR_USERINFO cvars.
+ */
+ public static String Userinfo() {
+ return BitInfo(CVAR_USERINFO);
+ }
+
+ public static void WriteVariables(String path) {
+ cvar_t var;
+ RandomAccessFile f;
+ String buffer;
+
+ f = Lib.fopen(path, "rw");
+ if (f == null)
+ return;
+
+ try {
+ f.seek(f.length());
+ } catch (IOException e1) {
+ Lib.fclose(f);
+ return;
+ }
+ for (var = cvar_vars; var != null; var = var.next) {
+ if ((var.flags & CVAR_ARCHIVE) != 0) {
+ buffer = "set " + var.name + " \"" + var.string + "\"\n";
+ try {
+ f.writeBytes(buffer);
+ } catch (IOException e) {
+ }
+ }
+ }
+ Lib.fclose(f);
+ }
+
+ /*
+ * ============ Cvar_CompleteVariable ============
+ */
+ public static Vector CompleteVariable(String partial) {
+
+ Vector vars = new Vector();
+
+ // check match
+ for (cvar_t cvar = Globals.cvar_vars; cvar != null; cvar = cvar.next)
+ if (cvar.name.startsWith(partial))
+ vars.add(cvar.name);
+
+ return vars;
+ }
+
+ /*
+ * ============ Cvar_InfoValidate ============
+ */
+ static boolean InfoValidate(String s) {
+ if (s.indexOf("\\") != -1)
+ return false;
+ if (s.indexOf("\"") != -1)
+ return false;
+ if (s.indexOf(";") != -1)
+ return false;
+ return true;
+ }
+} \ No newline at end of file
diff --git a/src/jake2/qcommon/MSG.java b/src/jake2/qcommon/MSG.java
index 4396ac3..ee2a089 100644
--- a/src/jake2/qcommon/MSG.java
+++ b/src/jake2/qcommon/MSG.java
@@ -1,562 +1,559 @@
/*
-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.
-
-*/
+ * 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 29.11.2003 by RST.
-// $Id: MSG.java,v 1.4 2004-07-28 11:58:10 hzi Exp $
-
+// $Id: MSG.java,v 1.5 2004-09-22 19:22:09 salomo Exp $
package jake2.qcommon;
+import jake2.Globals;
import jake2.game.*;
import jake2.util.*;
-public class MSG extends GameBase {
-
- //
- // writing functions
- //
-
- //ok.
- public static void WriteChar(sizebuf_t sb, int c) {
- sb.data[SZ.GetSpace(sb, 1)] = (byte) (c & 0xFF);
- }
-
- //ok.
- public static void WriteChar(sizebuf_t sb, float c) {
-
- WriteChar(sb, (int) c);
- }
-
- //ok.
- public static void WriteByte(sizebuf_t sb, int c) {
- sb.data[SZ.GetSpace(sb, 1)] = (byte) (c & 0xFF);
- }
-
- //ok.
- public static void WriteByte(sizebuf_t sb, float c) {
- WriteByte(sb, (int) c);
- }
-
-
- public static void WriteShort(sizebuf_t sb, int c) {
- int i = SZ.GetSpace(sb, 2);
- sb.data[i++] = (byte) (c & 0xff);
- sb.data[i] = (byte) ((c >>> 8) & 0xFF);
- }
-
- //ok.
- public static void WriteInt(sizebuf_t sb, int c) {
- int i = SZ.GetSpace(sb, 4);
- sb.data[i++] = (byte) ((c & 0xff));
- sb.data[i++] = (byte) ((c >>> 8) & 0xff);
- sb.data[i++] = (byte) ((c >>> 16) & 0xff);
- sb.data[i++] = (byte) ((c >>> 24) & 0xff);
- }
-
- //ok.
- public static void WriteLong(sizebuf_t sb, int c) {
- WriteInt(sb, c);
- }
-
- //ok.
- public static void WriteFloat(sizebuf_t sb, float f) {
- WriteInt(sb, Float.floatToIntBits(f));
- }
-
- // had a bug, now its ok.
- public static void WriteString(sizebuf_t sb, String s) {
- String x = s;
-
- if (s == null)
- x = "";
-
- SZ.Write(sb, x.getBytes());
- WriteByte(sb, 0);
- }
-
- //ok.
- public static void WriteString(sizebuf_t sb, byte s[]) {
- WriteString(sb, new String(s).trim());
- }
-
- public static void WriteCoord(sizebuf_t sb, float f) {
- WriteShort(sb, (int) (f * 8));
- }
-
- public static void WritePos(sizebuf_t sb, float[] pos) {
- assert(pos.length == 3) : "vec3_t bug";
- WriteShort(sb, (int) (pos[0] * 8));
- WriteShort(sb, (int) (pos[1] * 8));
- WriteShort(sb, (int) (pos[2] * 8));
- }
-
- public static void WriteAngle(sizebuf_t sb, float f) {
- WriteByte(sb, (int) (f * 256 / 360) & 255);
- }
-
- public static void WriteAngle16(sizebuf_t sb, float f) {
- WriteShort(sb, Math3D.ANGLE2SHORT(f));
- }
-
- public static void WriteDeltaUsercmd(sizebuf_t buf, usercmd_t from, usercmd_t cmd) {
- int bits;
-
- //
- // send the movement message
- //
- bits = 0;
- if (cmd.angles[0] != from.angles[0])
- bits |= CM_ANGLE1;
- if (cmd.angles[1] != from.angles[1])
- bits |= CM_ANGLE2;
- if (cmd.angles[2] != from.angles[2])
- bits |= CM_ANGLE3;
- if (cmd.forwardmove != from.forwardmove)
- bits |= CM_FORWARD;
- if (cmd.sidemove != from.sidemove)
- bits |= CM_SIDE;
- if (cmd.upmove != from.upmove)
- bits |= CM_UP;
- if (cmd.buttons != from.buttons)
- bits |= CM_BUTTONS;
- if (cmd.impulse != from.impulse)
- bits |= CM_IMPULSE;
-
- WriteByte(buf, bits);
-
- if ((bits & CM_ANGLE1) != 0)
- WriteShort(buf, cmd.angles[0]);
- if ((bits & CM_ANGLE2) != 0)
- WriteShort(buf, cmd.angles[1]);
- if ((bits & CM_ANGLE3) != 0)
- WriteShort(buf, cmd.angles[2]);
-
- if ((bits & CM_FORWARD) != 0)
- WriteShort(buf, cmd.forwardmove);
- if ((bits & CM_SIDE) != 0)
- WriteShort(buf, cmd.sidemove);
- if ((bits & CM_UP) != 0)
- WriteShort(buf, cmd.upmove);
-
- if ((bits & CM_BUTTONS) != 0)
- WriteByte(buf, cmd.buttons);
- if ((bits & CM_IMPULSE) != 0)
- WriteByte(buf, cmd.impulse);
-
- WriteByte(buf, cmd.msec);
- WriteByte(buf, cmd.lightlevel);
- }
-
- //should be ok.
- public static void WriteDir(sizebuf_t sb, float[] dir) {
- int i, best;
- float d, bestd;
-
- if (dir == null) {
- WriteByte(sb, 0);
- return;
- }
-
- bestd = 0;
- best = 0;
- for (i = 0; i < NUMVERTEXNORMALS; i++) {
- d = Math3D.DotProduct(dir, bytedirs[i]);
- if (d > bestd) {
- bestd = d;
- best = i;
- }
- }
- WriteByte(sb, best);
- }
-
- //should be ok.
- public static void ReadDir(sizebuf_t sb, float[] dir) {
- int b;
-
- b = ReadByte(sb);
- if (b >= NUMVERTEXNORMALS)
- Com.Error(ERR_DROP, "MSF_ReadDir: out of range");
- Math3D.VectorCopy(bytedirs[b], dir);
- }
-
- /*
- ==================
- WriteDeltaEntity
-
- Writes part of a packetentities message.
- Can delta from either a baseline or a previous packet_entity
- ==================
- */
- public static void WriteDeltaEntity(entity_state_t from, entity_state_t to, sizebuf_t msg, boolean force, boolean newentity) {
- int bits;
-
- if (0 == to.number)
- Com.Error(ERR_FATAL, "Unset entity number");
- if (to.number >= MAX_EDICTS)
- Com.Error(ERR_FATAL, "Entity number >= MAX_EDICTS");
-
- // send an update
- bits = 0;
-
- if (to.number >= 256)
- bits |= U_NUMBER16; // number8 is implicit otherwise
-
- if (to.origin[0] != from.origin[0])
- bits |= U_ORIGIN1;
- if (to.origin[1] != from.origin[1])
- bits |= U_ORIGIN2;
- if (to.origin[2] != from.origin[2])
- bits |= U_ORIGIN3;
-
- if (to.angles[0] != from.angles[0])
- bits |= U_ANGLE1;
- if (to.angles[1] != from.angles[1])
- bits |= U_ANGLE2;
- if (to.angles[2] != from.angles[2])
- bits |= U_ANGLE3;
-
- if (to.skinnum != from.skinnum) {
- if (to.skinnum < 256)
- bits |= U_SKIN8;
- else if (to.skinnum < 0x10000)
- bits |= U_SKIN16;
- else
- bits |= (U_SKIN8 | U_SKIN16);
- }
-
- if (to.frame != from.frame) {
- if (to.frame < 256)
- bits |= U_FRAME8;
- else
- bits |= U_FRAME16;
- }
-
- if (to.effects != from.effects) {
- if (to.effects < 256)
- bits |= U_EFFECTS8;
- else if (to.effects < 0x8000)
- bits |= U_EFFECTS16;
- else
- bits |= U_EFFECTS8 | U_EFFECTS16;
- }
-
- if (to.renderfx != from.renderfx) {
- if (to.renderfx < 256)
- bits |= U_RENDERFX8;
- else if (to.renderfx < 0x8000)
- bits |= U_RENDERFX16;
- else
- bits |= U_RENDERFX8 | U_RENDERFX16;
- }
-
- if (to.solid != from.solid)
- bits |= U_SOLID;
-
- // event is not delta compressed, just 0 compressed
- if (to.event != 0)
- bits |= U_EVENT;
-
- if (to.modelindex != from.modelindex)
- bits |= U_MODEL;
- if (to.modelindex2 != from.modelindex2)
- bits |= U_MODEL2;
- if (to.modelindex3 != from.modelindex3)
- bits |= U_MODEL3;
- if (to.modelindex4 != from.modelindex4)
- bits |= U_MODEL4;
-
- if (to.sound != from.sound)
- bits |= U_SOUND;
-
- if (newentity || (to.renderfx & RF_BEAM) != 0)
- bits |= U_OLDORIGIN;
-
- //
- // write the message
- //
- if (bits == 0 && !force)
- return; // nothing to send!
-
- //----------
-
- if ((bits & 0xff000000) != 0)
- bits |= U_MOREBITS3 | U_MOREBITS2 | U_MOREBITS1;
- else if ((bits & 0x00ff0000) != 0)
- bits |= U_MOREBITS2 | U_MOREBITS1;
- else if ((bits & 0x0000ff00) != 0)
- bits |= U_MOREBITS1;
-
- WriteByte(msg, bits & 255);
-
- if ((bits & 0xff000000) != 0) {
- WriteByte(msg, (bits >>> 8) & 255);
- WriteByte(msg, (bits >>> 16) & 255);
- WriteByte(msg, (bits >>> 24) & 255);
- }
- else if ((bits & 0x00ff0000) != 0) {
- WriteByte(msg, (bits >>> 8) & 255);
- WriteByte(msg, (bits >>> 16) & 255);
- }
- else if ((bits & 0x0000ff00) != 0) {
- WriteByte(msg, (bits >>> 8) & 255);
- }
-
- //----------
-
- if ((bits & U_NUMBER16) != 0)
- WriteShort(msg, to.number);
- else
- WriteByte(msg, to.number);
-
- if ((bits & U_MODEL) != 0)
- WriteByte(msg, to.modelindex);
- if ((bits & U_MODEL2) != 0)
- WriteByte(msg, to.modelindex2);
- if ((bits & U_MODEL3) != 0)
- WriteByte(msg, to.modelindex3);
- if ((bits & U_MODEL4) != 0)
- WriteByte(msg, to.modelindex4);
-
- if ((bits & U_FRAME8) != 0)
- WriteByte(msg, to.frame);
- if ((bits & U_FRAME16) != 0)
- WriteShort(msg, to.frame);
-
- if ((bits & U_SKIN8) != 0 && (bits & U_SKIN16) != 0) //used for laser colors
- WriteInt(msg, to.skinnum);
- else if ((bits & U_SKIN8) != 0)
- WriteByte(msg, to.skinnum);
- else if ((bits & U_SKIN16) != 0)
- WriteShort(msg, to.skinnum);
-
- if ((bits & (U_EFFECTS8 | U_EFFECTS16)) == (U_EFFECTS8 | U_EFFECTS16))
- WriteInt(msg, to.effects);
- else if ((bits & U_EFFECTS8) != 0)
- WriteByte(msg, to.effects);
- else if ((bits & U_EFFECTS16) != 0)
- WriteShort(msg, to.effects);
-
- if ((bits & (U_RENDERFX8 | U_RENDERFX16)) == (U_RENDERFX8 | U_RENDERFX16))
- WriteInt(msg, to.renderfx);
- else if ((bits & U_RENDERFX8) != 0)
- WriteByte(msg, to.renderfx);
- else if ((bits & U_RENDERFX16) != 0)
- WriteShort(msg, to.renderfx);
-
- if ((bits & U_ORIGIN1) != 0)
- WriteCoord(msg, to.origin[0]);
- if ((bits & U_ORIGIN2) != 0)
- WriteCoord(msg, to.origin[1]);
- if ((bits & U_ORIGIN3) != 0)
- WriteCoord(msg, to.origin[2]);
-
- if ((bits & U_ANGLE1) != 0)
- WriteAngle(msg, to.angles[0]);
- if ((bits & U_ANGLE2) != 0)
- WriteAngle(msg, to.angles[1]);
- if ((bits & U_ANGLE3) != 0)
- WriteAngle(msg, to.angles[2]);
-
- if ((bits & U_OLDORIGIN) != 0) {
- WriteCoord(msg, to.old_origin[0]);
- WriteCoord(msg, to.old_origin[1]);
- WriteCoord(msg, to.old_origin[2]);
- }
-
- if ((bits & U_SOUND) != 0)
- WriteByte(msg, to.sound);
- if ((bits & U_EVENT) != 0)
- WriteByte(msg, to.event);
- if ((bits & U_SOLID) != 0)
- WriteShort(msg, to.solid);
- }
-
- //============================================================
-
- //
- // reading functions
- //
-
- public static void BeginReading(sizebuf_t msg) {
- msg.readcount = 0;
- }
-
- // returns -1 if no more characters are available, but also [-128 , 127]
- public static int ReadChar(sizebuf_t msg_read) {
- int c;
-
- if (msg_read.readcount + 1 > msg_read.cursize)
- c = -1;
- else
- c = msg_read.data[msg_read.readcount];
- msg_read.readcount++;
- // kickangles bugfix (rst)
- return c;
- }
-
- public static int ReadByte(sizebuf_t msg_read) {
- int c;
-
- if (msg_read.readcount + 1 > msg_read.cursize)
- c = -1;
- else
- c = msg_read.data[msg_read.readcount] & 0xff;
- msg_read.readcount++;
-
- return c;
- }
-
- public static short ReadShort(sizebuf_t msg_read) {
- int c;
-
- if (msg_read.readcount + 2 > msg_read.cursize)
- c = -1;
- else
- c = (short) ((msg_read.data[msg_read.readcount] & 0xff) + (msg_read.data[msg_read.readcount + 1] << 8));
-
- msg_read.readcount += 2;
-
- return (short) c;
- }
-
- public static int ReadLong(sizebuf_t msg_read) {
- int c;
-
- if (msg_read.readcount + 4 > msg_read.cursize)
- {
- Com.Printf("buffer underrun in ReadLong!");
- c = -1;
- }
-
- else
- c =
- (msg_read.data[msg_read.readcount] & 0xff)
- | ((msg_read.data[msg_read.readcount + 1] & 0xff) << 8)
- | ((msg_read.data[msg_read.readcount + 2] & 0xff) << 16)
- | ((msg_read.data[msg_read.readcount + 3] & 0xff) << 24);
-
- msg_read.readcount += 4;
-
- return c;
- }
-
- public static float ReadFloat(sizebuf_t msg_read) {
- int n = ReadLong(msg_read);
- return Float.intBitsToFloat(n);
- }
-
- // 2k read buffer.
- public static byte readbuf[] = new byte[2048];
-
- public static String ReadString(sizebuf_t msg_read) {
-
- byte c;
- int l = 0;
- do {
- c = (byte)ReadByte(msg_read);
- if (c == -1 || c == 0)
- break;
-
- readbuf[l] = c;
- l++;
- } while (l < 2047);
-
- return new String(readbuf, 0, l);
- }
-
- public static String ReadStringLine(sizebuf_t msg_read) {
-
- int l;
- byte c;
-
- l = 0;
- do {
- c = (byte) ReadChar(msg_read);
- if (c == -1 || c == 0 || c == 0x0a)
- break;
- readbuf[l] = c;
- l++;
- } while (l < 2047);
-
- return new String(readbuf, 0, l).trim();
- }
-
- public static float ReadCoord(sizebuf_t msg_read) {
- return ReadShort(msg_read) * (1.0f / 8);
- }
-
- public static void ReadPos(sizebuf_t msg_read, float pos[]) {
- assert(pos.length == 3) : "vec3_t bug";
- pos[0] = ReadShort(msg_read) * (1.0f / 8);
- pos[1] = ReadShort(msg_read) * (1.0f / 8);
- pos[2] = ReadShort(msg_read) * (1.0f / 8);
- }
-
- public static float ReadAngle(sizebuf_t msg_read) {
- return ReadChar(msg_read) * (360.0f / 256);
- }
-
- public static float ReadAngle16(sizebuf_t msg_read) {
- return Math3D.SHORT2ANGLE(ReadShort(msg_read));
- }
-
- public static void ReadDeltaUsercmd(sizebuf_t msg_read, usercmd_t from, usercmd_t move) {
- int bits;
-
- //memcpy(move, from, sizeof(* move));
- // IMPORTANT!! copy without new
- move.set(from);
- bits = ReadByte(msg_read);
-
- // read current angles
- if ((bits & CM_ANGLE1) != 0)
- move.angles[0] = ReadShort(msg_read);
- if ((bits & CM_ANGLE2) != 0)
- move.angles[1] = ReadShort(msg_read);
- if ((bits & CM_ANGLE3) != 0)
- move.angles[2] = ReadShort(msg_read);
-
- // read movement
- if ((bits & CM_FORWARD) != 0)
- move.forwardmove = ReadShort(msg_read);
- if ((bits & CM_SIDE) != 0)
- move.sidemove = ReadShort(msg_read);
- if ((bits & CM_UP) != 0)
- move.upmove = ReadShort(msg_read);
-
- // read buttons
- if ((bits & CM_BUTTONS) != 0)
- move.buttons = (byte) ReadByte(msg_read);
-
- if ((bits & CM_IMPULSE) != 0)
- move.impulse = (byte) ReadByte(msg_read);
-
- // read time to run command
- move.msec = (byte) ReadByte(msg_read);
-
- // read the light level
- move.lightlevel = (byte) ReadByte(msg_read);
-
- }
-
- public static void ReadData(sizebuf_t msg_read, byte data[], int len) {
- for (int i = 0; i < len; i++)
- data[i] = (byte) ReadByte(msg_read);
- }
-}
+public class MSG extends Globals {
+
+ //
+ // writing functions
+ //
+
+ //ok.
+ public static void WriteChar(sizebuf_t sb, int c) {
+ sb.data[SZ.GetSpace(sb, 1)] = (byte) (c & 0xFF);
+ }
+
+ //ok.
+ public static void WriteChar(sizebuf_t sb, float c) {
+
+ WriteChar(sb, (int) c);
+ }
+
+ //ok.
+ public static void WriteByte(sizebuf_t sb, int c) {
+ sb.data[SZ.GetSpace(sb, 1)] = (byte) (c & 0xFF);
+ }
+
+ //ok.
+ public static void WriteByte(sizebuf_t sb, float c) {
+ WriteByte(sb, (int) c);
+ }
+
+ public static void WriteShort(sizebuf_t sb, int c) {
+ int i = SZ.GetSpace(sb, 2);
+ sb.data[i++] = (byte) (c & 0xff);
+ sb.data[i] = (byte) ((c >>> 8) & 0xFF);
+ }
+
+ //ok.
+ public static void WriteInt(sizebuf_t sb, int c) {
+ int i = SZ.GetSpace(sb, 4);
+ sb.data[i++] = (byte) ((c & 0xff));
+ sb.data[i++] = (byte) ((c >>> 8) & 0xff);
+ sb.data[i++] = (byte) ((c >>> 16) & 0xff);
+ sb.data[i++] = (byte) ((c >>> 24) & 0xff);
+ }
+
+ //ok.
+ public static void WriteLong(sizebuf_t sb, int c) {
+ WriteInt(sb, c);
+ }
+
+ //ok.
+ public static void WriteFloat(sizebuf_t sb, float f) {
+ WriteInt(sb, Float.floatToIntBits(f));
+ }
+
+ // had a bug, now its ok.
+ public static void WriteString(sizebuf_t sb, String s) {
+ String x = s;
+
+ if (s == null)
+ x = "";
+
+ SZ.Write(sb, x.getBytes());
+ WriteByte(sb, 0);
+ }
+
+ //ok.
+ public static void WriteString(sizebuf_t sb, byte s[]) {
+ WriteString(sb, new String(s).trim());
+ }
+
+ public static void WriteCoord(sizebuf_t sb, float f) {
+ WriteShort(sb, (int) (f * 8));
+ }
+
+ public static void WritePos(sizebuf_t sb, float[] pos) {
+ assert (pos.length == 3) : "vec3_t bug";
+ WriteShort(sb, (int) (pos[0] * 8));
+ WriteShort(sb, (int) (pos[1] * 8));
+ WriteShort(sb, (int) (pos[2] * 8));
+ }
+
+ public static void WriteAngle(sizebuf_t sb, float f) {
+ WriteByte(sb, (int) (f * 256 / 360) & 255);
+ }
+
+ public static void WriteAngle16(sizebuf_t sb, float f) {
+ WriteShort(sb, Math3D.ANGLE2SHORT(f));
+ }
+
+ public static void WriteDeltaUsercmd(sizebuf_t buf, usercmd_t from,
+ usercmd_t cmd) {
+ int bits;
+
+ //
+ // send the movement message
+ //
+ bits = 0;
+ if (cmd.angles[0] != from.angles[0])
+ bits |= CM_ANGLE1;
+ if (cmd.angles[1] != from.angles[1])
+ bits |= CM_ANGLE2;
+ if (cmd.angles[2] != from.angles[2])
+ bits |= CM_ANGLE3;
+ if (cmd.forwardmove != from.forwardmove)
+ bits |= CM_FORWARD;
+ if (cmd.sidemove != from.sidemove)
+ bits |= CM_SIDE;
+ if (cmd.upmove != from.upmove)
+ bits |= CM_UP;
+ if (cmd.buttons != from.buttons)
+ bits |= CM_BUTTONS;
+ if (cmd.impulse != from.impulse)
+ bits |= CM_IMPULSE;
+
+ WriteByte(buf, bits);
+
+ if ((bits & CM_ANGLE1) != 0)
+ WriteShort(buf, cmd.angles[0]);
+ if ((bits & CM_ANGLE2) != 0)
+ WriteShort(buf, cmd.angles[1]);
+ if ((bits & CM_ANGLE3) != 0)
+ WriteShort(buf, cmd.angles[2]);
+
+ if ((bits & CM_FORWARD) != 0)
+ WriteShort(buf, cmd.forwardmove);
+ if ((bits & CM_SIDE) != 0)
+ WriteShort(buf, cmd.sidemove);
+ if ((bits & CM_UP) != 0)
+ WriteShort(buf, cmd.upmove);
+
+ if ((bits & CM_BUTTONS) != 0)
+ WriteByte(buf, cmd.buttons);
+ if ((bits & CM_IMPULSE) != 0)
+ WriteByte(buf, cmd.impulse);
+
+ WriteByte(buf, cmd.msec);
+ WriteByte(buf, cmd.lightlevel);
+ }
+
+ //should be ok.
+ public static void WriteDir(sizebuf_t sb, float[] dir) {
+ int i, best;
+ float d, bestd;
+
+ if (dir == null) {
+ WriteByte(sb, 0);
+ return;
+ }
+
+ bestd = 0;
+ best = 0;
+ for (i = 0; i < NUMVERTEXNORMALS; i++) {
+ d = Math3D.DotProduct(dir, bytedirs[i]);
+ if (d > bestd) {
+ bestd = d;
+ best = i;
+ }
+ }
+ WriteByte(sb, best);
+ }
+
+ //should be ok.
+ public static void ReadDir(sizebuf_t sb, float[] dir) {
+ int b;
+
+ b = ReadByte(sb);
+ if (b >= NUMVERTEXNORMALS)
+ Com.Error(ERR_DROP, "MSF_ReadDir: out of range");
+ Math3D.VectorCopy(bytedirs[b], dir);
+ }
+
+ /*
+ * ================== WriteDeltaEntity
+ *
+ * Writes part of a packetentities message. Can delta from either a baseline
+ * or a previous packet_entity ==================
+ */
+ public static void WriteDeltaEntity(entity_state_t from, entity_state_t to,
+ sizebuf_t msg, boolean force, boolean newentity) {
+ int bits;
+
+ if (0 == to.number)
+ Com.Error(ERR_FATAL, "Unset entity number");
+ if (to.number >= MAX_EDICTS)
+ Com.Error(ERR_FATAL, "Entity number >= MAX_EDICTS");
+
+ // send an update
+ bits = 0;
+
+ if (to.number >= 256)
+ bits |= U_NUMBER16; // number8 is implicit otherwise
+
+ if (to.origin[0] != from.origin[0])
+ bits |= U_ORIGIN1;
+ if (to.origin[1] != from.origin[1])
+ bits |= U_ORIGIN2;
+ if (to.origin[2] != from.origin[2])
+ bits |= U_ORIGIN3;
+
+ if (to.angles[0] != from.angles[0])
+ bits |= U_ANGLE1;
+ if (to.angles[1] != from.angles[1])
+ bits |= U_ANGLE2;
+ if (to.angles[2] != from.angles[2])
+ bits |= U_ANGLE3;
+
+ if (to.skinnum != from.skinnum) {
+ if (to.skinnum < 256)
+ bits |= U_SKIN8;
+ else if (to.skinnum < 0x10000)
+ bits |= U_SKIN16;
+ else
+ bits |= (U_SKIN8 | U_SKIN16);
+ }
+
+ if (to.frame != from.frame) {
+ if (to.frame < 256)
+ bits |= U_FRAME8;
+ else
+ bits |= U_FRAME16;
+ }
+
+ if (to.effects != from.effects) {
+ if (to.effects < 256)
+ bits |= U_EFFECTS8;
+ else if (to.effects < 0x8000)
+ bits |= U_EFFECTS16;
+ else
+ bits |= U_EFFECTS8 | U_EFFECTS16;
+ }
+
+ if (to.renderfx != from.renderfx) {
+ if (to.renderfx < 256)
+ bits |= U_RENDERFX8;
+ else if (to.renderfx < 0x8000)
+ bits |= U_RENDERFX16;
+ else
+ bits |= U_RENDERFX8 | U_RENDERFX16;
+ }
+
+ if (to.solid != from.solid)
+ bits |= U_SOLID;
+
+ // event is not delta compressed, just 0 compressed
+ if (to.event != 0)
+ bits |= U_EVENT;
+
+ if (to.modelindex != from.modelindex)
+ bits |= U_MODEL;
+ if (to.modelindex2 != from.modelindex2)
+ bits |= U_MODEL2;
+ if (to.modelindex3 != from.modelindex3)
+ bits |= U_MODEL3;
+ if (to.modelindex4 != from.modelindex4)
+ bits |= U_MODEL4;
+
+ if (to.sound != from.sound)
+ bits |= U_SOUND;
+
+ if (newentity || (to.renderfx & RF_BEAM) != 0)
+ bits |= U_OLDORIGIN;
+
+ //
+ // write the message
+ //
+ if (bits == 0 && !force)
+ return; // nothing to send!
+
+ //----------
+
+ if ((bits & 0xff000000) != 0)
+ bits |= U_MOREBITS3 | U_MOREBITS2 | U_MOREBITS1;
+ else if ((bits & 0x00ff0000) != 0)
+ bits |= U_MOREBITS2 | U_MOREBITS1;
+ else if ((bits & 0x0000ff00) != 0)
+ bits |= U_MOREBITS1;
+
+ WriteByte(msg, bits & 255);
+
+ if ((bits & 0xff000000) != 0) {
+ WriteByte(msg, (bits >>> 8) & 255);
+ WriteByte(msg, (bits >>> 16) & 255);
+ WriteByte(msg, (bits >>> 24) & 255);
+ } else if ((bits & 0x00ff0000) != 0) {
+ WriteByte(msg, (bits >>> 8) & 255);
+ WriteByte(msg, (bits >>> 16) & 255);
+ } else if ((bits & 0x0000ff00) != 0) {
+ WriteByte(msg, (bits >>> 8) & 255);
+ }
+
+ //----------
+
+ if ((bits & U_NUMBER16) != 0)
+ WriteShort(msg, to.number);
+ else
+ WriteByte(msg, to.number);
+
+ if ((bits & U_MODEL) != 0)
+ WriteByte(msg, to.modelindex);
+ if ((bits & U_MODEL2) != 0)
+ WriteByte(msg, to.modelindex2);
+ if ((bits & U_MODEL3) != 0)
+ WriteByte(msg, to.modelindex3);
+ if ((bits & U_MODEL4) != 0)
+ WriteByte(msg, to.modelindex4);
+
+ if ((bits & U_FRAME8) != 0)
+ WriteByte(msg, to.frame);
+ if ((bits & U_FRAME16) != 0)
+ WriteShort(msg, to.frame);
+
+ if ((bits & U_SKIN8) != 0 && (bits & U_SKIN16) != 0) //used for laser
+ // colors
+ WriteInt(msg, to.skinnum);
+ else if ((bits & U_SKIN8) != 0)
+ WriteByte(msg, to.skinnum);
+ else if ((bits & U_SKIN16) != 0)
+ WriteShort(msg, to.skinnum);
+
+ if ((bits & (U_EFFECTS8 | U_EFFECTS16)) == (U_EFFECTS8 | U_EFFECTS16))
+ WriteInt(msg, to.effects);
+ else if ((bits & U_EFFECTS8) != 0)
+ WriteByte(msg, to.effects);
+ else if ((bits & U_EFFECTS16) != 0)
+ WriteShort(msg, to.effects);
+
+ if ((bits & (U_RENDERFX8 | U_RENDERFX16)) == (U_RENDERFX8 | U_RENDERFX16))
+ WriteInt(msg, to.renderfx);
+ else if ((bits & U_RENDERFX8) != 0)
+ WriteByte(msg, to.renderfx);
+ else if ((bits & U_RENDERFX16) != 0)
+ WriteShort(msg, to.renderfx);
+
+ if ((bits & U_ORIGIN1) != 0)
+ WriteCoord(msg, to.origin[0]);
+ if ((bits & U_ORIGIN2) != 0)
+ WriteCoord(msg, to.origin[1]);
+ if ((bits & U_ORIGIN3) != 0)
+ WriteCoord(msg, to.origin[2]);
+
+ if ((bits & U_ANGLE1) != 0)
+ WriteAngle(msg, to.angles[0]);
+ if ((bits & U_ANGLE2) != 0)
+ WriteAngle(msg, to.angles[1]);
+ if ((bits & U_ANGLE3) != 0)
+ WriteAngle(msg, to.angles[2]);
+
+ if ((bits & U_OLDORIGIN) != 0) {
+ WriteCoord(msg, to.old_origin[0]);
+ WriteCoord(msg, to.old_origin[1]);
+ WriteCoord(msg, to.old_origin[2]);
+ }
+
+ if ((bits & U_SOUND) != 0)
+ WriteByte(msg, to.sound);
+ if ((bits & U_EVENT) != 0)
+ WriteByte(msg, to.event);
+ if ((bits & U_SOLID) != 0)
+ WriteShort(msg, to.solid);
+ }
+
+ //============================================================
+
+ //
+ // reading functions
+ //
+
+ public static void BeginReading(sizebuf_t msg) {
+ msg.readcount = 0;
+ }
+
+ // returns -1 if no more characters are available, but also [-128 , 127]
+ public static int ReadChar(sizebuf_t msg_read) {
+ int c;
+
+ if (msg_read.readcount + 1 > msg_read.cursize)
+ c = -1;
+ else
+ c = msg_read.data[msg_read.readcount];
+ msg_read.readcount++;
+ // kickangles bugfix (rst)
+ return c;
+ }
+
+ public static int ReadByte(sizebuf_t msg_read) {
+ int c;
+
+ if (msg_read.readcount + 1 > msg_read.cursize)
+ c = -1;
+ else
+ c = msg_read.data[msg_read.readcount] & 0xff;
+ msg_read.readcount++;
+
+ return c;
+ }
+
+ public static short ReadShort(sizebuf_t msg_read) {
+ int c;
+
+ if (msg_read.readcount + 2 > msg_read.cursize)
+ c = -1;
+ else
+ c = (short) ((msg_read.data[msg_read.readcount] & 0xff) + (msg_read.data[msg_read.readcount + 1] << 8));
+
+ msg_read.readcount += 2;
+
+ return (short) c;
+ }
+
+ public static int ReadLong(sizebuf_t msg_read) {
+ int c;
+
+ if (msg_read.readcount + 4 > msg_read.cursize) {
+ Com.Printf("buffer underrun in ReadLong!");
+ c = -1;
+ }
+
+ else
+ c = (msg_read.data[msg_read.readcount] & 0xff)
+ | ((msg_read.data[msg_read.readcount + 1] & 0xff) << 8)
+ | ((msg_read.data[msg_read.readcount + 2] & 0xff) << 16)
+ | ((msg_read.data[msg_read.readcount + 3] & 0xff) << 24);
+
+ msg_read.readcount += 4;
+
+ return c;
+ }
+
+ public static float ReadFloat(sizebuf_t msg_read) {
+ int n = ReadLong(msg_read);
+ return Float.intBitsToFloat(n);
+ }
+
+ // 2k read buffer.
+ public static byte readbuf[] = new byte[2048];
+
+ public static String ReadString(sizebuf_t msg_read) {
+
+ byte c;
+ int l = 0;
+ do {
+ c = (byte) ReadByte(msg_read);
+ if (c == -1 || c == 0)
+ break;
+
+ readbuf[l] = c;
+ l++;
+ } while (l < 2047);
+
+ return new String(readbuf, 0, l);
+ }
+
+ public static String ReadStringLine(sizebuf_t msg_read) {
+
+ int l;
+ byte c;
+
+ l = 0;
+ do {
+ c = (byte) ReadChar(msg_read);
+ if (c == -1 || c == 0 || c == 0x0a)
+ break;
+ readbuf[l] = c;
+ l++;
+ } while (l < 2047);
+
+ return new String(readbuf, 0, l).trim();
+ }
+
+ public static float ReadCoord(sizebuf_t msg_read) {
+ return ReadShort(msg_read) * (1.0f / 8);
+ }
+
+ public static void ReadPos(sizebuf_t msg_read, float pos[]) {
+ assert (pos.length == 3) : "vec3_t bug";
+ pos[0] = ReadShort(msg_read) * (1.0f / 8);
+ pos[1] = ReadShort(msg_read) * (1.0f / 8);
+ pos[2] = ReadShort(msg_read) * (1.0f / 8);
+ }
+
+ public static float ReadAngle(sizebuf_t msg_read) {
+ return ReadChar(msg_read) * (360.0f / 256);
+ }
+
+ public static float ReadAngle16(sizebuf_t msg_read) {
+ return Math3D.SHORT2ANGLE(ReadShort(msg_read));
+ }
+
+ public static void ReadDeltaUsercmd(sizebuf_t msg_read, usercmd_t from,
+ usercmd_t move) {
+ int bits;
+
+ //memcpy(move, from, sizeof(* move));
+ // IMPORTANT!! copy without new
+ move.set(from);
+ bits = ReadByte(msg_read);
+
+ // read current angles
+ if ((bits & CM_ANGLE1) != 0)
+ move.angles[0] = ReadShort(msg_read);
+ if ((bits & CM_ANGLE2) != 0)
+ move.angles[1] = ReadShort(msg_read);
+ if ((bits & CM_ANGLE3) != 0)
+ move.angles[2] = ReadShort(msg_read);
+
+ // read movement
+ if ((bits & CM_FORWARD) != 0)
+ move.forwardmove = ReadShort(msg_read);
+ if ((bits & CM_SIDE) != 0)
+ move.sidemove = ReadShort(msg_read);
+ if ((bits & CM_UP) != 0)
+ move.upmove = ReadShort(msg_read);
+
+ // read buttons
+ if ((bits & CM_BUTTONS) != 0)
+ move.buttons = (byte) ReadByte(msg_read);
+
+ if ((bits & CM_IMPULSE) != 0)
+ move.impulse = (byte) ReadByte(msg_read);
+
+ // read time to run command
+ move.msec = (byte) ReadByte(msg_read);
+
+ // read the light level
+ move.lightlevel = (byte) ReadByte(msg_read);
+
+ }
+
+ public static void ReadData(sizebuf_t msg_read, byte data[], int len) {
+ for (int i = 0; i < len; i++)
+ data[i] = (byte) ReadByte(msg_read);
+ }
+} \ No newline at end of file
diff --git a/src/jake2/qcommon/Netchan.java b/src/jake2/qcommon/Netchan.java
index 3331646..458bcbd 100644
--- a/src/jake2/qcommon/Netchan.java
+++ b/src/jake2/qcommon/Netchan.java
@@ -2,27 +2,27 @@
* NetChannel.java
* Copyright (C) 2003
*
- * $Id: Netchan.java,v 1.3 2004-07-12 20:47:00 hzi Exp $
+ * $Id: Netchan.java,v 1.4 2004-09-22 19:22:09 salomo Exp $
*/
/*
-Copyright (C) 1997-2001 Id Software, Inc.
+ 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 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.
+ 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.
+ 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.
+ 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.qcommon;
import jake2.Defines;
@@ -37,350 +37,335 @@ import jake2.sys.Sys;
*/
public final class Netchan extends SV_MAIN {
- /*
-
- packet header
- -------------
- 31 sequence
- 1 does this message contains a reliable payload
- 31 acknowledge sequence
- 1 acknowledge receipt of even/odd message
- 16 qport
-
- The remote connection never knows if it missed a reliable message, the
- local side detects that it has been dropped by seeing a sequence acknowledge
- higher thatn the last reliable sequence, but without the correct evon/odd
- bit for the reliable set.
-
- If the sender notices that a reliable message has been dropped, it will be
- retransmitted. It will not be retransmitted again until a message after
- the retransmit has been acknowledged and the reliable still failed to get there.
-
- if the sequence number is -1, the packet should be handled without a netcon
-
- The reliable message can be added to at any time by doing
- MSG_Write* (&netchan.message, <data>).
-
- If the message buffer is overflowed, either by a single message, or by
- multiple frames worth piling up while the last reliable transmit goes
- unacknowledged, the netchan signals a fatal error.
-
- Reliable messages are always placed first in a packet, then the unreliable
- message is included if there is sufficient room.
-
- To the receiver, there is no distinction between the reliable and unreliable
- parts of the message, they are just processed out as a single larger message.
-
- Illogical packet sequence numbers cause the packet to be dropped, but do
- not kill the connection. This, combined with the tight window of valid
- reliable acknowledgement numbers provides protection against malicious
- address spoofing.
-
-
- The qport field is a workaround for bad address translating routers that
- sometimes remap the client's source port on a packet during gameplay.
-
- If the base part of the net address matches and the qport matches, then the
- channel matches even if the IP port differs. The IP port should be updated
- to the new value before sending out any replies.
-
-
- If there is no information that needs to be transfered on a given frame,
- such as during the connection stage while waiting for the client to load,
- then a packet only needs to be delivered if there is something in the
- unacknowledged reliable
- */
-
- public static cvar_t showpackets;
- public static cvar_t showdrop;
- public static cvar_t qport;
-
- //public static netadr_t net_from = new netadr_t();
- public static sizebuf_t net_message = new sizebuf_t();
- public static byte net_message_buffer[] = new byte[Defines.MAX_MSGLEN];
-
- /*
- ===============
- Netchan_Init
-
- ===============
- */
- //ok.
- public static void Netchan_Init() {
- long port;
-
- // pick a port value that should be nice and random
- port = Sys.Milliseconds() & 0xffff;
-
- showpackets = Cvar.Get("showpackets", "0", 0);
- showdrop = Cvar.Get("showdrop", "0", 0);
- qport = Cvar.Get("qport", "" + port, Defines.CVAR_NOSET);
- }
-
- /*
- ===============
- Netchan_OutOfBand
-
- Sends an out-of-band datagram
- ================
- */
- //ok.
- public static void Netchan_OutOfBand(int net_socket, netadr_t adr, int length, byte data[]) {
- sizebuf_t send = new sizebuf_t();
- byte send_buf[] = new byte[Defines.MAX_MSGLEN];
-
- // write the packet header
- SZ.Init(send, send_buf, Defines.MAX_MSGLEN);
-
- MSG.WriteInt(send, -1); // -1 sequence means out of band
- SZ.Write(send, data, length);
-
- // send the datagram
- NET.SendPacket(net_socket, send.cursize, send.data, adr);
- }
-
- public static void OutOfBandPrint(int net_socket, netadr_t adr, String s) {
- Netchan_OutOfBand(net_socket, adr, s.length(), s.getBytes());
- }
-
- /*
- ==============
- Netchan_Setup
-
- called to open a channel to a remote system
- ==============
- */
- public static void Setup(int sock, netchan_t chan, netadr_t adr, int qport) {
- //memset (chan, 0, sizeof(*chan));
-
- chan.clear();
- chan.sock = sock;
- chan.remote_address.set(adr);
- chan.qport = qport;
- chan.last_received = Globals.curtime;
- chan.incoming_sequence = 0;
- chan.outgoing_sequence = 1;
-
- SZ.Init(chan.message, chan.message_buf, chan.message_buf.length);
- chan.message.allowoverflow = true;
- }
-
- /*
- ===============
- Netchan_CanReliable
-
- Returns true if the last reliable message has acked
- ================
- */
- public static boolean Netchan_CanReliable(netchan_t chan) {
- if (chan.reliable_length != 0)
- return false; // waiting for ack
- return true;
- }
- // das ist richtig !!!
- public static boolean Netchan_NeedReliable(netchan_t chan) {
- boolean send_reliable;
-
- // if the remote side dropped the last reliable message, resend it
- send_reliable = false;
-
- if (chan.incoming_acknowledged > chan.last_reliable_sequence && chan.incoming_reliable_acknowledged != chan.reliable_sequence)
- send_reliable = true;
-
- // if the reliable transmit buffer is empty, copy the current message out
- if (0 == chan.reliable_length && chan.message.cursize != 0) {
- send_reliable = true;
- }
-
- return send_reliable;
- }
-
- /*
- ===============
- Netchan_Transmit
-
- tries to send an unreliable message to a connection, and handles the
- transmition / retransmition of the reliable messages.
-
- A 0 length will still generate a packet and deal with the reliable messages.
- ================
- */
- public static void Transmit(netchan_t chan, int length, byte data[]) {
- sizebuf_t send = new sizebuf_t();
- byte send_buf[] = new byte[MAX_MSGLEN];
- int send_reliable;
- int w1, w2;
-
- // check for message overflow
- if (chan.message.overflowed) {
- chan.fatal_error = true;
- Com.Printf(NET.AdrToString(chan.remote_address) + ":Outgoing message overflow\n");
- return;
- }
-
- send_reliable = Netchan_NeedReliable(chan) ? 1 : 0;
-
- if (chan.reliable_length == 0 && chan.message.cursize != 0) {
- System.arraycopy(chan.message_buf, 0, chan.reliable_buf, 0, chan.message.cursize);
- chan.reliable_length = chan.message.cursize;
- chan.message.cursize = 0;
- chan.reliable_sequence ^= 1;
- }
-
- // write the packet header
- SZ.Init(send, send_buf, send_buf.length);
-
- w1 = (chan.outgoing_sequence & ~(1 << 31)) | (send_reliable << 31);
- w2 = (chan.incoming_sequence & ~(1 << 31)) | (chan.incoming_reliable_sequence << 31);
-
- chan.outgoing_sequence++;
- chan.last_sent = (int) Globals.curtime;
-
- MSG.WriteInt(send, w1);
- MSG.WriteInt(send, w2);
-
- // send the qport if we are a client
- if (chan.sock == Defines.NS_CLIENT)
- MSG.WriteShort(send, (int) qport.value);
-
- // copy the reliable message to the packet first
- if (send_reliable != 0) {
- SZ.Write(send, chan.reliable_buf, chan.reliable_length);
- chan.last_reliable_sequence = chan.outgoing_sequence;
- }
-
- // add the unreliable part if space is available
- if (send.maxsize - send.cursize >= length)
- SZ.Write(send, data, length);
- else
- Com.Printf("Netchan_Transmit: dumped unreliable\n");
-
- // send the datagram
- NET.SendPacket(chan.sock, send.cursize, send.data, chan.remote_address);
-
- if (showpackets.value != 0) {
- if (send_reliable != 0)
- Com.Printf(//"send %4i : s=%i reliable=%i ack=%i rack=%i\n"
- "send "
- + send.cursize
- + " : s="
- + (chan.outgoing_sequence - 1)
- + " reliable="
- + chan.reliable_sequence
- + " ack="
- + chan.incoming_sequence
- + " rack="
- + chan.incoming_reliable_sequence
- + "\n");
- else
- Com.Printf(//"send %4i : s=%i ack=%i rack=%i\n"
- "send "
- + send.cursize
- + " : s="
- + (chan.outgoing_sequence - 1)
- + " ack="
- + chan.incoming_sequence
- + " rack="
- + chan.incoming_reliable_sequence
- + "\n");
- }
- }
-
- /*
- =================
- Netchan_Process
-
- called when the current net_message is from remote_address
- modifies net_message so that it points to the packet payload
- =================
- */
- public static boolean Process(netchan_t chan, sizebuf_t msg) {
- int sequence, sequence_ack;
- int reliable_ack, reliable_message;
- int qport;
-
- // get sequence numbers
- MSG.BeginReading(msg);
- sequence = MSG.ReadLong(msg);
- sequence_ack = MSG.ReadLong(msg);
-
- // read the qport if we are a server
- if (chan.sock == NS_SERVER)
- qport = MSG.ReadShort(msg);
-
- // achtung unsigned int
- reliable_message = sequence >>> 31;
- reliable_ack = sequence_ack >>> 31;
-
- sequence &= ~(1 << 31);
- sequence_ack &= ~(1 << 31);
-
- if (showpackets.value != 0) {
- if (reliable_message != 0)
- Com.Printf(//"recv %4i : s=%i reliable=%i ack=%i rack=%i\n"
- "recv "
- + msg.cursize
- + " : s="
- + sequence
- + " reliable="
- + (chan.incoming_reliable_sequence ^ 1)
- + " ack="
- + sequence_ack
- + " rack="
- + reliable_ack
- + "\n");
- else
- Com.Printf(//"recv %4i : s=%i ack=%i rack=%i\n"
- "recv " + msg.cursize + " : s=" + sequence + " ack=" + sequence_ack + " rack=" + reliable_ack + "\n");
- }
-
- //
- // discard stale or duplicated packets
- //
- if (sequence <= chan.incoming_sequence) {
- if (showdrop.value != 0)
- Com.Printf(
- NET.AdrToString(chan.remote_address)
- + ":Out of order packet "
- + sequence
- + " at "
- + chan.incoming_sequence
- + "\n");
- return false;
- }
-
- //
- // dropped packets don't keep the message from being used
- //
- chan.dropped = sequence - (chan.incoming_sequence + 1);
- if (chan.dropped > 0) {
- if (showdrop.value != 0)
- Com.Printf(NET.AdrToString(chan.remote_address) + ":Dropped " + chan.dropped + " packets at " + sequence + "\n");
- }
-
- //
- // if the current outgoing reliable message has been acknowledged
- // clear the buffer to make way for the next
- //
- if (reliable_ack == chan.reliable_sequence)
- chan.reliable_length = 0; // it has been received
-
- //
- // if this message contains a reliable message, bump incoming_reliable_sequence
- //
- chan.incoming_sequence = sequence;
- chan.incoming_acknowledged = sequence_ack;
- chan.incoming_reliable_acknowledged = reliable_ack;
- if (reliable_message != 0) {
- chan.incoming_reliable_sequence ^= 1;
- }
-
- //
- // the message can now be read from the current message pointer
- //
- chan.last_received = (int) Globals.curtime;
-
- return true;
- }
-
-}
+ /*
+ *
+ * packet header ------------- 31 sequence 1 does this message contains a
+ * reliable payload 31 acknowledge sequence 1 acknowledge receipt of
+ * even/odd message 16 qport
+ *
+ * The remote connection never knows if it missed a reliable message, the
+ * local side detects that it has been dropped by seeing a sequence
+ * acknowledge higher thatn the last reliable sequence, but without the
+ * correct evon/odd bit for the reliable set.
+ *
+ * If the sender notices that a reliable message has been dropped, it will
+ * be retransmitted. It will not be retransmitted again until a message
+ * after the retransmit has been acknowledged and the reliable still failed
+ * to get there.
+ *
+ * if the sequence number is -1, the packet should be handled without a
+ * netcon
+ *
+ * The reliable message can be added to at any time by doing MSG_Write*
+ * (&netchan.message, <data>).
+ *
+ * If the message buffer is overflowed, either by a single message, or by
+ * multiple frames worth piling up while the last reliable transmit goes
+ * unacknowledged, the netchan signals a fatal error.
+ *
+ * Reliable messages are always placed first in a packet, then the
+ * unreliable message is included if there is sufficient room.
+ *
+ * To the receiver, there is no distinction between the reliable and
+ * unreliable parts of the message, they are just processed out as a single
+ * larger message.
+ *
+ * Illogical packet sequence numbers cause the packet to be dropped, but do
+ * not kill the connection. This, combined with the tight window of valid
+ * reliable acknowledgement numbers provides protection against malicious
+ * address spoofing.
+ *
+ *
+ * The qport field is a workaround for bad address translating routers that
+ * sometimes remap the client's source port on a packet during gameplay.
+ *
+ * If the base part of the net address matches and the qport matches, then
+ * the channel matches even if the IP port differs. The IP port should be
+ * updated to the new value before sending out any replies.
+ *
+ *
+ * If there is no information that needs to be transfered on a given frame,
+ * such as during the connection stage while waiting for the client to load,
+ * then a packet only needs to be delivered if there is something in the
+ * unacknowledged reliable
+ */
+
+ public static cvar_t showpackets;
+
+ public static cvar_t showdrop;
+
+ public static cvar_t qport;
+
+ //public static netadr_t net_from = new netadr_t();
+ public static sizebuf_t net_message = new sizebuf_t();
+
+ public static byte net_message_buffer[] = new byte[Defines.MAX_MSGLEN];
+
+ /*
+ * =============== Netchan_Init
+ *
+ * ===============
+ */
+ //ok.
+ public static void Netchan_Init() {
+ long port;
+
+ // pick a port value that should be nice and random
+ port = Sys.Milliseconds() & 0xffff;
+
+ showpackets = Cvar.Get("showpackets", "0", 0);
+ showdrop = Cvar.Get("showdrop", "0", 0);
+ qport = Cvar.Get("qport", "" + port, Defines.CVAR_NOSET);
+ }
+
+ /*
+ * =============== Netchan_OutOfBand
+ *
+ * Sends an out-of-band datagram ================
+ */
+ //ok.
+ public static void Netchan_OutOfBand(int net_socket, netadr_t adr,
+ int length, byte data[]) {
+ sizebuf_t send = new sizebuf_t();
+ byte send_buf[] = new byte[Defines.MAX_MSGLEN];
+
+ // write the packet header
+ SZ.Init(send, send_buf, Defines.MAX_MSGLEN);
+
+ MSG.WriteInt(send, -1); // -1 sequence means out of band
+ SZ.Write(send, data, length);
+
+ // send the datagram
+ NET.SendPacket(net_socket, send.cursize, send.data, adr);
+ }
+
+ public static void OutOfBandPrint(int net_socket, netadr_t adr, String s) {
+ Netchan_OutOfBand(net_socket, adr, s.length(), s.getBytes());
+ }
+
+ /*
+ * ============== Netchan_Setup
+ *
+ * called to open a channel to a remote system ==============
+ */
+ public static void Setup(int sock, netchan_t chan, netadr_t adr, int qport) {
+ //memset (chan, 0, sizeof(*chan));
+
+ chan.clear();
+ chan.sock = sock;
+ chan.remote_address.set(adr);
+ chan.qport = qport;
+ chan.last_received = Globals.curtime;
+ chan.incoming_sequence = 0;
+ chan.outgoing_sequence = 1;
+
+ SZ.Init(chan.message, chan.message_buf, chan.message_buf.length);
+ chan.message.allowoverflow = true;
+ }
+
+ /*
+ * =============== Netchan_CanReliable
+ *
+ * Returns true if the last reliable message has acked ================
+ */
+ public static boolean Netchan_CanReliable(netchan_t chan) {
+ if (chan.reliable_length != 0)
+ return false; // waiting for ack
+ return true;
+ }
+
+ // das ist richtig !!!
+ public static boolean Netchan_NeedReliable(netchan_t chan) {
+ boolean send_reliable;
+
+ // if the remote side dropped the last reliable message, resend it
+ send_reliable = false;
+
+ if (chan.incoming_acknowledged > chan.last_reliable_sequence
+ && chan.incoming_reliable_acknowledged != chan.reliable_sequence)
+ send_reliable = true;
+
+ // if the reliable transmit buffer is empty, copy the current message
+ // out
+ if (0 == chan.reliable_length && chan.message.cursize != 0) {
+ send_reliable = true;
+ }
+
+ return send_reliable;
+ }
+
+ /*
+ * =============== Netchan_Transmit
+ *
+ * tries to send an unreliable message to a connection, and handles the
+ * transmition / retransmition of the reliable messages.
+ *
+ * A 0 length will still generate a packet and deal with the reliable
+ * messages. ================
+ */
+ public static void Transmit(netchan_t chan, int length, byte data[]) {
+ sizebuf_t send = new sizebuf_t();
+ byte send_buf[] = new byte[Defines.MAX_MSGLEN];
+ int send_reliable;
+ int w1, w2;
+
+ // check for message overflow
+ if (chan.message.overflowed) {
+ chan.fatal_error = true;
+ Com.Printf(NET.AdrToString(chan.remote_address)
+ + ":Outgoing message overflow\n");
+ return;
+ }
+
+ send_reliable = Netchan_NeedReliable(chan) ? 1 : 0;
+
+ if (chan.reliable_length == 0 && chan.message.cursize != 0) {
+ System.arraycopy(chan.message_buf, 0, chan.reliable_buf, 0,
+ chan.message.cursize);
+ chan.reliable_length = chan.message.cursize;
+ chan.message.cursize = 0;
+ chan.reliable_sequence ^= 1;
+ }
+
+ // write the packet header
+ SZ.Init(send, send_buf, send_buf.length);
+
+ w1 = (chan.outgoing_sequence & ~(1 << 31)) | (send_reliable << 31);
+ w2 = (chan.incoming_sequence & ~(1 << 31))
+ | (chan.incoming_reliable_sequence << 31);
+
+ chan.outgoing_sequence++;
+ chan.last_sent = (int) Globals.curtime;
+
+ MSG.WriteInt(send, w1);
+ MSG.WriteInt(send, w2);
+
+ // send the qport if we are a client
+ if (chan.sock == Defines.NS_CLIENT)
+ MSG.WriteShort(send, (int) qport.value);
+
+ // copy the reliable message to the packet first
+ if (send_reliable != 0) {
+ SZ.Write(send, chan.reliable_buf, chan.reliable_length);
+ chan.last_reliable_sequence = chan.outgoing_sequence;
+ }
+
+ // add the unreliable part if space is available
+ if (send.maxsize - send.cursize >= length)
+ SZ.Write(send, data, length);
+ else
+ Com.Printf("Netchan_Transmit: dumped unreliable\n");
+
+ // send the datagram
+ NET.SendPacket(chan.sock, send.cursize, send.data, chan.remote_address);
+
+ if (showpackets.value != 0) {
+ if (send_reliable != 0)
+ Com.Printf(
+ //"send %4i : s=%i reliable=%i ack=%i rack=%i\n"
+ "send " + send.cursize + " : s="
+ + (chan.outgoing_sequence - 1) + " reliable="
+ + chan.reliable_sequence + " ack="
+ + chan.incoming_sequence + " rack="
+ + chan.incoming_reliable_sequence + "\n");
+ else
+ Com.Printf(
+ //"send %4i : s=%i ack=%i rack=%i\n"
+ "send " + send.cursize + " : s="
+ + (chan.outgoing_sequence - 1) + " ack="
+ + chan.incoming_sequence + " rack="
+ + chan.incoming_reliable_sequence + "\n");
+ }
+ }
+
+ /*
+ * ================= Netchan_Process
+ *
+ * called when the current net_message is from remote_address modifies
+ * net_message so that it points to the packet payload =================
+ */
+ public static boolean Process(netchan_t chan, sizebuf_t msg) {
+ int sequence, sequence_ack;
+ int reliable_ack, reliable_message;
+ int qport;
+
+ // get sequence numbers
+ MSG.BeginReading(msg);
+ sequence = MSG.ReadLong(msg);
+ sequence_ack = MSG.ReadLong(msg);
+
+ // read the qport if we are a server
+ if (chan.sock == Defines.NS_SERVER)
+ qport = MSG.ReadShort(msg);
+
+ // achtung unsigned int
+ reliable_message = sequence >>> 31;
+ reliable_ack = sequence_ack >>> 31;
+
+ sequence &= ~(1 << 31);
+ sequence_ack &= ~(1 << 31);
+
+ if (showpackets.value != 0) {
+ if (reliable_message != 0)
+ Com.Printf(
+ //"recv %4i : s=%i reliable=%i ack=%i rack=%i\n"
+ "recv " + msg.cursize + " : s=" + sequence
+ + " reliable="
+ + (chan.incoming_reliable_sequence ^ 1)
+ + " ack=" + sequence_ack + " rack="
+ + reliable_ack + "\n");
+ else
+ Com
+ .Printf(
+ //"recv %4i : s=%i ack=%i rack=%i\n"
+ "recv " + msg.cursize + " : s=" + sequence + " ack="
+ + sequence_ack + " rack=" + reliable_ack + "\n");
+ }
+
+ //
+ // discard stale or duplicated packets
+ //
+ if (sequence <= chan.incoming_sequence) {
+ if (showdrop.value != 0)
+ Com.Printf(NET.AdrToString(chan.remote_address)
+ + ":Out of order packet " + sequence + " at "
+ + chan.incoming_sequence + "\n");
+ return false;
+ }
+
+ //
+ // dropped packets don't keep the message from being used
+ //
+ chan.dropped = sequence - (chan.incoming_sequence + 1);
+ if (chan.dropped > 0) {
+ if (showdrop.value != 0)
+ Com.Printf(NET.AdrToString(chan.remote_address) + ":Dropped "
+ + chan.dropped + " packets at " + sequence + "\n");
+ }
+
+ //
+ // if the current outgoing reliable message has been acknowledged
+ // clear the buffer to make way for the next
+ //
+ if (reliable_ack == chan.reliable_sequence)
+ chan.reliable_length = 0; // it has been received
+
+ //
+ // if this message contains a reliable message, bump
+ // incoming_reliable_sequence
+ //
+ chan.incoming_sequence = sequence;
+ chan.incoming_acknowledged = sequence_ack;
+ chan.incoming_reliable_acknowledged = reliable_ack;
+ if (reliable_message != 0) {
+ chan.incoming_reliable_sequence ^= 1;
+ }
+
+ //
+ // the message can now be read from the current message pointer
+ //
+ chan.last_received = (int) Globals.curtime;
+
+ return true;
+ }
+} \ No newline at end of file
diff --git a/src/jake2/qcommon/PMove.java b/src/jake2/qcommon/PMove.java
index 2043c8a..f4e92c3 100644
--- a/src/jake2/qcommon/PMove.java
+++ b/src/jake2/qcommon/PMove.java
@@ -1,1259 +1,1184 @@
/*
-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.
-
-*/
+ * 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 25.01.2004 by RST.
-// $Id: PMove.java,v 1.4 2004-09-10 19:02:53 salomo Exp $
-
+// $Id: PMove.java,v 1.5 2004-09-22 19:22:09 salomo Exp $
package jake2.qcommon;
import jake2.*;
import jake2.client.*;
import jake2.game.*;
-import jake2.qcommon.*;
import jake2.render.*;
import jake2.server.*;
+import jake2.util.Math3D;
+
+public class PMove {
+
+ // all of the locals will be zeroed before each
+ // pmove, just to make damn sure we don't have
+ // any differences when running on client or server
+
+ public static class pml_t {
+ public float[] origin = { 0, 0, 0 }; // full float precision
+
+ public float[] velocity = { 0, 0, 0 }; // full float precision
+
+ public float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 }, up = { 0, 0,
+ 0 };
+
+ public float frametime;
+
+ public csurface_t groundsurface;
+
+ public cplane_t groundplane = new cplane_t();
+
+ public int groundcontents;
+
+ public float[] previous_origin = { 0, 0, 0 };
+
+ public boolean ladder;
+ }
+
+ public static pmove_t pm;
+
+ public static PMove.pml_t pml = new PMove.pml_t();
+
+ // movement parameters
+ public static float pm_stopspeed = 100;
+
+ public static float pm_maxspeed = 300;
+
+ public static float pm_duckspeed = 100;
+
+ public static float pm_accelerate = 10;
+
+ public static float pm_airaccelerate = 0;
+
+ public static float pm_wateraccelerate = 10;
+
+ public static float pm_friction = 6;
+
+ public static float pm_waterfriction = 1;
+
+ public static float pm_waterspeed = 400;
+
+ /*
+ * ================ PM_SnapPosition
+ *
+ * On exit, the origin will have a value that is pre-quantized to the 0.125
+ * precision of the network channel and in a valid position.
+ * ================
+ */
+ // try all single bits first
+ public static int jitterbits[] = { 0, 4, 1, 2, 3, 5, 6, 7 };
+
+ /*
+ * ================ PM_InitialSnapPosition
+ *
+ * ================
+ */
+ public static int offset[] = { 0, -1, 1 };
+
+ /*
+ *
+ * walking up a step should kill some velocity
+ *
+ */
+
+ /*
+ * ================== PM_ClipVelocity
+ *
+ * Slide off of the impacting object returns the blocked flags (1 = floor, 2 =
+ * step / wall) ==================
+ */
-public class PMove extends Game
-{
-
- public final static int STEPSIZE = 18;
-
- // all of the locals will be zeroed before each
- // pmove, just to make damn sure we don't have
- // any differences when running on client or server
-
- public static class pml_t
- {
- float[] origin = { 0, 0, 0 }; // full float precision
- float[] velocity = { 0, 0, 0 }; // full float precision
-
- float[] forward = { 0, 0, 0 }, right = { 0, 0, 0 }, up = { 0, 0, 0 };
- float frametime;
-
- csurface_t groundsurface;
- cplane_t groundplane = new cplane_t();
- int groundcontents;
-
- float[] previous_origin = { 0, 0, 0 };
- boolean ladder;
- }
-
- public static pmove_t pm;
- public static pml_t pml = new pml_t();
-
- // movement parameters
- public static float pm_stopspeed = 100;
- public static float pm_maxspeed = 300;
- public static float pm_duckspeed = 100;
- public static float pm_accelerate = 10;
- public static float pm_airaccelerate = 0;
- public static float pm_wateraccelerate = 10;
- public static float pm_friction = 6;
- public static float pm_waterfriction = 1;
- public static float pm_waterspeed = 400;
-
- /*
-
- walking up a step should kill some velocity
-
- */
-
- /*
- ==================
- PM_ClipVelocity
-
- Slide off of the impacting object
- returns the blocked flags (1 = floor, 2 = step / wall)
- ==================
- */
- public static final float STOP_EPSILON = 0.1f;
-
- public static void PM_ClipVelocity(float[] in, float[] normal, float[] out, float overbounce)
- {
- float backoff;
- float change;
- int i;
-
- backoff = DotProduct(in, normal) * overbounce;
-
- for (i = 0; i < 3; i++)
- {
- change = normal[i] * backoff;
- out[i] = in[i] - change;
- if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
- out[i] = 0;
- }
- }
-
- /*
- ==================
- PM_StepSlideMove
-
- Each intersection will try to step over the obstruction instead of
- sliding along it.
-
- Returns a new origin, velocity, and contact entity
- Does not modify any world state?
- ==================
- */
- public final static float MIN_STEP_NORMAL = 0.7f; // can't step up onto very steep slopes
-
- public static void PM_StepSlideMove_()
- {
- int bumpcount, numbumps;
- float[] dir = { 0, 0, 0 };
- float d;
- int numplanes;
- float[] planes[] = new float[MAX_CLIP_PLANES][3];
- float[] primal_velocity = { 0, 0, 0 };
- int i, j;
- trace_t trace;
- float[] end = { 0, 0, 0 };
- float time_left;
-
- numbumps = 4;
-
- VectorCopy(pml.velocity, primal_velocity);
- numplanes = 0;
-
- time_left = pml.frametime;
-
- for (bumpcount = 0; bumpcount < numbumps; bumpcount++)
- {
- for (i = 0; i < 3; i++)
- end[i] = pml.origin[i] + time_left * pml.velocity[i];
-
- trace = pm.trace.trace(pml.origin, pm.mins, pm.maxs, end);
-
- if (trace.allsolid)
- { // entity is trapped in another solid
- pml.velocity[2] = 0; // don't build up falling damage
- return;
- }
-
- if (trace.fraction > 0)
- { // actually covered some distance
- VectorCopy(trace.endpos, pml.origin);
- numplanes = 0;
- }
-
- if (trace.fraction == 1)
- break; // moved the entire distance
-
- // save entity for contact
- if (pm.numtouch < MAXTOUCH && trace.ent != null)
- {
- //rst: just for debugging touches.
- //if (trace.ent.index != -1 && trace.ent.index != 0)
- //Com.p("touch: " + trace.ent.classname + " (" + trace.ent.index + ")" );
-
- pm.touchents[pm.numtouch] = trace.ent;
- pm.numtouch++;
- }
-
- time_left -= time_left * trace.fraction;
-
- // slide along this plane
- if (numplanes >= MAX_CLIP_PLANES)
- { // this shouldn't really happen
- VectorCopy(vec3_origin, pml.velocity);
- break;
- }
-
- VectorCopy(trace.plane.normal, planes[numplanes]);
- numplanes++;
-
- //
- // modify original_velocity so it parallels all of the clip planes
- //
-
- for (i = 0; i < numplanes; i++)
- {
- PM_ClipVelocity(pml.velocity, planes[i], pml.velocity, 1.01f);
- for (j = 0; j < numplanes; j++)
- if (j != i)
- {
- if (DotProduct(pml.velocity, planes[j]) < 0)
- break; // not ok
- }
- if (j == numplanes)
- break;
- }
-
- if (i != numplanes)
- { // go along this plane
- }
- else
- { // go along the crease
- if (numplanes != 2)
- {
- // Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
- VectorCopy(vec3_origin, pml.velocity);
- break;
- }
- CrossProduct(planes[0], planes[1], dir);
- d = DotProduct(dir, pml.velocity);
- VectorScale(dir, d, pml.velocity);
- }
-
- //
- // if velocity is against the original velocity, stop dead
- // to avoid tiny occilations in sloping corners
- //
- if (DotProduct(pml.velocity, primal_velocity) <= 0)
- {
- VectorCopy(vec3_origin, pml.velocity);
- break;
- }
- }
-
- if (pm.s.pm_time != 0)
- {
- VectorCopy(primal_velocity, pml.velocity);
- }
- }
-
- /*
- ==================
- PM_StepSlideMove
-
- ==================
- */
- public static void PM_StepSlideMove()
- {
- float[] start_o = { 0, 0, 0 }, start_v = { 0, 0, 0 };
- float[] down_o = { 0, 0, 0 }, down_v = { 0, 0, 0 };
- trace_t trace;
- float down_dist, up_dist;
- // float [] delta;
- float[] up = { 0, 0, 0 }, down = { 0, 0, 0 };
-
- VectorCopy(pml.origin, start_o);
- VectorCopy(pml.velocity, start_v);
-
- PM_StepSlideMove_();
-
- VectorCopy(pml.origin, down_o);
- VectorCopy(pml.velocity, down_v);
-
- VectorCopy(start_o, up);
- up[2] += STEPSIZE;
-
- trace = pm.trace.trace(up, pm.mins, pm.maxs, up);
- if (trace.allsolid)
- return; // can't step up
-
- // try sliding above
- VectorCopy(up, pml.origin);
- VectorCopy(start_v, pml.velocity);
-
- PM_StepSlideMove_();
-
- // push down the final amount
- VectorCopy(pml.origin, down);
- down[2] -= STEPSIZE;
- trace = pm.trace.trace(pml.origin, pm.mins, pm.maxs, down);
- if (!trace.allsolid)
- {
- VectorCopy(trace.endpos, pml.origin);
- }
-
- VectorCopy(pml.origin, up);
-
- // decide which one went farther
- down_dist = (down_o[0] - start_o[0]) * (down_o[0] - start_o[0]) + (down_o[1] - start_o[1]) * (down_o[1] - start_o[1]);
- up_dist = (up[0] - start_o[0]) * (up[0] - start_o[0]) + (up[1] - start_o[1]) * (up[1] - start_o[1]);
-
- if (down_dist > up_dist || trace.plane.normal[2] < MIN_STEP_NORMAL)
- {
- VectorCopy(down_o, pml.origin);
- VectorCopy(down_v, pml.velocity);
- return;
- }
- //!! Special case
- // if we were walking along a plane, then we need to copy the Z over
- pml.velocity[2] = down_v[2];
- }
-
- /*
- ==================
- PM_Friction
-
- Handles both ground friction and water friction
- ==================
- */
- public static void PM_Friction()
- {
- float vel[];
- float speed, newspeed, control;
- float friction;
- float drop;
-
- vel = pml.velocity;
-
- speed = (float) (Math.sqrt(vel[0] * vel[0] + vel[1] * vel[1] + vel[2] * vel[2]));
- if (speed < 1)
- {
- vel[0] = 0;
- vel[1] = 0;
- return;
- }
-
- drop = 0;
-
- // apply ground friction
- if ((pm.groundentity != null && pml.groundsurface != null && 0 == (pml.groundsurface.flags & SURF_SLICK)) || (pml.ladder))
- {
- friction = pm_friction;
- control = speed < pm_stopspeed ? pm_stopspeed : speed;
- drop += control * friction * pml.frametime;
- }
-
- // apply water friction
- if (pm.waterlevel != 0 && !pml.ladder)
- drop += speed * pm_waterfriction * pm.waterlevel * pml.frametime;
-
- // scale the velocity
- newspeed = speed - drop;
- if (newspeed < 0)
- {
- newspeed = 0;
- }
- newspeed /= speed;
-
- vel[0] = vel[0] * newspeed;
- vel[1] = vel[1] * newspeed;
- vel[2] = vel[2] * newspeed;
- }
-
- /*
- ==============
- PM_Accelerate
-
- Handles user intended acceleration
- ==============
- */
- public static void PM_Accelerate(float[] wishdir, float wishspeed, float accel)
- {
- int i;
- float addspeed, accelspeed, currentspeed;
-
- currentspeed = DotProduct(pml.velocity, wishdir);
- addspeed = wishspeed - currentspeed;
- if (addspeed <= 0)
- return;
- accelspeed = accel * pml.frametime * wishspeed;
- if (accelspeed > addspeed)
- accelspeed = addspeed;
-
- for (i = 0; i < 3; i++)
- pml.velocity[i] += accelspeed * wishdir[i];
- }
-
- public static void PM_AirAccelerate(float[] wishdir, float wishspeed, float accel)
- {
- int i;
- float addspeed, accelspeed, currentspeed, wishspd = wishspeed;
-
- if (wishspd > 30)
- wishspd = 30;
- currentspeed = DotProduct(pml.velocity, wishdir);
- addspeed = wishspd - currentspeed;
- if (addspeed <= 0)
- return;
- accelspeed = accel * wishspeed * pml.frametime;
- if (accelspeed > addspeed)
- accelspeed = addspeed;
-
- for (i = 0; i < 3; i++)
- pml.velocity[i] += accelspeed * wishdir[i];
- }
-
- /*
- =============
- PM_AddCurrents
- =============
- */
- public static void PM_AddCurrents(float[] wishvel)
- {
- float[] v = { 0, 0, 0 };
- float s;
-
- //
- // account for ladders
- //
-
- if (pml.ladder && Math.abs(pml.velocity[2]) <= 200)
- {
- if ((pm.viewangles[PITCH] <= -15) && (pm.cmd.forwardmove > 0))
- wishvel[2] = 200;
- else if ((pm.viewangles[PITCH] >= 15) && (pm.cmd.forwardmove > 0))
- wishvel[2] = -200;
- else if (pm.cmd.upmove > 0)
- wishvel[2] = 200;
- else if (pm.cmd.upmove < 0)
- wishvel[2] = -200;
- else
- wishvel[2] = 0;
-
- // limit horizontal speed when on a ladder
- if (wishvel[0] < -25)
- wishvel[0] = -25;
- else if (wishvel[0] > 25)
- wishvel[0] = 25;
-
- if (wishvel[1] < -25)
- wishvel[1] = -25;
- else if (wishvel[1] > 25)
- wishvel[1] = 25;
- }
-
- //
- // add water currents
- //
-
- if ((pm.watertype & MASK_CURRENT) != 0)
- {
- VectorClear(v);
-
- if ((pm.watertype & CONTENTS_CURRENT_0) != 0)
- v[0] += 1;
- if ((pm.watertype & CONTENTS_CURRENT_90) != 0)
- v[1] += 1;
- if ((pm.watertype & CONTENTS_CURRENT_180) != 0)
- v[0] -= 1;
- if ((pm.watertype & CONTENTS_CURRENT_270) != 0)
- v[1] -= 1;
- if ((pm.watertype & CONTENTS_CURRENT_UP) != 0)
- v[2] += 1;
- if ((pm.watertype & CONTENTS_CURRENT_DOWN) != 0)
- v[2] -= 1;
-
- s = pm_waterspeed;
- if ((pm.waterlevel == 1) && (pm.groundentity != null))
- s /= 2;
-
- VectorMA(wishvel, s, v, wishvel);
- }
-
- //
- // add conveyor belt velocities
- //
-
- if (pm.groundentity != null)
- {
- VectorClear(v);
-
- if ((pml.groundcontents & CONTENTS_CURRENT_0) != 0)
- v[0] += 1;
- if ((pml.groundcontents & CONTENTS_CURRENT_90) != 0)
- v[1] += 1;
- if ((pml.groundcontents & CONTENTS_CURRENT_180) != 0)
- v[0] -= 1;
- if ((pml.groundcontents & CONTENTS_CURRENT_270) != 0)
- v[1] -= 1;
- if ((pml.groundcontents & CONTENTS_CURRENT_UP) != 0)
- v[2] += 1;
- if ((pml.groundcontents & CONTENTS_CURRENT_DOWN) != 0)
- v[2] -= 1;
-
- VectorMA(wishvel, 100 /* pm.groundentity.speed */
- , v, wishvel);
- }
- }
-
- /*
- ===================
- PM_WaterMove
-
- ===================
- */
- public static void PM_WaterMove()
- {
- int i;
- float[] wishvel = { 0, 0, 0 };
- float wishspeed;
- float[] wishdir = { 0, 0, 0 };
-
- //
- // user intentions
- //
- for (i = 0; i < 3; i++)
- wishvel[i] = pml.forward[i] * pm.cmd.forwardmove + pml.right[i] * pm.cmd.sidemove;
-
- if (0 == pm.cmd.forwardmove && 0 == pm.cmd.sidemove && 0 == pm.cmd.upmove)
- wishvel[2] -= 60; // drift towards bottom
- else
- wishvel[2] += pm.cmd.upmove;
-
- PM_AddCurrents(wishvel);
-
- VectorCopy(wishvel, wishdir);
- wishspeed = VectorNormalize(wishdir);
-
- if (wishspeed > pm_maxspeed)
- {
- VectorScale(wishvel, pm_maxspeed / wishspeed, wishvel);
- wishspeed = pm_maxspeed;
- }
- wishspeed *= 0.5;
-
- PM_Accelerate(wishdir, wishspeed, pm_wateraccelerate);
-
- PM_StepSlideMove();
- }
-
- /*
- ===================
- PM_AirMove
-
- ===================
- */
- public static void PM_AirMove()
- {
- int i;
- float[] wishvel = { 0, 0, 0 };
- float fmove, smove;
- float[] wishdir = { 0, 0, 0 };
- float wishspeed;
- float maxspeed;
-
- fmove = pm.cmd.forwardmove;
- smove = pm.cmd.sidemove;
-
- for (i = 0; i < 2; i++)
- wishvel[i] = pml.forward[i] * fmove + pml.right[i] * smove;
- wishvel[2] = 0;
-
- PM_AddCurrents(wishvel);
-
- VectorCopy(wishvel, wishdir);
- wishspeed = VectorNormalize(wishdir);
-
- //
- // clamp to server defined max speed
- //
- maxspeed = (pm.s.pm_flags & PMF_DUCKED) != 0 ? pm_duckspeed : pm_maxspeed;
-
- if (wishspeed > maxspeed)
- {
- VectorScale(wishvel, maxspeed / wishspeed, wishvel);
- wishspeed = maxspeed;
- }
-
- if (pml.ladder)
- {
- PM_Accelerate(wishdir, wishspeed, pm_accelerate);
- if (0 == wishvel[2])
- {
- if (pml.velocity[2] > 0)
- {
- pml.velocity[2] -= pm.s.gravity * pml.frametime;
- if (pml.velocity[2] < 0)
- pml.velocity[2] = 0;
- }
- else
- {
- pml.velocity[2] += pm.s.gravity * pml.frametime;
- if (pml.velocity[2] > 0)
- pml.velocity[2] = 0;
- }
- }
- PM_StepSlideMove();
- }
- else if (pm.groundentity != null)
- { // walking on ground
- pml.velocity[2] = 0; //!!! this is before the accel
- PM_Accelerate(wishdir, wishspeed, pm_accelerate);
-
- // PGM -- fix for negative trigger_gravity fields
- // pml.velocity[2] = 0;
- if (pm.s.gravity > 0)
- pml.velocity[2] = 0;
- else
- pml.velocity[2] -= pm.s.gravity * pml.frametime;
- // PGM
-
- if (0 == pml.velocity[0] && 0 == pml.velocity[1])
- return;
- PM_StepSlideMove();
- }
- else
- { // not on ground, so little effect on velocity
- if (pm_airaccelerate != 0)
- PM_AirAccelerate(wishdir, wishspeed, pm_accelerate);
- else
- PM_Accelerate(wishdir, wishspeed, 1);
- // add gravity
- pml.velocity[2] -= pm.s.gravity * pml.frametime;
- PM_StepSlideMove();
- }
- }
-
- /*
- =============
- PM_CatagorizePosition
- =============
- */
- public static void PM_CatagorizePosition()
- {
- float[] point = { 0, 0, 0 };
- int cont;
- trace_t trace;
- int sample1;
- int sample2;
-
- // if the player hull point one unit down is solid, the player
- // is on ground
-
- // see if standing on something solid
- point[0] = pml.origin[0];
- point[1] = pml.origin[1];
- point[2] = pml.origin[2] - 0.25f;
- if (pml.velocity[2] > 180) //!!ZOID changed from 100 to 180 (ramp accel)
- {
- pm.s.pm_flags &= ~PMF_ON_GROUND;
- pm.groundentity = null;
- }
- else
- {
- trace = pm.trace.trace(pml.origin, pm.mins, pm.maxs, point);
- pml.groundplane = trace.plane;
- pml.groundsurface = trace.surface;
- pml.groundcontents = trace.contents;
-
- if (null == trace.ent || (trace.plane.normal[2] < 0.7 && !trace.startsolid))
- {
- pm.groundentity = null;
- pm.s.pm_flags &= ~PMF_ON_GROUND;
- }
- else
- {
- pm.groundentity = trace.ent;
- // hitting solid ground will end a waterjump
- if ((pm.s.pm_flags & PMF_TIME_WATERJUMP) != 0)
- {
- pm.s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT);
- pm.s.pm_time = 0;
- }
-
- if (0 == (pm.s.pm_flags & PMF_ON_GROUND))
- { // just hit the ground
- pm.s.pm_flags |= PMF_ON_GROUND;
- // don't do landing time if we were just going down a slope
- if (pml.velocity[2] < -200)
- {
- pm.s.pm_flags |= PMF_TIME_LAND;
- // don't allow another jump for a little while
- if (pml.velocity[2] < -400)
- pm.s.pm_time = 25;
- else
- pm.s.pm_time = 18;
- }
- }
- }
-
- if (pm.numtouch < MAXTOUCH && trace.ent != null)
- {
- pm.touchents[pm.numtouch] = trace.ent;
- pm.numtouch++;
- }
- }
-
- //
- // get waterlevel, accounting for ducking
- //
- pm.waterlevel = 0;
- pm.watertype = 0;
-
- sample2 = (int) (pm.viewheight - pm.mins[2]);
- sample1 = sample2 / 2;
-
- point[2] = pml.origin[2] + pm.mins[2] + 1;
- cont = pm.pointcontents.pointcontents(point);
-
- if ((cont & MASK_WATER) != 0)
- {
- pm.watertype = cont;
- pm.waterlevel = 1;
- point[2] = pml.origin[2] + pm.mins[2] + sample1;
- cont = pm.pointcontents.pointcontents(point);
- if ((cont & MASK_WATER) != 0)
- {
- pm.waterlevel = 2;
- point[2] = pml.origin[2] + pm.mins[2] + sample2;
- cont = pm.pointcontents.pointcontents(point);
- if ((cont & MASK_WATER) != 0)
- pm.waterlevel = 3;
- }
- }
-
- }
-
- /*
- =============
- PM_CheckJump
- =============
- */
- public static void PM_CheckJump()
- {
- if ((pm.s.pm_flags & PMF_TIME_LAND) != 0)
- { // hasn't been long enough since landing to jump again
- return;
- }
-
- if (pm.cmd.upmove < 10)
- { // not holding jump
- pm.s.pm_flags &= ~PMF_JUMP_HELD;
- return;
- }
-
- // must wait for jump to be released
- if ((pm.s.pm_flags & PMF_JUMP_HELD) != 0)
- return;
-
- if (pm.s.pm_type == PM_DEAD)
- return;
-
- if (pm.waterlevel >= 2)
- { // swimming, not jumping
- pm.groundentity = null;
-
- if (pml.velocity[2] <= -300)
- return;
-
- if (pm.watertype == CONTENTS_WATER)
- pml.velocity[2] = 100;
- else if (pm.watertype == CONTENTS_SLIME)
- pml.velocity[2] = 80;
- else
- pml.velocity[2] = 50;
- return;
- }
-
- if (pm.groundentity == null)
- return; // in air, so no effect
-
- pm.s.pm_flags |= PMF_JUMP_HELD;
-
- pm.groundentity = null;
- pml.velocity[2] += 270;
- if (pml.velocity[2] < 270)
- pml.velocity[2] = 270;
- }
-
- /*
- =============
- PM_CheckSpecialMovement
- =============
- */
- public static void PM_CheckSpecialMovement()
- {
- float[] spot = { 0, 0, 0 };
- int cont;
- float[] flatforward = { 0, 0, 0 };
- trace_t trace;
-
- if (pm.s.pm_time != 0)
- return;
-
- pml.ladder = false;
-
- // check for ladder
- flatforward[0] = pml.forward[0];
- flatforward[1] = pml.forward[1];
- flatforward[2] = 0;
- VectorNormalize(flatforward);
-
- VectorMA(pml.origin, 1, flatforward, spot);
- trace = pm.trace.trace(pml.origin, pm.mins, pm.maxs, spot);
- if ((trace.fraction < 1) && (trace.contents & CONTENTS_LADDER) != 0)
- pml.ladder = true;
-
- // check for water jump
- if (pm.waterlevel != 2)
- return;
-
- VectorMA(pml.origin, 30, flatforward, spot);
- spot[2] += 4;
- cont = pm.pointcontents.pointcontents(spot);
- if (0 == (cont & CONTENTS_SOLID))
- return;
-
- spot[2] += 16;
- cont = pm.pointcontents.pointcontents(spot);
- if (cont != 0)
- return;
- // jump out of water
- VectorScale(flatforward, 50, pml.velocity);
- pml.velocity[2] = 350;
-
- pm.s.pm_flags |= PMF_TIME_WATERJUMP;
- pm.s.pm_time = -1; // was 255
- }
-
- /*
- ===============
- PM_FlyMove
- ===============
- */
- public static void PM_FlyMove(boolean doclip)
- {
- float speed, drop, friction, control, newspeed;
- float currentspeed, addspeed, accelspeed;
- int i;
- float[] wishvel = { 0, 0, 0 };
- float fmove, smove;
- float[] wishdir = { 0, 0, 0 };
- float wishspeed;
- float[] end = { 0, 0, 0 };
- trace_t trace;
-
- pm.viewheight = 22;
-
- // friction
-
- speed = VectorLength(pml.velocity);
- if (speed < 1)
- {
- VectorCopy(vec3_origin, pml.velocity);
- }
- else
- {
- drop = 0;
-
- friction = pm_friction * 1.5f; // extra friction
- control = speed < pm_stopspeed ? pm_stopspeed : speed;
- drop += control * friction * pml.frametime;
-
- // scale the velocity
- newspeed = speed - drop;
- if (newspeed < 0)
- newspeed = 0;
- newspeed /= speed;
-
- VectorScale(pml.velocity, newspeed, pml.velocity);
- }
-
- // accelerate
- fmove = pm.cmd.forwardmove;
- smove = pm.cmd.sidemove;
-
- VectorNormalize(pml.forward);
- VectorNormalize(pml.right);
-
- for (i = 0; i < 3; i++)
- wishvel[i] = pml.forward[i] * fmove + pml.right[i] * smove;
- wishvel[2] += pm.cmd.upmove;
-
- VectorCopy(wishvel, wishdir);
- wishspeed = VectorNormalize(wishdir);
-
- //
- // clamp to server defined max speed
- //
- if (wishspeed > pm_maxspeed)
- {
- VectorScale(wishvel, pm_maxspeed / wishspeed, wishvel);
- wishspeed = pm_maxspeed;
- }
-
- currentspeed = DotProduct(pml.velocity, wishdir);
- addspeed = wishspeed - currentspeed;
- if (addspeed <= 0)
- return;
- accelspeed = pm_accelerate * pml.frametime * wishspeed;
- if (accelspeed > addspeed)
- accelspeed = addspeed;
-
- for (i = 0; i < 3; i++)
- pml.velocity[i] += accelspeed * wishdir[i];
-
- if (doclip)
- {
- for (i = 0; i < 3; i++)
- end[i] = pml.origin[i] + pml.frametime * pml.velocity[i];
-
- trace = pm.trace.trace(pml.origin, pm.mins, pm.maxs, end);
-
- VectorCopy(trace.endpos, pml.origin);
- }
- else
- {
- // move
- VectorMA(pml.origin, pml.frametime, pml.velocity, pml.origin);
- }
- }
-
- /*
- ==============
- PM_CheckDuck
-
- Sets mins, maxs, and pm.viewheight
- ==============
- */
- public static void PM_CheckDuck()
- {
- trace_t trace;
-
- pm.mins[0] = -16;
- pm.mins[1] = -16;
-
- pm.maxs[0] = 16;
- pm.maxs[1] = 16;
-
- if (pm.s.pm_type == PM_GIB)
- {
- pm.mins[2] = 0;
- pm.maxs[2] = 16;
- pm.viewheight = 8;
- return;
- }
-
- pm.mins[2] = -24;
-
- if (pm.s.pm_type == PM_DEAD)
- {
- pm.s.pm_flags |= PMF_DUCKED;
- }
- else if (pm.cmd.upmove < 0 && (pm.s.pm_flags & PMF_ON_GROUND) != 0)
- { // duck
- pm.s.pm_flags |= PMF_DUCKED;
- }
- else
- { // stand up if possible
- if ((pm.s.pm_flags & PMF_DUCKED) != 0)
- {
- // try to stand up
- pm.maxs[2] = 32;
- trace = pm.trace.trace(pml.origin, pm.mins, pm.maxs, pml.origin);
- if (!trace.allsolid)
- pm.s.pm_flags &= ~PMF_DUCKED;
- }
- }
-
- if ((pm.s.pm_flags & PMF_DUCKED) != 0)
- {
- pm.maxs[2] = 4;
- pm.viewheight = -2;
- }
- else
- {
- pm.maxs[2] = 32;
- pm.viewheight = 22;
- }
- }
-
- /*
- ==============
- PM_DeadMove
- ==============
- */
- public static void PM_DeadMove()
- {
- float forward;
-
- if (null == pm.groundentity)
- return;
-
- // extra friction
-
- forward = VectorLength(pml.velocity);
- forward -= 20;
- if (forward <= 0)
- {
- VectorClear(pml.velocity);
- }
- else
- {
- VectorNormalize(pml.velocity);
- VectorScale(pml.velocity, forward, pml.velocity);
- }
- }
-
- public static boolean PM_GoodPosition()
- {
- trace_t trace;
- float[] origin = { 0, 0, 0 }, end = { 0, 0, 0 };
- int i;
-
- if (pm.s.pm_type == PM_SPECTATOR)
- return true;
-
- for (i = 0; i < 3; i++)
- origin[i] = end[i] = pm.s.origin[i] * 0.125f;
- trace = pm.trace.trace(origin, pm.mins, pm.maxs, end);
-
- return !trace.allsolid;
- }
-
- /*
- ================
- PM_SnapPosition
-
- On exit, the origin will have a value that is pre-quantized to the 0.125
- precision of the network channel and in a valid position.
- ================
- */
- // try all single bits first
- static int jitterbits[] = { 0, 4, 1, 2, 3, 5, 6, 7 };
- public static void PM_SnapPosition()
- {
- int sign[] = { 0, 0, 0 };
- int i, j, bits;
- short base[] = { 0, 0, 0 };
-
- // snap velocity to eigths
- for (i = 0; i < 3; i++)
- pm.s.velocity[i] = (short) (pml.velocity[i] * 8);
-
- for (i = 0; i < 3; i++)
- {
- if (pml.origin[i] >= 0)
- sign[i] = 1;
- else
- sign[i] = -1;
- pm.s.origin[i] = (short) (pml.origin[i] * 8);
- if (pm.s.origin[i] * 0.125 == pml.origin[i])
- sign[i] = 0;
- }
- VectorCopy(pm.s.origin, base);
-
- // try all combinations
- for (j = 0; j < 8; j++)
- {
- bits = jitterbits[j];
- VectorCopy(base, pm.s.origin);
- for (i = 0; i < 3; i++)
- if ((bits & (1 << i)) != 0)
- pm.s.origin[i] += sign[i];
-
- if (PM_GoodPosition())
- return;
- }
-
- // go back to the last position
- VectorCopy(pml.previous_origin, pm.s.origin);
- // Com_DPrintf ("using previous_origin\n");
- }
-
- /*
- ================
- PM_InitialSnapPosition
-
- ================
- */
- static int offset[] = { 0, -1, 1 };
- public static void PM_InitialSnapPosition()
- {
- int x, y, z;
- short base[] = { 0, 0, 0 };
-
- VectorCopy(pm.s.origin, base);
-
- for (z = 0; z < 3; z++)
- {
- pm.s.origin[2] = (short) (base[2] + offset[z]);
- for (y = 0; y < 3; y++)
- {
- pm.s.origin[1] = (short) (base[1] + offset[y]);
- for (x = 0; x < 3; x++)
- {
- pm.s.origin[0] = (short) (base[0] + offset[x]);
- if (PM_GoodPosition())
- {
- pml.origin[0] = pm.s.origin[0] * 0.125f;
- pml.origin[1] = pm.s.origin[1] * 0.125f;
- pml.origin[2] = pm.s.origin[2] * 0.125f;
- VectorCopy(pm.s.origin, pml.previous_origin);
- return;
- }
- }
- }
- }
-
- Com.DPrintf("Bad InitialSnapPosition\n");
- }
-
- /*
- ================
- PM_ClampAngles
-
- ================
- */
- public static void PM_ClampAngles()
- {
- short temp;
- int i;
-
- if ((pm.s.pm_flags & PMF_TIME_TELEPORT) != 0)
- {
- pm.viewangles[YAW] = SHORT2ANGLE(pm.cmd.angles[YAW] + pm.s.delta_angles[YAW]);
- pm.viewangles[PITCH] = 0;
- pm.viewangles[ROLL] = 0;
- }
- else
- {
- // circularly clamp the angles with deltas
- for (i = 0; i < 3; i++)
- {
- temp = (short) (pm.cmd.angles[i] + pm.s.delta_angles[i]);
- pm.viewangles[i] = SHORT2ANGLE(temp);
- }
-
- // don't let the player look up or down more than 90 degrees
- if (pm.viewangles[PITCH] > 89 && pm.viewangles[PITCH] < 180)
- pm.viewangles[PITCH] = 89;
- else if (pm.viewangles[PITCH] < 271 && pm.viewangles[PITCH] >= 180)
- pm.viewangles[PITCH] = 271;
- }
- AngleVectors(pm.viewangles, pml.forward, pml.right, pml.up);
- }
-
- /*
- ================
- Pmove
-
- Can be called by either the server or the client
- ================
- */
- public static void Pmove(pmove_t pmove)
- {
- pm = pmove;
-
- // clear results
- pm.numtouch = 0;
- VectorClear(pm.viewangles);
- pm.viewheight = 0;
- pm.groundentity = null;
- pm.watertype = 0;
- pm.waterlevel = 0;
-
- // clear all pmove local vars
- pml = new pml_t();
-
- // convert origin and velocity to float values
- pml.origin[0] = pm.s.origin[0] * 0.125f;
- pml.origin[1] = pm.s.origin[1] * 0.125f;
- pml.origin[2] = pm.s.origin[2] * 0.125f;
-
- pml.velocity[0] = pm.s.velocity[0] * 0.125f;
- pml.velocity[1] = pm.s.velocity[1] * 0.125f;
- pml.velocity[2] = pm.s.velocity[2] * 0.125f;
-
- // save old org in case we get stuck
- VectorCopy(pm.s.origin, pml.previous_origin);
-
- pml.frametime = (pm.cmd.msec & 0xFF) * 0.001f;
-
- PM_ClampAngles();
-
- if (pm.s.pm_type == PM_SPECTATOR)
- {
- PM_FlyMove(false);
- PM_SnapPosition();
- return;
- }
-
- if (pm.s.pm_type >= PM_DEAD)
- {
- pm.cmd.forwardmove = 0;
- pm.cmd.sidemove = 0;
- pm.cmd.upmove = 0;
- }
-
- if (pm.s.pm_type == PM_FREEZE)
- return; // no movement at all
-
- // set mins, maxs, and viewheight
- PM_CheckDuck();
-
- if (pm.snapinitial)
- PM_InitialSnapPosition();
-
- // set groundentity, watertype, and waterlevel
- PM_CatagorizePosition();
-
- if (pm.s.pm_type == PM_DEAD)
- PM_DeadMove();
-
- PM_CheckSpecialMovement();
-
- // drop timing counter
- if (pm.s.pm_time != 0)
- {
- int msec;
-
- // TOD o bugfix cwei
- msec = pm.cmd.msec >>> 3;
- if (msec == 0)
- msec = 1;
- if (msec >= (pm.s.pm_time & 0xFF))
- {
- pm.s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT);
- pm.s.pm_time = 0;
- }
- else
- pm.s.pm_time = (byte)((pm.s.pm_time & 0xFF) - msec);
- }
-
- if ((pm.s.pm_flags & PMF_TIME_TELEPORT) != 0)
- { // teleport pause stays exactly in place
- }
- else if ((pm.s.pm_flags & PMF_TIME_WATERJUMP) != 0)
- { // waterjump has no control, but falls
- pml.velocity[2] -= pm.s.gravity * pml.frametime;
- if (pml.velocity[2] < 0)
- { // cancel as soon as we are falling down again
- pm.s.pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND | PMF_TIME_TELEPORT);
- pm.s.pm_time = 0;
- }
-
- PM_StepSlideMove();
- }
- else
- {
- PM_CheckJump();
-
- PM_Friction();
-
- if (pm.waterlevel >= 2)
- PM_WaterMove();
- else
- {
- float[] angles={0,0,0};
-
- VectorCopy(pm.viewangles, angles);
- if (angles[PITCH] > 180)
- angles[PITCH] = angles[PITCH] - 360;
- angles[PITCH] /= 3;
-
- AngleVectors(angles, pml.forward, pml.right, pml.up);
-
- PM_AirMove();
- }
- }
-
- // set groundentity, watertype, and waterlevel for final spot
- PM_CatagorizePosition();
-
- PM_SnapPosition();
- }
-}
+ public static void PM_ClipVelocity(float[] in, float[] normal, float[] out,
+ float overbounce) {
+ float backoff;
+ float change;
+ int i;
+
+ backoff = Math3D.DotProduct(in, normal) * overbounce;
+
+ for (i = 0; i < 3; i++) {
+ change = normal[i] * backoff;
+ out[i] = in[i] - change;
+ if (out[i] > -Defines.MOVE_STOP_EPSILON
+ && out[i] < Defines.MOVE_STOP_EPSILON)
+ out[i] = 0;
+ }
+ }
+
+ public static void PM_StepSlideMove_() {
+ int bumpcount, numbumps;
+ float[] dir = { 0, 0, 0 };
+ float d;
+ int numplanes;
+ float[] planes[] = new float[GameBase.MAX_CLIP_PLANES][3];
+ float[] primal_velocity = { 0, 0, 0 };
+ int i, j;
+ trace_t trace;
+ float[] end = { 0, 0, 0 };
+ float time_left;
+
+ numbumps = 4;
+
+ Math3D.VectorCopy(PMove.pml.velocity, primal_velocity);
+ numplanes = 0;
+
+ time_left = PMove.pml.frametime;
+
+ for (bumpcount = 0; bumpcount < numbumps; bumpcount++) {
+ for (i = 0; i < 3; i++)
+ end[i] = PMove.pml.origin[i] + time_left
+ * PMove.pml.velocity[i];
+
+ trace = PMove.pm.trace.trace(PMove.pml.origin, PMove.pm.mins,
+ PMove.pm.maxs, end);
+
+ if (trace.allsolid) { // entity is trapped in another solid
+ PMove.pml.velocity[2] = 0; // don't build up falling damage
+ return;
+ }
+
+ if (trace.fraction > 0) { // actually covered some distance
+ Math3D.VectorCopy(trace.endpos, PMove.pml.origin);
+ numplanes = 0;
+ }
+
+ if (trace.fraction == 1)
+ break; // moved the entire distance
+
+ // save entity for contact
+ if (PMove.pm.numtouch < Defines.MAXTOUCH && trace.ent != null) {
+ //rst: just for debugging touches.
+ //if (trace.ent.index != -1 && trace.ent.index != 0)
+ //Com.p("touch: " + trace.ent.classname + " (" +
+ // trace.ent.index + ")" );
+
+ PMove.pm.touchents[PMove.pm.numtouch] = trace.ent;
+ PMove.pm.numtouch++;
+ }
+
+ time_left -= time_left * trace.fraction;
+
+ // slide along this plane
+ if (numplanes >= GameBase.MAX_CLIP_PLANES) { // this shouldn't
+ // really happen
+ Math3D.VectorCopy(Globals.vec3_origin, PMove.pml.velocity);
+ break;
+ }
+
+ Math3D.VectorCopy(trace.plane.normal, planes[numplanes]);
+ numplanes++;
+
+ //
+ // modify original_velocity so it parallels all of the clip planes
+ //
+
+ for (i = 0; i < numplanes; i++) {
+ PMove.PM_ClipVelocity(PMove.pml.velocity, planes[i],
+ PMove.pml.velocity, 1.01f);
+ for (j = 0; j < numplanes; j++)
+ if (j != i) {
+ if (Math3D.DotProduct(PMove.pml.velocity, planes[j]) < 0)
+ break; // not ok
+ }
+ if (j == numplanes)
+ break;
+ }
+
+ if (i != numplanes) { // go along this plane
+ } else { // go along the crease
+ if (numplanes != 2) {
+ // Con_Printf ("clip velocity, numplanes ==
+ // %i\n",numplanes);
+ Math3D.VectorCopy(Globals.vec3_origin, PMove.pml.velocity);
+ break;
+ }
+ Math3D.CrossProduct(planes[0], planes[1], dir);
+ d = Math3D.DotProduct(dir, PMove.pml.velocity);
+ Math3D.VectorScale(dir, d, PMove.pml.velocity);
+ }
+
+ //
+ // if velocity is against the original velocity, stop dead
+ // to avoid tiny occilations in sloping corners
+ //
+ if (Math3D.DotProduct(PMove.pml.velocity, primal_velocity) <= 0) {
+ Math3D.VectorCopy(Globals.vec3_origin, PMove.pml.velocity);
+ break;
+ }
+ }
+
+ if (PMove.pm.s.pm_time != 0) {
+ Math3D.VectorCopy(primal_velocity, PMove.pml.velocity);
+ }
+ }
+
+ /*
+ * ================== PM_StepSlideMove
+ *
+ * ==================
+ */
+ public static void PM_StepSlideMove() {
+ float[] start_o = { 0, 0, 0 }, start_v = { 0, 0, 0 };
+ float[] down_o = { 0, 0, 0 }, down_v = { 0, 0, 0 };
+ trace_t trace;
+ float down_dist, up_dist;
+ // float [] delta;
+ float[] up = { 0, 0, 0 }, down = { 0, 0, 0 };
+
+ Math3D.VectorCopy(PMove.pml.origin, start_o);
+ Math3D.VectorCopy(PMove.pml.velocity, start_v);
+
+ PM_StepSlideMove_();
+
+ Math3D.VectorCopy(PMove.pml.origin, down_o);
+ Math3D.VectorCopy(PMove.pml.velocity, down_v);
+
+ Math3D.VectorCopy(start_o, up);
+ up[2] += Defines.STEPSIZE;
+
+ trace = PMove.pm.trace.trace(up, PMove.pm.mins, PMove.pm.maxs, up);
+ if (trace.allsolid)
+ return; // can't step up
+
+ // try sliding above
+ Math3D.VectorCopy(up, PMove.pml.origin);
+ Math3D.VectorCopy(start_v, PMove.pml.velocity);
+
+ PM_StepSlideMove_();
+
+ // push down the final amount
+ Math3D.VectorCopy(PMove.pml.origin, down);
+ down[2] -= Defines.STEPSIZE;
+ trace = PMove.pm.trace.trace(PMove.pml.origin, PMove.pm.mins,
+ PMove.pm.maxs, down);
+ if (!trace.allsolid) {
+ Math3D.VectorCopy(trace.endpos, PMove.pml.origin);
+ }
+
+ Math3D.VectorCopy(PMove.pml.origin, up);
+
+ // decide which one went farther
+ down_dist = (down_o[0] - start_o[0]) * (down_o[0] - start_o[0])
+ + (down_o[1] - start_o[1]) * (down_o[1] - start_o[1]);
+ up_dist = (up[0] - start_o[0]) * (up[0] - start_o[0])
+ + (up[1] - start_o[1]) * (up[1] - start_o[1]);
+
+ if (down_dist > up_dist
+ || trace.plane.normal[2] < Defines.MIN_STEP_NORMAL) {
+ Math3D.VectorCopy(down_o, PMove.pml.origin);
+ Math3D.VectorCopy(down_v, PMove.pml.velocity);
+ return;
+ }
+ //!! Special case
+ // if we were walking along a plane, then we need to copy the Z over
+ PMove.pml.velocity[2] = down_v[2];
+ }
+
+ /*
+ * ================== PM_Friction
+ *
+ * Handles both ground friction and water friction ==================
+ */
+ public static void PM_Friction() {
+ float vel[];
+ float speed, newspeed, control;
+ float friction;
+ float drop;
+
+ vel = PMove.pml.velocity;
+
+ speed = (float) (Math.sqrt(vel[0] * vel[0] + vel[1] * vel[1] + vel[2]
+ * vel[2]));
+ if (speed < 1) {
+ vel[0] = 0;
+ vel[1] = 0;
+ return;
+ }
+
+ drop = 0;
+
+ // apply ground friction
+ if ((PMove.pm.groundentity != null && PMove.pml.groundsurface != null && 0 == (PMove.pml.groundsurface.flags & Defines.SURF_SLICK))
+ || (PMove.pml.ladder)) {
+ friction = PMove.pm_friction;
+ control = speed < PMove.pm_stopspeed ? PMove.pm_stopspeed : speed;
+ drop += control * friction * PMove.pml.frametime;
+ }
+
+ // apply water friction
+ if (PMove.pm.waterlevel != 0 && !PMove.pml.ladder)
+ drop += speed * PMove.pm_waterfriction * PMove.pm.waterlevel
+ * PMove.pml.frametime;
+
+ // scale the velocity
+ newspeed = speed - drop;
+ if (newspeed < 0) {
+ newspeed = 0;
+ }
+ newspeed /= speed;
+
+ vel[0] = vel[0] * newspeed;
+ vel[1] = vel[1] * newspeed;
+ vel[2] = vel[2] * newspeed;
+ }
+
+ /*
+ * ============== PM_Accelerate
+ *
+ * Handles user intended acceleration ==============
+ */
+ public static void PM_Accelerate(float[] wishdir, float wishspeed,
+ float accel) {
+ int i;
+ float addspeed, accelspeed, currentspeed;
+
+ currentspeed = Math3D.DotProduct(PMove.pml.velocity, wishdir);
+ addspeed = wishspeed - currentspeed;
+ if (addspeed <= 0)
+ return;
+ accelspeed = accel * PMove.pml.frametime * wishspeed;
+ if (accelspeed > addspeed)
+ accelspeed = addspeed;
+
+ for (i = 0; i < 3; i++)
+ PMove.pml.velocity[i] += accelspeed * wishdir[i];
+ }
+
+ public static void PM_AirAccelerate(float[] wishdir, float wishspeed,
+ float accel) {
+ int i;
+ float addspeed, accelspeed, currentspeed, wishspd = wishspeed;
+
+ if (wishspd > 30)
+ wishspd = 30;
+ currentspeed = Math3D.DotProduct(PMove.pml.velocity, wishdir);
+ addspeed = wishspd - currentspeed;
+ if (addspeed <= 0)
+ return;
+ accelspeed = accel * wishspeed * PMove.pml.frametime;
+ if (accelspeed > addspeed)
+ accelspeed = addspeed;
+
+ for (i = 0; i < 3; i++)
+ PMove.pml.velocity[i] += accelspeed * wishdir[i];
+ }
+
+ /*
+ * ============= PM_AddCurrents =============
+ */
+ public static void PM_AddCurrents(float[] wishvel) {
+ float[] v = { 0, 0, 0 };
+ float s;
+
+ //
+ // account for ladders
+ //
+
+ if (PMove.pml.ladder && Math.abs(PMove.pml.velocity[2]) <= 200) {
+ if ((PMove.pm.viewangles[Defines.PITCH] <= -15)
+ && (PMove.pm.cmd.forwardmove > 0))
+ wishvel[2] = 200;
+ else if ((PMove.pm.viewangles[Defines.PITCH] >= 15)
+ && (PMove.pm.cmd.forwardmove > 0))
+ wishvel[2] = -200;
+ else if (PMove.pm.cmd.upmove > 0)
+ wishvel[2] = 200;
+ else if (PMove.pm.cmd.upmove < 0)
+ wishvel[2] = -200;
+ else
+ wishvel[2] = 0;
+
+ // limit horizontal speed when on a ladder
+ if (wishvel[0] < -25)
+ wishvel[0] = -25;
+ else if (wishvel[0] > 25)
+ wishvel[0] = 25;
+
+ if (wishvel[1] < -25)
+ wishvel[1] = -25;
+ else if (wishvel[1] > 25)
+ wishvel[1] = 25;
+ }
+
+ //
+ // add water currents
+ //
+
+ if ((PMove.pm.watertype & Defines.MASK_CURRENT) != 0) {
+ Math3D.VectorClear(v);
+
+ if ((PMove.pm.watertype & Defines.CONTENTS_CURRENT_0) != 0)
+ v[0] += 1;
+ if ((PMove.pm.watertype & Defines.CONTENTS_CURRENT_90) != 0)
+ v[1] += 1;
+ if ((PMove.pm.watertype & Defines.CONTENTS_CURRENT_180) != 0)
+ v[0] -= 1;
+ if ((PMove.pm.watertype & Defines.CONTENTS_CURRENT_270) != 0)
+ v[1] -= 1;
+ if ((PMove.pm.watertype & Defines.CONTENTS_CURRENT_UP) != 0)
+ v[2] += 1;
+ if ((PMove.pm.watertype & Defines.CONTENTS_CURRENT_DOWN) != 0)
+ v[2] -= 1;
+
+ s = PMove.pm_waterspeed;
+ if ((PMove.pm.waterlevel == 1) && (PMove.pm.groundentity != null))
+ s /= 2;
+
+ Math3D.VectorMA(wishvel, s, v, wishvel);
+ }
+
+ //
+ // add conveyor belt velocities
+ //
+
+ if (PMove.pm.groundentity != null) {
+ Math3D.VectorClear(v);
+
+ if ((PMove.pml.groundcontents & Defines.CONTENTS_CURRENT_0) != 0)
+ v[0] += 1;
+ if ((PMove.pml.groundcontents & Defines.CONTENTS_CURRENT_90) != 0)
+ v[1] += 1;
+ if ((PMove.pml.groundcontents & Defines.CONTENTS_CURRENT_180) != 0)
+ v[0] -= 1;
+ if ((PMove.pml.groundcontents & Defines.CONTENTS_CURRENT_270) != 0)
+ v[1] -= 1;
+ if ((PMove.pml.groundcontents & Defines.CONTENTS_CURRENT_UP) != 0)
+ v[2] += 1;
+ if ((PMove.pml.groundcontents & Defines.CONTENTS_CURRENT_DOWN) != 0)
+ v[2] -= 1;
+
+ Math3D.VectorMA(wishvel, 100 /* pm.groundentity.speed */
+ , v, wishvel);
+ }
+ }
+
+ /*
+ * =================== PM_WaterMove
+ *
+ * ===================
+ */
+ public static void PM_WaterMove() {
+ int i;
+ float[] wishvel = { 0, 0, 0 };
+ float wishspeed;
+ float[] wishdir = { 0, 0, 0 };
+
+ //
+ // user intentions
+ //
+ for (i = 0; i < 3; i++)
+ wishvel[i] = PMove.pml.forward[i] * PMove.pm.cmd.forwardmove
+ + PMove.pml.right[i] * PMove.pm.cmd.sidemove;
+
+ if (0 == PMove.pm.cmd.forwardmove && 0 == PMove.pm.cmd.sidemove
+ && 0 == PMove.pm.cmd.upmove)
+ wishvel[2] -= 60; // drift towards bottom
+ else
+ wishvel[2] += PMove.pm.cmd.upmove;
+
+ PM_AddCurrents(wishvel);
+
+ Math3D.VectorCopy(wishvel, wishdir);
+ wishspeed = Math3D.VectorNormalize(wishdir);
+
+ if (wishspeed > PMove.pm_maxspeed) {
+ Math3D.VectorScale(wishvel, PMove.pm_maxspeed / wishspeed, wishvel);
+ wishspeed = PMove.pm_maxspeed;
+ }
+ wishspeed *= 0.5;
+
+ PM_Accelerate(wishdir, wishspeed, PMove.pm_wateraccelerate);
+
+ PM_StepSlideMove();
+ }
+
+ /*
+ * =================== PM_AirMove
+ *
+ * ===================
+ */
+ public static void PM_AirMove() {
+ int i;
+ float[] wishvel = { 0, 0, 0 };
+ float fmove, smove;
+ float[] wishdir = { 0, 0, 0 };
+ float wishspeed;
+ float maxspeed;
+
+ fmove = PMove.pm.cmd.forwardmove;
+ smove = PMove.pm.cmd.sidemove;
+
+ for (i = 0; i < 2; i++)
+ wishvel[i] = PMove.pml.forward[i] * fmove + PMove.pml.right[i]
+ * smove;
+ wishvel[2] = 0;
+
+ PM_AddCurrents(wishvel);
+
+ Math3D.VectorCopy(wishvel, wishdir);
+ wishspeed = Math3D.VectorNormalize(wishdir);
+
+ //
+ // clamp to server defined max speed
+ //
+ maxspeed = (PMove.pm.s.pm_flags & pmove_t.PMF_DUCKED) != 0 ? PMove.pm_duckspeed
+ : PMove.pm_maxspeed;
+
+ if (wishspeed > maxspeed) {
+ Math3D.VectorScale(wishvel, maxspeed / wishspeed, wishvel);
+ wishspeed = maxspeed;
+ }
+
+ if (PMove.pml.ladder) {
+ PM_Accelerate(wishdir, wishspeed, PMove.pm_accelerate);
+ if (0 == wishvel[2]) {
+ if (PMove.pml.velocity[2] > 0) {
+ PMove.pml.velocity[2] -= PMove.pm.s.gravity
+ * PMove.pml.frametime;
+ if (PMove.pml.velocity[2] < 0)
+ PMove.pml.velocity[2] = 0;
+ } else {
+ PMove.pml.velocity[2] += PMove.pm.s.gravity
+ * PMove.pml.frametime;
+ if (PMove.pml.velocity[2] > 0)
+ PMove.pml.velocity[2] = 0;
+ }
+ }
+ PM_StepSlideMove();
+ } else if (PMove.pm.groundentity != null) { // walking on ground
+ PMove.pml.velocity[2] = 0; //!!! this is before the accel
+ PM_Accelerate(wishdir, wishspeed, PMove.pm_accelerate);
+
+ // PGM -- fix for negative trigger_gravity fields
+ // pml.velocity[2] = 0;
+ if (PMove.pm.s.gravity > 0)
+ PMove.pml.velocity[2] = 0;
+ else
+ PMove.pml.velocity[2] -= PMove.pm.s.gravity
+ * PMove.pml.frametime;
+ // PGM
+
+ if (0 == PMove.pml.velocity[0] && 0 == PMove.pml.velocity[1])
+ return;
+ PM_StepSlideMove();
+ } else { // not on ground, so little effect on velocity
+ if (PMove.pm_airaccelerate != 0)
+ PM_AirAccelerate(wishdir, wishspeed, PMove.pm_accelerate);
+ else
+ PM_Accelerate(wishdir, wishspeed, 1);
+ // add gravity
+ PMove.pml.velocity[2] -= PMove.pm.s.gravity * PMove.pml.frametime;
+ PM_StepSlideMove();
+ }
+ }
+
+ /*
+ * ============= PM_CatagorizePosition =============
+ */
+ public static void PM_CatagorizePosition() {
+ float[] point = { 0, 0, 0 };
+ int cont;
+ trace_t trace;
+ int sample1;
+ int sample2;
+
+ // if the player hull point one unit down is solid, the player
+ // is on ground
+
+ // see if standing on something solid
+ point[0] = PMove.pml.origin[0];
+ point[1] = PMove.pml.origin[1];
+ point[2] = PMove.pml.origin[2] - 0.25f;
+ if (PMove.pml.velocity[2] > 180) //!!ZOID changed from 100 to 180 (ramp
+ // accel)
+ {
+ PMove.pm.s.pm_flags &= ~pmove_t.PMF_ON_GROUND;
+ PMove.pm.groundentity = null;
+ } else {
+ trace = PMove.pm.trace.trace(PMove.pml.origin, PMove.pm.mins,
+ PMove.pm.maxs, point);
+ PMove.pml.groundplane = trace.plane;
+ PMove.pml.groundsurface = trace.surface;
+ PMove.pml.groundcontents = trace.contents;
+
+ if (null == trace.ent
+ || (trace.plane.normal[2] < 0.7 && !trace.startsolid)) {
+ PMove.pm.groundentity = null;
+ PMove.pm.s.pm_flags &= ~pmove_t.PMF_ON_GROUND;
+ } else {
+ PMove.pm.groundentity = trace.ent;
+ // hitting solid ground will end a waterjump
+ if ((PMove.pm.s.pm_flags & pmove_t.PMF_TIME_WATERJUMP) != 0) {
+ PMove.pm.s.pm_flags &= ~(pmove_t.PMF_TIME_WATERJUMP
+ | pmove_t.PMF_TIME_LAND | pmove_t.PMF_TIME_TELEPORT);
+ PMove.pm.s.pm_time = 0;
+ }
+
+ if (0 == (PMove.pm.s.pm_flags & pmove_t.PMF_ON_GROUND)) { // just
+ // hit
+ // the
+ // ground
+ PMove.pm.s.pm_flags |= pmove_t.PMF_ON_GROUND;
+ // don't do landing time if we were just going down a slope
+ if (PMove.pml.velocity[2] < -200) {
+ PMove.pm.s.pm_flags |= pmove_t.PMF_TIME_LAND;
+ // don't allow another jump for a little while
+ if (PMove.pml.velocity[2] < -400)
+ PMove.pm.s.pm_time = 25;
+ else
+ PMove.pm.s.pm_time = 18;
+ }
+ }
+ }
+
+ if (PMove.pm.numtouch < Defines.MAXTOUCH && trace.ent != null) {
+ PMove.pm.touchents[PMove.pm.numtouch] = trace.ent;
+ PMove.pm.numtouch++;
+ }
+ }
+
+ //
+ // get waterlevel, accounting for ducking
+ //
+ PMove.pm.waterlevel = 0;
+ PMove.pm.watertype = 0;
+
+ sample2 = (int) (PMove.pm.viewheight - PMove.pm.mins[2]);
+ sample1 = sample2 / 2;
+
+ point[2] = PMove.pml.origin[2] + PMove.pm.mins[2] + 1;
+ cont = PMove.pm.pointcontents.pointcontents(point);
+
+ if ((cont & Defines.MASK_WATER) != 0) {
+ PMove.pm.watertype = cont;
+ PMove.pm.waterlevel = 1;
+ point[2] = PMove.pml.origin[2] + PMove.pm.mins[2] + sample1;
+ cont = PMove.pm.pointcontents.pointcontents(point);
+ if ((cont & Defines.MASK_WATER) != 0) {
+ PMove.pm.waterlevel = 2;
+ point[2] = PMove.pml.origin[2] + PMove.pm.mins[2] + sample2;
+ cont = PMove.pm.pointcontents.pointcontents(point);
+ if ((cont & Defines.MASK_WATER) != 0)
+ PMove.pm.waterlevel = 3;
+ }
+ }
+
+ }
+
+ /*
+ * ============= PM_CheckJump =============
+ */
+ public static void PM_CheckJump() {
+ if ((PMove.pm.s.pm_flags & pmove_t.PMF_TIME_LAND) != 0) {
+ // hasn't been long enough since landing to jump again
+ return;
+ }
+
+ if (PMove.pm.cmd.upmove < 10) { // not holding jump
+ PMove.pm.s.pm_flags &= ~pmove_t.PMF_JUMP_HELD;
+ return;
+ }
+
+ // must wait for jump to be released
+ if ((PMove.pm.s.pm_flags & pmove_t.PMF_JUMP_HELD) != 0)
+ return;
+
+ if (PMove.pm.s.pm_type == Defines.PM_DEAD)
+ return;
+
+ if (PMove.pm.waterlevel >= 2) { // swimming, not jumping
+ PMove.pm.groundentity = null;
+
+ if (PMove.pml.velocity[2] <= -300)
+ return;
+
+ if (PMove.pm.watertype == Defines.CONTENTS_WATER)
+ PMove.pml.velocity[2] = 100;
+ else if (PMove.pm.watertype == Defines.CONTENTS_SLIME)
+ PMove.pml.velocity[2] = 80;
+ else
+ PMove.pml.velocity[2] = 50;
+ return;
+ }
+
+ if (PMove.pm.groundentity == null)
+ return; // in air, so no effect
+
+ PMove.pm.s.pm_flags |= pmove_t.PMF_JUMP_HELD;
+
+ PMove.pm.groundentity = null;
+ PMove.pml.velocity[2] += 270;
+ if (PMove.pml.velocity[2] < 270)
+ PMove.pml.velocity[2] = 270;
+ }
+
+ /*
+ * ============= PM_CheckSpecialMovement =============
+ */
+ public static void PM_CheckSpecialMovement() {
+ float[] spot = { 0, 0, 0 };
+ int cont;
+ float[] flatforward = { 0, 0, 0 };
+ trace_t trace;
+
+ if (PMove.pm.s.pm_time != 0)
+ return;
+
+ PMove.pml.ladder = false;
+
+ // check for ladder
+ flatforward[0] = PMove.pml.forward[0];
+ flatforward[1] = PMove.pml.forward[1];
+ flatforward[2] = 0;
+ Math3D.VectorNormalize(flatforward);
+
+ Math3D.VectorMA(PMove.pml.origin, 1, flatforward, spot);
+ trace = PMove.pm.trace.trace(PMove.pml.origin, PMove.pm.mins,
+ PMove.pm.maxs, spot);
+ if ((trace.fraction < 1)
+ && (trace.contents & Defines.CONTENTS_LADDER) != 0)
+ PMove.pml.ladder = true;
+
+ // check for water jump
+ if (PMove.pm.waterlevel != 2)
+ return;
+
+ Math3D.VectorMA(PMove.pml.origin, 30, flatforward, spot);
+ spot[2] += 4;
+ cont = PMove.pm.pointcontents.pointcontents(spot);
+ if (0 == (cont & Defines.CONTENTS_SOLID))
+ return;
+
+ spot[2] += 16;
+ cont = PMove.pm.pointcontents.pointcontents(spot);
+ if (cont != 0)
+ return;
+ // jump out of water
+ Math3D.VectorScale(flatforward, 50, PMove.pml.velocity);
+ PMove.pml.velocity[2] = 350;
+
+ PMove.pm.s.pm_flags |= pmove_t.PMF_TIME_WATERJUMP;
+ PMove.pm.s.pm_time = -1; // was 255
+ }
+
+ /*
+ * =============== PM_FlyMove ===============
+ */
+ public static void PM_FlyMove(boolean doclip) {
+ float speed, drop, friction, control, newspeed;
+ float currentspeed, addspeed, accelspeed;
+ int i;
+ float[] wishvel = { 0, 0, 0 };
+ float fmove, smove;
+ float[] wishdir = { 0, 0, 0 };
+ float wishspeed;
+ float[] end = { 0, 0, 0 };
+ trace_t trace;
+
+ PMove.pm.viewheight = 22;
+
+ // friction
+
+ speed = Math3D.VectorLength(PMove.pml.velocity);
+ if (speed < 1) {
+ Math3D.VectorCopy(Globals.vec3_origin, PMove.pml.velocity);
+ } else {
+ drop = 0;
+
+ friction = PMove.pm_friction * 1.5f; // extra friction
+ control = speed < PMove.pm_stopspeed ? PMove.pm_stopspeed : speed;
+ drop += control * friction * PMove.pml.frametime;
+
+ // scale the velocity
+ newspeed = speed - drop;
+ if (newspeed < 0)
+ newspeed = 0;
+ newspeed /= speed;
+
+ Math3D
+ .VectorScale(PMove.pml.velocity, newspeed,
+ PMove.pml.velocity);
+ }
+
+ // accelerate
+ fmove = PMove.pm.cmd.forwardmove;
+ smove = PMove.pm.cmd.sidemove;
+
+ Math3D.VectorNormalize(PMove.pml.forward);
+ Math3D.VectorNormalize(PMove.pml.right);
+
+ for (i = 0; i < 3; i++)
+ wishvel[i] = PMove.pml.forward[i] * fmove + PMove.pml.right[i]
+ * smove;
+ wishvel[2] += PMove.pm.cmd.upmove;
+
+ Math3D.VectorCopy(wishvel, wishdir);
+ wishspeed = Math3D.VectorNormalize(wishdir);
+
+ //
+ // clamp to server defined max speed
+ //
+ if (wishspeed > PMove.pm_maxspeed) {
+ Math3D.VectorScale(wishvel, PMove.pm_maxspeed / wishspeed, wishvel);
+ wishspeed = PMove.pm_maxspeed;
+ }
+
+ currentspeed = Math3D.DotProduct(PMove.pml.velocity, wishdir);
+ addspeed = wishspeed - currentspeed;
+ if (addspeed <= 0)
+ return;
+ accelspeed = PMove.pm_accelerate * PMove.pml.frametime * wishspeed;
+ if (accelspeed > addspeed)
+ accelspeed = addspeed;
+
+ for (i = 0; i < 3; i++)
+ PMove.pml.velocity[i] += accelspeed * wishdir[i];
+
+ if (doclip) {
+ for (i = 0; i < 3; i++)
+ end[i] = PMove.pml.origin[i] + PMove.pml.frametime
+ * PMove.pml.velocity[i];
+
+ trace = PMove.pm.trace.trace(PMove.pml.origin, PMove.pm.mins,
+ PMove.pm.maxs, end);
+
+ Math3D.VectorCopy(trace.endpos, PMove.pml.origin);
+ } else {
+ // move
+ Math3D.VectorMA(PMove.pml.origin, PMove.pml.frametime,
+ PMove.pml.velocity, PMove.pml.origin);
+ }
+ }
+
+ /*
+ * ============== PM_CheckDuck
+ *
+ * Sets mins, maxs, and pm.viewheight ==============
+ */
+ public static void PM_CheckDuck() {
+ trace_t trace;
+
+ PMove.pm.mins[0] = -16;
+ PMove.pm.mins[1] = -16;
+
+ PMove.pm.maxs[0] = 16;
+ PMove.pm.maxs[1] = 16;
+
+ if (PMove.pm.s.pm_type == Defines.PM_GIB) {
+ PMove.pm.mins[2] = 0;
+ PMove.pm.maxs[2] = 16;
+ PMove.pm.viewheight = 8;
+ return;
+ }
+
+ PMove.pm.mins[2] = -24;
+
+ if (PMove.pm.s.pm_type == Defines.PM_DEAD) {
+ PMove.pm.s.pm_flags |= pmove_t.PMF_DUCKED;
+ } else if (PMove.pm.cmd.upmove < 0
+ && (PMove.pm.s.pm_flags & pmove_t.PMF_ON_GROUND) != 0) { // duck
+ PMove.pm.s.pm_flags |= pmove_t.PMF_DUCKED;
+ } else { // stand up if possible
+ if ((PMove.pm.s.pm_flags & pmove_t.PMF_DUCKED) != 0) {
+ // try to stand up
+ PMove.pm.maxs[2] = 32;
+ trace = PMove.pm.trace.trace(PMove.pml.origin, PMove.pm.mins,
+ PMove.pm.maxs, PMove.pml.origin);
+ if (!trace.allsolid)
+ PMove.pm.s.pm_flags &= ~pmove_t.PMF_DUCKED;
+ }
+ }
+
+ if ((PMove.pm.s.pm_flags & pmove_t.PMF_DUCKED) != 0) {
+ PMove.pm.maxs[2] = 4;
+ PMove.pm.viewheight = -2;
+ } else {
+ PMove.pm.maxs[2] = 32;
+ PMove.pm.viewheight = 22;
+ }
+ }
+
+ /*
+ * ============== PM_DeadMove ==============
+ */
+ public static void PM_DeadMove() {
+ float forward;
+
+ if (null == PMove.pm.groundentity)
+ return;
+
+ // extra friction
+
+ forward = Math3D.VectorLength(PMove.pml.velocity);
+ forward -= 20;
+ if (forward <= 0) {
+ Math3D.VectorClear(PMove.pml.velocity);
+ } else {
+ Math3D.VectorNormalize(PMove.pml.velocity);
+ Math3D.VectorScale(PMove.pml.velocity, forward, PMove.pml.velocity);
+ }
+ }
+
+ public static boolean PM_GoodPosition() {
+ trace_t trace;
+ float[] origin = { 0, 0, 0 }, end = { 0, 0, 0 };
+ int i;
+
+ if (PMove.pm.s.pm_type == Defines.PM_SPECTATOR)
+ return true;
+
+ for (i = 0; i < 3; i++)
+ origin[i] = end[i] = PMove.pm.s.origin[i] * 0.125f;
+ trace = PMove.pm.trace.trace(origin, PMove.pm.mins, PMove.pm.maxs, end);
+
+ return !trace.allsolid;
+ }
+
+ public static void PM_SnapPosition() {
+ int sign[] = { 0, 0, 0 };
+ int i, j, bits;
+ short base[] = { 0, 0, 0 };
+
+ // snap velocity to eigths
+ for (i = 0; i < 3; i++)
+ PMove.pm.s.velocity[i] = (short) (PMove.pml.velocity[i] * 8);
+
+ for (i = 0; i < 3; i++) {
+ if (PMove.pml.origin[i] >= 0)
+ sign[i] = 1;
+ else
+ sign[i] = -1;
+ PMove.pm.s.origin[i] = (short) (PMove.pml.origin[i] * 8);
+ if (PMove.pm.s.origin[i] * 0.125 == PMove.pml.origin[i])
+ sign[i] = 0;
+ }
+ Math3D.VectorCopy(PMove.pm.s.origin, base);
+
+ // try all combinations
+ for (j = 0; j < 8; j++) {
+ bits = jitterbits[j];
+ Math3D.VectorCopy(base, PMove.pm.s.origin);
+ for (i = 0; i < 3; i++)
+ if ((bits & (1 << i)) != 0)
+ PMove.pm.s.origin[i] += sign[i];
+
+ if (PMove.PM_GoodPosition())
+ return;
+ }
+
+ // go back to the last position
+ Math3D.VectorCopy(PMove.pml.previous_origin, PMove.pm.s.origin);
+ // Com_DPrintf ("using previous_origin\n");
+ }
+
+ public static void PM_InitialSnapPosition() {
+ int x, y, z;
+ short base[] = { 0, 0, 0 };
+
+ Math3D.VectorCopy(PMove.pm.s.origin, base);
+
+ for (z = 0; z < 3; z++) {
+ PMove.pm.s.origin[2] = (short) (base[2] + offset[z]);
+ for (y = 0; y < 3; y++) {
+ PMove.pm.s.origin[1] = (short) (base[1] + offset[y]);
+ for (x = 0; x < 3; x++) {
+ PMove.pm.s.origin[0] = (short) (base[0] + offset[x]);
+ if (PMove.PM_GoodPosition()) {
+ PMove.pml.origin[0] = PMove.pm.s.origin[0] * 0.125f;
+ PMove.pml.origin[1] = PMove.pm.s.origin[1] * 0.125f;
+ PMove.pml.origin[2] = PMove.pm.s.origin[2] * 0.125f;
+ Math3D.VectorCopy(PMove.pm.s.origin,
+ PMove.pml.previous_origin);
+ return;
+ }
+ }
+ }
+ }
+
+ Com.DPrintf("Bad InitialSnapPosition\n");
+ }
+
+ /*
+ * ================ PM_ClampAngles
+ *
+ * ================
+ */
+ public static void PM_ClampAngles() {
+ short temp;
+ int i;
+
+ if ((PMove.pm.s.pm_flags & pmove_t.PMF_TIME_TELEPORT) != 0) {
+ PMove.pm.viewangles[Defines.YAW] = Math3D
+ .SHORT2ANGLE(PMove.pm.cmd.angles[Defines.YAW]
+ + PMove.pm.s.delta_angles[Defines.YAW]);
+ PMove.pm.viewangles[Defines.PITCH] = 0;
+ PMove.pm.viewangles[Defines.ROLL] = 0;
+ } else {
+ // circularly clamp the angles with deltas
+ for (i = 0; i < 3; i++) {
+ temp = (short) (PMove.pm.cmd.angles[i] + PMove.pm.s.delta_angles[i]);
+ PMove.pm.viewangles[i] = Math3D.SHORT2ANGLE(temp);
+ }
+
+ // don't let the player look up or down more than 90 degrees
+ if (PMove.pm.viewangles[Defines.PITCH] > 89
+ && PMove.pm.viewangles[Defines.PITCH] < 180)
+ PMove.pm.viewangles[Defines.PITCH] = 89;
+ else if (PMove.pm.viewangles[Defines.PITCH] < 271
+ && PMove.pm.viewangles[Defines.PITCH] >= 180)
+ PMove.pm.viewangles[Defines.PITCH] = 271;
+ }
+ Math3D.AngleVectors(PMove.pm.viewangles, PMove.pml.forward,
+ PMove.pml.right, PMove.pml.up);
+ }
+
+ /*
+ * ================ Pmove
+ *
+ * Can be called by either the server or the client ================
+ */
+ public static void Pmove(pmove_t pmove) {
+ PMove.pm = pmove;
+
+ // clear results
+ PMove.pm.numtouch = 0;
+ Math3D.VectorClear(PMove.pm.viewangles);
+ PMove.pm.viewheight = 0;
+ PMove.pm.groundentity = null;
+ PMove.pm.watertype = 0;
+ PMove.pm.waterlevel = 0;
+
+ // clear all pmove local vars
+ PMove.pml = new PMove.pml_t();
+
+ // convert origin and velocity to float values
+ PMove.pml.origin[0] = PMove.pm.s.origin[0] * 0.125f;
+ PMove.pml.origin[1] = PMove.pm.s.origin[1] * 0.125f;
+ PMove.pml.origin[2] = PMove.pm.s.origin[2] * 0.125f;
+
+ PMove.pml.velocity[0] = PMove.pm.s.velocity[0] * 0.125f;
+ PMove.pml.velocity[1] = PMove.pm.s.velocity[1] * 0.125f;
+ PMove.pml.velocity[2] = PMove.pm.s.velocity[2] * 0.125f;
+
+ // save old org in case we get stuck
+ Math3D.VectorCopy(PMove.pm.s.origin, PMove.pml.previous_origin);
+
+ PMove.pml.frametime = (PMove.pm.cmd.msec & 0xFF) * 0.001f;
+
+ PM_ClampAngles();
+
+ if (PMove.pm.s.pm_type == Defines.PM_SPECTATOR) {
+ PMove.PM_FlyMove(false);
+ PM_SnapPosition();
+ return;
+ }
+
+ if (PMove.pm.s.pm_type >= Defines.PM_DEAD) {
+ PMove.pm.cmd.forwardmove = 0;
+ PMove.pm.cmd.sidemove = 0;
+ PMove.pm.cmd.upmove = 0;
+ }
+
+ if (PMove.pm.s.pm_type == Defines.PM_FREEZE)
+ return; // no movement at all
+
+ // set mins, maxs, and viewheight
+ PMove.PM_CheckDuck();
+
+ if (PMove.pm.snapinitial)
+ PM_InitialSnapPosition();
+
+ // set groundentity, watertype, and waterlevel
+ PMove.PM_CatagorizePosition();
+
+ if (PMove.pm.s.pm_type == Defines.PM_DEAD)
+ PMove.PM_DeadMove();
+
+ PMove.PM_CheckSpecialMovement();
+
+ // drop timing counter
+ if (PMove.pm.s.pm_time != 0) {
+ int msec;
+
+ // TOD o bugfix cwei
+ msec = PMove.pm.cmd.msec >>> 3;
+ if (msec == 0)
+ msec = 1;
+ if (msec >= (PMove.pm.s.pm_time & 0xFF)) {
+ PMove.pm.s.pm_flags &= ~(pmove_t.PMF_TIME_WATERJUMP
+ | pmove_t.PMF_TIME_LAND | pmove_t.PMF_TIME_TELEPORT);
+ PMove.pm.s.pm_time = 0;
+ } else
+ PMove.pm.s.pm_time = (byte) ((PMove.pm.s.pm_time & 0xFF) - msec);
+ }
+
+ if ((PMove.pm.s.pm_flags & pmove_t.PMF_TIME_TELEPORT) != 0) { // teleport
+ // pause
+ // stays
+ // exactly
+ // in
+ // place
+ } else if ((PMove.pm.s.pm_flags & pmove_t.PMF_TIME_WATERJUMP) != 0) { // waterjump
+ // has
+ // no
+ // control,
+ // but
+ // falls
+ PMove.pml.velocity[2] -= PMove.pm.s.gravity * PMove.pml.frametime;
+ if (PMove.pml.velocity[2] < 0) { // cancel as soon as we are falling
+ // down again
+ PMove.pm.s.pm_flags &= ~(pmove_t.PMF_TIME_WATERJUMP
+ | pmove_t.PMF_TIME_LAND | pmove_t.PMF_TIME_TELEPORT);
+ PMove.pm.s.pm_time = 0;
+ }
+
+ PMove.PM_StepSlideMove();
+ } else {
+ PMove.PM_CheckJump();
+
+ PMove.PM_Friction();
+
+ if (PMove.pm.waterlevel >= 2)
+ PMove.PM_WaterMove();
+ else {
+ float[] angles = { 0, 0, 0 };
+
+ Math3D.VectorCopy(PMove.pm.viewangles, angles);
+ if (angles[Defines.PITCH] > 180)
+ angles[Defines.PITCH] = angles[Defines.PITCH] - 360;
+ angles[Defines.PITCH] /= 3;
+
+ Math3D.AngleVectors(angles, PMove.pml.forward, PMove.pml.right,
+ PMove.pml.up);
+
+ PMove.PM_AirMove();
+ }
+ }
+
+ // set groundentity, watertype, and waterlevel for final spot
+ PMove.PM_CatagorizePosition();
+
+ PM_SnapPosition();
+ }
+} \ No newline at end of file
diff --git a/src/jake2/qcommon/Q2DataDialog.java b/src/jake2/qcommon/Q2DataDialog.java
index cb7dc62..d139000 100644
--- a/src/jake2/qcommon/Q2DataDialog.java
+++ b/src/jake2/qcommon/Q2DataDialog.java
@@ -1,427 +1,427 @@
-/*
- * Q2DataDialog.java
- *
- * Created on 17. September 2004, 20:13
- */
-
-package jake2.qcommon;
-
-import java.awt.*;
-import java.io.*;
-import java.net.URL;
-import java.net.URLConnection;
-import java.util.Enumeration;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-
-import javax.swing.*;
-
-/**
- *
- * @author hoz
- */
-public class Q2DataDialog extends javax.swing.JDialog {
-
- /** Creates new form Q2DataDialog */
- public Q2DataDialog() {
- super();
- initComponents();
-
- DisplayMode mode = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDisplayMode();
- int x = (mode.getWidth() - getWidth()) / 2;
- int y = (mode.getHeight() - getHeight()) / 2;
- setLocation(x, y);
- dir = System.getProperty("user.home") + "/jake2";
- jTextField1.setText(dir);
- }
-
- /** This method is called from within the constructor to
- * initialize the form.
- * WARNING: Do NOT modify this code. The content of this method is
- * always regenerated by the Form Editor.
- */
- private void initComponents() {//GEN-BEGIN:initComponents
- java.awt.GridBagConstraints gridBagConstraints;
-
- choosePanel = new javax.swing.JPanel();
- statusPanel = new JPanel();
- status = new JLabel("initializing Jake2...");
- jTextField1 = new javax.swing.JTextField();
- changeButton = new javax.swing.JButton();
- installButton = new javax.swing.JButton();
- exitButton = new javax.swing.JButton();
- okButton = new javax.swing.JButton();
-
- setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
- setTitle("Jake2 - Bytonic Software");
-
- setResizable(false);
- addWindowListener(new java.awt.event.WindowAdapter() {
- public void windowClosing(java.awt.event.WindowEvent evt) {
- formWindowClosing(evt);
- }
- });
-
- choosePanel.setLayout(new java.awt.GridBagLayout());
-
- choosePanel.setMaximumSize(new java.awt.Dimension(400, 100));
- choosePanel.setMinimumSize(new java.awt.Dimension(400, 100));
- choosePanel.setPreferredSize(new java.awt.Dimension(400, 100));
- jTextField1.setPreferredSize(null);
- gridBagConstraints = new java.awt.GridBagConstraints();
- gridBagConstraints.gridx = 0;
- gridBagConstraints.gridy = 0;
- gridBagConstraints.gridwidth = 2;
- gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
- gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10);
- gridBagConstraints.weightx = 1.0;
- choosePanel.add(jTextField1, gridBagConstraints);
-
- changeButton.setText("change");
- changeButton.addActionListener(new java.awt.event.ActionListener() {
- public void actionPerformed(java.awt.event.ActionEvent evt) {
- changeButtonActionPerformed(evt);
- }
- });
-
- gridBagConstraints = new java.awt.GridBagConstraints();
- gridBagConstraints.gridx = 2;
- gridBagConstraints.gridy = 0;
- gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10);
- gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
- choosePanel.add(changeButton, gridBagConstraints);
-
- installButton.setText("Install");
- installButton.addActionListener(new java.awt.event.ActionListener() {
- public void actionPerformed(java.awt.event.ActionEvent evt) {
- installButtonActionPerformed(evt);
- }
- });
-
- gridBagConstraints = new java.awt.GridBagConstraints();
- gridBagConstraints.gridx = 0;
- gridBagConstraints.gridy = 1;
- gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10);
- gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
- choosePanel.add(installButton, gridBagConstraints);
-
- exitButton.setText("Exit");
- exitButton.addActionListener(new java.awt.event.ActionListener() {
- public void actionPerformed(java.awt.event.ActionEvent evt) {
- exitButtonActionPerformed(evt);
- }
- });
-
- gridBagConstraints = new java.awt.GridBagConstraints();
- gridBagConstraints.gridx = 1;
- gridBagConstraints.gridy = 1;
- gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10);
- choosePanel.add(exitButton, gridBagConstraints);
-
- okButton.setText("OK");
- okButton.addActionListener(new java.awt.event.ActionListener() {
- public void actionPerformed(java.awt.event.ActionEvent evt) {
- okButtonActionPerformed(evt);
- }
- });
-
- gridBagConstraints = new java.awt.GridBagConstraints();
- gridBagConstraints.gridx = 2;
- gridBagConstraints.gridy = 1;
- gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10);
- gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
- choosePanel.add(okButton, gridBagConstraints);
-
- //getContentPane().add(choosePanel, java.awt.BorderLayout.SOUTH);
-
- Jake2Canvas c = new Jake2Canvas();
- getContentPane().add(c, BorderLayout.CENTER);
-
- statusPanel.setLayout(new java.awt.GridBagLayout());
- statusPanel.setMaximumSize(new java.awt.Dimension(400, 100));
- statusPanel.setMinimumSize(new java.awt.Dimension(400, 100));
- statusPanel.setPreferredSize(new java.awt.Dimension(400, 100));
- gridBagConstraints = new java.awt.GridBagConstraints();
- gridBagConstraints.gridx = 0;
- gridBagConstraints.gridy = 0;
- gridBagConstraints.gridwidth = 1;
- gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
- gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10);
- gridBagConstraints.weightx = 1.0;
- statusPanel.add(status, gridBagConstraints);
- getContentPane().add(statusPanel, java.awt.BorderLayout.SOUTH);
-
- installPanel = new InstallPanel(this);
-
- pack();
- }//GEN-END:initComponents
-
-
- private void installButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_installButtonActionPerformed
- dir = jTextField1.getText();
- showInstallPanel();
- installPanel.destDir = dir;
-
- dir += "/baseq2";
- jTextField1.setText(dir);
-
- new Thread(installPanel).start();
- }//GEN-LAST:event_installButtonActionPerformed
-
- private void exitButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exitButtonActionPerformed
- System.exit(1);
- dispose();
- }//GEN-LAST:event_exitButtonActionPerformed
-
- private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
-
- dir = jTextField1.getText();
- Cvar.Set("cddir", dir);
- FS.setCDDir();
-
- synchronized(this) {
- notifyAll();
- }
- }//GEN-LAST:event_okButtonActionPerformed
-
- private void changeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_changeButtonActionPerformed
- JFileChooser chooser = new JFileChooser();
- chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
- chooser.setDialogType(JFileChooser.CUSTOM_DIALOG);
- chooser.setMultiSelectionEnabled(false);
- chooser.setDialogTitle("choose a valid baseq2 directory");
- chooser.showDialog(this, "OK");
-
- dir = null;
- try {
- dir = chooser.getSelectedFile().getCanonicalPath();
- } catch (IOException e) {}
- jTextField1.setText(dir);
-
- }//GEN-LAST:event_changeButtonActionPerformed
-
- private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing
- System.exit(1);
- dispose();
- }//GEN-LAST:event_formWindowClosing
-
- // Variables declaration - do not modify//GEN-BEGIN:variables
- private javax.swing.JButton changeButton;
- private javax.swing.JButton exitButton;
- private javax.swing.JButton installButton;
- private Jake2Canvas canvas;
- private javax.swing.JPanel choosePanel;
- private JPanel statusPanel;
- private InstallPanel installPanel;
- private JLabel status;
- private javax.swing.JTextField jTextField1;
- private javax.swing.JButton okButton;
- // End of variables declaration//GEN-END:variables
-
- private String dir;
-
- void showChooseDialog() {
- getContentPane().remove(statusPanel);
- getContentPane().remove(installPanel);
- getContentPane().add(choosePanel, BorderLayout.SOUTH);
- validate();
- repaint();
- }
-
- void showStatus() {
- getContentPane().remove(choosePanel);
- getContentPane().add(statusPanel, BorderLayout.SOUTH);
- validate();
- repaint();
- }
-
- void showInstallPanel() {
- getContentPane().remove(choosePanel);
- getContentPane().add(installPanel, BorderLayout.SOUTH);
- validate();
- repaint();
- }
-
- void setStatus(String text) {
- status.setText(text);
- }
-
- void testQ2Data() {
- while (FS.LoadFile("pics/colormap.pcx") == null) {
- showChooseDialog();
-
- try {
- synchronized(this) {
- wait();
- }
- } catch (InterruptedException e) {}
- }
- showStatus();
- repaint();
- }
-
- static class Jake2Canvas extends Canvas {
- private Image image;
- Jake2Canvas() {
- setSize(400, 200);
- image = Toolkit.getDefaultToolkit().getImage(getClass().getResource("/splash.png"));
- while (!Toolkit.getDefaultToolkit().prepareImage(image, -1, -1, null)) {
- try {
- Thread.sleep(50);
- } catch (InterruptedException e) {}
- }
- }
-
-
- /* (non-Javadoc)
- * @see java.awt.Component#paint(java.awt.Graphics)
- */
- public void paint(Graphics g) {
- g.drawImage(image, 0, 0, null);
- }
-
- }
-
- static class InstallPanel extends JPanel implements Runnable {
-
- static final String[] locs = {
- "ftp://ftp.fu-berlin.de/pc/msdos/games/idgames/idstuff/quake2/q2-314-demo-x86.exe",
- "ftp://ftp.demon.co.uk/pub/mirrors/idsoftware/quake2/q2-314-demo-x86.exe",
- "ftp://ftp.fragzone.se/pub/spel/quake2/q2-314-demo-x86.exe",
- "ftp://ftp.idsoftware.com/idstuff/quake2/q2-314-demo-x86.exe" };
- static byte[] buf = new byte[8192];
- String destDir;
-
- JProgressBar progress = new JProgressBar();
- JLabel label = new JLabel("test");
- Q2DataDialog parent;
-
- public InstallPanel(Q2DataDialog d) {
- initComponents();
- parent = d;
- }
-
- void initComponents() {
- progress.setMinimum(0);
- progress.setMaximum(100);
- setLayout(new GridBagLayout());
- GridBagConstraints gridBagConstraints = new GridBagConstraints();
-
- gridBagConstraints = new java.awt.GridBagConstraints();
- gridBagConstraints.gridx = 0;
- gridBagConstraints.gridy = 0;
- gridBagConstraints.gridwidth = 1;
- gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
- gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10);
- gridBagConstraints.weightx = 1.0;
- gridBagConstraints.anchor = GridBagConstraints.SOUTH;
- add(label, gridBagConstraints);
- gridBagConstraints.gridy = 1;
- gridBagConstraints.anchor = GridBagConstraints.NORTH;
- add(progress, gridBagConstraints);
- Dimension d = new Dimension(400, 100);
- setMinimumSize(d);
- setMaximumSize(d);
- setPreferredSize(d);
- }
-
- public void run() {
-
- InputStream in = null;
- OutputStream out = null;
- File outFile = null;
-
- label.setText("downloading...");
-
- File dir = null;
- try {
- dir = new File(destDir);
- dir.mkdirs();
- }
- catch (Exception e) {}
- try {
- if (!dir.isDirectory() || !dir.canWrite()) return;
- }
- catch (Exception e) {
- return;
- }
-
- for (int i = 0; i < locs.length; i++) {
- try {
- URL url = new URL(locs[i]);
- URLConnection conn = url.openConnection();
- int length = conn.getContentLength();
- progress.setMaximum(length / 1024);
-
- in = conn.getInputStream();
-
- outFile = File.createTempFile("Jake2Data", ".zip");
- outFile.deleteOnExit();
- out = new FileOutputStream(outFile);
-
- copyStream(in, out);
- break;
- } catch (Exception e) {}
- }
- try {
- installData(outFile.getCanonicalPath());
- } catch (Exception e) {}
-
-
- try {
- if (outFile != null) outFile.delete();
- } catch (Exception e) {}
-
- parent.showChooseDialog();
- parent.okButtonActionPerformed(null);
- }
-
-
- void installData(String filename) {
- try {
- ZipFile f = new ZipFile(filename);
- Enumeration e = f.entries();
- while (e.hasMoreElements()) {
- ZipEntry entry = (ZipEntry)e.nextElement();
- String name = entry.getName();
- int i;
- if ((i = name.indexOf("/baseq2")) > -1 && name.indexOf(".dll") == -1) {
- name = destDir + name.substring(i);
- File outFile = new File(name);
- if (entry.isDirectory()) {
- outFile.mkdirs();
- } else {
- label.setText("installing " + outFile.getName());
- progress.setMaximum((int)entry.getSize()/1024);
- progress.setValue(0);
- outFile.getParentFile().mkdirs();
- OutputStream out = new FileOutputStream(outFile);
- InputStream in = f.getInputStream(entry);
- copyStream(in, out);
- }
- }
- }
- } catch (Exception e) {}
- }
-
- void copyStream(InputStream in, OutputStream out) {
- try {
- int c = 0;
- int l;
- while ((l = in.read(buf)) > 0) {
- out.write(buf, 0, l);
- c += l;
- progress.setValue(c / 1024);
- }
- } catch (Exception e) {}
-
- try {
- in.close();
- } catch (Exception e) {}
- try {
- out.close();
- } catch (Exception e) {}
- }
- }
-
-}
+/*
+ * Q2DataDialog.java
+ *
+ * Created on 17. September 2004, 20:13
+ */
+
+package jake2.qcommon;
+
+import java.awt.*;
+import java.io.*;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Enumeration;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import javax.swing.*;
+
+/**
+ *
+ * @author hoz
+ */
+public class Q2DataDialog extends javax.swing.JDialog {
+
+ /** Creates new form Q2DataDialog */
+ public Q2DataDialog() {
+ super();
+ initComponents();
+
+ DisplayMode mode = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDisplayMode();
+ int x = (mode.getWidth() - getWidth()) / 2;
+ int y = (mode.getHeight() - getHeight()) / 2;
+ setLocation(x, y);
+ dir = System.getProperty("user.home") + "/jake2";
+ jTextField1.setText(dir);
+ }
+
+ /** This method is called from within the constructor to
+ * initialize the form.
+ * WARNING: Do NOT modify this code. The content of this method is
+ * always regenerated by the Form Editor.
+ */
+ private void initComponents() {//GEN-BEGIN:initComponents
+ java.awt.GridBagConstraints gridBagConstraints;
+
+ choosePanel = new javax.swing.JPanel();
+ statusPanel = new JPanel();
+ status = new JLabel("initializing Jake2...");
+ jTextField1 = new javax.swing.JTextField();
+ changeButton = new javax.swing.JButton();
+ installButton = new javax.swing.JButton();
+ exitButton = new javax.swing.JButton();
+ okButton = new javax.swing.JButton();
+
+ setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
+ setTitle("Jake2 - Bytonic Software");
+
+ setResizable(false);
+ addWindowListener(new java.awt.event.WindowAdapter() {
+ public void windowClosing(java.awt.event.WindowEvent evt) {
+ formWindowClosing(evt);
+ }
+ });
+
+ choosePanel.setLayout(new java.awt.GridBagLayout());
+
+ choosePanel.setMaximumSize(new java.awt.Dimension(400, 100));
+ choosePanel.setMinimumSize(new java.awt.Dimension(400, 100));
+ choosePanel.setPreferredSize(new java.awt.Dimension(400, 100));
+ jTextField1.setPreferredSize(null);
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 0;
+ gridBagConstraints.gridy = 0;
+ gridBagConstraints.gridwidth = 2;
+ gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
+ gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10);
+ gridBagConstraints.weightx = 1.0;
+ choosePanel.add(jTextField1, gridBagConstraints);
+
+ changeButton.setText("change");
+ changeButton.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ changeButtonActionPerformed(evt);
+ }
+ });
+
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 2;
+ gridBagConstraints.gridy = 0;
+ gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10);
+ gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
+ choosePanel.add(changeButton, gridBagConstraints);
+
+ installButton.setText("Install");
+ installButton.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ installButtonActionPerformed(evt);
+ }
+ });
+
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 0;
+ gridBagConstraints.gridy = 1;
+ gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10);
+ gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
+ choosePanel.add(installButton, gridBagConstraints);
+
+ exitButton.setText("Exit");
+ exitButton.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ exitButtonActionPerformed(evt);
+ }
+ });
+
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 1;
+ gridBagConstraints.gridy = 1;
+ gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10);
+ choosePanel.add(exitButton, gridBagConstraints);
+
+ okButton.setText("OK");
+ okButton.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ okButtonActionPerformed(evt);
+ }
+ });
+
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 2;
+ gridBagConstraints.gridy = 1;
+ gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10);
+ gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
+ choosePanel.add(okButton, gridBagConstraints);
+
+ //getContentPane().add(choosePanel, java.awt.BorderLayout.SOUTH);
+
+ Jake2Canvas c = new Jake2Canvas();
+ getContentPane().add(c, BorderLayout.CENTER);
+
+ statusPanel.setLayout(new java.awt.GridBagLayout());
+ statusPanel.setMaximumSize(new java.awt.Dimension(400, 100));
+ statusPanel.setMinimumSize(new java.awt.Dimension(400, 100));
+ statusPanel.setPreferredSize(new java.awt.Dimension(400, 100));
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 0;
+ gridBagConstraints.gridy = 0;
+ gridBagConstraints.gridwidth = 1;
+ gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
+ gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10);
+ gridBagConstraints.weightx = 1.0;
+ statusPanel.add(status, gridBagConstraints);
+ getContentPane().add(statusPanel, java.awt.BorderLayout.SOUTH);
+
+ installPanel = new InstallPanel(this);
+
+ pack();
+ }//GEN-END:initComponents
+
+
+ private void installButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_installButtonActionPerformed
+ dir = jTextField1.getText();
+ showInstallPanel();
+ installPanel.destDir = dir;
+
+ dir += "/baseq2";
+ jTextField1.setText(dir);
+
+ new Thread(installPanel).start();
+ }//GEN-LAST:event_installButtonActionPerformed
+
+ private void exitButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exitButtonActionPerformed
+ System.exit(1);
+ dispose();
+ }//GEN-LAST:event_exitButtonActionPerformed
+
+ private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
+
+ dir = jTextField1.getText();
+ Cvar.Set("cddir", dir);
+ FS.setCDDir();
+
+ synchronized(this) {
+ notifyAll();
+ }
+ }//GEN-LAST:event_okButtonActionPerformed
+
+ private void changeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_changeButtonActionPerformed
+ JFileChooser chooser = new JFileChooser();
+ chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+ chooser.setDialogType(JFileChooser.CUSTOM_DIALOG);
+ chooser.setMultiSelectionEnabled(false);
+ chooser.setDialogTitle("choose a valid baseq2 directory");
+ chooser.showDialog(this, "OK");
+
+ dir = null;
+ try {
+ dir = chooser.getSelectedFile().getCanonicalPath();
+ } catch (IOException e) {}
+ jTextField1.setText(dir);
+
+ }//GEN-LAST:event_changeButtonActionPerformed
+
+ private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing
+ System.exit(1);
+ dispose();
+ }//GEN-LAST:event_formWindowClosing
+
+ // Variables declaration - do not modify//GEN-BEGIN:variables
+ private javax.swing.JButton changeButton;
+ private javax.swing.JButton exitButton;
+ private javax.swing.JButton installButton;
+ private Jake2Canvas canvas;
+ private javax.swing.JPanel choosePanel;
+ private JPanel statusPanel;
+ private InstallPanel installPanel;
+ private JLabel status;
+ private javax.swing.JTextField jTextField1;
+ private javax.swing.JButton okButton;
+ // End of variables declaration//GEN-END:variables
+
+ private String dir;
+
+ void showChooseDialog() {
+ getContentPane().remove(statusPanel);
+ getContentPane().remove(installPanel);
+ getContentPane().add(choosePanel, BorderLayout.SOUTH);
+ validate();
+ repaint();
+ }
+
+ void showStatus() {
+ getContentPane().remove(choosePanel);
+ getContentPane().add(statusPanel, BorderLayout.SOUTH);
+ validate();
+ repaint();
+ }
+
+ void showInstallPanel() {
+ getContentPane().remove(choosePanel);
+ getContentPane().add(installPanel, BorderLayout.SOUTH);
+ validate();
+ repaint();
+ }
+
+ void setStatus(String text) {
+ status.setText(text);
+ }
+
+ void testQ2Data() {
+ while (FS.LoadFile("pics/colormap.pcx") == null) {
+ showChooseDialog();
+
+ try {
+ synchronized(this) {
+ wait();
+ }
+ } catch (InterruptedException e) {}
+ }
+ showStatus();
+ repaint();
+ }
+
+ static class Jake2Canvas extends Canvas {
+ private Image image;
+ Jake2Canvas() {
+ setSize(400, 200);
+ image = Toolkit.getDefaultToolkit().getImage(getClass().getResource("/splash.png"));
+ while (!Toolkit.getDefaultToolkit().prepareImage(image, -1, -1, null)) {
+ try {
+ Thread.sleep(50);
+ } catch (InterruptedException e) {}
+ }
+ }
+
+
+ /* (non-Javadoc)
+ * @see java.awt.Component#paint(java.awt.Graphics)
+ */
+ public void paint(Graphics g) {
+ g.drawImage(image, 0, 0, null);
+ }
+
+ }
+
+ static class InstallPanel extends JPanel implements Runnable {
+
+ static final String[] locs = {
+ "ftp://ftp.fu-berlin.de/pc/msdos/games/idgames/idstuff/quake2/q2-314-demo-x86.exe",
+ "ftp://ftp.demon.co.uk/pub/mirrors/idsoftware/quake2/q2-314-demo-x86.exe",
+ "ftp://ftp.fragzone.se/pub/spel/quake2/q2-314-demo-x86.exe",
+ "ftp://ftp.idsoftware.com/idstuff/quake2/q2-314-demo-x86.exe" };
+ static byte[] buf = new byte[8192];
+ String destDir;
+
+ JProgressBar progress = new JProgressBar();
+ JLabel label = new JLabel("test");
+ Q2DataDialog parent;
+
+ public InstallPanel(Q2DataDialog d) {
+ initComponents();
+ parent = d;
+ }
+
+ void initComponents() {
+ progress.setMinimum(0);
+ progress.setMaximum(100);
+ setLayout(new GridBagLayout());
+ GridBagConstraints gridBagConstraints = new GridBagConstraints();
+
+ gridBagConstraints = new java.awt.GridBagConstraints();
+ gridBagConstraints.gridx = 0;
+ gridBagConstraints.gridy = 0;
+ gridBagConstraints.gridwidth = 1;
+ gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
+ gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 10);
+ gridBagConstraints.weightx = 1.0;
+ gridBagConstraints.anchor = GridBagConstraints.SOUTH;
+ add(label, gridBagConstraints);
+ gridBagConstraints.gridy = 1;
+ gridBagConstraints.anchor = GridBagConstraints.NORTH;
+ add(progress, gridBagConstraints);
+ Dimension d = new Dimension(400, 100);
+ setMinimumSize(d);
+ setMaximumSize(d);
+ setPreferredSize(d);
+ }
+
+ public void run() {
+
+ InputStream in = null;
+ OutputStream out = null;
+ File outFile = null;
+
+ label.setText("downloading...");
+
+ File dir = null;
+ try {
+ dir = new File(destDir);
+ dir.mkdirs();
+ }
+ catch (Exception e) {}
+ try {
+ if (!dir.isDirectory() || !dir.canWrite()) return;
+ }
+ catch (Exception e) {
+ return;
+ }
+
+ for (int i = 0; i < locs.length; i++) {
+ try {
+ URL url = new URL(locs[i]);
+ URLConnection conn = url.openConnection();
+ int length = conn.getContentLength();
+ progress.setMaximum(length / 1024);
+
+ in = conn.getInputStream();
+
+ outFile = File.createTempFile("Jake2Data", ".zip");
+ outFile.deleteOnExit();
+ out = new FileOutputStream(outFile);
+
+ copyStream(in, out);
+ break;
+ } catch (Exception e) {}
+ }
+ try {
+ installData(outFile.getCanonicalPath());
+ } catch (Exception e) {}
+
+
+ try {
+ if (outFile != null) outFile.delete();
+ } catch (Exception e) {}
+
+ parent.showChooseDialog();
+ parent.okButtonActionPerformed(null);
+ }
+
+
+ void installData(String filename) {
+ try {
+ ZipFile f = new ZipFile(filename);
+ Enumeration e = f.entries();
+ while (e.hasMoreElements()) {
+ ZipEntry entry = (ZipEntry)e.nextElement();
+ String name = entry.getName();
+ int i;
+ if ((i = name.indexOf("/baseq2")) > -1 && name.indexOf(".dll") == -1) {
+ name = destDir + name.substring(i);
+ File outFile = new File(name);
+ if (entry.isDirectory()) {
+ outFile.mkdirs();
+ } else {
+ label.setText("installing " + outFile.getName());
+ progress.setMaximum((int)entry.getSize()/1024);
+ progress.setValue(0);
+ outFile.getParentFile().mkdirs();
+ OutputStream out = new FileOutputStream(outFile);
+ InputStream in = f.getInputStream(entry);
+ copyStream(in, out);
+ }
+ }
+ }
+ } catch (Exception e) {}
+ }
+
+ void copyStream(InputStream in, OutputStream out) {
+ try {
+ int c = 0;
+ int l;
+ while ((l = in.read(buf)) > 0) {
+ out.write(buf, 0, l);
+ c += l;
+ progress.setValue(c / 1024);
+ }
+ } catch (Exception e) {}
+
+ try {
+ in.close();
+ } catch (Exception e) {}
+ try {
+ out.close();
+ } catch (Exception e) {}
+ }
+ }
+
+}
diff --git a/src/jake2/qcommon/netchan_t.java b/src/jake2/qcommon/netchan_t.java
index 06a283a..77022d6 100644
--- a/src/jake2/qcommon/netchan_t.java
+++ b/src/jake2/qcommon/netchan_t.java
@@ -1,79 +1,87 @@
/*
-Copyright (C) 1997-2001 Id Software, Inc.
+ * 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.
+ *
+ */
-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.
+// Created on 27.11.2003 by RST.
+// $Id: netchan_t.java,v 1.2 2004-09-22 19:22:09 salomo Exp $
+package jake2.qcommon;
-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.
+import jake2.*;
-See the GNU General Public License for more details.
+public class netchan_t {
-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.
+ public boolean fatal_error;
-*/
+ // was enum {NS_CLIENT, NS_SERVER}
+ public int sock;
-// Created on 27.11.2003 by RST.
-// $Id: netchan_t.java,v 1.1 2004-07-07 19:59:34 hzi Exp $
+ public int dropped; // between last packet and previous
-package jake2.qcommon;
+ public int last_received; // for timeouts
-import jake2.*;
+ public int last_sent; // for retransmits
-public class netchan_t {
+ public netadr_t remote_address = new netadr_t();
+
+ public int qport; // qport value to write when transmitting
+
+ // sequencing variables
+ public int incoming_sequence;
+
+ public int incoming_acknowledged;
+
+ public int incoming_reliable_acknowledged; // single bit
+ public int incoming_reliable_sequence; // single bit, maintained local
- public boolean fatal_error;
+ public int outgoing_sequence;
- // was enum {NS_CLIENT, NS_SERVER}
- public int sock;
+ public int reliable_sequence; // single bit
- public int dropped; // between last packet and previous
+ public int last_reliable_sequence; // sequence number of last send
- public int last_received; // for timeouts
- public int last_sent; // for retransmits
+ // reliable staging and holding areas
+ public sizebuf_t message = new sizebuf_t(); // writing buffer to send to
+ // server
- public netadr_t remote_address = new netadr_t();
- public int qport; // qport value to write when transmitting
+ public byte message_buf[] = new byte[Defines.MAX_MSGLEN - 16]; // leave
+ // space for
+ // header
- // sequencing variables
- public int incoming_sequence;
- public int incoming_acknowledged;
- public int incoming_reliable_acknowledged; // single bit
+ // message is copied to this buffer when it is first transfered
+ public int reliable_length;
- public int incoming_reliable_sequence; // single bit, maintained local
+ public byte reliable_buf[] = new byte[Defines.MAX_MSGLEN - 16]; // unpcked
+ // reliable
+ // message
- public int outgoing_sequence;
- public int reliable_sequence; // single bit
- public int last_reliable_sequence; // sequence number of last send
+ //ok.
+ public void clear() {
+ sock = dropped = last_received = last_sent = 0;
+ remote_address = new netadr_t();
+ qport = incoming_sequence = incoming_acknowledged = incoming_reliable_acknowledged = incoming_reliable_sequence = outgoing_sequence = reliable_sequence = last_reliable_sequence = 0;
+ message = new sizebuf_t();
- // reliable staging and holding areas
- public sizebuf_t message = new sizebuf_t(); // writing buffer to send to server
- public byte message_buf[] = new byte[Defines.MAX_MSGLEN - 16]; // leave space for header
+ message_buf = new byte[Defines.MAX_MSGLEN - 16];
- // message is copied to this buffer when it is first transfered
- int reliable_length;
-
- byte reliable_buf[] = new byte[Defines.MAX_MSGLEN - 16]; // unpcked reliable message
+ reliable_length = 0;
+ reliable_buf = new byte[Defines.MAX_MSGLEN - 16];
+ }
- //ok.
- public void clear()
- {
- sock=dropped=last_received=last_sent=0;
- remote_address = new netadr_t();
- qport = incoming_sequence = incoming_acknowledged = incoming_reliable_acknowledged = incoming_reliable_sequence
- = outgoing_sequence = reliable_sequence = last_reliable_sequence =0;
- message = new sizebuf_t();
-
- message_buf = new byte[Defines.MAX_MSGLEN - 16];
-
- reliable_length =0;
- reliable_buf = new byte[Defines.MAX_MSGLEN - 16];
- }
-
-}
+} \ No newline at end of file